GIT 17c44c62d6ec233f2f52cd036d0a7dd51c2d6da4 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git#ALL commit 0c7599c9bce56e3c7063436f53616eb58e8e816a Author: Scott Feldman Date: Wed Nov 9 02:18:52 2005 -0500 [netdrvr e100] experiment with doing RX in a similar manner to eepro100 I was going to say that eepro100's speedo_rx_link() does the same DMA abuse as e100, but then I noticed one little detail: eepro100 sets both EL (end of list) and S (suspend) bits in the RFD as it chains it to the RFD list. e100 was only setting the EL bit. Hmmm, that's interesting. That means that if HW reads a RFD with the S-bit set, it'll process that RFD and then suspend the receive unit. The receive unit will resume when SW clears the S-bit. There is no need for SW to restart the receive unit. Which means a lot of the receive unit state tracking code in the driver goes away. So here's a patch against 2.6.14. (Sorry for inlining it; the mailer I'm using now will mess with the word wrap). I can't test this on XScale (unless someone has an e100 module for Gumstix :) . It should be doing exactly what eepro100 does with RFDs. I don't believe this change will introduce a performance hit because the S-bit and EL-bit go hand-in-hand meaning if we're going to suspend because of the S- bit, we're on the last resource anyway, so we'll have to wait for SW to replenish. (cherry picked from 29e79da9495261119e3b2e4e7c72507348e75976 commit) commit 774117277159acff20ebb70679ec72e8ef08f9fe Author: Richard Knutsson Date: Tue Mar 6 02:41:58 2007 -0800 drivers/net/vioc/vioc_driver.c: replace pci_module_init with pci_register_driver Replace pci_module_init with pci_register_driver Signed-off-by: Richard Knutson Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 3f8832341a42374fe0adc9c433d69b5452f33942 Author: Andrew Morton Date: Tue Feb 20 12:03:46 2007 -0800 Fabric7 VIOC driver fixes drivers/net/vioc/vioc_driver.c: In function `vioc_free_resources': drivers/net/vioc/vioc_driver.c:364: warning: implicit declaration of function `vfree' drivers/net/vioc/vioc_driver.c: In function `vioc_alloc_resources': drivers/net/vioc/vioc_driver.c:547: warning: implicit declaration of function `vmalloc' drivers/net/vioc/vioc_driver.c:547: warning: assignment makes pointer from integer without a cast drivers/net/vioc/vioc_driver.c:572: warning: cast to pointer from integer of different size and drivers/net/vioc/vioc_irq.c:50:22: asm/apic.h: No such file or directory and drivers/net/vioc/vioc_transmit.c:64:21: asm/msr.h: No such file or directory and drivers/net/vioc/vioc_transmit.c: In function `vnic_alloc_tx_resources': drivers/net/vioc/vioc_transmit.c:917: warning: implicit declaration of function `vmalloc' drivers/net/vioc/vioc_transmit.c:917: warning: assignment makes pointer from integer without a cast drivers/net/vioc/vioc_transmit.c: In function `vnic_free_tx_resources': drivers/net/vioc/vioc_transmit.c:951: warning: implicit declaration of function `vfree' Cc: Sriram Chidambaram Acked-by: Fabric7 Driver-Support Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 6fddbb215fd9a8474c617dad790b6078a069dfeb Author: Sriram Chidambaram Date: Tue Feb 6 18:41:35 2007 -0800 Fabric7 VIOC driver source code This patch provides the Fabric7 VIOC driver source code. This patch is built against git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev.2.6.git Signed-off-by: Fabric7 Driver-Support Signed-off-by: Jeff Garzik commit 758b167cdedd8d524f995d1b81092b7853fb68b6 Author: Jan-Bernd Themann Date: Thu Mar 22 17:50:24 2007 +0100 ehea: code cleanup This patch includes: - code cleanup related to resource management - extended error data gathering for resource management - removing trailing whitespaces Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik commit 3b6de6c0925172c867d8147cf7b6637caee8bb88 Author: Jan-Bernd Themann Date: Thu Mar 22 17:49:42 2007 +0100 ehea: fix for dynamic lpar support The patch fixes bugs related to the probe / remove adapter functionality (handling of OFDT nodes) Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik commit cd8fe2eb43e6d977c3e013bdbf2115ed8c79ac59 Author: Deepak Saxena Date: Mon Mar 19 15:43:11 2007 -0700 Netpoll support for Sibyte MAC NETPOLL support for Sibyte MAC Signed-off-by: Manish Lachwani Signed-off-by: Deepak Saxena Signed-off-by: Jeff Garzik commit c438a768177229e965045c2a7291e1685b6582fb Author: Ramkrishna Vepa Date: Fri Mar 9 18:28:32 2007 -0800 S2io: Remove unused variables - Remove unused variables from s2io_nic structure - Changed the memory failure printk messages to print only in debug mode - Updated the copyright messages (Resending; due to patch being corrupted) Signed-off-by: Santosh Rastapur Signed-off-by: Jeff Garzik commit 84aa59fdccf87c982f4125f4c9d01215273239a7 Author: Ralf Baechle Date: Sun Mar 18 23:21:22 2007 +0000 MIPSnet: Modernize use platform_device API. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit 00e6018da2f6afc44bda16c9aa206f5b7cc81884 Author: Stephen Hemminger Date: Fri Mar 16 14:01:32 2007 -0700 skge: version 1.11 New version to track changes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 7779dbbb93e3fa86bb59be39695729f081688a22 Author: Stephen Hemminger Date: Fri Mar 16 14:01:31 2007 -0700 skge: rearrange fields Do some minor rearrangement of data structures to try and optimize cache usage. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit db4c11ee9662969a7bf6b80f185bfdf07297d613 Author: Stephen Hemminger Date: Fri Mar 16 14:01:30 2007 -0700 skge: transmit locking improvements Don't need to lock when processing transmit complete unless queue fills. Modeled after tg3. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit d792122def5567afb263bdfef2d3077d55413d15 Author: Stephen Hemminger Date: Fri Mar 16 14:01:29 2007 -0700 skge: ignore unused error interrupts The following hardware error bits only show up on Genesis chipset and are handled elsewhere, so they can be masked off. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit d5354dd889395d6f79e9603ebc7e22defa9beba9 Author: Michal Schmidt Date: Fri Mar 16 12:44:40 2007 +0100 [PATCH] airo: Make /sys/bus/pci/drivers/airo/{,un}bind work The way airo.c keeps track of all its devices is complicated and buggy as well (del_airo_dev forgets to free the memory add_airo_dev allocates). It's cleaner to use the standard list primitives. While we're at it, it's not necessary to put PCI cards in the list, because the kernel already keeps track of them. We can take advantage of it and use the .remove callback as it was meant to be. This makes /sys/bus/pci/drivers/airo/{,un}bind work. Signed-off-by: Michal Schmidt Signed-off-by: John W. Linville commit 617e90055a6a07c9869dbb011428310c1cbcb182 Author: Michal Schmidt Date: Fri Mar 16 12:40:00 2007 +0100 [PATCH] airo: Don't check for NULL before kfree() It's unnecessary to check for NULL before calling kfree(). Signed-off-by: Michal Schmidt Signed-off-by: John W. Linville commit ac66066e12369aa0c2d3c3ce2b962282924debfb Author: Larry Finger Date: Wed Mar 14 15:06:22 2007 -0500 [PATCH] bcm43xx:Eliminate some 'G Mode Enable' magic numbers In code manipulating the TM State Low register of 802.11 cores, two different magic numbers are used to reference the 'G Mode Enable' bit. One of these, 0x20000000, is clear, but the other, (0x800 << 18), is not. This patch replaces both types with a defined constant. In addition, two bits in the TM State High registers are given definitions to help in following the code. Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit 7e915baead7b871f84d8684138053beaaebd4f0e Author: Daniel Drake Date: Sun Mar 11 19:54:39 2007 +0000 [PATCH] zd1211rw: More device IDs ASUS A9Rp Tested by Serge zd1211b chip 0b05:171b v4802 high 00-17-31 AL2230_RF pa0 g-- ZyXEL G-202 Tested by Marcus D. Hanwell zd1211b chip 0586:3410 v4810 high 00-13-49 AL2230_RF pa0 g--- US Robotics USR805423 Tested by Pascal S. de Kloe FCC ID: RAXWN4501H zd1211b chip 0baf:0121 v4810 high 00-14-c1 AL2230_RF pa0 g--N Julien Pinon reports this also comes in AL2230S form Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 62cd2fd6cea376e337d8910b950677bad235d0b1 Author: Daniel Drake Date: Sun Mar 11 19:54:28 2007 +0000 [PATCH] zd1211rw: Add AL2230S RF support ZD1211 appears to be back in production: a number of new devices have been appearing! Some of them are using new radios. This patch adds support for the next generation AL2230 RF chip which has been spotted in a few new devices. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 9b0190459fe0016c78fa1df8b36b11a58faaf55a Author: Daniel Drake Date: Sun Mar 11 19:54:11 2007 +0000 [PATCH] zd1211rw: Reject AL2230S devices zd1211rw currently detects AL2230S-based devices as AL2230, and hence programs the RF incorrectly. Transmit silently fails on this misconfiguration. After this patch, AL2230S devices are rejected with an error message, to avoid any confusion with an apparent driver bug. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 81f4490f4c37c6e2c866246edf780abdfb2edc6d Author: Daniel Drake Date: Sun Mar 11 19:53:40 2007 +0000 [PATCH] zd1211rw: Use compare_ether_addr() Suggested by Maxime Austruy, based on mac80211 changes from Stephen Hemminger Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit ecfa29609807cd68a10b424d348e29faae946a9f Author: Valerie Henson Date: Mon Mar 12 02:31:34 2007 -0700 Rev tulip version Rev tulip version... things have changed since 2002! Signed-off-by: Valerie Henson Cc: Jeff Garzik Signed-off-by: Jeff Garzik commit ec0648ca76aa43e2ae03af274616f76c481723e9 Author: Valerie Henson Date: Mon Mar 12 02:31:33 2007 -0700 Fix tulip SytemError typo Fix an annoying typo - SytemError -> SystemError Signed-off-by: Valerie Henson Cc: Jeff Garzik Signed-off-by: Jeff Garzik commit 5ef1b75153a82a67256eb89d0d6248f1f40b3b2b Author: Thibaut VARENE Date: Mon Mar 12 02:31:30 2007 -0700 TULIP: Natsemi dp83840a PHY fix Fix a problem with Tulip 21142 HP branded PCI cards (PN#: B5509-66001), which feature a NatSemi DP83840A PHY. Without that patch, it is impossible to properly initialize the card's PHY, and it's thus impossible to monitor/configure it. [VAL: I'm happy with the 1.5 ms max delay; it doesn't seem excessive.] Signed-off-by: Thibaut VARENE Cc: Jeff Garzik Acked-by: Grant Grundler Signed-off-by: Valerie Henson Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 905d1a9ccebf9445843460f6faee0db69dc2bdfd Author: Valerie Henson Date: Mon Mar 12 02:31:29 2007 -0700 TULIP: Fix for 64-bit MIPS From: Jim Gifford , Grant Grundler , Peter Horton With Grant's help I was able to get the tulip driver to work with 64 bit MIPS. [VAL: I'm happy with the 1.5 ms max delay; it doesn't seem excessive.] Signed-off-by: Valerie Henson Signed-off-by: Andrew Morton Cc: Jeff Garzik Signed-off-by: Jeff Garzik commit 2a33038110a2d4337163a5dc10abb1232b150702 Author: Atsushi Nemoto Date: Thu Mar 15 00:10:37 2007 +0900 tc35815: Zap changelog from source code Signed-off-by: Atsushi Nemoto Signed-off-by: Jeff Garzik commit 22afe4d233741c249182f3e2175ddeaffd5d5e2b Author: Atsushi Nemoto Date: Wed Mar 14 01:02:20 2007 +0900 tc35815: Fix an usage of streaming DMA API. The tc35815 driver lacks a call to pci_dma_sync_single_for_device() on receiving. Recent fix of MIPS dma_sync_single_for_cpu() reveal this bug. Signed-off-by: Atsushi Nemoto Signed-off-by: Jeff Garzik commit ddb894a44086a3233776261cd3f85e9b6ffca799 Author: Don Fry Date: Tue Mar 6 10:55:00 2007 -0800 pcnet32: change to use netdev_priv use netdev_priv() instead of dev->priv Signed-off-by: Thomas Bogendoerfer Signed-off-by: Don Fry Signed-off-by: Jeff Garzik commit aada5e7a88ba488ef03a4f9443e26911e7005ce2 Author: Don Fry Date: Tue Mar 6 10:45:23 2007 -0800 pcnet32: only allocate init_block dma consistent The patch below moves the init_block out of the private struct and only allocates init block with pci_alloc_consistent. This has two effects: 1. Performance increase for non cache coherent machines, because the CPU only data in the private struct are now cached 2. locks are working now for platforms, which need to have locks in cached memory Signed-off-by: Thomas Bogendoerfer Acked-by: Don Fry Signed-off-by: Jeff Garzik commit 74231c22f0e0bfd94f0668867d248b48015d9ac5 Author: Ahmed S. Darwish Date: Tue Mar 6 11:08:28 2007 -0800 ixgb: Use ARRAY_SIZE macro when appropriate. Signed-off-by: Ahmed S. Darwish Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit 65507a4e438be21a9340d3b6837a6ed119d6f90f Author: Ramkrishna Vepa Date: Tue Mar 6 17:01:00 2007 -0800 S2IO: Save/Restore unused buffer mappings in 2/3 buffer mode - Save/Restore unused buffer mappings in 2/3 buffer mode to avoid frequent mapping - Save/Restore adapter reset count during adapter reset (Resending; forgot to cc netdev) Signed-off-by: Santosh Rastapur Signed-off-by: Jeff Garzik commit 677c46a263163f7ff4283f04cbe3f3decf11ae13 Author: Auke Kok Date: Tue Mar 6 08:58:06 2007 -0800 e1000: list e1000-devel mailing list in MAINTAINERS Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit 070c3619e1a4d3ad1e9aae0ec5c049ed2d735dd4 Author: Yan Burman Date: Tue Mar 6 08:58:04 2007 -0800 e1000: Use kcalloc() Replace kmalloc+memsetout the driver. Slightly modified by Auke Kok. Signed-off-by: Yan Burman Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit 4e0c3caf1a978940c7206b7e09a58c88a228877a Author: Ahmed S. Darwish Date: Tue Mar 6 08:58:02 2007 -0800 e1000: Use ARRAY_SIZE macro when appropriate A patch to use ARRAY_SIZE macro already defined in kernel.h. Signed-off-by: Ahmed S. Darwish Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit f1a32e2f66c331046c5629fb4362f9b2994fb457 Author: Sam Ravnborg Date: Sat Mar 3 23:55:08 2007 -0600 [PATCH] bcm43xx: do not rebuild when kernel version changes In bcm43xx_ethtool, UTS_RELEASE is used. Replacing this with utsname()->release avoids rebuilding this module each time the kernel version changes. Signed-off-by: Sam Ravnborg Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit fc92ece2d8000a994e54e663e5b10fe93e3926b0 Author: Jouni Malinen Date: Tue Feb 27 19:46:46 2007 -0800 [PATCH] hostap: Add D-Link DWL-650 Rev. P1 product id It looks like some of the PC Card manfid/product strings were lost when Host AP driver was converted to use PCMCIA_DEVICE_* helpers. This patch adds back D-Link DWL-650 Rev. P1 using the same product ID string match as the pcmcia-cs/cardmgr configuration used before. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville commit 6cf8d32b20bbfbbe462075fd95cfed521141beb0 Author: Andrew Morton Date: Thu Mar 1 08:19:29 2007 -0500 [PATCH] ipw2200: fix ieee80211_get_geo typo testing much? Cc: Zhu Yi Signed-off-by: Andrew Morton Signed-off-by: John W. Linville commit dffccffee588ff6ec7c4e468196248b8d4737488 Author: Shan Lu Date: Tue Mar 6 02:42:03 2007 -0800 network: add the missing phy_device speed information to phy_mii_ioctl Function `phy_mii_ioctl' returns physical device's information based on user requests. When requested to return the basic mode control register information (BMCR), the original implementation only returns the physical device's duplex information and forgets to return speed information, which should not be because BMCR register is used to hold both duplex and speed information. The patch checks the BMCR value against speed-related flags and fills the return structure's speed field accordingly. Signed-off-by: Shan Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 9c3339030e543fe971dcf31816abe74298a9390f Author: Dmitriy Monakhov Date: Tue Mar 6 02:42:01 2007 -0800 sk98lin: handle pci_enable_device() return value in skge_resume() Signed-off-by: Monakhov Dmitriy Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit d6a785df9d874c0cf29418998b705a5b493f5540 Author: Maxim Levitsky Date: Tue Mar 6 02:41:54 2007 -0800 dmfe: add support for Wake on lan Add support for WOL on Magic Packet and on link change Signed-off-by: Maxim Levitsky Cc: Valerie Henson Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 60d31f98ae7185fc6fcbbf7766289cc12b817d3c Author: Maxim Levitsky Date: Tue Mar 6 02:41:53 2007 -0800 dmfe: add support for suspend/resume This adds support for suspend resume [akpm@linux-foundation.org: fix CONFIG_PM=n, coding style] Signed-off-by: Maxim Levitsky Cc: Valerie Henson Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 7f69c183950ecef4810b92b2ab59ef7dbe9e582a Author: Randy Dunlap Date: Tue Mar 6 02:41:48 2007 -0800 phy layer: add kernel-doc + DocBook Convert function documentation in drivers/net/phy/ to kernel-doc and add it to DocBook. Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit e672ccfa09d7534208cb4427d89ba097b42072cd Author: Arjan van de Ven Date: Tue Mar 6 02:41:48 2007 -0800 user of the jiffies rounding code: e1000 Use the round_jiffies() function in e1000. These timers all were of the "about once a second" or "about once every X seconds" variety and several showed up in the "what wakes the cpu up" profiles that the tickless patches provide. Some timers are highly dynamic based on network load; but even on low activity systems they still show up so the rounding is done only in cases of low activity, allowing higher frequency timers in the high activity case. The various hardware watchdogs are an obvious case; they run every 2 seconds but aren't otherwise specific of exactly when they need to run. Signed-off-by: Arjan van de Ven Acked-by: Auke Kok Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit c7f385452a18f0c63d67cdf2e06a0a117f954384 Author: Atsushi Nemoto Date: Sat Mar 3 23:54:59 2007 +0900 tc35815 driver update (take 2) Current tc35815 driver is very obsolete and less maintained for a long time. Replace it with a new driver based on one from CELF patch archive. Major advantages of CELF version (version 1.23, for kernel 2.6.10) are: * Independent of JMR3927. (Actually independent of MIPS, but AFAIK the chip is used only on MIPS platforms) * TX4938 support. * 64-bit proof. * Asynchronous and on-demand auto negotiation. * High performance on non-coherent architecture. * ethtool support. * Many bugfixes and cleanups. And improvoments since version 1.23 are: * TX4939 support. * NETPOLL support. * NAPI support. (disabled by default) * Reduce memcpy on receiving. * PM support. * Many cleanups and bugfixes. Signed-off-by: Atsushi Nemoto Signed-off-by: Jeff Garzik commit 001fc8d2582c52f95aed7c103e334a81ca41e905 Author: Adrian Bunk Date: Mon Mar 5 02:49:27 2007 +0100 drivers/net/qla3xxx.c: make 2 functions static This patch makes two needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik commit fcd6b47a1d1ae074e364cd716f6bce0fb2909ab4 Author: Adrian Bunk Date: Mon Mar 5 02:49:25 2007 +0100 make drivers/net/s2io.c:vlan_strip_flag static This patch makes the needlessly global vlan_strip_flag static. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik commit f7f321f2963a92ebb39240b9df2ea05c3f0e0a17 Author: Ladislav Michl Date: Wed Feb 28 01:18:35 2007 +0000 Add support for Seeq 8003 on Challenge S Mezz board. Thanks to Jö Fahlke for donating hardware. Signed-off-by: Ladislav Michl Forward porting of Ladis' 2.4 patch. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit 52a82debb9a8488d471fcd322a4c685fd3657854 Author: Jan-Bernd Themann Date: Wed Feb 28 18:34:10 2007 +0100 ehea: NAPI multi queue TX/RX path for SMP This patch provides a functionality that allows parallel RX processing on multiple RX queues by using dummy netdevices. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik commit c564f77d1cc9e7974945b203a42f52eda1253754 Author: Jan-Bernd Themann Date: Wed Feb 28 18:34:02 2007 +0100 ehea: dynamic add / remove port This patch introduces functionality to dynamically add / remove ehea ports via an userspace DLPAR tool. It creates a subnode for each logical port in the sysfs. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik commit 9689d3cf4c141cd265e5e0a4824669b987b9533b Author: Stephen Hemminger Date: Tue Feb 20 15:58:02 2007 -0800 chelsio: use const for virtual functions There are several uses of _ops structure in this driver that can be converted to const. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit d6171a83bc4ca58c1d17c81f5506b2310f01392a Author: Stephen Hemminger Date: Tue Feb 20 15:58:01 2007 -0800 chelsio: use C99 style initialization Convert some initialized structures to C99 style. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 82a52fc53f087d27750e53c2af447c698eca3d83 Author: Stephen Hemminger Date: Tue Feb 20 15:58:00 2007 -0800 chelsio: remove unused code for 1G boards Some code for Chelsio 1G boards was put in the driver based on the vendor version (minus TOE). Well some of those board versions are only supported with TOE on the vendor driver, so additional dead code was added. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 99c1749ca5282e05c80d25bdc737b238af41424b Author: John W. Linville Date: Tue Feb 27 14:39:04 2007 -0500 [PATCH] libertas: fix build breakage from netdev class_device -> device Signed-off-by: John W. Linville commit be1834759e49b9e30c8232dedc5c8ddd745accc0 Author: John W. Linville Date: Tue Feb 27 13:41:26 2007 -0500 [PATCH] wireless: remove obsolete text files Signed-off-by: John W. Linville commit 03126b0045e8eaea5bd119dc8f22ad165365a2f6 Author: Larry Finger Date: Tue Feb 20 10:33:13 2007 -0600 [PATCH] bcm43xx: Update Documentation/bcm43xx.txt The in-kernel documentation of the bcm43xx driver is out of date. Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit 4607656912a5c80de82c7db503e1028de463224d Author: Pavel Roskin Date: Sun Feb 18 20:44:06 2007 -0500 [PATCH] hostap: use offsetof() instead of own equivalent The original macros result in gcc 4.2 warning about "cast from pointer to integer of different size" on 64-bit systems. Use of offsetof() on fields in substructures is widespread throughout the kernel code and should work whether offsetof() is defined using __compiler_offsetof() or a cast. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville commit 3c52b721de6681f51d6d7c3c5e480edf63cb88a4 Author: Marcelo Tosatti Date: Sat Feb 10 12:25:27 2007 -0200 [PATCH] Marvell Libertas 8388 802.11b/g USB driver Add the Marvell Libertas 8388 802.11 USB driver. Signed-off-by: Marcelo Tosatti Signed-off-by: John W. Linville commit c96bb297cbf6f32158032d8aa78bfe71924317f8 Author: Ulrich Kunitz Date: Sun Feb 18 20:28:23 2007 +0000 [PATCH] zd1211rw: changed GFP_NOFS to GFP_KERNEL Michael Buesch commented that GFP_NOFS should not be used in a network driver. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 8dd7c69eb452d8236a990fae3b7611ad149376b4 Author: Zhu Yi Date: Wed Feb 14 16:04:24 2007 +0800 [PATCH] ipw2200: add channels sysfs entry Add 'channels' sysfs entry for ipw2200. The entry exports channels information for the user space. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville commit a00820de74f070c6f73f7607bf2378f531fef9d6 Author: Mark Huth Date: Tue Mar 6 08:57:26 2007 -0800 e1000: FIX: Stop raw interrupts disabled nag from RT Current e1000_xmit_frame spews raw interrupt disabled nag messages when used with RT kernel patches. This patch uses spin_trylock_irqsave, which allows RT patches to properly manage the irq semantics. Signed-off-by: Mark Huth Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit 23c3bf8f06a8c04bfd6e270a6f07d1a21ab3fbc4 Author: Bruce Allan Date: Tue Mar 6 08:57:24 2007 -0800 e1000: FIX: firmware handover bits Upon code inspection it was spotted that the firmware handover bit get/set mismatched, which may have resulted in management issues on PCI-E adapters. Setting them correctly may fix some management issues such as arp routing etc. Signed-off-by: Auke Kok Signed-off-by: Bruce Allan Signed-off-by: Jeff Garzik commit 41a32c069fea1c14df48ac3cea26e49c4b46f25b Author: Auke Kok Date: Tue Mar 6 08:57:21 2007 -0800 e1000: FIX: be ready for incoming irq at pci_request_irq DEBUG_SHIRQ code exposed that e1000 was not ready for incoming interrupts after having called pci_request_irq. This obviously requires us to finish our software setup which assigns the irq handler before we request the irq. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik commit 7c2e5bbcac4879992851ab89dd65d7378ee42e40 Author: Sam Ravnborg Date: Sat Mar 3 23:55:08 2007 -0600 [PATCH] bcm43xx: do not rebuild when kernel version changes In bcm43xx_ethtool, UTS_RELEASE is used. Replacing this with utsname()->release avoids rebuilding this module each time the kernel version changes. Signed-off-by: Sam Ravnborg Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit c6ae9f8c752a6ce29f8fec18c7cea60703db51fc Author: Jouni Malinen Date: Tue Feb 27 19:46:46 2007 -0800 [PATCH] hostap: Add D-Link DWL-650 Rev. P1 product id It looks like some of the PC Card manfid/product strings were lost when Host AP driver was converted to use PCMCIA_DEVICE_* helpers. This patch adds back D-Link DWL-650 Rev. P1 using the same product ID string match as the pcmcia-cs/cardmgr configuration used before. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville commit d8d94d13bfef43575c7db87e717fb83ca80cc661 Author: Andrew Morton Date: Thu Mar 1 08:19:29 2007 -0500 [PATCH] ipw2200: fix ieee80211_get_geo typo testing much? Cc: Zhu Yi Signed-off-by: Andrew Morton Signed-off-by: John W. Linville commit a0e18003a6b9e9d24634bf725bceb1b381d99366 Author: John W. Linville Date: Tue Feb 27 13:41:26 2007 -0500 [PATCH] wireless: remove obsolete text files Signed-off-by: John W. Linville commit e0d7b8f1190c0e309bf81f6485e1449371a21a7f Author: Larry Finger Date: Tue Feb 20 10:33:13 2007 -0600 [PATCH] bcm43xx: Update Documentation/bcm43xx.txt The in-kernel documentation of the bcm43xx driver is out of date. Signed-off-by: Larry Finger Signed-off-by: John W. Linville commit 375c1c3dfd8f666f4ce4cc6f3091d995800ec06b Author: Pavel Roskin Date: Sun Feb 18 20:44:06 2007 -0500 [PATCH] hostap: use offsetof() instead of own equivalent The original macros result in gcc 4.2 warning about "cast from pointer to integer of different size" on 64-bit systems. Use of offsetof() on fields in substructures is widespread throughout the kernel code and should work whether offsetof() is defined using __compiler_offsetof() or a cast. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville commit 797cad60f3cc6cf07c3d264f0f841c78d62a5577 Author: Ulrich Kunitz Date: Sun Feb 18 20:28:23 2007 +0000 [PATCH] zd1211rw: changed GFP_NOFS to GFP_KERNEL Michael Buesch commented that GFP_NOFS should not be used in a network driver. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 95d680bd744415b89fd25acf9e0622a4daf7e1e2 Author: Zhu Yi Date: Wed Feb 14 16:04:24 2007 +0800 [PATCH] ipw2200: add channels sysfs entry Add 'channels' sysfs entry for ipw2200. The entry exports channels information for the user space. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville Documentation/DocBook/kernel-api.tmpl | 6 Documentation/networking/bcm43xx.txt | 97 + Documentation/networking/vioc.txt | 98 + MAINTAINERS | 8 arch/mips/mips-boards/sim/Makefile | 3 arch/mips/mips-boards/sim/sim_platform.c | 35 drivers/net/Kconfig | 16 drivers/net/Makefile | 1 drivers/net/chelsio/Makefile | 4 drivers/net/chelsio/common.h | 6 drivers/net/chelsio/cphy.h | 16 drivers/net/chelsio/gmac.h | 10 drivers/net/chelsio/ixf1010.c | 505 ---- drivers/net/chelsio/mac.c | 2 drivers/net/chelsio/mv88e1xxx.c | 8 drivers/net/chelsio/mv88x201x.c | 8 drivers/net/chelsio/my3126.c | 8 drivers/net/chelsio/pm3393.c | 8 drivers/net/chelsio/subr.c | 199 +- drivers/net/chelsio/vsc7326.c | 2 drivers/net/chelsio/vsc8244.c | 367 --- drivers/net/chelsio/vsc8244_reg.h | 172 - drivers/net/e100.c | 72 - drivers/net/e1000/e1000_ethtool.c | 28 drivers/net/e1000/e1000_main.c | 139 + drivers/net/ehea/ehea.h | 19 drivers/net/ehea/ehea_main.c | 781 ++++--- drivers/net/ehea/ehea_phyp.c | 6 drivers/net/ehea/ehea_phyp.h | 6 drivers/net/ehea/ehea_qmr.c | 184 +- drivers/net/ehea/ehea_qmr.h | 14 drivers/net/ixgb/ixgb_param.c | 4 drivers/net/mipsnet.c | 53 drivers/net/pcnet32.c | 159 + drivers/net/phy/mdio_bus.c | 19 drivers/net/phy/phy.c | 194 +- drivers/net/phy/phy_device.c | 114 + drivers/net/qla3xxx.c | 4 drivers/net/s2io-regs.h | 2 drivers/net/s2io.c | 77 - drivers/net/s2io.h | 8 drivers/net/sb1250-mac.c | 23 drivers/net/sgiseeq.c | 28 drivers/net/sk98lin/skge.c | 20 drivers/net/skge.c | 30 drivers/net/skge.h | 10 drivers/net/tc35815.c | 2554 ++++++++++++++++------ drivers/net/tulip/dmfe.c | 118 + drivers/net/tulip/interrupt.c | 4 drivers/net/tulip/media.c | 40 drivers/net/tulip/tulip.h | 9 drivers/net/tulip/tulip_core.c | 6 drivers/net/tulip/winbond-840.c | 2 drivers/net/vioc/Makefile | 34 drivers/net/vioc/driver_version.h | 27 drivers/net/vioc/f7/spp.h | 68 + drivers/net/vioc/f7/spp_msgdata.h | 54 drivers/net/vioc/f7/sppapi.h | 240 ++ drivers/net/vioc/f7/vioc_bmc_registers.h | 1343 ++++++++++++ drivers/net/vioc/f7/vioc_ht_registers.h | 771 +++++++ drivers/net/vioc/f7/vioc_hw_registers.h | 160 + drivers/net/vioc/f7/vioc_ihcu_registers.h | 550 +++++ drivers/net/vioc/f7/vioc_le_registers.h | 241 ++ drivers/net/vioc/f7/vioc_msi_registers.h | 111 + drivers/net/vioc/f7/vioc_pkts_defs.h | 853 +++++++ drivers/net/vioc/f7/vioc_veng_registers.h | 299 +++ drivers/net/vioc/f7/vioc_ving_registers.h | 327 +++ drivers/net/vioc/f7/vnic_defs.h | 2168 +++++++++++++++++++ drivers/net/vioc/khash.h | 65 + drivers/net/vioc/spp.c | 626 +++++ drivers/net/vioc/spp_vnic.c | 131 + drivers/net/vioc/vioc_api.c | 384 +++ drivers/net/vioc/vioc_api.h | 64 + drivers/net/vioc/vioc_driver.c | 873 ++++++++ drivers/net/vioc/vioc_ethtool.c | 303 +++ drivers/net/vioc/vioc_irq.c | 514 ++++ drivers/net/vioc/vioc_provision.c | 226 ++ drivers/net/vioc/vioc_receive.c | 367 +++ drivers/net/vioc/vioc_spp.c | 390 +++ drivers/net/vioc/vioc_transmit.c | 1034 +++++++++ drivers/net/vioc/vioc_vnic.h | 515 ++++ drivers/net/wireless/Kconfig | 13 drivers/net/wireless/Makefile | 1 drivers/net/wireless/README | 25 drivers/net/wireless/airo.c | 70 - drivers/net/wireless/bcm43xx/bcm43xx.h | 3 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c | 4 drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 8 drivers/net/wireless/hostap/hostap_common.h | 4 drivers/net/wireless/hostap/hostap_cs.c | 5 drivers/net/wireless/ipw2200.c | 47 drivers/net/wireless/libertas/11d.c | 754 +++++++ drivers/net/wireless/libertas/11d.h | 105 + drivers/net/wireless/libertas/LICENSE | 16 drivers/net/wireless/libertas/Makefile | 21 drivers/net/wireless/libertas/README | 1044 +++++++++ drivers/net/wireless/libertas/assoc.c | 588 +++++ drivers/net/wireless/libertas/assoc.h | 30 drivers/net/wireless/libertas/cmd.c | 1958 +++++++++++++++++ drivers/net/wireless/libertas/cmdresp.c | 1031 +++++++++ drivers/net/wireless/libertas/debugfs.c | 1968 +++++++++++++++++ drivers/net/wireless/libertas/debugfs.h | 6 drivers/net/wireless/libertas/decl.h | 83 + drivers/net/wireless/libertas/defs.h | 369 +++ drivers/net/wireless/libertas/dev.h | 403 +++ drivers/net/wireless/libertas/ethtool.c | 184 ++ drivers/net/wireless/libertas/fw.c | 361 +++ drivers/net/wireless/libertas/fw.h | 13 drivers/net/wireless/libertas/host.h | 338 +++ drivers/net/wireless/libertas/hostcmd.h | 693 ++++++ drivers/net/wireless/libertas/if_bootcmd.c | 38 drivers/net/wireless/libertas/if_usb.c | 952 ++++++++ drivers/net/wireless/libertas/if_usb.h | 109 + drivers/net/wireless/libertas/ioctl.c | 2500 ++++++++++++++++++++++ drivers/net/wireless/libertas/join.c | 1055 +++++++++ drivers/net/wireless/libertas/join.h | 64 + drivers/net/wireless/libertas/main.c | 1258 +++++++++++ drivers/net/wireless/libertas/radiotap.h | 57 drivers/net/wireless/libertas/rx.c | 459 ++++ drivers/net/wireless/libertas/sbi.h | 40 drivers/net/wireless/libertas/scan.c | 2044 ++++++++++++++++++ drivers/net/wireless/libertas/scan.h | 216 ++ drivers/net/wireless/libertas/thread.h | 52 drivers/net/wireless/libertas/tx.c | 285 ++ drivers/net/wireless/libertas/types.h | 289 +++ drivers/net/wireless/libertas/version.h | 8 drivers/net/wireless/libertas/wext.c | 2769 ++++++++++++++++++++++++ drivers/net/wireless/libertas/wext.h | 147 + drivers/net/wireless/todo.txt | 15 drivers/net/wireless/zd1211rw/zd_chip.c | 10 drivers/net/wireless/zd1211rw/zd_chip.h | 2 drivers/net/wireless/zd1211rw/zd_mac.c | 10 drivers/net/wireless/zd1211rw/zd_rf.c | 2 drivers/net/wireless/zd1211rw/zd_rf.h | 2 drivers/net/wireless/zd1211rw/zd_rf_al2230.c | 83 + drivers/net/wireless/zd1211rw/zd_usb.c | 23 include/linux/pci_ids.h | 2 include/net/ieee80211_radiotap.h | 31 139 files changed, 38933 insertions(+), 2782 deletions(-) diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 0bb9023..b61dfc7 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -236,6 +236,12 @@ X!Ilib/string.c !Enet/core/dev.c !Enet/ethernet/eth.c !Iinclude/linux/etherdevice.h +!Edrivers/net/phy/phy.c +!Idrivers/net/phy/phy.c +!Edrivers/net/phy/phy_device.c +!Idrivers/net/phy/phy_device.c +!Edrivers/net/phy/mdio_bus.c +!Idrivers/net/phy/mdio_bus.c diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt index 28541d2..a136721 100644 --- a/Documentation/networking/bcm43xx.txt +++ b/Documentation/networking/bcm43xx.txt @@ -2,35 +2,88 @@ BCM43xx Linux Driver Project ============================ -About this software -------------------- +Introduction +------------ -The goal of this project is to develop a linux driver for Broadcom -BCM43xx chips, based on the specification at -http://bcm-specs.sipsolutions.net/ +Many of the wireless devices found in modern notebook computers are +based on the wireless chips produced by Broadcom. These devices have +been a problem for Linux users as there is no open-source driver +available. In addition, Broadcom has not released specifications +for the device, and driver availability has been limited to the +binary-only form used in the GPL versions of AP hardware such as the +Linksys WRT54G, and the Windows and OS X drivers. Before this project +began, the only way to use these devices were to use the Windows or +OS X drivers with either the Linuxant or ndiswrapper modules. There +is a strong penalty if this method is used as loading the binary-only +module "taints" the kernel, and no kernel developer will help diagnose +any kernel problems. -The project page is http://bcm43xx.berlios.de/ +Development +----------- +This driver has been developed using +a clean-room technique that is described at +http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal +reasons, none of the clean-room crew works on the on the Linux driver, +and none of the Linux developers sees anything but the specifications, +which are the ultimate product of the reverse-engineering group. -Requirements ------------- +Software +-------- + +Since the release of the 2.6.17 kernel, the bcm43xx driver has been +distributed with the kernel source, and is prebuilt in most, if not +all, distributions. There is, however, additional software that is +required. The firmware used by the chip is the intellectual property +of Broadcom and they have not given the bcm43xx team redistribution +rights to this firmware. Since we cannot legally redistribute +the firwmare we cannot include it with the driver. Furthermore, it +cannot be placed in the downloadable archives of any distributing +organization; therefore, the user is responsible for obtaining the +firmware and placing it in the appropriate location so that the driver +can find it when initializing. + +To help with this process, the bcm43xx developers provide a separate +program named bcm43xx-fwcutter to "cut" the firmware out of a +Windows or OS X driver and write the extracted files to the proper +location. This program is usually provided with the distribution; +however, it may be downloaded from + +http://developer.berlios.de/project/showfiles.php?group_id=4547 -1) Linux Kernel 2.6.16 or later - http://www.kernel.org/ +The firmware is available in two versions. V3 firmware is used with +the in-kernel bcm43xx driver that uses a software MAC layer called +SoftMAC, and will have a microcode revision of 0x127 or smaller. The +V4 firmware is used by an out-of-kernel driver employing a variation of +the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches +a satisfactory level of development, it will replace bcm43xx-softmac +in the kernel as it is much more flexible and powerful. - You may want to configure your kernel with: +A source for the latest V3 firmware is - CONFIG_DEBUG_FS (optional): - -> Kernel hacking - -> Debug Filesystem +http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o -2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 - modules: - http://softmac.sipsolutions.net/ +Once this file is downloaded, the command +'bcm43xx-fwcutter -w ' +will extract the microcode and write it to directory +. The correct directory will depend on your distribution; +however, most use '/lib/firmware'. Once this step is completed, +the bcm3xx driver should load when the system is booted. To see +any messages relating to the driver, issue the command 'dmesg | +grep bcm43xx' from a terminal window. If there are any problems, +please send that output to Bcm43xx-dev@lists.berlios.de. -3) Firmware Files +Although the driver has been in-kernel since 2.6.17, the earliest +version is quite limited in its capability. Patches that include +all features of later versions are available for the stable kernel +versions from 2.6.18. These will be needed if you use a BCM4318, +or a PCI Express version (BCM4311 and BCM4312). In addition, if you +have an early BCM4306 and more than 1 GB RAM, your kernel will need +to be patched. These patches, which are being updated regularly, +are available at ftp://lwfinger.dynalias.org/patches. Look for +combined_2.6.YY.patch. Of course you will need kernel source downloaded +from kernel.org, or the source from your distribution. - Please try fwcutter. Fwcutter can extract the firmware from various - binary driver files. It supports driver files from Windows, MacOS and - Linux. You can get fwcutter from http://bcm43xx.berlios.de/. - Also, fwcutter comes with a README file for further instructions. +If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG +and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is +essential for solving any problems. diff --git a/Documentation/networking/vioc.txt b/Documentation/networking/vioc.txt new file mode 100644 index 0000000..f735fa9 --- /dev/null +++ b/Documentation/networking/vioc.txt @@ -0,0 +1,98 @@ + VIOC Driver Release Notes (07/12/06) + ==================================== + driver-support@fabric7.com + + +Overview +======== + +A Virtual Input-Output Controller (VIOC) is a PCI device that provides +10Gbps of I/O bandwidth that can be shared by up to 16 virtual network +interfaces (VNICs). VIOC hardware supports several features such as +large frames, checksum offload, gathered send, MSI/MSI-X, bandwidth +control, interrupt mitigation, etc. + +VNICs are provisioned to a host partition via an out-of-band interface +from the System Controller -- typically before the partition boots, +although they can be dynamically added or removed from a running +partition as well. + +Each provisioned VNIC appears as an Ethernet netdevice to the host OS, +and maintains its own transmit ring in DMA memory. VNICs are +configured to share up to 4 of total 16 receive rings and 1 of total +16 receive-completion rings in DMA memory. VIOC hardware classifies +packets into receive rings based on size, allowing more efficient use +of DMA buffer memory. The default, and recommended, configuration +uses groups of 'receive sets' (rxsets), each with 3 receive rings, a +receive completion ring, and a VIOC Rx interrupt. The driver gives +each rxset a NAPI poll handler associated with a phantom (invisible) +netdevice, for concurrency. VNICs are assigned to rxsets using a +simple modulus. + +VIOC provides 4 interrupts in INTx mode: 2 for Rx, 1 for Tx, and 1 for +out-of-band messages from the System Controller and errors. VIOC also +provides 19 MSI-X interrupts: 16 for Rx, 1 for Tx, 1 for out-of-band +messages from the System Controller, and 1 for error signalling from +the hardware. The VIOC driver makes a determination whether MSI-X +functionality is supported and initializes interrupts accordingly. +[Note: The Linux kernel disables MSI-X for VIOCs on modules with AMD +8131, even if the device is on the HT link.] + + +Module loadable parameters +========================== + +- poll_weight (default 8) - the number of received packets will be + processed during one call into the NAPI poll handler. + +- rx_intr_timeout (default 1) - hardware rx interrupt mitigation + timer, in units of 5us. + +- rx_intr_pkt_cnt (default 64) - hardware rx interrupt mitigation + counter, in units of packets. + +- tx_pkts_per_irq (default 64) - hardware tx interrupt mitigation + counter, in units of packets. + +- tx_pkts_per_bell (default 1) - the number of packets to enqueue on a + transmit ring before issuing a doorbell to hardware. + +Performance Tuning +================== + +You may want to use the following sysctl settings to improve +performance. [NOTE: To be re-checked] + +# set in /etc/sysctl.conf + +net.ipv4.tcp_timestamps = 0 +net.ipv4.tcp_sack = 0 +net.ipv4.tcp_rmem = 10000000 10000000 10000000 +net.ipv4.tcp_wmem = 10000000 10000000 10000000 +net.ipv4.tcp_mem = 10000000 10000000 10000000 + +net.core.rmem_max = 5242879 +net.core.wmem_max = 5242879 +net.core.rmem_default = 5242879 +net.core.wmem_default = 5242879 +net.core.optmem_max = 5242879 +net.core.netdev_max_backlog = 100000 + +Out-of-band Communications with System Controller +================================================= + +System operators can use the out-of-band facility to allow for remote +shutdown or reboot of the host partition. Upon receiving such a +command, the VIOC driver executes "/sbin/reboot" or "/sbin/shutdown" +via the usermodehelper() call. + +This same communications facility is used for dynamic VNIC +provisioning (plug in and out). + +The VIOC driver also registers a callback with +register_reboot_notifier(). When the callback is executed, the driver +records the shutdown event and reason in a VIOC register to notify the +System Controller. + + + diff --git a/MAINTAINERS b/MAINTAINERS index 2524323..3843455 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1794,6 +1794,7 @@ P: Jeff Kirsher M: jeffrey.t.kirsher@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com +L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1808,6 +1809,7 @@ P: Jeff Kirsher M: jeffrey.t.kirsher@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com +L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1822,6 +1824,7 @@ P: Jesse Brandeburg M: jesse.brandeburg@intel.com P: Auke Kok M: auke-jan.h.kok@intel.com +L: e1000-devel@lists.sourceforge.net W: http://sourceforge.net/projects/e1000/ S: Supported @@ -3696,6 +3699,11 @@ L: rio500-users@lists.sourceforge.net W: http://rio500.sourceforge.net S: Maintained +VIOC NETWORK DRIVER +P: support@fabric7.com +L: netdev@vger.kernel.org +S: Maintained + VIDEO FOR LINUX P: Mauro Carvalho Chehab M: mchehab@infradead.org diff --git a/arch/mips/mips-boards/sim/Makefile b/arch/mips/mips-boards/sim/Makefile index 6aeebc9..dc0bfda 100644 --- a/arch/mips/mips-boards/sim/Makefile +++ b/arch/mips/mips-boards/sim/Makefile @@ -17,7 +17,8 @@ # with this program; if not, write to th # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # -obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o +obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \ + sim_cmdline.o obj-$(CONFIG_EARLY_PRINTK) += sim_console.o obj-$(CONFIG_SMP) += sim_smp.o diff --git a/arch/mips/mips-boards/sim/sim_platform.c b/arch/mips/mips-boards/sim/sim_platform.c new file mode 100644 index 0000000..53210a8 --- /dev/null +++ b/arch/mips/mips-boards/sim/sim_platform.c @@ -0,0 +1,35 @@ +/* + * 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) 2007 by Ralf Baechle (ralf@linux-mips.org) + */ +#include +#include +#include +#include + +static char mipsnet_string[] = "mipsnet"; + +static struct platform_device eth1_device = { + .name = mipsnet_string, + .id = 0, +}; + +/* + * Create a platform device for the GPI port that receives the + * image data from the embedded camera. + */ +static int __init mipsnet_devinit(void) +{ + int err; + + err = platform_device_register(ð1_device); + if (err) + printk(KERN_ERR "%s: registration failed\n", mipsnet_string); + + return err; +} + +device_initcall(mipsnet_devinit); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c3f9f59..d50e60d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM enables offloading for checksums on transmit. If unsure, say Y. config MIPS_SIM_NET - tristate "MIPS simulator Network device (EXPERIMENTAL)" - depends on MIPS_SIM && EXPERIMENTAL + tristate "MIPS simulator Network device" + depends on NET_ETHERNET && MIPS_SIM help The MIPSNET device is a simple Ethernet network device which is emulated by the MIPS Simulator. @@ -1444,7 +1444,8 @@ config CS89x0 config TC35815 tristate "TOSHIBA TC35815 Ethernet support" - depends on NET_PCI && PCI && TOSHIBA_JMR3927 + depends on NET_PCI && PCI && MIPS + select MII config DGRS tristate "Digi Intl. RightSwitch SE-X support" @@ -2493,6 +2494,15 @@ config PASEMI_MAC This driver supports the on-chip 1/10Gbit Ethernet controller on PA Semi's PWRficient line of chips. +config VIOC + tristate "Fabric7 VIOC support" + depends on PCI + help + This driver supports the Virtual Input-Output Controller (VIOC) a + single PCI device that provides 10Gbps of I/O bandwidth that can be + shared by up to 16 virtual network interfaces (VNICs). + See for more information + endmenu source "drivers/net/tokenring/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 33af833..c53fa03 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ +obj-$(CONFIG_VIOC) += vioc/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atl1/ diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 382d23f..743ad8b 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile @@ -4,8 +4,6 @@ # obj-$(CONFIG_CHELSIO_T1) += cxgb.o -cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o +cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ mv88x201x.o my3126.o $(cxgb-y) - - diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 787f2f2..8ba702c 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -322,9 +322,9 @@ struct board_info { unsigned char mdio_mdiinv; unsigned char mdio_mdc; unsigned char mdio_phybaseaddr; - struct gmac *gmac; - struct gphy *gphy; - struct mdio_ops *mdio_ops; + const struct gmac *gmac; + const struct gphy *gphy; + const struct mdio_ops *mdio_ops; const char *desc; }; diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index cf91434..79d855e 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h @@ -100,7 +100,7 @@ struct cphy { u32 elmer_gpo; - struct cphy_ops *ops; /* PHY operations */ + 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, @@ -136,7 +136,7 @@ static inline int simple_mdio_write(stru /* Convenience initializer */ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, int phy_addr, struct cphy_ops *phy_ops, - struct mdio_ops *mdio_ops) + const struct mdio_ops *mdio_ops) { phy->adapter = adapter; phy->addr = phy_addr; @@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy struct gphy { /* Construct a PHY instance with the given PHY address */ struct cphy *(*create)(adapter_t *adapter, int phy_addr, - struct mdio_ops *mdio_ops); + const struct mdio_ops *mdio_ops); /* * Reset the PHY chip. This resets the whole PHY chip, not individual @@ -160,11 +160,9 @@ struct gphy { int (*reset)(adapter_t *adapter); }; -extern struct gphy t1_my3126_ops; -extern struct gphy t1_mv88e1xxx_ops; -extern struct gphy t1_vsc8244_ops; -extern struct gphy t1_xpak_ops; -extern struct gphy t1_mv88x201x_ops; -extern struct gphy t1_dummy_phy_ops; +extern const struct gphy t1_my3126_ops; +extern const struct gphy t1_mv88e1xxx_ops; +extern const struct gphy t1_vsc8244_ops; +extern const struct gphy t1_mv88x201x_ops; #endif /* _CXGB_CPHY_H_ */ diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h index 006a2eb..d423374 100644 --- a/drivers/net/chelsio/gmac.h +++ b/drivers/net/chelsio/gmac.h @@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_insta struct cmac { struct cmac_statistics stats; adapter_t *adapter; - struct cmac_ops *ops; + const struct cmac_ops *ops; cmac_instance *instance; }; @@ -136,11 +136,7 @@ struct gmac { int (*reset)(adapter_t *); }; -extern struct gmac t1_pm3393_ops; -extern struct gmac t1_chelsio_mac_ops; -extern struct gmac t1_vsc7321_ops; -extern struct gmac t1_vsc7326_ops; -extern struct gmac t1_ixf1010_ops; -extern struct gmac t1_dummy_mac_ops; +extern const struct gmac t1_pm3393_ops; +extern const struct gmac t1_vsc7326_ops; #endif /* _CXGB_GMAC_H_ */ diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c deleted file mode 100644 index 10b2a9a..0000000 --- a/drivers/net/chelsio/ixf1010.c +++ /dev/null @@ -1,505 +0,0 @@ -/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */ -#include "gmac.h" -#include "elmer0.h" - -/* Update fast changing statistics every 15 seconds */ -#define STATS_TICK_SECS 15 -/* 30 minutes for full statistics update */ -#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) - -/* - * The IXF1010 can handle frames up to 16383 bytes but it's optimized for - * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this. - * This length includes ethernet header and FCS. - */ -#define MAX_FRAME_SIZE 0x2667 - -/* MAC registers */ -enum { - /* Per-port registers */ - REG_MACADDR_LOW = 0, - REG_MACADDR_HIGH = 0x4, - REG_FDFC_TYPE = 0xC, - REG_FC_TX_TIMER_VALUE = 0x1c, - REG_IPG_RX_TIME1 = 0x28, - REG_IPG_RX_TIME2 = 0x2c, - REG_IPG_TX_TIME = 0x30, - REG_PAUSE_THRES = 0x38, - REG_MAX_FRAME_SIZE = 0x3c, - REG_RGMII_SPEED = 0x40, - REG_FC_ENABLE = 0x48, - REG_DISCARD_CTRL_FRAMES = 0x54, - REG_DIVERSE_CONFIG = 0x60, - REG_RX_FILTER = 0x64, - REG_MC_ADDR_LOW = 0x68, - REG_MC_ADDR_HIGH = 0x6c, - - REG_RX_OCTETS_OK = 0x80, - REG_RX_OCTETS_BAD = 0x84, - REG_RX_UC_PKTS = 0x88, - REG_RX_MC_PKTS = 0x8c, - REG_RX_BC_PKTS = 0x90, - REG_RX_FCS_ERR = 0xb0, - REG_RX_TAGGED = 0xb4, - REG_RX_DATA_ERR = 0xb8, - REG_RX_ALIGN_ERR = 0xbc, - REG_RX_LONG_ERR = 0xc0, - REG_RX_JABBER_ERR = 0xc4, - REG_RX_PAUSE_FRAMES = 0xc8, - REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc, - REG_RX_VERY_LONG_ERR = 0xd0, - REG_RX_RUNT_ERR = 0xd4, - REG_RX_SHORT_ERR = 0xd8, - REG_RX_SYMBOL_ERR = 0xe4, - - REG_TX_OCTETS_OK = 0x100, - REG_TX_OCTETS_BAD = 0x104, - REG_TX_UC_PKTS = 0x108, - REG_TX_MC_PKTS = 0x10c, - REG_TX_BC_PKTS = 0x110, - REG_TX_EXCESSIVE_LEN_DROP = 0x14c, - REG_TX_UNDERRUN = 0x150, - REG_TX_TAGGED = 0x154, - REG_TX_PAUSE_FRAMES = 0x15C, - - /* Global registers */ - REG_PORT_ENABLE = 0x1400, - - REG_JTAG_ID = 0x1430, - - RX_FIFO_HIGH_WATERMARK_BASE = 0x1600, - RX_FIFO_LOW_WATERMARK_BASE = 0x1628, - RX_FIFO_FRAMES_REMOVED_BASE = 0x1650, - - REG_RX_ERR_DROP = 0x167c, - REG_RX_FIFO_OVERFLOW_EVENT = 0x1680, - - TX_FIFO_HIGH_WATERMARK_BASE = 0x1800, - TX_FIFO_LOW_WATERMARK_BASE = 0x1828, - TX_FIFO_XFER_THRES_BASE = 0x1850, - - REG_TX_FIFO_OVERFLOW_EVENT = 0x1878, - REG_TX_FIFO_OOS_EVENT = 0x1884, - - TX_FIFO_FRAMES_REMOVED_BASE = 0x1888, - - REG_SPI_RX_BURST = 0x1c00, - REG_SPI_RX_TRAINING = 0x1c04, - REG_SPI_RX_CALENDAR = 0x1c08, - REG_SPI_TX_SYNC = 0x1c0c -}; - -enum { /* RMON registers */ - REG_RxOctetsTotalOK = 0x80, - REG_RxOctetsBad = 0x84, - REG_RxUCPkts = 0x88, - REG_RxMCPkts = 0x8c, - REG_RxBCPkts = 0x90, - REG_RxJumboPkts = 0xac, - REG_RxFCSErrors = 0xb0, - REG_RxDataErrors = 0xb8, - REG_RxAlignErrors = 0xbc, - REG_RxLongErrors = 0xc0, - REG_RxJabberErrors = 0xc4, - REG_RxPauseMacControlCounter = 0xc8, - REG_RxVeryLongErrors = 0xd0, - REG_RxRuntErrors = 0xd4, - REG_RxShortErrors = 0xd8, - REG_RxSequenceErrors = 0xe0, - REG_RxSymbolErrors = 0xe4, - - REG_TxOctetsTotalOK = 0x100, - REG_TxOctetsBad = 0x104, - REG_TxUCPkts = 0x108, - REG_TxMCPkts = 0x10c, - REG_TxBCPkts = 0x110, - REG_TxJumboPkts = 0x12C, - REG_TxTotalCollisions = 0x134, - REG_TxExcessiveLengthDrop = 0x14c, - REG_TxUnderrun = 0x150, - REG_TxCRCErrors = 0x158, - REG_TxPauseFrames = 0x15c -}; - -enum { - DIVERSE_CONFIG_PAD_ENABLE = 0x80, - DIVERSE_CONFIG_CRC_ADD = 0x40 -}; - -#define MACREG_BASE 0 -#define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg)) - -struct _cmac_instance { - u32 mac_base; - u32 index; - u32 version; - u32 ticks; -}; - -static void disable_port(struct cmac *mac) -{ - u32 val; - - t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val); - val &= ~(1 << mac->instance->index); - t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); -} - -/* - * Read the current values of the RMON counters and add them to the cumulative - * port statistics. The HW RMON counters are cleared by this operation. - */ -static void port_stats_update(struct cmac *mac) -{ - static struct { - unsigned int reg; - unsigned int offset; - } hw_stats[] = { - -#define HW_STAT(name, stat_name) \ - { REG_##name, \ - (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } - - /* Rx stats */ - HW_STAT(RxOctetsTotalOK, RxOctetsOK), - HW_STAT(RxOctetsBad, RxOctetsBad), - HW_STAT(RxUCPkts, RxUnicastFramesOK), - HW_STAT(RxMCPkts, RxMulticastFramesOK), - HW_STAT(RxBCPkts, RxBroadcastFramesOK), - HW_STAT(RxJumboPkts, RxJumboFramesOK), - HW_STAT(RxFCSErrors, RxFCSErrors), - HW_STAT(RxAlignErrors, RxAlignErrors), - HW_STAT(RxLongErrors, RxFrameTooLongErrors), - HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors), - HW_STAT(RxPauseMacControlCounter, RxPauseFrames), - HW_STAT(RxDataErrors, RxDataErrors), - HW_STAT(RxJabberErrors, RxJabberErrors), - HW_STAT(RxRuntErrors, RxRuntErrors), - HW_STAT(RxShortErrors, RxRuntErrors), - HW_STAT(RxSequenceErrors, RxSequenceErrors), - HW_STAT(RxSymbolErrors, RxSymbolErrors), - - /* Tx stats (skip collision stats as we are full-duplex only) */ - HW_STAT(TxOctetsTotalOK, TxOctetsOK), - HW_STAT(TxOctetsBad, TxOctetsBad), - HW_STAT(TxUCPkts, TxUnicastFramesOK), - HW_STAT(TxMCPkts, TxMulticastFramesOK), - HW_STAT(TxBCPkts, TxBroadcastFramesOK), - HW_STAT(TxJumboPkts, TxJumboFramesOK), - HW_STAT(TxPauseFrames, TxPauseFrames), - HW_STAT(TxExcessiveLengthDrop, TxLengthErrors), - HW_STAT(TxUnderrun, TxUnderrun), - HW_STAT(TxCRCErrors, TxFCSErrors) - }, *p = hw_stats; - u64 *stats = (u64 *) &mac->stats; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { - u32 val; - - t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val); - stats[p->offset] += val; - } -} - -/* No-op interrupt operation as this MAC does not support interrupts */ -static int mac_intr_op(struct cmac *mac) -{ - return 0; -} - -/* Expect MAC address to be in network byte order. */ -static int mac_set_address(struct cmac *mac, u8 addr[6]) -{ - u32 addr_lo, addr_hi; - - addr_lo = addr[2]; - addr_lo = (addr_lo << 8) | addr[3]; - addr_lo = (addr_lo << 8) | addr[4]; - addr_lo = (addr_lo << 8) | addr[5]; - - addr_hi = addr[0]; - addr_hi = (addr_hi << 8) | addr[1]; - - t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo); - t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi); - return 0; -} - -static int mac_get_address(struct cmac *mac, u8 addr[6]) -{ - u32 addr_lo, addr_hi; - - t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo); - t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi); - - addr[0] = (u8) (addr_hi >> 8); - addr[1] = (u8) addr_hi; - addr[2] = (u8) (addr_lo >> 24); - addr[3] = (u8) (addr_lo >> 16); - addr[4] = (u8) (addr_lo >> 8); - addr[5] = (u8) addr_lo; - return 0; -} - -/* This is intended to reset a port, not the whole MAC */ -static int mac_reset(struct cmac *mac) -{ - return 0; -} - -static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) -{ - u32 val, new_mode; - adapter_t *adapter = mac->adapter; - u32 addr_lo, addr_hi; - u8 *addr; - - t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val); - new_mode = val & ~7; - if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0) - new_mode |= 1; /* only set if version > 0 due to erratum */ - if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm) - && t1_rx_mode_mc_cnt(rm) <= 1) - new_mode |= 2; - if (new_mode != val) - t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode); - switch (t1_rx_mode_mc_cnt(rm)) { - case 0: - t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0); - t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0); - break; - case 1: - addr = t1_get_next_mcaddr(rm); - addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | - addr[5]; - addr_hi = (addr[0] << 8) | addr[1]; - t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo); - t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi); - break; - default: - break; - } - return 0; -} - -static int mac_set_mtu(struct cmac *mac, int mtu) -{ - /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ - if (mtu > (MAX_FRAME_SIZE - 14 - 4)) - return -EINVAL; - t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), - mtu + 14 + 4); - return 0; -} - -static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, - int fc) -{ - u32 val; - - if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000) - return -1; - if (duplex >= 0 && duplex != DUPLEX_FULL) - return -1; - - if (speed >= 0) { - val = speed == SPEED_100 ? 1 : 2; - t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val); - } - - t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); - val &= ~3; - if (fc & PAUSE_RX) - val |= 1; - if (fc & PAUSE_TX) - val |= 2; - t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val); - return 0; -} - -static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex, - int *fc) -{ - u32 val; - - if (duplex) - *duplex = DUPLEX_FULL; - if (speed) { - t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED), - &val); - *speed = (val & 2) ? SPEED_1000 : SPEED_100; - } - if (fc) { - t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); - *fc = 0; - if (val & 1) - *fc |= PAUSE_RX; - if (val & 2) - *fc |= PAUSE_TX; - } - return 0; -} - -static void enable_port(struct cmac *mac) -{ - u32 val; - u32 index = mac->instance->index; - adapter_t *adapter = mac->adapter; - - t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val); - val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE; - t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val); - if (mac->instance->version > 0) - t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3); - else /* Don't enable unicast address filtering due to IXF1010 bug */ - t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2); - - t1_tpi_read(adapter, REG_RX_ERR_DROP, &val); - val |= (1 << index); - t1_tpi_write(adapter, REG_RX_ERR_DROP, val); - - /* - * Clear the port RMON registers by adding their current values to the - * cumulatice port stats and then clearing the stats. Really. - */ - port_stats_update(mac); - memset(&mac->stats, 0, sizeof(struct cmac_statistics)); - mac->instance->ticks = 0; - - t1_tpi_read(adapter, REG_PORT_ENABLE, &val); - val |= (1 << index); - t1_tpi_write(adapter, REG_PORT_ENABLE, val); - - index <<= 2; - if (is_T2(adapter)) { - /* T204: set the Fifo water level & threshold */ - t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); - t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); - t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600); - t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0); - t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100); - } else { - /* - * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around - * Underrun problem. Intel has blessed this solution. - */ - t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400); - } -} - -/* IXF1010 ports do not have separate enables for TX and RX */ -static int mac_enable(struct cmac *mac, int which) -{ - if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) - enable_port(mac); - return 0; -} - -static int mac_disable(struct cmac *mac, int which) -{ - if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) - disable_port(mac); - return 0; -} - -#define RMON_UPDATE(mac, name, stat_name) \ - t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ - (mac)->stats.stat_name += val; - -/* - * This function is called periodically to accumulate the current values of the - * RMON counters into the port statistics. Since the counters are only 32 bits - * some of them can overflow in less than a minute at GigE speeds, so this - * function should be called every 30 seconds or so. - * - * To cut down on reading costs we update only the octet counters at each tick - * and do a full update at major ticks, which can be every 30 minutes or more. - */ -static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, - int flag) -{ - if (flag == MAC_STATS_UPDATE_FULL || - MAJOR_UPDATE_TICKS <= mac->instance->ticks) { - port_stats_update(mac); - mac->instance->ticks = 0; - } else { - u32 val; - - RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); - RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); - mac->instance->ticks++; - } - return &mac->stats; -} - -static void mac_destroy(struct cmac *mac) -{ - kfree(mac); -} - -static struct cmac_ops ixf1010_ops = { - .destroy = mac_destroy, - .reset = mac_reset, - .interrupt_enable = mac_intr_op, - .interrupt_disable = mac_intr_op, - .interrupt_clear = mac_intr_op, - .enable = mac_enable, - .disable = mac_disable, - .set_mtu = mac_set_mtu, - .set_rx_mode = mac_set_rx_mode, - .set_speed_duplex_fc = mac_set_speed_duplex_fc, - .get_speed_duplex_fc = mac_get_speed_duplex_fc, - .statistics_update = mac_update_statistics, - .macaddress_get = mac_get_address, - .macaddress_set = mac_set_address, -}; - -static int ixf1010_mac_reset(adapter_t *adapter) -{ - u32 val; - - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - if ((val & 1) != 0) { - val &= ~1; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(2); - } - val |= 1; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(2); - - t1_tpi_write(adapter, REG_PORT_ENABLE, 0); - return 0; -} - -static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index) -{ - struct cmac *mac; - u32 val; - - if (index > 9) - return NULL; - - mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) - return NULL; - - mac->ops = &ixf1010_ops; - mac->instance = (cmac_instance *)(mac + 1); - - mac->instance->mac_base = MACREG_BASE + (index * 0x200); - mac->instance->index = index; - mac->adapter = adapter; - mac->instance->ticks = 0; - - t1_tpi_read(adapter, REG_JTAG_ID, &val); - mac->instance->version = val >> 28; - return mac; -} - -struct gmac t1_ixf1010_ops = { - STATS_TICK_SECS, - ixf1010_mac_create, - ixf1010_mac_reset -}; diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c index 6af39dc..1d97282 100644 --- a/drivers/net/chelsio/mac.c +++ b/drivers/net/chelsio/mac.c @@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t return mac; } -struct gmac t1_chelsio_mac_ops = { +const struct gmac t1_chelsio_mac_ops = { .create = mac_create }; diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 5867e3b..0632be0 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = { }; static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, - struct mdio_ops *mdio_ops) + const struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); @@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t return 0; } -struct gphy t1_mv88e1xxx_ops = { - mv88e1xxx_phy_create, - mv88e1xxx_phy_reset +const struct gphy t1_mv88e1xxx_ops = { + .create = mv88e1xxx_phy_create, + .reset = mv88e1xxx_phy_reset }; diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index c8e8948..cd85604 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c @@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = { }; static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, - struct mdio_ops *mdio_ops) + const struct mdio_ops *mdio_ops) { u32 val; struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); @@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t return 0; } -struct gphy t1_mv88x201x_ops = { - mv88x201x_phy_create, - mv88x201x_phy_reset +const struct gphy t1_mv88x201x_ops = { + .create = mv88x201x_phy_create, + .reset = mv88x201x_phy_reset }; diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 87dde3e..040acd2 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = { }; static struct cphy *my3126_phy_create(adapter_t *adapter, - int phy_addr, struct mdio_ops *mdio_ops) + int phy_addr, const struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); @@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * return 0; } -struct gphy t1_my3126_ops = { - my3126_phy_create, - my3126_phy_reset +const struct gphy t1_my3126_ops = { + .create = my3126_phy_create, + .reset = my3126_phy_reset }; diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 69129ed..678778a 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c @@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * return successful_reset ? 0 : 1; } -struct gmac t1_pm3393_ops = { - STATS_TICK_SECS, - pm3393_mac_create, - pm3393_mac_reset +const struct gmac t1_pm3393_ops = { + .stats_update_period = STATS_TICK_SECS, + .create = pm3393_mac_create, + .reset = pm3393_mac_reset, }; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index c2522cd..7de9a61 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *ada } #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR) -static struct mdio_ops mi1_mdio_ops = { - mi1_mdio_init, - mi1_mdio_read, - mi1_mdio_write +static const struct mdio_ops mi1_mdio_ops = { + .init = mi1_mdio_init, + .read = mi1_mdio_read, + .write = mi1_mdio_write }; #endif @@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t return 0; } -static struct mdio_ops mi1_mdio_ext_ops = { - mi1_mdio_init, - mi1_mdio_ext_read, - mi1_mdio_ext_write +static const struct mdio_ops mi1_mdio_ext_ops = { + .init = mi1_mdio_init, + .read = mi1_mdio_ext_read, + .write = mi1_mdio_ext_write }; enum { @@ -392,63 +392,136 @@ enum { CH_BRD_N204_4CU, }; -static struct board_info t1_board[] = { - -{ CHBT_BOARD_CHT110, 1/*ports#*/, - SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1, - CHBT_MAC_PM3393, CHBT_PHY_MY3126, - 125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/, - 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, - 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, - &t1_my3126_ops, &mi1_mdio_ext_ops, - "Chelsio T110 1x10GBase-CX4 TOE" }, - -{ CHBT_BOARD_N110, 1/*ports#*/, - SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1, - CHBT_MAC_PM3393, CHBT_PHY_88X2010, - 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, - 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, - 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, - &t1_mv88x201x_ops, &mi1_mdio_ext_ops, - "Chelsio N110 1x10GBaseX NIC" }, - -{ CHBT_BOARD_N210, 1/*ports#*/, - SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2, - CHBT_MAC_PM3393, CHBT_PHY_88X2010, - 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, - 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, - 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, - &t1_mv88x201x_ops, &mi1_mdio_ext_ops, - "Chelsio N210 1x10GBaseX NIC" }, - -{ CHBT_BOARD_CHT210, 1/*ports#*/, - SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, - CHBT_MAC_PM3393, CHBT_PHY_88X2010, - 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, - 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, - 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, - &t1_mv88x201x_ops, &mi1_mdio_ext_ops, - "Chelsio T210 1x10GBaseX TOE" }, - -{ CHBT_BOARD_CHT210, 1/*ports#*/, - SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, - CHBT_MAC_PM3393, CHBT_PHY_MY3126, - 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, - 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, - 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, - &t1_my3126_ops, &mi1_mdio_ext_ops, - "Chelsio T210 1x10GBase-CX4 TOE" }, +static const struct board_info t1_board[] = { + { + .board = CHBT_BOARD_CHT110, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T1, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_MY3126, + .clock_core = 125000000, + .clock_mc3 = 150000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 1, + .mdio_mdiinv = 1, + .mdio_mdc = 1, + .mdio_phybaseaddr = 1, + .gmac = &t1_pm3393_ops, + .gphy = &t1_my3126_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T110 1x10GBase-CX4 TOE", + }, + + { + .board = CHBT_BOARD_N110, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, + .chip_term = CHBT_TERM_T1, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio N110 1x10GBaseX NIC", + }, + + { + .board = CHBT_BOARD_N210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio N210 1x10GBaseX NIC", + }, + + { + .board = CHBT_BOARD_CHT210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .clock_mc3 = 133000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T210 1x10GBaseX TOE", + }, + + { + .board = CHBT_BOARD_CHT210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_MY3126, + .clock_core = 125000000, + .clock_mc3 = 133000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 1, + .mdio_mdiinv = 1, + .mdio_mdc = 1, + .mdio_phybaseaddr = 1, + .gmac = &t1_pm3393_ops, + .gphy = &t1_my3126_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T210 1x10GBase-CX4 TOE", + }, #ifdef CONFIG_CHELSIO_T1_1G -{ CHBT_BOARD_CHN204, 4/*ports#*/, - SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | - SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111, - 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, - 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, - 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops, - &t1_mv88e1xxx_ops, &mi1_mdio_ops, - "Chelsio N204 4x100/1000BaseT NIC" }, + { + .board = CHBT_BOARD_CHN204, + .port_number = 4, + .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_PAUSE | SUPPORTED_TP, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_VSC7321, + .chip_phy = CHBT_PHY_88E1111, + .clock_core = 100000000, + .espi_nports = 4, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 0, + .mdio_phybaseaddr = 4, + .gmac = &t1_vsc7326_ops, + .gphy = &t1_mv88e1xxx_ops, + .mdio_ops = &mi1_mdio_ops, + .desc = "Chelsio N204 4x100/1000BaseT NIC", + }, #endif }; diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c index 534ffa0..99b51f6 100644 --- a/drivers/net/chelsio/vsc7326.c +++ b/drivers/net/chelsio/vsc7326.c @@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t * return 0; } -struct gmac t1_vsc7326_ops = { +const struct gmac t1_vsc7326_ops = { .stats_update_period = STATS_TICK_SECS, .create = vsc7326_mac_create, .reset = vsc7326_mac_reset, diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c deleted file mode 100644 index 251d485..0000000 --- a/drivers/net/chelsio/vsc8244.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * This file is part of the Chelsio T2 Ethernet driver. - * - * Copyright (C) 2005 Chelsio Communications. All rights reserved. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this - * release for licensing terms and conditions. - */ - -#include "common.h" -#include "cphy.h" -#include "elmer0.h" - -#ifndef ADVERTISE_PAUSE_CAP -# define ADVERTISE_PAUSE_CAP 0x400 -#endif -#ifndef ADVERTISE_PAUSE_ASYM -# define ADVERTISE_PAUSE_ASYM 0x800 -#endif - -/* Gigabit MII registers */ -#ifndef MII_CTRL1000 -# define MII_CTRL1000 9 -#endif - -#ifndef ADVERTISE_1000FULL -# define ADVERTISE_1000FULL 0x200 -# define ADVERTISE_1000HALF 0x100 -#endif - -/* VSC8244 PHY specific registers. */ -enum { - VSC8244_INTR_ENABLE = 25, - VSC8244_INTR_STATUS = 26, - VSC8244_AUX_CTRL_STAT = 28, -}; - -enum { - VSC_INTR_RX_ERR = 1 << 0, - VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ - VSC_INTR_CABLE = 1 << 2, /* cable impairment */ - VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ - VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ - VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ - VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ - VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ - VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ - VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ - VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ - VSC_INTR_LINK_CHG = 1 << 13, /* link change */ - VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ -}; - -#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ - VSC_INTR_NEG_DONE) -#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ - VSC_INTR_ENABLE) - -/* PHY specific auxiliary control & status register fields */ -#define S_ACSR_ACTIPHY_TMR 0 -#define M_ACSR_ACTIPHY_TMR 0x3 -#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) - -#define S_ACSR_SPEED 3 -#define M_ACSR_SPEED 0x3 -#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) - -#define S_ACSR_DUPLEX 5 -#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) - -#define S_ACSR_ACTIPHY 6 -#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) - -/* - * Reset the PHY. This PHY completes reset immediately so we never wait. - */ -static int vsc8244_reset(struct cphy *cphy, int wait) -{ - int err; - unsigned int ctl; - - err = simple_mdio_read(cphy, MII_BMCR, &ctl); - if (err) - return err; - - ctl &= ~BMCR_PDOWN; - ctl |= BMCR_RESET; - return simple_mdio_write(cphy, MII_BMCR, ctl); -} - -static int vsc8244_intr_enable(struct cphy *cphy) -{ - simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK); - - /* Enable interrupts through Elmer */ - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - - return 0; -} - -static int vsc8244_intr_disable(struct cphy *cphy) -{ - simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0); - - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - - return 0; -} - -static int vsc8244_intr_clear(struct cphy *cphy) -{ - u32 val; - u32 elmer; - - /* Clear PHY interrupts by reading the register. */ - simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val); - - if (t1_is_asic(cphy->adapter)) { - t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); - elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); - } - - return 0; -} - -/* - * Force the PHY speed and duplex. This also disables auto-negotiation, except - * for 1Gb/s, where auto-negotiation is mandatory. - */ -static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex) -{ - int err; - unsigned int ctl; - - err = simple_mdio_read(phy, MII_BMCR, &ctl); - if (err) - return err; - - if (speed >= 0) { - ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); - if (speed == SPEED_100) - ctl |= BMCR_SPEED100; - else if (speed == SPEED_1000) - ctl |= BMCR_SPEED1000; - } - if (duplex >= 0) { - ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); - if (duplex == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - } - if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ - ctl |= BMCR_ANENABLE; - return simple_mdio_write(phy, MII_BMCR, ctl); -} - -int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits) -{ - int ret; - unsigned int val; - - ret = mdio_read(phy, mmd, reg, &val); - if (!ret) - ret = mdio_write(phy, mmd, reg, val | bits); - return ret; -} - -static int vsc8244_autoneg_enable(struct cphy *cphy) -{ - return t1_mdio_set_bits(cphy, 0, MII_BMCR, - BMCR_ANENABLE | BMCR_ANRESTART); -} - -static int vsc8244_autoneg_restart(struct cphy *cphy) -{ - return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART); -} - -static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map) -{ - int err; - unsigned int val = 0; - - err = simple_mdio_read(phy, MII_CTRL1000, &val); - if (err) - return err; - - val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); - if (advertise_map & ADVERTISED_1000baseT_Half) - val |= ADVERTISE_1000HALF; - if (advertise_map & ADVERTISED_1000baseT_Full) - val |= ADVERTISE_1000FULL; - - err = simple_mdio_write(phy, MII_CTRL1000, val); - if (err) - return err; - - val = 1; - if (advertise_map & ADVERTISED_10baseT_Half) - val |= ADVERTISE_10HALF; - if (advertise_map & ADVERTISED_10baseT_Full) - val |= ADVERTISE_10FULL; - if (advertise_map & ADVERTISED_100baseT_Half) - val |= ADVERTISE_100HALF; - if (advertise_map & ADVERTISED_100baseT_Full) - val |= ADVERTISE_100FULL; - if (advertise_map & ADVERTISED_PAUSE) - val |= ADVERTISE_PAUSE_CAP; - if (advertise_map & ADVERTISED_ASYM_PAUSE) - val |= ADVERTISE_PAUSE_ASYM; - return simple_mdio_write(phy, MII_ADVERTISE, val); -} - -static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - unsigned int bmcr, status, lpa, adv; - int err, sp = -1, dplx = -1, pause = 0; - - err = simple_mdio_read(cphy, MII_BMCR, &bmcr); - if (!err) - err = simple_mdio_read(cphy, MII_BMSR, &status); - if (err) - return err; - - if (link_ok) { - /* - * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it - * once more to get the current link state. - */ - if (!(status & BMSR_LSTATUS)) - err = simple_mdio_read(cphy, MII_BMSR, &status); - if (err) - return err; - *link_ok = (status & BMSR_LSTATUS) != 0; - } - if (!(bmcr & BMCR_ANENABLE)) { - dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; - if (bmcr & BMCR_SPEED1000) - sp = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - sp = SPEED_100; - else - sp = SPEED_10; - } else if (status & BMSR_ANEGCOMPLETE) { - err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status); - if (err) - return err; - - dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; - sp = G_ACSR_SPEED(status); - if (sp == 0) - sp = SPEED_10; - else if (sp == 1) - sp = SPEED_100; - else - sp = SPEED_1000; - - if (fc && dplx == DUPLEX_FULL) { - err = simple_mdio_read(cphy, MII_LPA, &lpa); - if (!err) - err = simple_mdio_read(cphy, MII_ADVERTISE, - &adv); - if (err) - return err; - - if (lpa & adv & ADVERTISE_PAUSE_CAP) - pause = PAUSE_RX | PAUSE_TX; - else if ((lpa & ADVERTISE_PAUSE_CAP) && - (lpa & ADVERTISE_PAUSE_ASYM) && - (adv & ADVERTISE_PAUSE_ASYM)) - pause = PAUSE_TX; - else if ((lpa & ADVERTISE_PAUSE_ASYM) && - (adv & ADVERTISE_PAUSE_CAP)) - pause = PAUSE_RX; - } - } - if (speed) - *speed = sp; - if (duplex) - *duplex = dplx; - if (fc) - *fc = pause; - return 0; -} - -static int vsc8244_intr_handler(struct cphy *cphy) -{ - unsigned int cause; - int err, cphy_cause = 0; - - err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause); - if (err) - return err; - - cause &= INTR_MASK; - if (cause & CFG_CHG_INTR_MASK) - cphy_cause |= cphy_cause_link_change; - if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) - cphy_cause |= cphy_cause_fifo_error; - return cphy_cause; -} - -static void vsc8244_destroy(struct cphy *cphy) -{ - kfree(cphy); -} - -static struct cphy_ops vsc8244_ops = { - .destroy = vsc8244_destroy, - .reset = vsc8244_reset, - .interrupt_enable = vsc8244_intr_enable, - .interrupt_disable = vsc8244_intr_disable, - .interrupt_clear = vsc8244_intr_clear, - .interrupt_handler = vsc8244_intr_handler, - .autoneg_enable = vsc8244_autoneg_enable, - .autoneg_restart = vsc8244_autoneg_restart, - .advertise = vsc8244_advertise, - .set_speed_duplex = vsc8244_set_speed_duplex, - .get_link_status = vsc8244_get_link_status -}; - -static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, - struct mdio_ops *mdio_ops) -{ - struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - - if (!cphy) - return NULL; - - cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops); - - return cphy; -} - - -static int vsc8244_phy_reset(adapter_t* adapter) -{ - return 0; -} - -struct gphy t1_vsc8244_ops = { - vsc8244_phy_create, - vsc8244_phy_reset -}; - - diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h deleted file mode 100644 index d3c1829..0000000 --- a/drivers/net/chelsio/vsc8244_reg.h +++ /dev/null @@ -1,172 +0,0 @@ -/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */ -#ifndef CHELSIO_MV8E1XXX_H -#define CHELSIO_MV8E1XXX_H - -#ifndef BMCR_SPEED1000 -# define BMCR_SPEED1000 0x40 -#endif - -#ifndef ADVERTISE_PAUSE -# define ADVERTISE_PAUSE 0x400 -#endif -#ifndef ADVERTISE_PAUSE_ASYM -# define ADVERTISE_PAUSE_ASYM 0x800 -#endif - -/* Gigabit MII registers */ -#define MII_GBMR 1 /* 1000Base-T mode register */ -#define MII_GBCR 9 /* 1000Base-T control register */ -#define MII_GBSR 10 /* 1000Base-T status register */ - -/* 1000Base-T control register fields */ -#define GBCR_ADV_1000HALF 0x100 -#define GBCR_ADV_1000FULL 0x200 -#define GBCR_PREFER_MASTER 0x400 -#define GBCR_MANUAL_AS_MASTER 0x800 -#define GBCR_MANUAL_CONFIG_ENABLE 0x1000 - -/* 1000Base-T status register fields */ -#define GBSR_LP_1000HALF 0x400 -#define GBSR_LP_1000FULL 0x800 -#define GBSR_REMOTE_OK 0x1000 -#define GBSR_LOCAL_OK 0x2000 -#define GBSR_LOCAL_MASTER 0x4000 -#define GBSR_MASTER_FAULT 0x8000 - -/* Vitesse PHY interrupt status bits. */ -#if 0 -#define VSC8244_INTR_JABBER 0x0001 -#define VSC8244_INTR_POLARITY_CHNG 0x0002 -#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 -#define VSC8244_INTR_DOWNSHIFT 0x0020 -#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 -#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 -#define VSC8244_INTR_FALSE_CARRIER 0x0100 -#define VSC8244_INTR_SYMBOL_ERROR 0x0200 -#define VSC8244_INTR_LINK_CHNG 0x0400 -#define VSC8244_INTR_AUTONEG_DONE 0x0800 -#define VSC8244_INTR_PAGE_RECV 0x1000 -#define VSC8244_INTR_DUPLEX_CHNG 0x2000 -#define VSC8244_INTR_SPEED_CHNG 0x4000 -#define VSC8244_INTR_AUTONEG_ERR 0x8000 -#else -//#define VSC8244_INTR_JABBER 0x0001 -//#define VSC8244_INTR_POLARITY_CHNG 0x0002 -//#define VSC8244_INTR_BIT2 0x0004 -//#define VSC8244_INTR_BIT3 0x0008 -#define VSC8244_INTR_RX_ERR 0x0001 -#define VSC8244_INTR_MASTER_SLAVE 0x0002 -#define VSC8244_INTR_CABLE_IMPAIRED 0x0004 -#define VSC8244_INTR_FALSE_CARRIER 0x0008 -//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 -//#define VSC8244_INTR_DOWNSHIFT 0x0020 -//#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 -//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 -#define VSC8244_INTR_BIT4 0x0010 -#define VSC8244_INTR_FIFO_RX 0x0020 -#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040 -#define VSC8244_INTR_LOCK_LOST 0x0080 -//#define VSC8244_INTR_FALSE_CARRIER 0x0100 -//#define VSC8244_INTR_SYMBOL_ERROR 0x0200 -//#define VSC8244_INTR_LINK_CHNG 0x0400 -//#define VSC8244_INTR_AUTONEG_DONE 0x0800 -#define VSC8244_INTR_SYMBOL_ERROR 0x0100 -#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200 -#define VSC8244_INTR_AUTONEG_DONE 0x0400 -#define VSC8244_INTR_AUTONEG_ERR 0x0800 -//#define VSC8244_INTR_PAGE_RECV 0x1000 -//#define VSC8244_INTR_DUPLEX_CHNG 0x2000 -//#define VSC8244_INTR_SPEED_CHNG 0x4000 -//#define VSC8244_INTR_AUTONEG_ERR 0x8000 -#define VSC8244_INTR_DUPLEX_CHNG 0x1000 -#define VSC8244_INTR_LINK_CHNG 0x2000 -#define VSC8244_INTR_SPEED_CHNG 0x4000 -#define VSC8244_INTR_STATUS 0x8000 -#endif - - -/* Vitesse PHY specific registers. */ -#define VSC8244_SPECIFIC_CNTRL_REGISTER 16 -#define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c -#define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19 -#define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a -#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20 -#define VSC8244_RECV_ERR_CNTR_REGISTER 21 -#define VSC8244_RES_REGISTER 22 -#define VSC8244_GLOBAL_STATUS_REGISTER 23 -#define VSC8244_LED_CONTROL_REGISTER 24 -#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25 -#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26 -#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27 -#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28 -#define VSC8244_EXTENDED_ADDR_REGISTER 29 -#define VSC8244_EXTENDED_REGISTER 30 - -/* PHY specific control register fields */ -#define S_PSCR_MDI_XOVER_MODE 5 -#define M_PSCR_MDI_XOVER_MODE 0x3 -#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE) -#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE) - -/* Extended PHY specific control register fields */ -#define S_DOWNSHIFT_ENABLE 8 -#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE) - -#define S_DOWNSHIFT_CNT 9 -#define M_DOWNSHIFT_CNT 0x7 -#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT) -#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT) - -/* PHY specific status register fields */ -#define S_PSSR_JABBER 0 -#define V_PSSR_JABBER (1 << S_PSSR_JABBER) - -#define S_PSSR_POLARITY 1 -#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY) - -#define S_PSSR_RX_PAUSE 2 -#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE) - -#define S_PSSR_TX_PAUSE 3 -#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE) - -#define S_PSSR_ENERGY_DETECT 4 -#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT) - -#define S_PSSR_DOWNSHIFT_STATUS 5 -#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS) - -#define S_PSSR_MDI 6 -#define V_PSSR_MDI (1 << S_PSSR_MDI) - -#define S_PSSR_CABLE_LEN 7 -#define M_PSSR_CABLE_LEN 0x7 -#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN) -#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN) - -//#define S_PSSR_LINK 10 -//#define S_PSSR_LINK 13 -#define S_PSSR_LINK 2 -#define V_PSSR_LINK (1 << S_PSSR_LINK) - -//#define S_PSSR_STATUS_RESOLVED 11 -//#define S_PSSR_STATUS_RESOLVED 10 -#define S_PSSR_STATUS_RESOLVED 15 -#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED) - -#define S_PSSR_PAGE_RECEIVED 12 -#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED) - -//#define S_PSSR_DUPLEX 13 -//#define S_PSSR_DUPLEX 12 -#define S_PSSR_DUPLEX 5 -#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX) - -//#define S_PSSR_SPEED 14 -//#define S_PSSR_SPEED 14 -#define S_PSSR_SPEED 3 -#define M_PSSR_SPEED 0x3 -#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED) -#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED) - -#endif diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 0cefef5..1dd1a22 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -282,12 +282,6 @@ enum scb_status { rus_mask = 0x3C, }; -enum ru_state { - RU_SUSPENDED = 0, - RU_RUNNING = 1, - RU_UNINITIALIZED = -1, -}; - enum scb_stat_ack { stat_ack_not_ours = 0x00, stat_ack_sw_gen = 0x04, @@ -529,7 +523,6 @@ struct nic { struct rx *rx_to_use; struct rx *rx_to_clean; struct rfd blank_rfd; - enum ru_state ru_running; spinlock_t cb_lock ____cacheline_aligned; spinlock_t cmd_lock; @@ -951,7 +944,7 @@ static void e100_get_defaults(struct nic ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); /* Template for a freshly allocated RFD */ - nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s); nic->blank_rfd.rbd = 0xFFFFFFFF; nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); @@ -1746,19 +1739,11 @@ static int e100_alloc_cbs(struct nic *ni return 0; } -static inline void e100_start_receiver(struct nic *nic, struct rx *rx) +static inline void e100_start_receiver(struct nic *nic) { - if(!nic->rxs) return; - if(RU_SUSPENDED != nic->ru_running) return; - - /* handle init time starts */ - if(!rx) rx = nic->rxs; - - /* (Re)start RU if suspended or idle and RFA is non-NULL */ - if(rx->skb) { - e100_exec_cmd(nic, ruc_start, rx->dma_addr); - nic->ru_running = RU_RUNNING; - } + /* Start if RFA is non-NULL */ + if(nic->rx_to_clean->skb) + e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr); } #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) @@ -1787,7 +1772,7 @@ static int e100_rx_alloc_skb(struct nic put_unaligned(cpu_to_le32(rx->dma_addr), (u32 *)&prev_rfd->link); wmb(); - prev_rfd->command &= ~cpu_to_le16(cb_el); + prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s); pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, sizeof(struct rfd), PCI_DMA_TODEVICE); } @@ -1825,10 +1810,6 @@ static int e100_rx_indicate(struct nic * pci_unmap_single(nic->pdev, rx->dma_addr, RFD_BUF_LEN, PCI_DMA_FROMDEVICE); - /* this allows for a fast restart without re-enabling interrupts */ - if(le16_to_cpu(rfd->command) & cb_el) - nic->ru_running = RU_SUSPENDED; - /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); skb_put(skb, actual_size); @@ -1859,45 +1840,18 @@ static void e100_rx_clean(struct nic *ni unsigned int work_to_do) { struct rx *rx; - int restart_required = 0; - struct rx *rx_to_start = NULL; - - /* are we already rnr? then pay attention!!! this ensures that - * the state machine progression never allows a start with a - * partially cleaned list, avoiding a race between hardware - * and rx_to_clean when in NAPI mode */ - if(RU_SUSPENDED == nic->ru_running) - restart_required = 1; /* Indicate newly arrived packets */ for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { - int err = e100_rx_indicate(nic, rx, work_done, work_to_do); - if(-EAGAIN == err) { - /* hit quota so have more work to do, restart once - * cleanup is complete */ - restart_required = 0; - break; - } else if(-ENODATA == err) + if(e100_rx_indicate(nic, rx, work_done, work_to_do)) break; /* No more to clean */ } - /* save our starting point as the place we'll restart the receiver */ - if(restart_required) - rx_to_start = nic->rx_to_clean; - /* Alloc new skbs to refill list */ for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { if(unlikely(e100_rx_alloc_skb(nic, rx))) break; /* Better luck next time (see watchdog) */ } - - if(restart_required) { - // ack the rnr? - writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); - e100_start_receiver(nic, rx_to_start); - if(work_done) - (*work_done)++; - } } static void e100_rx_clean_list(struct nic *nic) @@ -1905,8 +1859,6 @@ static void e100_rx_clean_list(struct ni struct rx *rx; unsigned int i, count = nic->params.rfds.count; - nic->ru_running = RU_UNINITIALIZED; - if(nic->rxs) { for(rx = nic->rxs, i = 0; i < count; rx++, i++) { if(rx->skb) { @@ -1928,7 +1880,6 @@ static int e100_rx_alloc_list(struct nic unsigned int i, count = nic->params.rfds.count; nic->rx_to_use = nic->rx_to_clean = NULL; - nic->ru_running = RU_UNINITIALIZED; if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC))) return -ENOMEM; @@ -1943,7 +1894,6 @@ static int e100_rx_alloc_list(struct nic } nic->rx_to_use = nic->rx_to_clean = nic->rxs; - nic->ru_running = RU_SUSPENDED; return 0; } @@ -1963,10 +1913,6 @@ static irqreturn_t e100_intr(int irq, vo /* Ack interrupt(s) */ writeb(stat_ack, &nic->csr->scb.stat_ack); - /* We hit Receive No Resource (RNR); restart RU after cleaning */ - if(stat_ack & stat_ack_rnr) - nic->ru_running = RU_SUSPENDED; - if(likely(netif_rx_schedule_prep(netdev))) { e100_disable_irq(nic); __netif_rx_schedule(netdev); @@ -2058,7 +2004,7 @@ static int e100_up(struct nic *nic) if((err = e100_hw_init(nic))) goto err_clean_cbs; e100_set_multicast_list(nic->netdev); - e100_start_receiver(nic, NULL); + e100_start_receiver(nic); mod_timer(&nic->watchdog, jiffies); if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, nic->netdev->name, nic->netdev))) @@ -2139,7 +2085,7 @@ static int e100_loopback_test(struct nic mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, BMCR_LOOPBACK); - e100_start_receiver(nic, NULL); + e100_start_receiver(nic); if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) { err = -ENOMEM; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 6777887..2881da1 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *n e1000_mac_type mac_type = adapter->hw.mac_type; struct e1000_tx_ring *txdr, *tx_old; struct e1000_rx_ring *rxdr, *rx_old; - int i, err, tx_ring_size, rx_ring_size; + int i, err; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; - tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; - rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; - while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) msleep(1); @@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *n rx_old = adapter->rx_ring; err = -ENOMEM; - txdr = kzalloc(tx_ring_size, GFP_KERNEL); + txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL); if (!txdr) goto err_alloc_tx; - rxdr = kzalloc(rx_ring_size, GFP_KERNEL); + rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL); if (!rxdr) goto err_alloc_rx; @@ -742,7 +739,7 @@ #define REG_PATTERN_TEST(R, M, W) uint32_t pat, value; \ uint32_t test[] = \ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ - for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ value = E1000_READ_REG(&adapter->hw, R); \ if (value != (test[pat] & W & M)) { \ @@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adap struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; - int size, i, ret_val; + int i, ret_val; /* Setup Tx descriptor ring and Tx buffers */ if (!txdr->count) txdr->count = E1000_DEFAULT_TXD; - size = txdr->count * sizeof(struct e1000_buffer); - if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + if (!(txdr->buffer_info = kcalloc(txdr->count, + sizeof(struct e1000_buffer), + GFP_KERNEL))) { ret_val = 1; goto err_nomem; } - memset(txdr->buffer_info, 0, size); txdr->size = txdr->count * sizeof(struct e1000_tx_desc); E1000_ROUNDUP(txdr->size, 4096); - if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { + if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, + &txdr->dma))) { ret_val = 2; goto err_nomem; } @@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adap if (!rxdr->count) rxdr->count = E1000_DEFAULT_RXD; - size = rxdr->count * sizeof(struct e1000_buffer); - if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + if (!(rxdr->buffer_info = kcalloc(rxdr->count, + sizeof(struct e1000_buffer), + GFP_KERNEL))) { ret_val = 4; goto err_nomem; } - memset(rxdr->buffer_info, 0, size); rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 1d08e93..a561329 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -409,25 +409,21 @@ e1000_release_hw_control(struct e1000_ad { uint32_t ctrl_ext; uint32_t swsm; - uint32_t extcnf; /* Let firmware taken over control of h/w */ switch (adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - case e1000_80003es2lan: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); - break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, swsm & ~E1000_SWSM_DRV_LOAD); + break; + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: case e1000_ich8lan: - extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT); + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - extcnf & ~E1000_CTRL_EXT_DRV_LOAD); + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); break; default: break; @@ -450,26 +446,21 @@ e1000_get_hw_control(struct e1000_adapte { uint32_t ctrl_ext; uint32_t swsm; - uint32_t extcnf; /* Let firmware know the driver has taken over */ switch (adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - case e1000_80003es2lan: - ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); - E1000_WRITE_REG(&adapter->hw, CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); - break; case e1000_82573: swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, swsm | E1000_SWSM_DRV_LOAD); break; + case e1000_82571: + case e1000_82572: + case e1000_80003es2lan: case e1000_ich8lan: - extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL); - E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL, - extcnf | E1000_EXTCNF_CTRL_SWFLAG); + ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); break; default: break; @@ -522,14 +513,15 @@ e1000_release_manageability(struct e1000 } } -int -e1000_up(struct e1000_adapter *adapter) +/** + * e1000_configure - configure the hardware for RX and TX + * @adapter = private board structure + **/ +static void e1000_configure(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; int i; - /* hardware has been reset, we need to reload some things */ - e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -548,14 +540,20 @@ e1000_up(struct e1000_adapter *adapter) } adapter->tx_queue_len = netdev->tx_queue_len; +} + +int e1000_up(struct e1000_adapter *adapter) +{ + /* hardware has been reset, we need to reload some things */ + e1000_configure(adapter); + + clear_bit(__E1000_DOWN, &adapter->flags); #ifdef CONFIG_E1000_NAPI - netif_poll_enable(netdev); + netif_poll_enable(adapter->netdev); #endif e1000_irq_enable(adapter); - clear_bit(__E1000_DOWN, &adapter->flags); - /* fire a link change interrupt to start the watchdog */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); return 0; @@ -640,15 +638,15 @@ e1000_down(struct e1000_adapter *adapter * reschedule our watchdog timer */ set_bit(__E1000_DOWN, &adapter->flags); +#ifdef CONFIG_E1000_NAPI + netif_poll_disable(netdev); +#endif e1000_irq_disable(adapter); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); -#ifdef CONFIG_E1000_NAPI - netif_poll_disable(netdev); -#endif netdev->tx_queue_len = adapter->tx_queue_len; adapter->link_speed = 0; adapter->link_duplex = 0; @@ -1356,31 +1354,27 @@ #endif static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) { - int size; - - size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; - adapter->tx_ring = kmalloc(size, GFP_KERNEL); + adapter->tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct e1000_tx_ring), GFP_KERNEL); if (!adapter->tx_ring) return -ENOMEM; - memset(adapter->tx_ring, 0, size); - size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; - adapter->rx_ring = kmalloc(size, GFP_KERNEL); + adapter->rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct e1000_rx_ring), GFP_KERNEL); if (!adapter->rx_ring) { kfree(adapter->tx_ring); return -ENOMEM; } - memset(adapter->rx_ring, 0, size); #ifdef CONFIG_E1000_NAPI - size = sizeof(struct net_device) * adapter->num_rx_queues; - adapter->polling_netdev = kmalloc(size, GFP_KERNEL); + adapter->polling_netdev = kcalloc(adapter->num_rx_queues, + sizeof(struct net_device), + GFP_KERNEL); if (!adapter->polling_netdev) { kfree(adapter->tx_ring); kfree(adapter->rx_ring); return -ENOMEM; } - memset(adapter->polling_netdev, 0, size); #endif return E1000_SUCCESS; @@ -1410,21 +1404,17 @@ e1000_open(struct net_device *netdev) return -EBUSY; /* allocate transmit descriptors */ - if ((err = e1000_setup_all_tx_resources(adapter))) + err = e1000_setup_all_tx_resources(adapter); + if (err) goto err_setup_tx; /* allocate receive descriptors */ - if ((err = e1000_setup_all_rx_resources(adapter))) - goto err_setup_rx; - - err = e1000_request_irq(adapter); + err = e1000_setup_all_rx_resources(adapter); if (err) - goto err_req_irq; + goto err_setup_rx; e1000_power_up_phy(adapter); - if ((err = e1000_up(adapter))) - goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) { @@ -1437,12 +1427,33 @@ e1000_open(struct net_device *netdev) e1000_check_mng_mode(&adapter->hw)) e1000_get_hw_control(adapter); + /* before we allocate an interrupt, we must be ready to handle it. + * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt + * as soon as we call pci_request_irq, so we have to setup our + * clean_rx handler before we do so. */ + e1000_configure(adapter); + + err = e1000_request_irq(adapter); + if (err) + goto err_req_irq; + + /* From here on the code is the same as e1000_up() */ + clear_bit(__E1000_DOWN, &adapter->flags); + +#ifdef CONFIG_E1000_NAPI + netif_poll_enable(netdev); +#endif + + e1000_irq_enable(adapter); + + /* fire a link status change interrupt to start the watchdog */ + E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC); + return E1000_SUCCESS; -err_up: - e1000_power_down_phy(adapter); - e1000_free_irq(adapter); err_req_irq: + e1000_release_hw_control(adapter); + e1000_power_down_phy(adapter); e1000_free_all_rx_resources(adapter); err_setup_rx: e1000_free_all_tx_resources(adapter); @@ -1759,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_ad } memset(rxdr->buffer_info, 0, size); - size = sizeof(struct e1000_ps_page) * rxdr->count; - rxdr->ps_page = kmalloc(size, GFP_KERNEL); + rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page), + GFP_KERNEL); if (!rxdr->ps_page) { vfree(rxdr->buffer_info); DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } - memset(rxdr->ps_page, 0, size); - size = sizeof(struct e1000_ps_page_dma) * rxdr->count; - rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); + rxdr->ps_page_dma = kcalloc(rxdr->count, + sizeof(struct e1000_ps_page_dma), + GFP_KERNEL); if (!rxdr->ps_page_dma) { vfree(rxdr->buffer_info); kfree(rxdr->ps_page); @@ -1778,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_ad "Unable to allocate memory for the receive descriptor ring\n"); return -ENOMEM; } - memset(rxdr->ps_page_dma, 0, size); if (adapter->hw.mac_type <= e1000_82547_rev_2) desc_len = sizeof(struct e1000_rx_desc); @@ -2652,7 +2662,7 @@ e1000_watchdog(unsigned long data) netif_carrier_on(netdev); netif_wake_queue(netdev); - mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); adapter->smartspeed = 0; } else { /* make sure the receive unit is started */ @@ -2669,7 +2679,7 @@ e1000_watchdog(unsigned long data) DPRINTK(LINK, INFO, "NIC Link is Down\n"); netif_carrier_off(netdev); netif_stop_queue(netdev); - mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); /* 80003ES2LAN workaround-- * For packet buffer work-around on link down event; @@ -2721,7 +2731,7 @@ e1000_watchdog(unsigned long data) e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); } enum latency_range { @@ -3363,12 +3373,9 @@ e1000_xmit_frame(struct sk_buff *skb, st (adapter->hw.mac_type == e1000_82573)) e1000_transfer_dhcp_info(adapter, skb); - local_irq_save(flags); - if (!spin_trylock(&tx_ring->tx_lock)) { + if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); return NETDEV_TX_LOCKED; - } /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 42295d6..f889933 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0046" +#define DRV_VERSION "EHEA_0054" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) @@ -78,8 +78,6 @@ #define EHEA_MAX_PACKET_SIZE 9022 /* #define EHEA_RQ2_PKT_SIZE 1522 #define EHEA_L_PKT_SIZE 256 /* low latency */ -#define EHEA_POLL_MAX_RWQE 1000 - /* Send completion signaling */ #define EHEA_SIG_IV_LONG 1 @@ -311,6 +309,7 @@ struct ehea_cq { * Memory Region */ struct ehea_mr { + struct ehea_adapter *adapter; u64 handle; u64 vaddr; u32 lkey; @@ -357,8 +356,8 @@ struct ehea_port_res { struct ehea_qp *qp; struct ehea_cq *send_cq; struct ehea_cq *recv_cq; - struct ehea_eq *send_eq; - struct ehea_eq *recv_eq; + struct ehea_eq *eq; + struct net_device *d_netdev; spinlock_t send_lock; struct ehea_q_skb_arr rq1_skba; struct ehea_q_skb_arr rq2_skba; @@ -372,7 +371,6 @@ struct ehea_port_res { int swqe_count; u32 swqe_id_counter; u64 tx_packets; - struct tasklet_struct send_comp_task; spinlock_t recv_lock; struct port_state p_state; u64 rx_packets; @@ -380,10 +378,11 @@ struct ehea_port_res { }; +#define EHEA_MAX_PORTS 16 struct ehea_adapter { u64 handle; - u8 num_ports; - struct ehea_port *port[16]; + struct ibmebus_dev *ebus_dev; + struct ehea_port *port[EHEA_MAX_PORTS]; struct ehea_eq *neq; /* notification event queue */ struct workqueue_struct *ehea_wq; struct tasklet_struct neq_tasklet; @@ -406,7 +405,7 @@ struct ehea_port { struct net_device *netdev; struct net_device_stats stats; struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; - struct device_node *of_dev_node; /* Open Firmware Device Node */ + struct of_device ofdev; /* Open Firmware Device */ struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ struct vlan_group *vgrp; struct ehea_eq *qp_eq; @@ -415,7 +414,9 @@ struct ehea_port { char int_aff_name[EHEA_IRQ_NAME_SIZE]; int allmulti; /* Indicates IFF_ALLMULTI state */ int promisc; /* Indicates IFF_PROMISC state */ + int num_tx_qps; int num_add_tx_qps; + int num_mcs; int resets; u64 mac_addr; u32 logical_port_id; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 0e4042b..546e50c 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIE static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; static int sq_entries = EHEA_DEF_ENTRIES_SQ; +static int use_mcs = 0; +static int num_tx_qps = EHEA_NUM_TX_QP; module_param(msg_level, int, 0); module_param(rq1_entries, int, 0); module_param(rq2_entries, int, 0); module_param(rq3_entries, int, 0); module_param(sq_entries, int, 0); +module_param(use_mcs, int, 0); +module_param(num_tx_qps, int, 0); +MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); MODULE_PARM_DESC(msg_level, "msg_level"); MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " "[2^x - 1], x = [6..14]. Default = " @@ -71,6 +76,7 @@ MODULE_PARM_DESC(rq1_entries, "Number of MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " "[2^x - 1], x = [6..14]. Default = " __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); +MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); void ehea_dump(void *adr, int len, char *msg) { int x; @@ -197,7 +203,7 @@ static int ehea_refill_rq_def(struct ehe struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); if (!skb) { ehea_error("%s: no mem for skb/%d wqes filled", - dev->name, i); + pr->port->netdev->name, i); q_skba->os_skbs = fill_wqes - i; ret = -ENOMEM; break; @@ -345,10 +351,11 @@ static int ehea_treat_poll_error(struct return 0; } -static int ehea_poll(struct net_device *dev, int *budget) +static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, + struct ehea_port_res *pr, + int *budget) { - struct ehea_port *port = netdev_priv(dev); - struct ehea_port_res *pr = &port->port_res[0]; + struct ehea_port *port = pr->port; struct ehea_qp *qp = pr->qp; struct ehea_cqe *cqe; struct sk_buff *skb; @@ -359,14 +366,12 @@ static int ehea_poll(struct net_device * int skb_arr_rq2_len = pr->rq2_skba.len; int skb_arr_rq3_len = pr->rq3_skba.len; int processed, processed_rq1, processed_rq2, processed_rq3; - int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset; + int wqe_index, last_wqe_index, rq, my_quota, port_reset; processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; last_wqe_index = 0; my_quota = min(*budget, dev->quota); - my_quota = min(my_quota, EHEA_POLL_MAX_RWQE); - /* rq0 is low latency RQ */ cqe = ehea_poll_rq1(qp, &wqe_index); while ((my_quota > 0) && cqe) { ehea_inc_rq1(qp); @@ -386,14 +391,15 @@ static int ehea_poll(struct net_device * if (unlikely(!skb)) { if (netif_msg_rx_err(port)) ehea_error("LL rq1: skb=NULL"); - skb = netdev_alloc_skb(dev, + + skb = netdev_alloc_skb(port->netdev, EHEA_L_PKT_SIZE); if (!skb) break; } memcpy(skb->data, ((char*)cqe) + 64, cqe->num_bytes_transfered - 4); - ehea_fill_skb(dev, skb, cqe); + ehea_fill_skb(port->netdev, skb, cqe); } else if (rq == 2) { /* RQ2 */ skb = get_skb_by_index(skb_arr_rq2, skb_arr_rq2_len, cqe); @@ -402,7 +408,7 @@ static int ehea_poll(struct net_device * ehea_error("rq2: skb=NULL"); break; } - ehea_fill_skb(dev, skb, cqe); + ehea_fill_skb(port->netdev, skb, cqe); processed_rq2++; } else { /* RQ3 */ skb = get_skb_by_index(skb_arr_rq3, @@ -412,7 +418,7 @@ static int ehea_poll(struct net_device * ehea_error("rq3: skb=NULL"); break; } - ehea_fill_skb(dev, skb, cqe); + ehea_fill_skb(port->netdev, skb, cqe); processed_rq3++; } @@ -421,8 +427,7 @@ static int ehea_poll(struct net_device * cqe->vlan_tag); else netif_receive_skb(skb); - - } else { /* Error occured */ + } else { pr->p_state.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, &processed_rq2, @@ -433,32 +438,18 @@ static int ehea_poll(struct net_device * cqe = ehea_poll_rq1(qp, &wqe_index); } - dev->quota -= processed; - *budget -= processed; - - pr->p_state.ehea_poll += 1; pr->rx_packets += processed; + *budget -= processed; ehea_refill_rq1(pr, last_wqe_index, processed_rq1); ehea_refill_rq2(pr, processed_rq2); ehea_refill_rq3(pr, processed_rq3); - intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF); - - if (!cqe || intreq) { - netif_rx_complete(dev); - ehea_reset_cq_ep(pr->recv_cq); - ehea_reset_cq_n1(pr->recv_cq); - cqe = hw_qeit_get_valid(&qp->hw_rqueue1); - if (!cqe || intreq) - return 0; - if (!netif_rx_reschedule(dev, my_quota)) - return 0; - } - return 1; + cqe = ehea_poll_rq1(qp, &wqe_index); + return cqe; } -void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) +static void ehea_free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) { struct sk_buff *skb; int index, max_index_mask, i; @@ -479,26 +470,19 @@ void free_sent_skbs(struct ehea_cqe *cqe } } -#define MAX_SENDCOMP_QUOTA 400 -void ehea_send_irq_tasklet(unsigned long data) +static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { - struct ehea_port_res *pr = (struct ehea_port_res*)data; struct ehea_cq *send_cq = pr->send_cq; struct ehea_cqe *cqe; - int quota = MAX_SENDCOMP_QUOTA; + int quota = my_quota; int cqe_counter = 0; int swqe_av = 0; unsigned long flags; - do { - cqe = ehea_poll_cq(send_cq); - if (!cqe) { - ehea_reset_cq_ep(send_cq); - ehea_reset_cq_n1(send_cq); - cqe = ehea_poll_cq(send_cq); - if (!cqe) - break; - } + cqe = ehea_poll_cq(send_cq); + while(cqe && (quota > 0)) { + ehea_inc_cq(send_cq); + cqe_counter++; rmb(); if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { @@ -515,16 +499,19 @@ void ehea_send_irq_tasklet(unsigned long if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) == EHEA_SWQE2_TYPE)) - free_sent_skbs(cqe, pr); + ehea_free_sent_skbs(cqe, pr); swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); quota--; - } while (quota > 0); + + cqe = ehea_poll_cq(send_cq); + }; ehea_update_feca(send_cq, cqe_counter); atomic_add(swqe_av, &pr->swqe_avail); spin_lock_irqsave(&pr->netif_queue, flags); + if (pr->queue_stopped && (atomic_read(&pr->swqe_avail) >= pr->swqe_refill_th)) { netif_wake_queue(pr->port->netdev); @@ -532,22 +519,55 @@ void ehea_send_irq_tasklet(unsigned long } spin_unlock_irqrestore(&pr->netif_queue, flags); - if (unlikely(cqe)) - tasklet_hi_schedule(&pr->send_comp_task); + return cqe; } -static irqreturn_t ehea_send_irq_handler(int irq, void *param) +#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 + +static int ehea_poll(struct net_device *dev, int *budget) { - struct ehea_port_res *pr = param; - tasklet_hi_schedule(&pr->send_comp_task); - return IRQ_HANDLED; + struct ehea_port_res *pr = dev->priv; + struct ehea_cqe *cqe; + struct ehea_cqe *cqe_skb = NULL; + int force_irq, wqe_index; + + cqe = ehea_poll_rq1(pr->qp, &wqe_index); + cqe_skb = ehea_poll_cq(pr->send_cq); + + force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); + + if ((!cqe && !cqe_skb) || force_irq) { + pr->poll_counter = 0; + netif_rx_complete(dev); + ehea_reset_cq_ep(pr->recv_cq); + ehea_reset_cq_ep(pr->send_cq); + ehea_reset_cq_n1(pr->recv_cq); + ehea_reset_cq_n1(pr->send_cq); + cqe = ehea_poll_rq1(pr->qp, &wqe_index); + cqe_skb = ehea_poll_cq(pr->send_cq); + + if (!cqe && !cqe_skb) + return 0; + + if (!netif_rx_reschedule(dev, dev->quota)) + return 0; + } + + cqe = ehea_proc_rwqes(dev, pr, budget); + cqe_skb = ehea_proc_cqes(pr, 300); + + if (cqe || cqe_skb) + pr->poll_counter++; + + return 1; } static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - struct ehea_port *port = pr->port; - netif_rx_schedule(port->netdev); + + netif_rx_schedule(pr->d_netdev); + return IRQ_HANDLED; } @@ -580,7 +600,7 @@ static struct ehea_port *ehea_get_port(s { int i; - for (i = 0; i < adapter->num_ports; i++) + for (i = 0; i < EHEA_MAX_PORTS; i++) if (adapter->port[i]) if (adapter->port[i]->logical_port_id == logical_port) return adapter->port[i]; @@ -650,19 +670,25 @@ int ehea_sense_port_attr(struct ehea_por } port->autoneg = 1; + port->num_mcs = cb0->num_default_qps; /* Number of default QPs */ - port->num_def_qps = cb0->num_default_qps; + if (use_mcs) + port->num_def_qps = cb0->num_default_qps; + else + port->num_def_qps = 1; if (!port->num_def_qps) { ret = -EINVAL; goto out_free; } - if (port->num_def_qps >= EHEA_NUM_TX_QP) + port->num_tx_qps = num_tx_qps; + + if (port->num_def_qps >= port->num_tx_qps) port->num_add_tx_qps = 0; else - port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps; + port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps; ret = 0; out_free: @@ -882,23 +908,6 @@ static int ehea_reg_interrupts(struct ne struct ehea_port_res *pr; int i, ret; - for (i = 0; i < port->num_def_qps; i++) { - pr = &port->port_res[i]; - snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1 - , "%s-recv%d", dev->name, i); - ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1, - ehea_recv_irq_handler, - IRQF_DISABLED, pr->int_recv_name, pr); - if (ret) { - ehea_error("failed registering irq for ehea_recv_int:" - "port_res_nr:%d, ist=%X", i, - pr->recv_eq->attr.ist1); - goto out_free_seq; - } - if (netif_msg_ifup(port)) - ehea_info("irq_handle 0x%X for funct ehea_recv_int %d " - "registered", pr->recv_eq->attr.ist1, i); - } snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", dev->name); @@ -916,41 +925,41 @@ static int ehea_reg_interrupts(struct ne ehea_info("irq_handle 0x%X for function qp_aff_irq_handler " "registered", port->qp_eq->attr.ist1); + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, - "%s-send%d", dev->name, i); - ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1, - ehea_send_irq_handler, + "%s-queue%d", dev->name, i); + ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1, + ehea_recv_irq_handler, IRQF_DISABLED, pr->int_send_name, pr); if (ret) { - ehea_error("failed registering irq for ehea_send " + ehea_error("failed registering irq for ehea_queue " "port_res_nr:%d, ist=%X", i, - pr->send_eq->attr.ist1); + pr->eq->attr.ist1); goto out_free_req; } if (netif_msg_ifup(port)) - ehea_info("irq_handle 0x%X for function ehea_send_int " - "%d registered", pr->send_eq->attr.ist1, i); + ehea_info("irq_handle 0x%X for function ehea_queue_int " + "%d registered", pr->eq->attr.ist1, i); } out: return ret; + out_free_req: while (--i >= 0) { - u32 ist = port->port_res[i].send_eq->attr.ist1; + u32 ist = port->port_res[i].eq->attr.ist1; ibmebus_free_irq(NULL, ist, &port->port_res[i]); } + out_free_qpeq: ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port); i = port->num_def_qps; -out_free_seq: - while (--i >= 0) { - u32 ist = port->port_res[i].recv_eq->attr.ist1; - ibmebus_free_irq(NULL, ist, &port->port_res[i]); - } + goto out; + } static void ehea_free_interrupts(struct net_device *dev) @@ -960,21 +969,13 @@ static void ehea_free_interrupts(struct int i; /* send */ + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { pr = &port->port_res[i]; - ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr); + ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr); if (netif_msg_intr(port)) ehea_info("free send irq for res %d with handle 0x%X", - i, pr->send_eq->attr.ist1); - } - - /* receive */ - for (i = 0; i < port->num_def_qps; i++) { - pr = &port->port_res[i]; - ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr); - if (netif_msg_intr(port)) - ehea_info("free recv irq for res %d with handle 0x%X", - i, pr->recv_eq->attr.ist1); + i, pr->eq->attr.ist1); } /* associated events */ @@ -1003,8 +1004,13 @@ static int ehea_configure_port(struct eh PXLY_RC_VLAN_FILTER) | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); - for (i = 0; i < port->num_def_qps; i++) - cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; + for (i = 0; i < port->num_mcs; i++) + if (use_mcs) + cb0->default_qpn_arr[i] = + port->port_res[i].qp->init_attr.qp_nr; + else + cb0->default_qpn_arr[i] = + port->port_res[0].qp->init_attr.qp_nr; if (netif_msg_ifup(port)) ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); @@ -1027,52 +1033,35 @@ out: return ret; } -static int ehea_gen_smrs(struct ehea_port_res *pr) +int ehea_gen_smrs(struct ehea_port_res *pr) { - u64 hret; + int ret; struct ehea_adapter *adapter = pr->port->adapter; - hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, - adapter->mr.vaddr, EHEA_MR_ACC_CTRL, - adapter->pd, &pr->send_mr); - if (hret != H_SUCCESS) + ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr); + if (ret) goto out; - hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, - adapter->mr.vaddr, EHEA_MR_ACC_CTRL, - adapter->pd, &pr->recv_mr); - if (hret != H_SUCCESS) - goto out_freeres; + ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr); + if (ret) + goto out_free; return 0; -out_freeres: - hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); - if (hret != H_SUCCESS) - ehea_error("failed freeing SMR"); +out_free: + ehea_rem_mr(&pr->send_mr); out: + ehea_error("Generating SMRS failed\n"); return -EIO; } -static int ehea_rem_smrs(struct ehea_port_res *pr) +int ehea_rem_smrs(struct ehea_port_res *pr) { - struct ehea_adapter *adapter = pr->port->adapter; - int ret = 0; - u64 hret; - - hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); - if (hret != H_SUCCESS) { - ret = -EIO; - ehea_error("failed freeing send SMR for pr=%p", pr); - } - - hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle); - if (hret != H_SUCCESS) { - ret = -EIO; - ehea_error("failed freeing recv SMR for pr=%p", pr); - } - - return ret; + if ((ehea_rem_mr(&pr->send_mr)) + || (ehea_rem_mr(&pr->recv_mr))) + return -EIO; + else + return 0; } static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) @@ -1108,20 +1097,14 @@ static int ehea_init_port_res(struct ehe spin_lock_init(&pr->xmit_lock); spin_lock_init(&pr->netif_queue); - pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); - if (!pr->recv_eq) { - ehea_error("create_eq failed (recv_eq)"); - goto out_free; - } - - pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); - if (!pr->send_eq) { - ehea_error("create_eq failed (send_eq)"); + pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); + if (!pr->eq) { + ehea_error("create_eq failed (eq)"); goto out_free; } pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, - pr->recv_eq->fw_handle, + pr->eq->fw_handle, port->logical_port_id); if (!pr->recv_cq) { ehea_error("create_cq failed (cq_recv)"); @@ -1129,7 +1112,7 @@ static int ehea_init_port_res(struct ehe } pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, - pr->send_eq->fw_handle, + pr->eq->fw_handle, port->logical_port_id); if (!pr->send_cq) { ehea_error("create_cq failed (cq_send)"); @@ -1194,11 +1177,20 @@ static int ehea_init_port_res(struct ehe ret = -EIO; goto out_free; } - tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet, - (unsigned long)pr); + atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); kfree(init_attr); + + pr->d_netdev = alloc_netdev(0, "", ether_setup); + if (!pr->d_netdev) + goto out_free; + pr->d_netdev->priv = pr; + pr->d_netdev->weight = 64; + pr->d_netdev->poll = ehea_poll; + set_bit(__LINK_STATE_START, &pr->d_netdev->state); + strcpy(pr->d_netdev->name, port->netdev->name); + ret = 0; goto out; @@ -1211,8 +1203,7 @@ out_free: ehea_destroy_qp(pr->qp); ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->send_eq); - ehea_destroy_eq(pr->recv_eq); + ehea_destroy_eq(pr->eq); out: return ret; } @@ -1221,13 +1212,14 @@ static int ehea_clean_portres(struct ehe { int ret, i; + free_netdev(pr->d_netdev); + ret = ehea_destroy_qp(pr->qp); if (!ret) { ehea_destroy_cq(pr->send_cq); ehea_destroy_cq(pr->recv_cq); - ehea_destroy_eq(pr->send_eq); - ehea_destroy_eq(pr->recv_eq); + ehea_destroy_eq(pr->eq); for (i = 0; i < pr->rq1_skba.len; i++) if (pr->rq1_skba.arr[i]) @@ -1789,6 +1781,22 @@ static void ehea_xmit3(struct sk_buff *s dev_kfree_skb(skb); } +static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps) +{ + struct tcphdr *tcp; + u32 tmp; + + if ((skb->protocol == htons(ETH_P_IP)) && + (skb->nh.iph->protocol == IPPROTO_TCP)) { + tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4)); + tmp = (tcp->source + (tcp->dest << 16)) % 31; + tmp += skb->nh.iph->daddr % 31; + return tmp % num_qps; + } + else + return 0; +} + static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ehea_port *port = netdev_priv(dev); @@ -1796,9 +1804,18 @@ static int ehea_start_xmit(struct sk_buf unsigned long flags; u32 lkey; int swqe_index; - struct ehea_port_res *pr = &port->port_res[0]; + struct ehea_port_res *pr; + + pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)]; + - spin_lock(&pr->xmit_lock); + if (!spin_trylock(&pr->xmit_lock)) + return NETDEV_TX_BUSY; + + if (pr->queue_stopped) { + spin_unlock(&pr->xmit_lock); + return NETDEV_TX_BUSY; + } swqe = ehea_get_swqe(pr->qp, &swqe_index); memset(swqe, 0, SWQE_HEADER_SIZE); @@ -2057,7 +2074,7 @@ static int ehea_port_res_setup(struct eh } pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; - pr_cfg.max_entries_scq = sq_entries; + pr_cfg.max_entries_scq = sq_entries * 2; pr_cfg.max_entries_sq = sq_entries; pr_cfg.max_entries_rq1 = rq1_entries; pr_cfg.max_entries_rq2 = rq2_entries; @@ -2205,8 +2222,10 @@ static int ehea_down(struct net_device * ehea_drop_multicast_list(dev); ehea_free_interrupts(dev); - for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) - tasklet_kill(&port->port_res[i].send_comp_task); + for (i = 0; i < port->num_def_qps; i++) + while (test_bit(__LINK_STATE_RX_SCHED, + &port->port_res[i].d_netdev->state)) + msleep(1); ehea_broadcast_reg_helper(port, H_DEREG_BCMC); ret = ehea_clean_all_portres(port); @@ -2273,8 +2292,6 @@ static void ehea_tx_watchdog(struct net_ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) { struct hcp_query_ehea *cb; - struct device_node *lhea_dn = NULL; - struct device_node *eth_dn = NULL; u64 hret; int ret; @@ -2291,18 +2308,6 @@ int ehea_sense_adapter_attr(struct ehea_ goto out_herr; } - /* Determine the number of available logical ports - * by counting the child nodes of the lhea OFDT entry - */ - adapter->num_ports = 0; - lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); - do { - eth_dn = of_get_next_child(lhea_dn, eth_dn); - if (eth_dn) - adapter->num_ports++; - } while ( eth_dn ); - of_node_put(lhea_dn); - adapter->max_mc_mac = cb->max_mc_mac - 1; ret = 0; @@ -2312,79 +2317,150 @@ out: return ret; } -static int ehea_setup_single_port(struct ehea_port *port, - struct device_node *dn) +int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) { - int ret; - u64 hret; - struct net_device *dev = port->netdev; - struct ehea_adapter *adapter = port->adapter; struct hcp_ehea_port_cb4 *cb4; - u32 *dn_log_port_id; - int jumbo = 0; - - sema_init(&port->port_lock, 1); - port->state = EHEA_PORT_DOWN; - port->sig_comp_iv = sq_entries / 10; - - if (!dn) { - ehea_error("bad device node: dn=%p", dn); - ret = -EINVAL; - goto out; - } - - port->of_dev_node = dn; - - /* Determine logical port id */ - dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL); - - if (!dn_log_port_id) { - ehea_error("bad device node: dn_log_port_id=%p", - dn_log_port_id); - ret = -EINVAL; - goto out; - } - port->logical_port_id = *dn_log_port_id; - - port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); - if (!port->mc_list) { - ret = -ENOMEM; - goto out; - } - - INIT_LIST_HEAD(&port->mc_list->list); + u64 hret; + int ret = 0; - ret = ehea_sense_port_attr(port); - if (ret) - goto out; + *jumbo = 0; - /* Enable Jumbo frames */ + /* (Try to) enable *jumbo frames */ cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb4) { ehea_error("no mem for cb4"); + ret = -ENOMEM; + goto out; } else { - hret = ehea_h_query_ehea_port(adapter->handle, + hret = ehea_h_query_ehea_port(port->adapter->handle, port->logical_port_id, H_PORT_CB4, H_PORT_CB4_JUMBO, cb4); - if (hret == H_SUCCESS) { if (cb4->jumbo_frame) - jumbo = 1; + *jumbo = 1; else { cb4->jumbo_frame = 1; - hret = ehea_h_modify_ehea_port(adapter->handle, + hret = ehea_h_modify_ehea_port(port->adapter-> + handle, port-> - logical_port_id, + logical_port_id, H_PORT_CB4, H_PORT_CB4_JUMBO, cb4); if (hret == H_SUCCESS) - jumbo = 1; + *jumbo = 1; } - } + } else + ret = -EINVAL; + kfree(cb4); } +out: + return ret; +} + +static ssize_t ehea_show_port_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); + return sprintf(buf, "0x%X", port->logical_port_id); +} + +static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id, + NULL); + +static void __devinit logical_port_release(struct device *dev) +{ + struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); + of_node_put(port->ofdev.node); +} + +static struct device *ehea_register_port(struct ehea_port *port, + struct device_node *dn) +{ + int ret; + + port->ofdev.node = of_node_get(dn); + port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; + + sprintf(port->ofdev.dev.bus_id, "port%d", port->logical_port_id); + port->ofdev.dev.release = logical_port_release; + + ret = of_device_register(&port->ofdev); + if (ret) { + ehea_error("failed to register device. ret=%d", ret); + goto out; + } + + ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); + if (ret) { + ehea_error("failed to register attributes, ret=%d", ret); + goto out_unreg_of_dev; + } + + return &port->ofdev.dev; + +out_unreg_of_dev: + of_device_unregister(&port->ofdev); +out: + return NULL; +} + +static void ehea_unregister_port(struct ehea_port *port) +{ + device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); + of_device_unregister(&port->ofdev); +} + +struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, + u32 logical_port_id, + struct device_node *dn) +{ + int ret; + struct net_device *dev; + struct ehea_port *port; + struct device *port_dev; + int jumbo; + + /* allocate memory for the port structures */ + dev = alloc_etherdev(sizeof(struct ehea_port)); + + if (!dev) { + ehea_error("no mem for net_device"); + ret = -ENOMEM; + goto out_err; + } + + port = netdev_priv(dev); + + sema_init(&port->port_lock, 1); + port->state = EHEA_PORT_DOWN; + port->sig_comp_iv = sq_entries / 10; + + port->adapter = adapter; + port->netdev = dev; + port->logical_port_id = logical_port_id; + + port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); + + port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); + if (!port->mc_list) { + ret = -ENOMEM; + goto out_free_ethdev; + } + + INIT_LIST_HEAD(&port->mc_list->list); + + ret = ehea_sense_port_attr(port); + if (ret) + goto out_free_mc_list; + + port_dev = ehea_register_port(port, dn); + if (!port_dev) + goto out_free_mc_list; + + SET_NETDEV_DEV(dev, port_dev); /* initialize net_device structure */ SET_MODULE_OWNER(dev); @@ -2417,84 +2493,216 @@ static int ehea_setup_single_port(struct ret = register_netdev(dev); if (ret) { ehea_error("register_netdev failed. ret=%d", ret); - goto out_free; + goto out_unreg_port; } + ret = ehea_get_jumboframe_status(port, &jumbo); + if (ret) + ehea_error("failed determining jumbo frame status for %s", + port->netdev->name); + ehea_info("%s: Jumbo frames are %sabled", dev->name, jumbo == 1 ? "en" : "dis"); - port->netdev = dev; - ret = 0; - goto out; + return port; -out_free: +out_unreg_port: + ehea_unregister_port(port); + +out_free_mc_list: kfree(port->mc_list); -out: - return ret; + +out_free_ethdev: + free_netdev(dev); + +out_err: + ehea_error("setting up logical port with id=%d failed, ret=%d", + logical_port_id, ret); + return NULL; +} + +static void ehea_shutdown_single_port(struct ehea_port *port) +{ + unregister_netdev(port->netdev); + ehea_unregister_port(port); + kfree(port->mc_list); + free_netdev(port->netdev); } static int ehea_setup_ports(struct ehea_adapter *adapter) { - int ret; + struct device_node *lhea_dn; + struct device_node *eth_dn = NULL; + + u32 *dn_log_port_id; int port_setup_ok = 0; + int i = 0; + + lhea_dn = adapter->ebus_dev->ofdev.node; + while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { + + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + NULL); + if (!dn_log_port_id) { + ehea_error("bad device node: eth_dn name=%s", + eth_dn->full_name); + continue; + } + + adapter->port[i] = ehea_setup_single_port(adapter, + *dn_log_port_id, + eth_dn); + if (adapter->port[i]) + ehea_info("%s -> logical port id #%d", + adapter->port[i]->netdev->name, + *dn_log_port_id); + i++; + }; + + /* Check for succesfully set up ports */ + for (i = 0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i]) + port_setup_ok++; + + if (port_setup_ok) + return 0; /* At least some ports are setup correctly */ + + return -EINVAL; +} + +static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, + u32 logical_port_id) +{ + struct device_node *lhea_dn; + struct device_node *eth_dn = NULL; + u32 *dn_log_port_id; + + lhea_dn = adapter->ebus_dev->ofdev.node; + while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { + + dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", + NULL); + if (dn_log_port_id) + if (*dn_log_port_id == logical_port_id) + return eth_dn; + }; + + return NULL; +} + +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_port *port; - struct device_node *dn = NULL; - struct net_device *dev; + struct device_node *eth_dn = NULL; int i; - /* get port properties for all ports */ - for (i = 0; i < adapter->num_ports; i++) { + u32 logical_port_id; - if (adapter->port[i]) - continue; /* port already up and running */ + sscanf(buf, "%X", &logical_port_id); - /* allocate memory for the port structures */ - dev = alloc_etherdev(sizeof(struct ehea_port)); + port = ehea_get_port(adapter, logical_port_id); - if (!dev) { - ehea_error("no mem for net_device"); - break; - } + if (port) { + ehea_info("adding port with logical port id=%d failed. port " + "already configured as %s.", logical_port_id, + port->netdev->name); + return -EINVAL; + } - port = netdev_priv(dev); - port->adapter = adapter; - port->netdev = dev; - adapter->port[i] = port; - port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); + eth_dn = ehea_get_eth_dn(adapter, logical_port_id); - dn = of_find_node_by_name(dn, "ethernet"); - ret = ehea_setup_single_port(port, dn); - if (ret) { - /* Free mem for this port struct. The others will be - processed on rollback */ - free_netdev(dev); - adapter->port[i] = NULL; - ehea_error("eHEA port %d setup failed, ret=%d", i, ret); - } + if (!eth_dn) { + ehea_info("no logical port with id %d found", logical_port_id); + return -EINVAL; } - of_node_put(dn); + port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); - /* Check for succesfully set up ports */ - for (i = 0; i < adapter->num_ports; i++) - if (adapter->port[i]) - port_setup_ok++; + of_node_put(eth_dn); - if (port_setup_ok) - ret = 0; /* At least some ports are setup correctly */ - else - ret = -EINVAL; + if (port) { + for (i=0; i < EHEA_MAX_PORTS; i++) + if (!adapter->port[i]) { + adapter->port[i] = port; + break; + } + + ehea_info("added %s (logical port id=%d)", port->netdev->name, + logical_port_id); + } else + return -EIO; + + return (ssize_t) count; +} + +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_port *port; + int i; + u32 logical_port_id; + + sscanf(buf, "%X", &logical_port_id); + + port = ehea_get_port(adapter, logical_port_id); + + if (port) { + ehea_info("removed %s (logical port id=%d)", port->netdev->name, + logical_port_id); + + ehea_shutdown_single_port(port); + for (i=0; i < EHEA_MAX_PORTS; i++) + if (adapter->port[i] == port) { + adapter->port[i] = NULL; + break; + } + } else { + ehea_error("removing port with logical port id=%d failed. port " + "not configured.", logical_port_id); + return -EINVAL; + } + + return (ssize_t) count; +} + +static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port); +static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port); + +int ehea_create_device_sysfs(struct ibmebus_dev *dev) +{ + int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port); + if (ret) + goto out; + + ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port); +out: return ret; } -static int __devinit ehea_probe(struct ibmebus_dev *dev, - const struct of_device_id *id) +void ehea_remove_device_sysfs(struct ibmebus_dev *dev) +{ + device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port); + device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port); +} + +static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, + const struct of_device_id *id) { struct ehea_adapter *adapter; u64 *adapter_handle; int ret; + if (!dev || !dev->ofdev.node) { + ehea_error("Invalid ibmebus device probed"); + return -EINVAL; + } + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); if (!adapter) { ret = -ENOMEM; @@ -2502,6 +2710,8 @@ static int __devinit ehea_probe(struct i goto out; } + adapter->ebus_dev = dev; + adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", NULL); if (adapter_handle) @@ -2518,7 +2728,7 @@ static int __devinit ehea_probe(struct i dev->ofdev.dev.driver_data = adapter; - ret = ehea_reg_mr_adapter(adapter); + ret = ehea_reg_kernel_mr(adapter, &adapter->mr); if (ret) { dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n"); goto out_free_ad; @@ -2531,11 +2741,11 @@ static int __devinit ehea_probe(struct i dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); goto out_free_res; } - dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports); adapter->neq = ehea_create_eq(adapter, EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); if (!adapter->neq) { + ret = -EIO; dev_err(&dev->ofdev.dev, "NEQ creation failed"); goto out_free_res; } @@ -2552,18 +2762,27 @@ static int __devinit ehea_probe(struct i } adapter->ehea_wq = create_workqueue("ehea_wq"); - if (!adapter->ehea_wq) + if (!adapter->ehea_wq) { + ret = -EIO; goto out_free_irq; + } + + ret = ehea_create_device_sysfs(dev); + if (ret) + goto out_kill_wq; ret = ehea_setup_ports(adapter); if (ret) { dev_err(&dev->ofdev.dev, "setup_ports failed"); - goto out_kill_wq; + goto out_rem_dev_sysfs; } ret = 0; goto out; +out_rem_dev_sysfs: + ehea_remove_device_sysfs(dev); + out_kill_wq: destroy_workqueue(adapter->ehea_wq); @@ -2574,7 +2793,7 @@ out_kill_eq: ehea_destroy_eq(adapter->neq); out_free_res: - ehea_h_free_resource(adapter->handle, adapter->mr.handle); + ehea_rem_mr(&adapter->mr); out_free_ad: kfree(adapter); @@ -2582,36 +2801,26 @@ out: return ret; } -static void ehea_shutdown_single_port(struct ehea_port *port) -{ - unregister_netdev(port->netdev); - kfree(port->mc_list); - free_netdev(port->netdev); -} - static int __devexit ehea_remove(struct ibmebus_dev *dev) { struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; - u64 hret; int i; - for (i = 0; i < adapter->num_ports; i++) + for (i = 0; i < EHEA_MAX_PORTS; i++) if (adapter->port[i]) { ehea_shutdown_single_port(adapter->port[i]); adapter->port[i] = NULL; } + + ehea_remove_device_sysfs(dev); + destroy_workqueue(adapter->ehea_wq); ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); tasklet_kill(&adapter->neq_tasklet); ehea_destroy_eq(adapter->neq); - - hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle); - if (hret) { - dev_err(&dev->ofdev.dev, "free_resource_mr failed"); - return -EIO; - } + ehea_rem_mr(&adapter->mr); kfree(adapter); return 0; } @@ -2655,7 +2864,7 @@ static struct of_device_id ehea_device_t static struct ibmebus_driver ehea_driver = { .name = "ehea", .id_table = ehea_device_table, - .probe = ehea_probe, + .probe = ehea_probe_adapter, .remove = ehea_remove, }; diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index bc3c005..95c4a7f 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64 0, 0, 0, 0, 0, 0); /* R7-R12 */ } -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) +u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, + u64 force_bit) { return ehea_plpar_hcall_norets(H_FREE_RESOURCE, adapter_handle, /* R4 */ res_handle, /* R5 */ - 0, 0, 0, 0, 0); /* R6-R10 */ + force_bit, + 0, 0, 0, 0); /* R7-R10 */ } u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 90acddb..d17a45a 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h @@ -414,7 +414,11 @@ #define H_DISABLE_GET_RQC 3 u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle); -u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle); +#define FORCE_FREE 1 +#define NORMAL_FREE 0 + +u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, + u64 force_bit); u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u64 length, const u32 access_ctrl, diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 96ff3b6..f24a886 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -197,7 +197,7 @@ out_kill_hwq: hw_queue_dtor(&cq->hw_queue); out_freeres: - ehea_h_free_resource(adapter->handle, cq->fw_handle); + ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE); out_freemem: kfree(cq); @@ -206,25 +206,38 @@ out_nomem: return NULL; } -int ehea_destroy_cq(struct ehea_cq *cq) +u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force) { - u64 adapter_handle, hret; + u64 hret; + u64 adapter_handle = cq->adapter->handle; + + /* deregister all previous registered pages */ + hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force); + if (hret != H_SUCCESS) + return hret; + + hw_queue_dtor(&cq->hw_queue); + kfree(cq); + + return hret; +} +int ehea_destroy_cq(struct ehea_cq *cq) +{ + u64 hret; if (!cq) return 0; - adapter_handle = cq->adapter->handle; + if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) { + ehea_error_data(cq->adapter, cq->fw_handle); + hret = ehea_destroy_cq_res(cq, FORCE_FREE); + } - /* deregister all previous registered pages */ - hret = ehea_h_free_resource(adapter_handle, cq->fw_handle); if (hret != H_SUCCESS) { ehea_error("destroy CQ failed"); return -EIO; } - hw_queue_dtor(&cq->hw_queue); - kfree(cq); - return 0; } @@ -297,7 +310,7 @@ out_kill_hwq: hw_queue_dtor(&eq->hw_queue); out_freeres: - ehea_h_free_resource(adapter->handle, eq->fw_handle); + ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE); out_freemem: kfree(eq); @@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehe return eqe; } -int ehea_destroy_eq(struct ehea_eq *eq) +u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force) { u64 hret; unsigned long flags; - if (!eq) - return 0; - spin_lock_irqsave(&eq->spinlock, flags); - hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle); + hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force); spin_unlock_irqrestore(&eq->spinlock, flags); - if (hret != H_SUCCESS) { - ehea_error("destroy_eq failed"); - return -EIO; - } + if (hret != H_SUCCESS) + return hret; hw_queue_dtor(&eq->hw_queue); kfree(eq); + return hret; +} + +int ehea_destroy_eq(struct ehea_eq *eq) +{ + u64 hret; + if (!eq) + return 0; + + if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) { + ehea_error_data(eq->adapter, eq->fw_handle); + hret = ehea_destroy_eq_res(eq, FORCE_FREE); + } + + if (hret != H_SUCCESS) { + ehea_error("destroy EQ failed"); + return -EIO; + } + return 0; } @@ -471,41 +498,56 @@ out_kill_hwsq: out_freeres: ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); - ehea_h_free_resource(adapter->handle, qp->fw_handle); + ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE); out_freemem: kfree(qp); return NULL; } -int ehea_destroy_qp(struct ehea_qp *qp) +u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force) { - u64 hret; - struct ehea_qp_init_attr *qp_attr = &qp->init_attr; + u64 hret; + struct ehea_qp_init_attr *qp_attr = &qp->init_attr; - if (!qp) - return 0; - ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); - hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); - if (hret != H_SUCCESS) { - ehea_error("destroy_qp failed"); - return -EIO; - } + ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); + hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force); + if (hret != H_SUCCESS) + return hret; - hw_queue_dtor(&qp->hw_squeue); - hw_queue_dtor(&qp->hw_rqueue1); + hw_queue_dtor(&qp->hw_squeue); + hw_queue_dtor(&qp->hw_rqueue1); - if (qp_attr->rq_count > 1) - hw_queue_dtor(&qp->hw_rqueue2); - if (qp_attr->rq_count > 2) - hw_queue_dtor(&qp->hw_rqueue3); - kfree(qp); + if (qp_attr->rq_count > 1) + hw_queue_dtor(&qp->hw_rqueue2); + if (qp_attr->rq_count > 2) + hw_queue_dtor(&qp->hw_rqueue3); + kfree(qp); - return 0; + return hret; } -int ehea_reg_mr_adapter(struct ehea_adapter *adapter) +int ehea_destroy_qp(struct ehea_qp *qp) +{ + u64 hret; + if (!qp) + return 0; + + if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) { + ehea_error_data(qp->adapter, qp->fw_handle); + hret = ehea_destroy_qp_res(qp, FORCE_FREE); + } + + if (hret != H_SUCCESS) { + ehea_error("destroy QP failed"); + return -EIO; + } + + return 0; +} + +int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) { int i, k, ret; u64 hret, pt_abs, start, end, nr_pages; @@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adap hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, acc_ctrl, adapter->pd, - &adapter->mr.handle, &adapter->mr.lkey); + &mr->handle, &mr->lkey); if (hret != H_SUCCESS) { ehea_error("alloc_resource_mr failed"); ret = -EIO; goto out; } - adapter->mr.vaddr = KERNELBASE; + mr->vaddr = KERNELBASE; k = 0; while (nr_pages > 0) { @@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adap EHEA_PAGESIZE))); hret = ehea_h_register_rpage_mr(adapter->handle, - adapter->mr.handle, 0, + mr->handle, 0, 0, (u64)pt_abs, num_pages); nr_pages -= num_pages; @@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adap (k * EHEA_PAGESIZE))); hret = ehea_h_register_rpage_mr(adapter->handle, - adapter->mr.handle, 0, + mr->handle, 0, 0, abs_adr,1); nr_pages--; } if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) { ehea_h_free_resource(adapter->handle, - adapter->mr.handle); - ehea_error("register_rpage_mr failed: hret = %lX", - hret); + mr->handle, FORCE_FREE); + ehea_error("register_rpage_mr failed"); ret = -EIO; goto out; } } if (hret != H_SUCCESS) { - ehea_h_free_resource(adapter->handle, adapter->mr.handle); - ehea_error("register_rpage failed for last page: hret = %lX", - hret); + ehea_h_free_resource(adapter->handle, mr->handle, + FORCE_FREE); + ehea_error("register_rpage failed for last page"); ret = -EIO; goto out; } + + mr->adapter = adapter; ret = 0; out: kfree(pt); return ret; } +int ehea_rem_mr(struct ehea_mr *mr) +{ + u64 hret; + + if (!mr || !mr->adapter) + return -EINVAL; + + hret = ehea_h_free_resource(mr->adapter->handle, mr->handle, + FORCE_FREE); + if (hret != H_SUCCESS) { + ehea_error("destroy MR failed"); + return -EIO; + } + + return 0; +} + +int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, + struct ehea_mr *shared_mr) +{ + u64 hret; + + hret = ehea_h_register_smr(adapter->handle, old_mr->handle, + old_mr->vaddr, EHEA_MR_ACC_CTRL, + adapter->pd, shared_mr); + if (hret != H_SUCCESS) + return -EIO; + + shared_mr->adapter = adapter; + + return 0; +} + void print_error_data(u64 *data) { int length; @@ -597,6 +673,14 @@ void print_error_data(u64 *data) ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " "port=%lX", resource, data[6], data[12], data[22]); + if (type == 0x4) /* Completion Queue */ + ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource, + data[6]); + + if (type == 0x3) /* Event Queue */ + ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource, + data[6]); + ehea_dump(data, length, "error data"); } diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 1ff6098..2460331 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h @@ -320,6 +320,11 @@ static inline struct ehea_cqe *ehea_poll return hw_qeit_get_valid(queue); } +static inline void ehea_inc_cq(struct ehea_cq *cq) +{ + hw_qeit_inc(&cq->hw_queue); +} + static inline void ehea_inc_rq1(struct ehea_qp *qp) { hw_qeit_inc(&qp->hw_rqueue1); @@ -327,7 +332,7 @@ static inline void ehea_inc_rq1(struct e static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq) { - return hw_qeit_get_inc_valid(&my_cq->hw_queue); + return hw_qeit_get_valid(&my_cq->hw_queue); } #define EHEA_CQ_REGISTER_ORIG 0 @@ -356,7 +361,12 @@ struct ehea_qp *ehea_create_qp(struct eh int ehea_destroy_qp(struct ehea_qp *qp); -int ehea_reg_mr_adapter(struct ehea_adapter *adapter); +int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr); + +int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, + struct ehea_mr *shared_mr); + +int ehea_rem_mr(struct ehea_mr *mr); void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c index b27442a..c38ce73 100644 --- a/drivers/net/ixgb/ixgb_param.c +++ b/drivers/net/ixgb/ixgb_param.c @@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct return -1; } -#define LIST_LEN(l) (sizeof(l) / sizeof(l[0])) - /** * ixgb_check_options - Range Checking for Command Line Parameters * @adapter: board private structure @@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter * .name = "Flow Control", .err = "reading default settings from EEPROM", .def = ixgb_fc_tx_pause, - .arg = { .l = { .nr = LIST_LEN(fc_list), + .arg = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }} }; diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index f42b9e2..83d70b2 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c @@ -26,8 +26,6 @@ struct mipsnet_priv { struct net_device_stats stats; }; -static struct platform_device *mips_plat_dev; - static char mipsnet_string[] = "mipsnet"; /* @@ -298,64 +296,17 @@ static struct device_driver mipsnet_driv .remove = __devexit_p(mipsnet_device_remove), }; -static void mipsnet_platform_release(struct device *device) -{ - struct platform_device *pldev; - - /* free device */ - pldev = to_platform_device(device); - kfree(pldev); -} - static int __init mipsnet_init_module(void) { - struct platform_device *pldev; int err; printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); - if (driver_register(&mipsnet_driver)) { + err = driver_register(&mipsnet_driver); + if (err) printk(KERN_ERR "Driver registration failed\n"); - err = -ENODEV; - goto out; - } - - if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { - err = -ENOMEM; - goto out_unregister_driver; - } - - memset (pldev, 0, sizeof (*pldev)); - pldev->name = mipsnet_string; - pldev->id = 0; - pldev->dev.release = mipsnet_platform_release; - if (platform_device_register(pldev)) { - err = -ENODEV; - goto out_free_pldev; - } - - if (!pldev->dev.driver) { - /* - * The driver was not bound to this device, there was - * no hardware at this address. Unregister it, as the - * release fuction will take care of freeing the - * allocated structure - */ - platform_device_unregister (pldev); - } - - mips_plat_dev = pldev; - - return 0; - -out_free_pldev: - kfree(pldev); - -out_unregister_driver: - driver_unregister(&mipsnet_driver); -out: return err; } diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 4d94ba7..37ba09a 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -253,12 +253,12 @@ struct pcnet32_access { * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { - struct pcnet32_init_block init_block; + struct pcnet32_init_block *init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ struct pcnet32_rx_head *rx_ring; struct pcnet32_tx_head *tx_ring; - dma_addr_t dma_addr;/* DMA address of beginning of this - object, returned by pci_alloc_consistent */ + dma_addr_t init_dma_addr;/* DMA address of beginning of the init block, + returned by pci_alloc_consistent */ struct pci_dev *pci_dev; const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ @@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(stru static void pcnet32_purge_rx_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int i; /* free all allocated skbuffs */ @@ -681,7 +681,7 @@ #endif static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; @@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct n static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; @@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct n static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct n static u32 pcnet32_get_link(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r; @@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_d static u32 pcnet32_get_msglevel(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); return lp->msg_enable; } static void pcnet32_set_msglevel(struct net_device *dev, u32 value) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); lp->msg_enable = value; } static int pcnet32_nway_reset(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; @@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); ering->tx_max_pending = TX_MAX_RING_SIZE; ering->tx_pending = lp->tx_ring_size; @@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; unsigned int size; ulong ioaddr = dev->base_addr; @@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struc static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *test, u64 * data) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int rc; if (test->flags == ETH_TEST_FL_OFFLINE) { @@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; /* access to registers */ ulong ioaddr = dev->base_addr; /* card base I/O address */ struct sk_buff *skb; /* sk buff */ @@ -1047,7 +1047,7 @@ #endif static void pcnet32_led_blink_callback(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(s static int pcnet32_phys_id(struct net_device *dev, u32 data) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_de int can_sleep) { int csr5; - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; int ticks; @@ -1258,7 +1258,7 @@ #endif static int pcnet32_rx(struct net_device *dev, int quota) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int entry = lp->cur_rx & lp->rx_mod_mask; struct pcnet32_rx_head *rxp = &lp->rx_ring[entry]; int npackets = 0; @@ -1283,7 +1283,7 @@ static int pcnet32_rx(struct net_device static int pcnet32_tx(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned int dirty_tx = lp->dirty_tx; int delta; int must_restart = 0; @@ -1382,7 +1382,7 @@ #endif #ifdef CONFIG_PCNET32_NAPI static int pcnet32_poll(struct net_device *dev, int *budget) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int quota = min(dev->quota, *budget); unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -1429,7 +1429,7 @@ #define PCNET32_REGS_PER_PHY 32 #define PCNET32_MAX_PHYS 32 static int pcnet32_get_regs_len(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int j = lp->phycount * PCNET32_REGS_PER_PHY; return ((PCNET32_NUM_REGS + j) * sizeof(u16)); @@ -1440,7 +1440,7 @@ static void pcnet32_get_regs(struct net_ { int i, csr0; u16 *buff = ptr; - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; ulong ioaddr = dev->base_addr; unsigned long flags; @@ -1593,7 +1593,6 @@ static int __devinit pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { struct pcnet32_private *lp; - dma_addr_t lp_dma_addr; int i, media; int fdx, mii, fset, dxsuflo; int chip_version; @@ -1715,7 +1714,7 @@ pcnet32_probe1(unsigned long ioaddr, int dxsuflo = 1; } - dev = alloc_etherdev(0); + dev = alloc_etherdev(sizeof(*lp)); if (!dev) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Memory allocation failed.\n"); @@ -1806,25 +1805,22 @@ pcnet32_probe1(unsigned long ioaddr, int } dev->base_addr = ioaddr; + lp = netdev_priv(dev); /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ - if ((lp = - pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { + if ((lp->init_block = + pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); ret = -ENOMEM; goto err_free_netdev; } - - memset(lp, 0, sizeof(*lp)); - lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; spin_lock_init(&lp->lock); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ @@ -1871,23 +1867,21 @@ pcnet32_probe1(unsigned long ioaddr, int && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = + lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ + lp->init_block->tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->phys_addr[i] = dev->dev_addr[i]; + lp->init_block->filter[0] = 0x00000000; + lp->init_block->filter[1] = 0x00000000; + lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); - a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, - init_block)) & 0xffff); - a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, - init_block)) >> 16); + a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); + a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); if (pdev) { /* use the IRQ provided by PCI */ dev->irq = pdev->irq; @@ -1993,7 +1987,8 @@ #endif err_free_ring: pcnet32_free_ring(dev); err_free_consistent: - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + lp->init_block, lp->init_dma_addr); err_free_netdev: free_netdev(dev); err_release_region: @@ -2004,7 +1999,7 @@ #endif /* if any allocation fails, caller must also call pcnet32_free_ring */ static int pcnet32_alloc_ring(struct net_device *dev, char *name) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * @@ -2071,7 +2066,7 @@ static int pcnet32_alloc_ring(struct net static void pcnet32_free_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); kfree(lp->tx_skbuff); lp->tx_skbuff = NULL; @@ -2104,7 +2099,7 @@ static void pcnet32_free_ring(struct net static int pcnet32_open(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 val; int i; @@ -2135,8 +2130,7 @@ static int pcnet32_open(struct net_devic "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), (u32) (lp->rx_ring_dma_addr), - (u32) (lp->dma_addr + - offsetof(struct pcnet32_private, init_block))); + (u32) (lp->init_dma_addr)); /* set/reset autoselect bit */ val = lp->a.read_bcr(ioaddr, 2) & ~2; @@ -2275,7 +2269,7 @@ #ifdef DO_DXSUFLO } #endif - lp->init_block.mode = + lp->init_block->mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); pcnet32_load_multicast(dev); @@ -2285,12 +2279,8 @@ #endif } /* Re-initialize the PCNET32, and start it when done. */ - lp->a.write_csr(ioaddr, 1, (lp->dma_addr + - offsetof(struct pcnet32_private, - init_block)) & 0xffff); - lp->a.write_csr(ioaddr, 2, - (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)) >> 16); + lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); + lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT); @@ -2317,8 +2307,7 @@ #endif printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, - (u32) (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)), + (u32) (lp->init_dma_addr), lp->a.read_csr(ioaddr, CSR0)); spin_unlock_irqrestore(&lp->lock, flags); @@ -2356,7 +2345,7 @@ #endif static void pcnet32_purge_tx_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int i; for (i = 0; i < lp->tx_ring_size; i++) { @@ -2376,7 +2365,7 @@ static void pcnet32_purge_tx_ring(struct /* Initialize the PCNET32 Rx and Tx rings. */ static int pcnet32_init_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int i; lp->tx_full = 0; @@ -2418,12 +2407,12 @@ static int pcnet32_init_ring(struct net_ lp->tx_dma_addr[i] = 0; } - lp->init_block.tlen_rlen = + lp->init_block->tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + lp->init_block->phys_addr[i] = dev->dev_addr[i]; + lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0; } @@ -2434,7 +2423,7 @@ static int pcnet32_init_ring(struct net_ */ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int i; @@ -2464,7 +2453,7 @@ static void pcnet32_restart(struct net_d static void pcnet32_tx_timeout(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr, flags; spin_lock_irqsave(&lp->lock, flags); @@ -2505,7 +2494,7 @@ static void pcnet32_tx_timeout(struct ne static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 status; int entry; @@ -2570,7 +2559,7 @@ pcnet32_interrupt(int irq, void *dev_id) int boguscnt = max_interrupt_work; ioaddr = dev->base_addr; - lp = dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -2652,7 +2641,7 @@ #endif static int pcnet32_close(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; del_timer_sync(&lp->watchdog_timer); @@ -2693,7 +2682,7 @@ static int pcnet32_close(struct net_devi static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -2707,8 +2696,8 @@ static struct net_device_stats *pcnet32_ /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - volatile struct pcnet32_init_block *ib = &lp->init_block; + struct pcnet32_private *lp = netdev_priv(dev); + volatile struct pcnet32_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *) & ib->filter; struct dev_mc_list *dmi = dev->mc_list; unsigned long ioaddr = dev->base_addr; @@ -2757,7 +2746,7 @@ static void pcnet32_load_multicast(struc static void pcnet32_set_multicast_list(struct net_device *dev) { unsigned long ioaddr = dev->base_addr, flags; - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int csr15, suspended; spin_lock_irqsave(&lp->lock, flags); @@ -2768,12 +2757,12 @@ static void pcnet32_set_multicast_list(s if (netif_msg_hw(lp)) printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - lp->init_block.mode = + lp->init_block->mode = le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); } else { - lp->init_block.mode = + lp->init_block->mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); pcnet32_load_multicast(dev); @@ -2796,7 +2785,7 @@ static void pcnet32_set_multicast_list(s /* This routine assumes that the lp->lock is held */ static int mdio_read(struct net_device *dev, int phy_id, int reg_num) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 val_out; @@ -2812,7 +2801,7 @@ static int mdio_read(struct net_device * /* This routine assumes that the lp->lock is held */ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; if (!lp->mii) @@ -2824,7 +2813,7 @@ static void mdio_write(struct net_device static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int rc; unsigned long flags; @@ -2842,7 +2831,7 @@ static int pcnet32_ioctl(struct net_devi static int pcnet32_check_otherphy(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); struct mii_if_info mii = lp->mii_if; u16 bmcr; int i; @@ -2889,7 +2878,7 @@ static int pcnet32_check_otherphy(struct static void pcnet32_check_media(struct net_device *dev, int verbose) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); int curr_link; int prev_link = netif_carrier_ok(dev) ? 1 : 0; u32 bcr9; @@ -2945,7 +2934,7 @@ static void pcnet32_check_media(struct n static void pcnet32_watchdog(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; /* Print the link status if it has changed */ @@ -2961,12 +2950,13 @@ static void __devexit pcnet32_remove_one struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = netdev_priv(dev); unregister_netdev(dev); pcnet32_free_ring(dev); release_region(dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + lp->init_block, lp->init_dma_addr); free_netdev(dev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); @@ -3041,12 +3031,13 @@ static void __exit pcnet32_cleanup_modul struct net_device *next_dev; while (pcnet32_dev) { - struct pcnet32_private *lp = pcnet32_dev->priv; + struct pcnet32_private *lp = netdev_priv(pcnet32_dev); next_dev = lp->next; unregister_netdev(pcnet32_dev); pcnet32_free_ring(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), + lp->init_block, lp->init_dma_addr); free_netdev(pcnet32_dev); pcnet32_dev = next_dev; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index b31ce27..fc4aee9 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -35,10 +35,14 @@ #include #include #include -/* mdiobus_register +/** + * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus + * @bus: target mii_bus * - * description: Called by a bus driver to bring up all the PHYs - * on a given bus, and attach them to the bus + * Description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus. + * + * Returns 0 on success or < 0 on error. */ int mdiobus_register(struct mii_bus *bus) { @@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus * } EXPORT_SYMBOL(mdiobus_unregister); -/* mdio_bus_match +/** + * mdio_bus_match - determine if given PHY driver supports the given PHY device + * @dev: target PHY device + * @drv: given PHY driver * - * description: Given a PHY device, and a PHY driver, return 1 if - * the driver supports the device. Otherwise, return 0 + * Description: Given a PHY device, and a PHY driver, return 1 if + * the driver supports the device. Otherwise, return 0. */ static int mdio_bus_match(struct device *dev, struct device_driver *drv) { diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c94a1fb..eed433d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -39,7 +39,9 @@ #include #include #include -/* Convenience function to print out the current phy status +/** + * phy_print_status - Convenience function to print out the current phy status + * @phydev: the phy_device struct */ void phy_print_status(struct phy_device *phydev) { @@ -55,10 +57,15 @@ void phy_print_status(struct phy_device EXPORT_SYMBOL(phy_print_status); -/* Convenience functions for reading/writing a given PHY - * register. They MUST NOT be called from interrupt context, +/** + * phy_read - Convenience function for reading a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt - * to conclude the operation. */ + * to conclude the operation. + */ int phy_read(struct phy_device *phydev, u16 regnum) { int retval; @@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, } EXPORT_SYMBOL(phy_read); +/** + * phy_write - Convenience function for writing a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ int phy_write(struct phy_device *phydev, u16 regnum, u16 val) { int err; @@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev, } EXPORT_SYMBOL(phy_write); - +/** + * phy_clear_interrupt - Ack the phy device's interrupt + * @phydev: the phy_device struct + * + * If the @phydev driver has an ack_interrupt function, call it to + * ack and clear the phy device's interrupt. + * + * Returns 0 on success on < 0 on error. + */ int phy_clear_interrupt(struct phy_device *phydev) { int err = 0; @@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_devic return err; } - +/** + * phy_config_interrupt - configure the PHY device for the requested interrupts + * @phydev: the phy_device struct + * @interrupts: interrupt flags to configure for this @phydev + * + * Returns 0 on success on < 0 on error. + */ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) { int err = 0; @@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_devi } -/* phy_aneg_done +/** + * phy_aneg_done - return auto-negotiation status + * @phydev: target phy_device struct * - * description: Reads the status register and returns 0 either if + * Description: Reads the status register and returns 0 either if * auto-negotiation is incomplete, or if there was an error. * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. */ @@ -173,9 +206,12 @@ static const struct phy_setting settings #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) -/* phy_find_setting +/** + * phy_find_setting - find a PHY settings array entry that matches speed & duplex + * @speed: speed to match + * @duplex: duplex to match * - * description: Searches the settings array for the setting which + * Description: Searches the settings array for the setting which * matches the desired speed and duplex, and returns the index * of that setting. Returns the index of the last setting if * none of the others match. @@ -192,11 +228,12 @@ static inline int phy_find_setting(int s return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } -/* phy_find_valid - * idx: The first index in settings[] to search - * features: A mask of the valid settings +/** + * phy_find_valid - find a PHY setting that matches the requested features mask + * @idx: The first index in settings[] to search + * @features: A mask of the valid settings * - * description: Returns the index of the first valid setting less + * Description: Returns the index of the first valid setting less * than or equal to the one pointed to by idx, as determined by * the mask in features. Returns the index of the last setting * if nothing else matches. @@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } -/* phy_sanitize_settings +/** + * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex + * @phydev: the target phy_device struct * - * description: Make sure the PHY is set to supported speeds and + * Description: Make sure the PHY is set to supported speeds and * duplexes. Drop down by one in this order: 1000/FULL, - * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF + * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. */ void phy_sanitize_settings(struct phy_device *phydev) { @@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_de } EXPORT_SYMBOL(phy_sanitize_settings); -/* phy_ethtool_sset: - * A generic ethtool sset function. Handles all the details +/** + * phy_ethtool_sset - generic ethtool sset function, handles all the details + * @phydev: target phy_device struct + * @cmd: ethtool_cmd * * A few notes about parameter checking: * - We don't set port or transceiver, so we don't care what they * were set to. * - phy_start_aneg() will make sure forced settings are sane, and * choose the next best ones from the ones selected, so we don't - * care if ethtool tries to give us bad values - * + * care if ethtool tries to give us bad values. */ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) { @@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device * } EXPORT_SYMBOL(phy_ethtool_gset); -/* Note that this function is currently incompatible with the +/** + * phy_mii_ioctl - generic PHY MII ioctl interface + * @phydev: the phy_device struct + * @mii_data: MII ioctl data + * @cmd: ioctl cmd to execute + * + * Note that this function is currently incompatible with the * PHYCONTROL layer. It changes registers without regard to - * current state. Use at own risk + * current state. Use at own risk. */ int phy_mii_ioctl(struct phy_device *phydev, struct mii_ioctl_data *mii_data, int cmd) @@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phy phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; + if ((!phydev->autoneg) && + (val & BMCR_SPEED1000)) + phydev->speed = SPEED_1000; + else if ((!phydev->autoneg) && + (val & BMCR_SPEED100)) + phydev->speed = SPEED_100; break; case MII_ADVERTISE: phydev->advertising = val; @@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phy return 0; } -/* phy_start_aneg +/** + * phy_start_aneg - start auto-negotiation for this PHY device + * @phydev: the phy_device struct * - * description: Sanitizes the settings (if we're not - * autonegotiating them), and then calls the driver's - * config_aneg function. If the PHYCONTROL Layer is operating, - * we change the state to reflect the beginning of - * Auto-negotiation or forcing. + * Description: Sanitizes the settings (if we're not autonegotiating + * them), and then calls the driver's config_aneg function. + * If the PHYCONTROL Layer is operating, we change the state to + * reflect the beginning of Auto-negotiation or forcing. */ int phy_start_aneg(struct phy_device *phydev) { @@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg); static void phy_change(struct work_struct *work); static void phy_timer(unsigned long data); -/* phy_start_machine: +/** + * phy_start_machine - start PHY state machine tracking + * @phydev: the phy_device struct + * @handler: callback function for state change notifications * - * description: The PHY infrastructure can run a state machine + * Description: The PHY infrastructure can run a state machine * which tracks whether the PHY is starting up, negotiating, * etc. This function starts the timer which tracks the state - * of the PHY. If you want to be notified when the state - * changes, pass in the callback, otherwise, pass NULL. If you + * of the PHY. If you want to be notified when the state changes, + * pass in the callback @handler, otherwise, pass NULL. If you * want to maintain your own state machine, do not call this - * function. */ + * function. + */ void phy_start_machine(struct phy_device *phydev, void (*handler)(struct net_device *)) { @@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device mod_timer(&phydev->phy_timer, jiffies + HZ); } -/* phy_stop_machine +/** + * phy_stop_machine - stop the PHY state machine tracking + * @phydev: target phy_device struct * - * description: Stops the state machine timer, sets the state to UP + * Description: Stops the state machine timer, sets the state to UP * (unless it wasn't up yet). This function must be called BEFORE * phy_detach. */ @@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device phydev->adjust_state = NULL; } -/* phy_force_reduction +/** + * phy_force_reduction - reduce PHY speed/duplex settings by one step + * @phydev: target phy_device struct * - * description: Reduces the speed/duplex settings by - * one notch. The order is so: - * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, - * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. + * Description: Reduces the speed/duplex settings by one notch, + * in this order-- + * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. + * The function bottoms out at 10/HALF. */ static void phy_force_reduction(struct phy_device *phydev) { @@ -464,7 +525,9 @@ static void phy_force_reduction(struct p } -/* phy_error: +/** + * phy_error - enter HALTED state for this PHY device + * @phydev: target phy_device struct * * Moves the PHY to the HALTED state in response to a read * or write error, and tells the controller the link is down. @@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev spin_unlock(&phydev->lock); } -/* phy_interrupt +/** + * phy_interrupt - PHY interrupt handler + * @irq: interrupt line + * @phy_dat: phy_device pointer * - * description: When a PHY interrupt occurs, the handler disables + * Description: When a PHY interrupt occurs, the handler disables * interrupts, and schedules a work task to clear the interrupt. */ static irqreturn_t phy_interrupt(int irq, void *phy_dat) @@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq return IRQ_HANDLED; } -/* Enable the interrupts from the PHY side */ +/** + * phy_enable_interrupts - Enable the interrupts from the PHY side + * @phydev: target phy_device struct + */ int phy_enable_interrupts(struct phy_device *phydev) { int err; @@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_dev } EXPORT_SYMBOL(phy_enable_interrupts); -/* Disable the PHY interrupts from the PHY side */ +/** + * phy_disable_interrupts - Disable the PHY interrupts from the PHY side + * @phydev: target phy_device struct + */ int phy_disable_interrupts(struct phy_device *phydev) { int err; @@ -543,13 +615,15 @@ phy_err: } EXPORT_SYMBOL(phy_disable_interrupts); -/* phy_start_interrupts +/** + * phy_start_interrupts - request and enable interrupts for a PHY device + * @phydev: target phy_device struct * - * description: Request the interrupt for the given PHY. If - * this fails, then we set irq to PHY_POLL. + * Description: Request the interrupt for the given PHY. + * If this fails, then we set irq to PHY_POLL. * Otherwise, we enable the interrupts in the PHY. - * Returns 0 on success. * This should only be called with a valid IRQ number. + * Returns 0 on success or < 0 on error. */ int phy_start_interrupts(struct phy_device *phydev) { @@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_devi } EXPORT_SYMBOL(phy_start_interrupts); +/** + * phy_stop_interrupts - disable interrupts from a PHY device + * @phydev: target phy_device struct + */ int phy_stop_interrupts(struct phy_device *phydev) { int err; @@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_devic EXPORT_SYMBOL(phy_stop_interrupts); -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +/** + * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes + * @work: work_struct that describes the work to be done + */ static void phy_change(struct work_struct *work) { int err; @@ -630,7 +711,10 @@ phy_err: phy_error(phydev); } -/* Bring down the PHY link, and stop checking the status. */ +/** + * phy_stop - Bring down the PHY link, and stop checking the status + * @phydev: target phy_device struct + */ void phy_stop(struct phy_device *phydev) { spin_lock(&phydev->lock); @@ -659,9 +743,11 @@ out_unlock: } -/* phy_start +/** + * phy_start - start or restart a PHY device + * @phydev: target phy_device struct * - * description: Indicates the attached device's readiness to + * Description: Indicates the attached device's readiness to * handle PHY-related work. Used during startup to start the * PHY, and after a call to phy_stop() to resume operation. * Also used to indicate the MDIO bus has cleared an error diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 7d5b6d1..bc52a1d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -74,11 +74,13 @@ struct phy_device* phy_device_create(str } EXPORT_SYMBOL(phy_device_create); -/* get_phy_device +/** + * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * @bus: the target MII bus + * @addr: PHY address on the MII bus * - * description: Reads the ID registers of the PHY at addr on the - * bus, then allocates and returns the phy_device to - * represent it. + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, then allocates and returns the phy_device to represent it. */ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) { @@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struc return dev; } -/* phy_prepare_link: +/** + * phy_prepare_link - prepares the PHY layer to monitor link status + * @phydev: target phy_device struct + * @handler: callback function for link status change notifications * - * description: Tells the PHY infrastructure to handle the + * Description: Tells the PHY infrastructure to handle the * gory details on monitoring link status (whether through * polling or an interrupt), and to call back to the * connected device driver when the link status changes. * If you want to monitor your own link state, don't call - * this function */ + * this function. + */ void phy_prepare_link(struct phy_device *phydev, void (*handler)(struct net_device *)) { phydev->adjust_link = handler; } -/* phy_connect: +/** + * phy_connect - connect an ethernet device to a PHY device + * @dev: the network device to connect + * @phy_id: the PHY device to connect + * @handler: callback function for state change notifications + * @flags: PHY device's dev_flags + * @interface: PHY device's interface * - * description: Convenience function for connecting ethernet + * Description: Convenience function for connecting ethernet * devices to PHY devices. The default behavior is for * the PHY infrastructure to handle everything, and only notify * the connected driver when the link status changes. If you @@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct n } EXPORT_SYMBOL(phy_connect); +/** + * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device + * @phydev: target phy_device struct + */ void phy_disconnect(struct phy_device *phydev) { if (phydev->irq > 0) @@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *p } EXPORT_SYMBOL(phy_disconnect); -/* phy_attach: +static int phy_compare_id(struct device *dev, void *data) +{ + return strcmp((char *)data, dev->bus_id) ? 0 : 1; +} + +/** + * phy_attach - attach a network device to a particular PHY device + * @dev: network device to attach + * @phy_id: PHY device to attach + * @flags: PHY device's dev_flags + * @interface: PHY device's interface * - * description: Called by drivers to attach to a particular PHY + * Description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up * to the phy_driver. If no driver is attached, then the * genphy_driver is used. The phy_device is given a ptr to * the attaching device, and given a callback for link status - * change. The phy_device is returned to the attaching - * driver. + * change. The phy_device is returned to the attaching driver. */ -static int phy_compare_id(struct device *dev, void *data) -{ - return strcmp((char *)data, dev->bus_id) ? 0 : 1; -} - struct phy_device *phy_attach(struct net_device *dev, const char *phy_id, u32 flags, phy_interface_t interface) { @@ -250,6 +270,10 @@ struct phy_device *phy_attach(struct net } EXPORT_SYMBOL(phy_attach); +/** + * phy_detach - detach a PHY device from its network device + * @phydev: target phy_device struct + */ void phy_detach(struct phy_device *phydev) { phydev->attached_dev = NULL; @@ -269,11 +293,13 @@ EXPORT_SYMBOL(phy_detach); /* Generic PHY support and helper functions */ -/* genphy_config_advert +/** + * genphy_config_advert - sanitize and advertise auto-negotation parameters + * @phydev: target phy_device struct * - * description: Writes MII_ADVERTISE with the appropriate values, + * Description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise - * what is supported + * what is supported. */ int genphy_config_advert(struct phy_device *phydev) { @@ -335,11 +361,14 @@ int genphy_config_advert(struct phy_devi } EXPORT_SYMBOL(genphy_config_advert); -/* genphy_setup_forced +/** + * genphy_setup_forced - configures/forces speed/duplex from @phydev + * @phydev: target phy_device struct * - * description: Configures MII_BMCR to force speed/duplex + * Description: Configures MII_BMCR to force speed/duplex * to the values in phydev. Assumes that the values are valid. - * Please see phy_sanitize_settings() */ + * Please see phy_sanitize_settings(). + */ int genphy_setup_forced(struct phy_device *phydev) { int ctl = BMCR_RESET; @@ -368,7 +397,10 @@ int genphy_setup_forced(struct phy_devic } -/* Enable and Restart Autonegotiation */ +/** + * genphy_restart_aneg - Enable and Restart Autonegotiation + * @phydev: target phy_device struct + */ int genphy_restart_aneg(struct phy_device *phydev) { int ctl; @@ -389,11 +421,13 @@ int genphy_restart_aneg(struct phy_devic } -/* genphy_config_aneg +/** + * genphy_config_aneg - restart auto-negotiation or write BMCR + * @phydev: target phy_device struct * - * description: If auto-negotiation is enabled, we configure the + * Description: If auto-negotiation is enabled, we configure the * advertising, and then restart auto-negotiation. If it is not - * enabled, then we write the BMCR + * enabled, then we write the BMCR. */ int genphy_config_aneg(struct phy_device *phydev) { @@ -413,11 +447,13 @@ int genphy_config_aneg(struct phy_device } EXPORT_SYMBOL(genphy_config_aneg); -/* genphy_update_link +/** + * genphy_update_link - update link status in @phydev + * @phydev: target phy_device struct * - * description: Update the value in phydev->link to reflect the + * Description: Update the value in phydev->link to reflect the * current link value. In order to do this, we need to read - * the status register twice, keeping the second value + * the status register twice, keeping the second value. */ int genphy_update_link(struct phy_device *phydev) { @@ -444,9 +480,11 @@ int genphy_update_link(struct phy_device } EXPORT_SYMBOL(genphy_update_link); -/* genphy_read_status +/** + * genphy_read_status - check the link status and update current link state + * @phydev: target phy_device struct * - * description: Check the link, then figure out the current state + * Description: Check the link, then figure out the current state * by comparing what we advertise with what the link partner * advertises. Start by checking the gigabit possibilities, * then move on to 10/100. @@ -586,9 +624,11 @@ static int genphy_config_init(struct phy } -/* phy_probe +/** + * phy_probe - probe and init a PHY device + * @dev: device to probe and init * - * description: Take care of setting up the phy_device structure, + * Description: Take care of setting up the phy_device structure, * set the state to READY (the driver's init function should * set it to STARTING if needed). */ @@ -650,6 +690,10 @@ static int phy_remove(struct device *dev return 0; } +/** + * phy_driver_register - register a phy_driver with the PHY layer + * @new_driver: new phy_driver to register + */ int phy_driver_register(struct phy_driver *new_driver) { int retval; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index d3f65da..356b1c4 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1797,14 +1797,14 @@ invalid_seg_count: atomic_inc(&qdev->tx_count); } -void ql_get_sbuf(struct ql3_adapter *qdev) +static void ql_get_sbuf(struct ql3_adapter *qdev) { if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) qdev->small_buf_index = 0; qdev->small_buf_release_cnt++; } -struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) +static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) { struct ql_rcv_buf_cb *lrg_buf_cb = NULL; lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index]; diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 33fb7f3..4cb710b 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -1,6 +1,6 @@ /************************************************************************ * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2005 Neterion Inc. + * Copyright(c) 2002-2007 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 46ebf14..8b24762 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1,6 +1,6 @@ /************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2005 Neterion Inc. + * Copyright(c) 2002-2007 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. @@ -84,7 +84,7 @@ #include #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.17.1" +#define DRV_VERSION "2.0.19.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct } /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ -int vlan_strip_flag; +static int vlan_strip_flag; /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) @@ -516,7 +516,7 @@ static int init_shared_mem(struct s2io_n mac_control->fifos[i].list_info = kmalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { - DBG_PRINT(ERR_DBG, + DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } @@ -542,9 +542,9 @@ static int init_shared_mem(struct s2io_n tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(ERR_DBG, + DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); - DBG_PRINT(ERR_DBG, "failed for TxDL\n"); + DBG_PRINT(INFO_DBG, "failed for TxDL\n"); return -ENOMEM; } /* If we got a zero DMA address(can happen on @@ -561,9 +561,9 @@ static int init_shared_mem(struct s2io_n tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { - DBG_PRINT(ERR_DBG, + DBG_PRINT(INFO_DBG, "pci_alloc_consistent "); - DBG_PRINT(ERR_DBG, "failed for TxDL\n"); + DBG_PRINT(INFO_DBG, "failed for TxDL\n"); return -ENOMEM; } } @@ -2187,7 +2187,7 @@ static int fill_rxd_3buf(struct s2io_nic /* skb_shinfo(skb)->frag_list will have L4 data payload */ skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE); if (skb_shinfo(skb)->frag_list == NULL) { - DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name); + DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name); return -ENOMEM ; } frag_list = skb_shinfo(skb)->frag_list; @@ -2242,6 +2242,7 @@ static int fill_rx_buffers(struct s2io_n struct buffAdd *ba; unsigned long flags; struct RxD_t *first_rxdp = NULL; + u64 Buffer0_ptr = 0, Buffer1_ptr = 0; mac_control = &nic->mac_control; config = &nic->config; @@ -2313,8 +2314,8 @@ static int fill_rx_buffers(struct s2io_n /* allocate skb */ skb = dev_alloc_skb(size); if(!skb) { - DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); - DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); + DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); if (first_rxdp) { wmb(); first_rxdp->Control_1 |= RXD_OWN_XENA; @@ -2342,7 +2343,14 @@ static int fill_rx_buffers(struct s2io_n * payload */ + /* save the buffer pointers to avoid frequent dma mapping */ + Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr; + Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr; memset(rxdp, 0, sizeof(struct RxD3)); + /* restore the buffer pointers for dma sync*/ + ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr; + ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr; + ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = (u64)(unsigned long) skb->data; @@ -2573,8 +2581,8 @@ static int s2io_poll(struct net_device * for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); + DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); break; } } @@ -2590,8 +2598,8 @@ no_rx: for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); + DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); break; } } @@ -2640,8 +2648,8 @@ static void s2io_netpoll(struct net_devi for (i = 0; i < config->rx_ring_num; i++) { if (fill_rx_buffers(nic, i) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); - DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n"); + DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); break; } } @@ -3307,6 +3315,7 @@ static void s2io_reset(struct s2io_nic * u16 subid, pci_cmd; int i; u16 val16; + unsigned long long reset_cnt = 0; DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", __FUNCTION__, sp->dev->name); @@ -3372,6 +3381,11 @@ new_way: /* Reset device statistics maintained by OS */ memset(&sp->stats, 0, sizeof (struct net_device_stats)); + /* save reset count */ + reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt; + memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); + /* restore reset count */ + sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt; /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; @@ -3659,7 +3673,7 @@ static int s2io_enable_msi_x(struct s2io nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), GFP_KERNEL); if (nic->entries == NULL) { - DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); return -ENOMEM; } memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); @@ -3668,7 +3682,7 @@ static int s2io_enable_msi_x(struct s2io kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), GFP_KERNEL); if (nic->s2io_entries == NULL) { - DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); + DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); kfree(nic->entries); return -ENOMEM; } @@ -4019,7 +4033,7 @@ static int s2io_chk_rx_buffers(struct s2 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); DBG_PRINT(INTR_DBG, "PANIC levels\n"); if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "Out of memory in %s", + DBG_PRINT(INFO_DBG, "Out of memory in %s", __FUNCTION__); clear_bit(0, (&sp->tasklet_status)); return -1; @@ -4029,8 +4043,8 @@ static int s2io_chk_rx_buffers(struct s2 tasklet_schedule(&sp->task); } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name); - DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); + DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name); + DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); } return 0; } @@ -4279,9 +4293,7 @@ static void s2io_updt_stats(struct s2io_ if (cnt == 5) break; /* Updt failed */ } while(1); - } else { - memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); - } + } } /** @@ -5949,12 +5961,12 @@ static void s2io_tasklet(unsigned long d for (i = 0; i < config->rx_ring_num; i++) { ret = fill_rx_buffers(sp, i); if (ret == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s: Out of ", + DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); DBG_PRINT(ERR_DBG, "memory in tasklet\n"); break; } else if (ret == -EFILL) { - DBG_PRINT(ERR_DBG, + DBG_PRINT(INFO_DBG, "%s: Rx Ring %d is full\n", dev->name, i); break; @@ -6065,8 +6077,8 @@ static int set_rxd_buffer_pointer(struct } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); - DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); + DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); + DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); return -ENOMEM ; } /* storing the mapped addr in a temp variable @@ -6088,7 +6100,7 @@ static int set_rxd_buffer_pointer(struct } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", + DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", dev->name); return -ENOMEM; } @@ -6115,7 +6127,7 @@ static int set_rxd_buffer_pointer(struct } else { *skb = dev_alloc_skb(size); if (!(*skb)) { - DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", + DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", dev->name); return -ENOMEM; } @@ -6616,7 +6628,6 @@ static int rx_osm_handler(struct ring_in /* Updating statistics */ rxdp->Host_Control = 0; - sp->rx_pkt_count++; sp->stats.rx_packets++; if (sp->rxd_mode == RXD_MODE_1) { int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); @@ -7252,7 +7263,7 @@ #endif goto register_failed; } s2io_vpd_read(sp); - DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n"); + DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n"); DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, sp->product_name, get_xena_rev_id(sp->pdev)); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 803137c..a656d18 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -1,6 +1,6 @@ /************************************************************************ * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC - * Copyright(c) 2002-2005 Neterion Inc. + * Copyright(c) 2002-2007 Neterion Inc. * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. @@ -760,7 +760,6 @@ #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; - struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; int high_dma_flag; @@ -794,11 +793,6 @@ #define MAX_ADDRS_SUPPORTED 64 u16 all_multi_pos; u16 promisc_flg; - u16 tx_pkt_count; - u16 rx_pkt_count; - u16 tx_err_count; - u16 rx_err_count; - /* Id timer, used to blink NIC to physically identify NIC. */ struct timer_list id_timer; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 103c317..46cbebe 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1128,6 +1128,26 @@ static void sbdma_fillring(sbmacdma_t *d } } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sbmac_netpoll(struct net_device *netdev) +{ + struct sbmac_softc *sc = netdev_priv(netdev); + int irq = sc->sbm_dev->irq; + + __raw_writeq(0, sc->sbm_imr); + + sbmac_intr(irq, netdev, NULL); + +#ifdef CONFIG_SBMAC_COALESCE + __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | + ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), + sc->sbm_imr); +#else + __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | + (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); +#endif +} +#endif /********************************************************************** * SBDMA_RX_PROCESS(sc,d) @@ -2402,6 +2422,9 @@ static int sbmac_init(struct net_device dev->watchdog_timeo = TX_TIMEOUT; dev->change_mtu = sb1250_change_mtu; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = sbmac_netpoll; +#endif /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 52ed522..b881330 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -625,7 +625,7 @@ static inline void setup_rx_ring(struct #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) -static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) +static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) { struct sgiseeq_init_block *sr; struct sgiseeq_private *sp; @@ -651,7 +651,9 @@ static int sgiseeq_init(struct hpc3_regs #define EADDR_NVOFS 250 for (i = 0; i < 3; i++) { - unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i); + unsigned short tmp = has_eeprom ? + ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) : + ip22_nvram_read(EADDR_NVOFS / 2+i); dev->dev_addr[2 * i] = tmp >> 8; dev->dev_addr[2 * i + 1] = tmp & 0xff; @@ -684,6 +686,11 @@ #endif sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; + /* Setup PIO and DMA transfer timing */ + sp->hregs->pconfig = 0x161; + sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | + HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; + /* Reset the chip. */ hpc3_eth_reset(sp->hregs); @@ -730,8 +737,23 @@ err_out: static int __init sgiseeq_probe(void) { + unsigned int tmp, ret1, ret2 = 0; + /* On board adapter on 1st HPC is always present */ - return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); + ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0); + /* Let's see if second HPC is there */ + if (!(ip22_is_fullhouse()) && + get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) { + sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | + SGIMC_GIOPAR_EXP164 | + SGIMC_GIOPAR_HPC264; + hpc3c1->pbus_piocfg[0][0] = 0x3ffff; + /* interrupt/config register on Challenge S Mezz board */ + hpc3c1->pbus_extregs[0][0] = 0x30; + ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1); + } + + return (ret1 & ret2) ? ret1 : 0; } static void __exit sgiseeq_exit(void) diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index e94ab25..b8bf80f 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -5125,7 +5125,12 @@ static int skge_resume(struct pci_dev *p pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret) { + printk(KERN_WARNING "sk98lin: unable to enable device %s " + "in resume\n", dev->name); + goto err_out; + } pci_set_master(pdev); if (pAC->GIni.GIMacsFound == 2) ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); @@ -5133,10 +5138,8 @@ static int skge_resume(struct pci_dev *p ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev); if (ret) { printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq); - pAC->AllocFlag &= ~SK_ALLOC_IRQ; - dev->irq = 0; - pci_disable_device(pdev); - return -EBUSY; + ret = -EBUSY; + goto err_out_disable_pdev; } netif_device_attach(dev); @@ -5153,6 +5156,13 @@ static int skge_resume(struct pci_dev *p } return 0; + +err_out_disable_pdev: + pci_disable_device(pdev); +err_out: + pAC->AllocFlag &= ~SK_ALLOC_IRQ; + dev->irq = 0; + return ret; } #else #define skge_suspend NULL diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 39c6677..b15077a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.10" +#define DRV_VERSION "1.11" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -2602,6 +2602,7 @@ static int skge_down(struct net_device * static inline int skge_avail(const struct skge_ring *ring) { + smp_mb(); return ((ring->to_clean > ring->to_use) ? 0 : ring->count) + (ring->to_clean - ring->to_use) - 1; } @@ -2690,6 +2691,8 @@ static int skge_xmit_frame(struct sk_buf dev->name, e - skge->tx_ring.start, skb->len); skge->tx_ring.to_use = e->next; + smp_wmb(); + if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) { pr_debug("%s: transmit queue full\n", dev->name); netif_stop_queue(dev); @@ -2707,8 +2710,6 @@ static void skge_tx_free(struct skge_por { struct pci_dev *pdev = skge->hw->pdev; - BUG_ON(!e->skb); - /* skb header vs. fragment */ if (control & BMU_STF) pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), @@ -2726,7 +2727,6 @@ static void skge_tx_free(struct skge_por dev_kfree_skb(e->skb); } - e->skb = NULL; } /* Free all buffers in transmit ring */ @@ -2998,21 +2998,29 @@ static void skge_tx_done(struct net_devi skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); - netif_tx_lock(dev); for (e = ring->to_clean; e != ring->to_use; e = e->next) { - struct skge_tx_desc *td = e->desc; + u32 control = ((const struct skge_tx_desc *) e->desc)->control; - if (td->control & BMU_OWN) + if (control & BMU_OWN) break; - skge_tx_free(skge, e, td->control); + skge_tx_free(skge, e, control); } skge->tx_ring.to_clean = e; - if (skge_avail(&skge->tx_ring) > TX_LOW_WATER) - netif_wake_queue(dev); + /* Can run lockless until we need to synchronize to restart queue. */ + smp_mb(); + + if (unlikely(netif_queue_stopped(dev) && + skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { + netif_tx_lock(dev); + if (unlikely(netif_queue_stopped(dev) && + skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { + netif_wake_queue(dev); - netif_tx_unlock(dev); + } + netif_tx_unlock(dev); + } } static int skge_poll(struct net_device *dev, int *budget) diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 86467ae..edd7146 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -232,7 +232,6 @@ enum { IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT - | IS_NO_STAT_M1 | IS_NO_STAT_M2 | IS_RAM_RD_PAR | IS_RAM_WR_PAR | IS_M1_PAR_ERR | IS_M2_PAR_ERR | IS_R1_PAR_ERR | IS_R2_PAR_ERR, @@ -2447,15 +2446,15 @@ enum pause_status { struct skge_port { - u32 msg_enable; struct skge_hw *hw; struct net_device *netdev; int port; + u32 msg_enable; struct skge_ring tx_ring; - struct skge_ring rx_ring; - struct net_device_stats net_stats; + struct skge_ring rx_ring ____cacheline_aligned_in_smp; + unsigned int rx_buf_size; struct timer_list link_timer; enum pause_control flow_control; @@ -2471,7 +2470,8 @@ struct skge_port { void *mem; /* PCI memory for rings */ dma_addr_t dma; unsigned long mem_size; - unsigned int rx_buf_size; + + struct net_device_stats net_stats; }; diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index e3a7e3c..755fdd4 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -1,35 +1,34 @@ -/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ahennessy@mvista.com +/* + * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. * * Based on skelton.c by Donald Becker. - * Copyright (C) 2000-2001 Toshiba 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 driver is a replacement of older and less maintained version. + * This is a header of the older version: + * ---------- + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * Copyright (C) 2000-2001 Toshiba Corporation + * static const char *version = + * "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; + * ---------- * - * 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. + * 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. * - * You 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. + * (C) Copyright TOSHIBA CORPORATION 2004-2005 + * All Rights Reserved. */ -static const char *version = - "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; +#ifdef TC35815_NAPI +#define DRV_VERSION "1.35-NAPI" +#else +#define DRV_VERSION "1.35" +#endif +static const char *version = "tc35815.c:v" DRV_VERSION "\n"; +#define MODNAME "tc35815" #include #include @@ -40,6 +39,7 @@ #include #include #include #include +#include #include #include #include @@ -47,36 +47,47 @@ #include #include #include #include -#include -#include -#include - -#include +#include +#include #include -#include #include -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ -static const char* cardname = "TC35815CF"; -#define TC35815_PROC_ENTRY "net/tc35815" - -#define TC35815_MODULE_NAME "TC35815CF" -#define TX_TIMEOUT (4*HZ) - /* First, a few definitions that the brave might change. */ -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef TC35815_DEBUG -#define TC35815_DEBUG 1 -#endif -static unsigned int tc35815_debug = TC35815_DEBUG; - #define GATHER_TXINT /* On-Demand Tx Interrupt */ +#define WORKAROUND_LOSTCAR +#define WORKAROUND_100HALF_PROMISC +/* #define TC35815_USE_PACKEDBUFFER */ + +typedef enum { + TC35815CF = 0, + TC35815_NWU, + TC35815_TX4939, +} board_t; + +/* indexed by board_t, above */ +static const struct { + const char *name; +} board_info[] __devinitdata = { + { "TOSHIBA TC35815CF 10/100BaseTX" }, + { "TOSHIBA TC35815 with Wake on LAN" }, + { "TOSHIBA TC35815/TX4939" }, +}; + +static const struct pci_device_id tc35815_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF }, + {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU }, + {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 }, + {0,} +}; +MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); -#define vtonocache(p) KSEG1ADDR(virt_to_phys(p)) +/* see MODULE_PARM_DESC */ +static struct tc35815_options { + int speed; + int duplex; + int doforce; +} options; /* * Registers @@ -119,6 +130,11 @@ struct tc35815_regs { * Bit assignments */ /* DMA_Ctl bit asign ------------------------------------------------------- */ +#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ +#define DMA_RxAlign_1 0x00400000 +#define DMA_RxAlign_2 0x00800000 +#define DMA_RxAlign_3 0x00c00000 +#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ #define DMA_IntMask 0x00040000 /* 1:Interupt mask */ #define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ #define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ @@ -269,42 +285,6 @@ #define MD_CA_Busy 0x0000080 #define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */ -/* MII register offsets */ -#define MII_CONTROL 0x0000 -#define MII_STATUS 0x0001 -#define MII_PHY_ID0 0x0002 -#define MII_PHY_ID1 0x0003 -#define MII_ANAR 0x0004 -#define MII_ANLPAR 0x0005 -#define MII_ANER 0x0006 -/* MII Control register bit definitions. */ -#define MIICNTL_FDX 0x0100 -#define MIICNTL_RST_AUTO 0x0200 -#define MIICNTL_ISOLATE 0x0400 -#define MIICNTL_PWRDWN 0x0800 -#define MIICNTL_AUTO 0x1000 -#define MIICNTL_SPEED 0x2000 -#define MIICNTL_LPBK 0x4000 -#define MIICNTL_RESET 0x8000 -/* MII Status register bit significance. */ -#define MIISTAT_EXT 0x0001 -#define MIISTAT_JAB 0x0002 -#define MIISTAT_LINK 0x0004 -#define MIISTAT_CAN_AUTO 0x0008 -#define MIISTAT_FAULT 0x0010 -#define MIISTAT_AUTO_DONE 0x0020 -#define MIISTAT_CAN_T 0x0800 -#define MIISTAT_CAN_T_FDX 0x1000 -#define MIISTAT_CAN_TX 0x2000 -#define MIISTAT_CAN_TX_FDX 0x4000 -#define MIISTAT_CAN_T4 0x8000 -/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */ -#define MII_AN_TX_FDX 0x0100 -#define MII_AN_TX_HDX 0x0080 -#define MII_AN_10_FDX 0x0040 -#define MII_AN_10_HDX 0x0020 - - /* * Descriptors */ @@ -352,32 +332,51 @@ #undef NO_CHECK_CARRIER /* Does not chec #ifdef NO_CHECK_CARRIER #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ - Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ - Tx_En) /* maybe 0x7d01 */ + Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ + Tx_En) /* maybe 0x7b01 */ #else #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ - Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ - Tx_En) /* maybe 0x7f01 */ + Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ + Tx_En) /* maybe 0x7b01 */ #endif #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ - #define INT_EN_CMD (Int_NRAbtEn | \ - Int_DParDEn | Int_DParErrEn | \ + Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ Int_STargAbtEn | \ Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/ +#define DMA_CTL_CMD DMA_BURST_SIZE +#define HAVE_DMA_RXALIGN(lp) likely((lp)->boardtype != TC35815CF) /* Tuning parameters */ #define DMA_BURST_SIZE 32 #define TX_THRESHOLD 1024 +#define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/ +#define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */ +/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */ +#ifdef TC35815_USE_PACKEDBUFFER #define FD_PAGE_NUM 2 -#define FD_PAGE_ORDER 1 -/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */ -#define RX_BUF_PAGES 8 /* >= 2 */ +#define RX_BUF_NUM 8 /* >= 2 */ #define RX_FD_NUM 250 /* >= 32 */ #define TX_FD_NUM 128 +#define RX_BUF_SIZE PAGE_SIZE +#else /* TC35815_USE_PACKEDBUFFER */ +#define FD_PAGE_NUM 4 +#define RX_BUF_NUM 128 /* < 256 */ +#define RX_FD_NUM 256 /* >= 32 */ +#define TX_FD_NUM 128 +#if RX_CTL_CMD & Rx_LongEn +#define RX_BUF_SIZE PAGE_SIZE +#elif RX_CTL_CMD & Rx_StripCRC +#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ +#else +#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ +#endif +#endif /* TC35815_USE_PACKEDBUFFER */ +#define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ +#define NAPI_WEIGHT 16 struct TxFD { struct FDesc fd; @@ -392,18 +391,27 @@ struct RxFD { struct FrFD { struct FDesc fd; - struct BDesc bd[RX_BUF_PAGES]; + struct BDesc bd[RX_BUF_NUM]; }; -extern unsigned long tc_readl(volatile __u32 *addr); -extern void tc_writel(unsigned long data, volatile __u32 *addr); +#define tc_readl(addr) readl(addr) +#define tc_writel(d, addr) writel(d, addr) + +#define TC35815_TX_TIMEOUT msecs_to_jiffies(400) -dma_addr_t priv_dma_handle; +/* Timer state engine. */ +enum tc35815_timer_state { + arbwait = 0, /* Waiting for auto negotiation to complete. */ + lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ + ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ + asleep = 3, /* Time inactive. */ + lcheck = 4, /* Check link status. */ +}; /* Information that need to be kept for each board. */ struct tc35815_local { - struct net_device *next_module; + struct pci_dev *pci_dev; /* statistics */ struct net_device_stats stats; @@ -411,216 +419,372 @@ struct tc35815_local { int max_tx_qlen; int tx_ints; int rx_ints; + int tx_underrun; } lstats; - int tbusy; - int option; -#define TC35815_OPT_AUTO 0x00 -#define TC35815_OPT_10M 0x01 -#define TC35815_OPT_100M 0x02 -#define TC35815_OPT_FULLDUP 0x04 - int linkspeed; /* 10 or 100 */ + /* Tx control lock. This protects the transmit buffer ring + * state along with the "tx full" state of the driver. This + * means all netif_queue flow control actions are protected + * by this lock as well. + */ + spinlock_t lock; + + int phy_addr; int fullduplex; + unsigned short saved_lpa; + struct timer_list timer; + enum tc35815_timer_state timer_state; /* State of auto-neg timer. */ + unsigned int timer_ticks; /* Number of clicks at each state */ /* * Transmitting: Batch Mode. * 1 BD in 1 TxFD. - * Receiving: Packing Mode. + * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER) * 1 circular FD for Free Buffer List. - * RX_BUG_PAGES BD in Free Buffer FD. + * RX_BUF_NUM BD in Free Buffer FD. * One Free Buffer BD has PAGE_SIZE data buffer. + * Or Non-Packing Mode. + * 1 circular FD for Free Buffer List. + * RX_BUF_NUM BD in Free Buffer FD. + * One Free Buffer BD has ETH_FRAME_LEN data buffer. */ - struct pci_dev *pdev; - dma_addr_t fd_buf_dma_handle; - void * fd_buf; /* for TxFD, TxFD, FrFD */ + void * fd_buf; /* for TxFD, RxFD, FrFD */ + dma_addr_t fd_buf_dma; struct TxFD *tfd_base; - int tfd_start; - int tfd_end; + unsigned int tfd_start; + unsigned int tfd_end; struct RxFD *rfd_base; struct RxFD *rfd_limit; struct RxFD *rfd_cur; struct FrFD *fbl_ptr; +#ifdef TC35815_USE_PACKEDBUFFER unsigned char fbl_curid; - dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; - void * data_buf[RX_BUF_PAGES]; /* packing */ - spinlock_t lock; + void * data_buf[RX_BUF_NUM]; /* packing */ + dma_addr_t data_buf_dma[RX_BUF_NUM]; + struct { + struct sk_buff *skb; + dma_addr_t skb_dma; + } tx_skbs[TX_FD_NUM]; +#else + unsigned int fbl_count; + struct { + struct sk_buff *skb; + dma_addr_t skb_dma; + } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM]; +#endif + struct mii_if_info mii; + unsigned short mii_id[2]; + u32 msg_enable; + board_t boardtype; }; -/* Index to functions, as function prototypes. */ +static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt) +{ + return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf); +} +#ifdef DEBUG +static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) +{ + return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma)); +} +#endif +#ifdef TC35815_USE_PACKEDBUFFER +static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) +{ + int i; + for (i = 0; i < RX_BUF_NUM; i++) { + if (bus >= lp->data_buf_dma[i] && + bus < lp->data_buf_dma[i] + PAGE_SIZE) + return (void *)((u8 *)lp->data_buf[i] + + (bus - lp->data_buf_dma[i])); + } + return NULL; +} -static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq); +#define TC35815_DMA_SYNC_ONDEMAND +static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) +{ +#ifdef TC35815_DMA_SYNC_ONDEMAND + void *buf; + /* pci_map + pci_dma_sync will be more effective than + * pci_alloc_consistent on some archs. */ + if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL) + return NULL; + *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(*dma_handle)) { + free_page((unsigned long)buf); + return NULL; + } + return buf; +#else + return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle); +#endif +} + +static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle) +{ +#ifdef TC35815_DMA_SYNC_ONDEMAND + pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE); + free_page((unsigned long)buf); +#else + pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle); +#endif +} +#else /* TC35815_USE_PACKEDBUFFER */ +static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, + struct pci_dev *hwdev, + dma_addr_t *dma_handle) +{ + struct sk_buff *skb; + skb = dev_alloc_skb(RX_BUF_SIZE); + if (!skb) + return NULL; + skb->dev = dev; + *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(*dma_handle)) { + dev_kfree_skb_any(skb); + return NULL; + } + skb_reserve(skb, 2); /* make IP header 4byte aligned */ + return skb; +} + +static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle) +{ + pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); +} +#endif /* TC35815_USE_PACKEDBUFFER */ + +/* Index to functions, as function prototypes. */ static int tc35815_open(struct net_device *dev); static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); -static void tc35815_tx_timeout(struct net_device *dev); -static irqreturn_t tc35815_interrupt(int irq, void *dev_id); +static irqreturn_t tc35815_interrupt(int irq, void *dev_id); +#ifdef TC35815_NAPI +static int tc35815_rx(struct net_device *dev, int limit); +static int tc35815_poll(struct net_device *dev, int *budget); +#else static void tc35815_rx(struct net_device *dev); +#endif static void tc35815_txdone(struct net_device *dev); static int tc35815_close(struct net_device *dev); static struct net_device_stats *tc35815_get_stats(struct net_device *dev); static void tc35815_set_multicast_list(struct net_device *dev); +static void tc35815_tx_timeout(struct net_device *dev); +static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tc35815_poll_controller(struct net_device *dev); +#endif +static const struct ethtool_ops tc35815_ethtool_ops; +/* Example routines you must write ;->. */ static void tc35815_chip_reset(struct net_device *dev); static void tc35815_chip_init(struct net_device *dev); +static void tc35815_find_phy(struct net_device *dev); static void tc35815_phy_chip_init(struct net_device *dev); -/* A list of all installed tc35815 devices. */ -static struct net_device *root_tc35815_dev = NULL; +#ifdef DEBUG +static void panic_queues(struct net_device *dev); +#endif -/* - * PCI device identifiers for "new style" Linux PCI Device Drivers - */ -static struct pci_device_id tc35815_pci_tbl[] = { - { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; +static void tc35815_timer(unsigned long data); +static void tc35815_start_auto_negotiation(struct net_device *dev, + struct ethtool_cmd *ep); +static int tc_mdio_read(struct net_device *dev, int phy_id, int location); +static void tc_mdio_write(struct net_device *dev, int phy_id, int location, + int val); -MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); +static void __devinit tc35815_init_dev_addr (struct net_device *dev) +{ + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + int i; -int -tc35815_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) + /* dev_addr will be overwritten on NETDEV_REGISTER event */ + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + for (i = 0; i < 6; i += 2) { + unsigned short data; + tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); + while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) + ; + data = tc_readl(&tr->PROM_Data); + dev->dev_addr[i] = data & 0xff; + dev->dev_addr[i+1] = data >> 8; + } +} + +static int __devinit tc35815_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - int err = 0; - int ret; - unsigned long pci_memaddr; - unsigned int pci_irq_line; + void __iomem *ioaddr = NULL; + struct net_device *dev; + struct tc35815_local *lp; + int rc; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + + static int printed_version; + if (!printed_version++) { + printk(version); + dev_printk(KERN_DEBUG, &pdev->dev, + "speed:%d duplex:%d doforce:%d\n", + options.speed, options.duplex, options.doforce); + } - printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); + if (!pdev->irq) { + dev_warn(&pdev->dev, "no IRQ assigned.\n"); + return -ENODEV; + } - err = pci_enable_device(pdev); - if (err) - return err; + /* dev zeroed in alloc_etherdev */ + dev = alloc_etherdev (sizeof (*lp)); + if (dev == NULL) { + dev_err(&pdev->dev, "unable to alloc new ethernet\n"); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + lp = dev->priv; + + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; - pci_memaddr = pci_resource_start (pdev, 1); + mmio_start = pci_resource_start (pdev, 1); + mmio_end = pci_resource_end (pdev, 1); + mmio_flags = pci_resource_flags (pdev, 1); + mmio_len = pci_resource_len (pdev, 1); - printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); + /* set this immediately, we need to know before + * we talk to the chip directly */ - if (!pci_memaddr) { - printk(KERN_WARNING "no PCI MEM resources, aborting\n"); - ret = -ENODEV; + /* make sure PCI base addr 1 is MMIO */ + if (!(mmio_flags & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; goto err_out; } - pci_irq_line = pdev->irq; - /* irq disabled. */ - if (pci_irq_line == 0) { - printk(KERN_WARNING "no PCI irq, aborting\n"); - ret = -ENODEV; + + /* check for weird/broken PCI region reporting */ + if ((mmio_len < sizeof(struct tc35815_regs))) { + dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; goto err_out; } - ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); - if (ret) + rc = pci_request_regions (pdev, MODNAME); + if (rc) goto err_out; - pci_set_master(pdev); - - return 0; + pci_set_master (pdev); -err_out: - pci_disable_device(pdev); - return ret; -} + /* ioremap MMIO region */ + ioaddr = ioremap (mmio_start, mmio_len); + if (ioaddr == NULL) { + dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); + rc = -EIO; + goto err_out_free_res; + } -static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) -{ - static unsigned version_printed = 0; - int i, ret; - struct tc35815_local *lp; - struct tc35815_regs *tr; - struct net_device *dev; + /* Initialize the device structure. */ + dev->open = tc35815_open; + dev->hard_start_xmit = tc35815_send_packet; + dev->stop = tc35815_close; + dev->get_stats = tc35815_get_stats; + dev->set_multicast_list = tc35815_set_multicast_list; + dev->do_ioctl = tc35815_ioctl; + dev->ethtool_ops = &tc35815_ethtool_ops; + dev->tx_timeout = tc35815_tx_timeout; + dev->watchdog_timeo = TC35815_TX_TIMEOUT; +#ifdef TC35815_NAPI + dev->poll = tc35815_poll; + dev->weight = NAPI_WEIGHT; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tc35815_poll_controller; +#endif - /* Allocate a new 'dev' if needed. */ - dev = alloc_etherdev(sizeof(struct tc35815_local)); - if (dev == NULL) - return -ENOMEM; + dev->irq = pdev->irq; + dev->base_addr = (unsigned long) ioaddr; - /* - * alloc_etherdev allocs and zeros dev->priv - */ + /* dev->priv/lp zeroed and aligned in alloc_etherdev */ lp = dev->priv; + spin_lock_init(&lp->lock); + lp->pci_dev = pdev; + lp->boardtype = ent->driver_data; - if (tc35815_debug && version_printed++ == 0) - printk(KERN_DEBUG "%s", version); - - /* Fill in the 'dev' fields. */ - dev->irq = irq; - dev->base_addr = (unsigned long)ioremap(base_addr, - sizeof(struct tc35815_regs)); - if (!dev->base_addr) { - ret = -ENOMEM; - goto err_out; - } - tr = (struct tc35815_regs*)dev->base_addr; + lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK; + pci_set_drvdata(pdev, dev); + /* Soft reset the chip. */ tc35815_chip_reset(dev); - /* Retrieve and print the ethernet address. */ - while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) - ; - for (i = 0; i < 6; i += 2) { - unsigned short data; - tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); - while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) - ; - data = tc_readl(&tr->PROM_Data); - dev->dev_addr[i] = data & 0xff; - dev->dev_addr[i+1] = data >> 8; - } + /* Retrieve the ethernet address. */ + tc35815_init_dev_addr(dev); + + rc = register_netdev (dev); + if (rc) + goto err_out_unmap; + + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + printk(KERN_INFO "%s: %s at 0x%lx, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "IRQ %d\n", + dev->name, + board_info[ent->driver_data].name, + dev->base_addr, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5], + dev->irq); + + setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev); + lp->mii.dev = dev; + lp->mii.mdio_read = tc_mdio_read; + lp->mii.mdio_write = tc_mdio_write; + lp->mii.phy_id_mask = 0x1f; + lp->mii.reg_num_mask = 0x1f; + tc35815_find_phy(dev); + lp->mii.phy_id = lp->phy_addr; + lp->mii.full_duplex = 0; + lp->mii.force_media = 0; - /* Initialize the device structure. */ - lp->pdev = pdev; - lp->next_module = root_tc35815_dev; - root_tc35815_dev = dev; + return 0; - spin_lock_init(&lp->lock); +err_out_unmap: + iounmap(ioaddr); +err_out_free_res: + pci_release_regions (pdev); +err_out: + free_netdev (dev); + return rc; +} - if (dev->mem_start > 0) { - lp->option = dev->mem_start; - if ((lp->option & TC35815_OPT_10M) && - (lp->option & TC35815_OPT_100M)) { - /* if both speed speficied, auto select. */ - lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); - } - } - //XXX fixme - lp->option |= TC35815_OPT_10M; - /* do auto negotiation */ - tc35815_phy_chip_init(dev); +static void __devexit tc35815_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata (pdev); + unsigned long mmio_addr; - dev->open = tc35815_open; - dev->stop = tc35815_close; - dev->tx_timeout = tc35815_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->hard_start_xmit = tc35815_send_packet; - dev->get_stats = tc35815_get_stats; - dev->set_multicast_list = tc35815_set_multicast_list; - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); + mmio_addr = dev->base_addr; - ret = register_netdev(dev); - if (ret) - goto err_out_iounmap; + unregister_netdev (dev); - printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", - dev->name, cardname, base_addr, irq); - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - printk("\n"); - printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", - dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); + if (mmio_addr) { + iounmap ((void __iomem *)mmio_addr); + pci_release_regions (pdev); + } - return 0; + free_netdev (dev); -err_out_iounmap: - iounmap((void *) dev->base_addr); -err_out: - free_netdev(dev); - return ret; + pci_set_drvdata (pdev, NULL); } - static int tc35815_init_queues(struct net_device *dev) { @@ -629,44 +793,64 @@ tc35815_init_queues(struct net_device *d unsigned long fd_addr; if (!lp->fd_buf) { - if (sizeof(struct FDesc) + - sizeof(struct BDesc) * RX_BUF_PAGES + - sizeof(struct FDesc) * RX_FD_NUM + - sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { - printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); - return -ENOMEM; - } + BUG_ON(sizeof(struct FDesc) + + sizeof(struct BDesc) * RX_BUF_NUM + + sizeof(struct FDesc) * RX_FD_NUM + + sizeof(struct TxFD) * TX_FD_NUM > + PAGE_SIZE * FD_PAGE_NUM); - if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) + if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0) return -ENOMEM; - for (i = 0; i < RX_BUF_PAGES; i++) { - if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) { + for (i = 0; i < RX_BUF_NUM; i++) { +#ifdef TC35815_USE_PACKEDBUFFER + if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) { while (--i >= 0) { - free_page((unsigned long)lp->data_buf[i]); - lp->data_buf[i] = 0; + free_rxbuf_page(lp->pci_dev, + lp->data_buf[i], + lp->data_buf_dma[i]); + lp->data_buf[i] = NULL; } - free_page((unsigned long)lp->fd_buf); - lp->fd_buf = 0; + pci_free_consistent(lp->pci_dev, + PAGE_SIZE * FD_PAGE_NUM, + lp->fd_buf, + lp->fd_buf_dma); + lp->fd_buf = NULL; + return -ENOMEM; + } +#else + lp->rx_skbs[i].skb = + alloc_rxbuf_skb(dev, lp->pci_dev, + &lp->rx_skbs[i].skb_dma); + if (!lp->rx_skbs[i].skb) { + while (--i >= 0) { + free_rxbuf_skb(lp->pci_dev, + lp->rx_skbs[i].skb, + lp->rx_skbs[i].skb_dma); + lp->rx_skbs[i].skb = NULL; + } + pci_free_consistent(lp->pci_dev, + PAGE_SIZE * FD_PAGE_NUM, + lp->fd_buf, + lp->fd_buf_dma); + lp->fd_buf = NULL; return -ENOMEM; } -#ifdef __mips__ - dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM); #endif } -#ifdef __mips__ - dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); + printk(KERN_DEBUG "%s: FD buf %p DataBuf", + dev->name, lp->fd_buf); +#ifdef TC35815_USE_PACKEDBUFFER + printk(" DataBuf"); + for (i = 0; i < RX_BUF_NUM; i++) + printk(" %p", lp->data_buf[i]); #endif + printk("\n"); } else { - memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM); -#ifdef __mips__ - dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); -#endif + for (i = 0; i < FD_PAGE_NUM; i++) { + clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE)); + } } -#ifdef __mips__ - fd_addr = (unsigned long)vtonocache(lp->fd_buf); -#else fd_addr = (unsigned long)lp->fd_buf; -#endif /* Free Descriptors (for Receive) */ lp->rfd_base = (struct RxFD *)fd_addr; @@ -675,34 +859,66 @@ #endif lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); } lp->rfd_cur = lp->rfd_base; - lp->rfd_limit = (struct RxFD *)(fd_addr - - sizeof(struct FDesc) - - sizeof(struct BDesc) * 30); + lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1); /* Transmit Descriptors */ lp->tfd_base = (struct TxFD *)fd_addr; fd_addr += sizeof(struct TxFD) * TX_FD_NUM; for (i = 0; i < TX_FD_NUM; i++) { - lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1])); + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); } - lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); + lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0])); lp->tfd_start = 0; lp->tfd_end = 0; /* Buffer List (for Receive) */ lp->fbl_ptr = (struct FrFD *)fd_addr; - lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); - lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); - for (i = 0; i < RX_BUF_PAGES; i++) { - lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); + lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr)); + lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD); +#ifndef TC35815_USE_PACKEDBUFFER + /* + * move all allocated skbs to head of rx_skbs[] array. + * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in + * tc35815_rx() had failed. + */ + lp->fbl_count = 0; + for (i = 0; i < RX_BUF_NUM; i++) { + if (lp->rx_skbs[i].skb) { + if (i != lp->fbl_count) { + lp->rx_skbs[lp->fbl_count].skb = + lp->rx_skbs[i].skb; + lp->rx_skbs[lp->fbl_count].skb_dma = + lp->rx_skbs[i].skb_dma; + } + lp->fbl_count++; + } + } +#endif + for (i = 0; i < RX_BUF_NUM; i++) { +#ifdef TC35815_USE_PACKEDBUFFER + lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]); +#else + if (i >= lp->fbl_count) { + lp->fbl_ptr->bd[i].BuffData = 0; + lp->fbl_ptr->bd[i].BDCtl = 0; + continue; + } + lp->fbl_ptr->bd[i].BuffData = + cpu_to_le32(lp->rx_skbs[i].skb_dma); +#endif /* BDID is index of FrFD.bd[] */ lp->fbl_ptr->bd[i].BDCtl = - cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); + cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | + RX_BUF_SIZE); } +#ifdef TC35815_USE_PACKEDBUFFER lp->fbl_curid = 0; +#endif + printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n", + dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr); return 0; } @@ -713,11 +929,25 @@ tc35815_clear_queues(struct net_device * int i; for (i = 0; i < TX_FD_NUM; i++) { - struct sk_buff *skb = (struct sk_buff *) - le32_to_cpu(lp->tfd_base[i].fd.FDSystem); - if (skb) + u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + struct sk_buff *skb = + fdsystem != 0xffffffff ? + lp->tx_skbs[fdsystem].skb : NULL; +#ifdef DEBUG + if (lp->tx_skbs[i].skb != skb) { + printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); + panic_queues(dev); + } +#else + BUG_ON(lp->tx_skbs[i].skb != skb); +#endif + if (skb) { + pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); + lp->tx_skbs[i].skb = NULL; + lp->tx_skbs[i].skb_dma = 0; dev_kfree_skb_any(skb); - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + } + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); } tc35815_init_queues(dev); @@ -731,28 +961,53 @@ tc35815_free_queues(struct net_device *d if (lp->tfd_base) { for (i = 0; i < TX_FD_NUM; i++) { - struct sk_buff *skb = (struct sk_buff *) - le32_to_cpu(lp->tfd_base[i].fd.FDSystem); - if (skb) - dev_kfree_skb_any(skb); - lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); + u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); + struct sk_buff *skb = + fdsystem != 0xffffffff ? + lp->tx_skbs[fdsystem].skb : NULL; +#ifdef DEBUG + if (lp->tx_skbs[i].skb != skb) { + printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); + panic_queues(dev); + } +#else + BUG_ON(lp->tx_skbs[i].skb != skb); +#endif + if (skb) { + dev_kfree_skb(skb); + pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); + lp->tx_skbs[i].skb = NULL; + lp->tx_skbs[i].skb_dma = 0; + } + lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); } } lp->rfd_base = NULL; - lp->rfd_base = NULL; lp->rfd_limit = NULL; lp->rfd_cur = NULL; lp->fbl_ptr = NULL; - for (i = 0; i < RX_BUF_PAGES; i++) { - if (lp->data_buf[i]) - free_page((unsigned long)lp->data_buf[i]); - lp->data_buf[i] = 0; + for (i = 0; i < RX_BUF_NUM; i++) { +#ifdef TC35815_USE_PACKEDBUFFER + if (lp->data_buf[i]) { + free_rxbuf_page(lp->pci_dev, + lp->data_buf[i], lp->data_buf_dma[i]); + lp->data_buf[i] = NULL; + } +#else + if (lp->rx_skbs[i].skb) { + free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb, + lp->rx_skbs[i].skb_dma); + lp->rx_skbs[i].skb = NULL; + } +#endif + } + if (lp->fd_buf) { + pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, + lp->fd_buf, lp->fd_buf_dma); + lp->fd_buf = NULL; } - if (lp->fd_buf) - __free_pages(lp->fd_buf, FD_PAGE_ORDER); - lp->fd_buf = NULL; } static void @@ -792,6 +1047,7 @@ dump_rxfd(struct RxFD *fd) return bd_count; } +#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER) static void dump_frfd(struct FrFD *fd) { @@ -802,20 +1058,22 @@ dump_frfd(struct FrFD *fd) le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); printk("BD: "); - for (i = 0; i < RX_BUF_PAGES; i++) + for (i = 0; i < RX_BUF_NUM; i++) printk(" %08x %08x", le32_to_cpu(fd->bd[i].BuffData), le32_to_cpu(fd->bd[i].BDCtl)); printk("\n"); } +#endif +#ifdef DEBUG static void panic_queues(struct net_device *dev) { struct tc35815_local *lp = dev->priv; int i; - printk("TxFD base %p, start %d, end %d\n", + printk("TxFD base %p, start %u, end %u\n", lp->tfd_base, lp->tfd_start, lp->tfd_end); printk("RxFD base %p limit %p cur %p\n", lp->rfd_base, lp->rfd_limit, lp->rfd_cur); @@ -829,31 +1087,13 @@ panic_queues(struct net_device *dev) dump_frfd(lp->fbl_ptr); panic("%s: Illegal queue state.", dev->name); } - -#if 0 -static void print_buf(char *add, int length) -{ - int i; - int len = length; - - printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); - - if (len > 100) - len = 100; - for (i = 0; i < len; i++) { - printk(" %2.2X", (unsigned char) add[i]); - if (!(i % 16)) - printk("\n"); - } - printk("\n"); -} #endif static void print_eth(char *add) { int i; - printk("print_eth(%08x)\n", (unsigned int) add); + printk("print_eth(%p)\n", add); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char) add[i + 6]); printk(" =>"); @@ -862,6 +1102,73 @@ static void print_eth(char *add) printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); } +static int tc35815_tx_full(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end); +} + +static void tc35815_restart(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + int do_phy_reset = 1; + del_timer(&lp->timer); /* Kill if running */ + + if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) { + /* Resetting PHY cause problem on some chip... (SEEQ 80221) */ + do_phy_reset = 0; + } + if (do_phy_reset) { + int timeout; + tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET); + timeout = 100; + while (--timeout) { + if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET)) + break; + udelay(1); + } + if (!timeout) + printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); + } + + tc35815_chip_reset(dev); + tc35815_clear_queues(dev); + tc35815_chip_init(dev); + /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ + tc35815_set_multicast_list(dev); +} + +static void tc35815_tx_timeout(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + + printk(KERN_WARNING "%s: transmit timed out, status %#x\n", + dev->name, tc_readl(&tr->Tx_Stat)); + + /* Try to restart the adaptor. */ + spin_lock_irq(&lp->lock); + tc35815_restart(dev); + spin_unlock_irq(&lp->lock); + + lp->stats.tx_errors++; + + /* If we have space available to accept new transmit + * requests, wake up the queueing layer. This would + * be the case if the chipset_init() call above just + * flushes out the tx queue and empties it. + * + * If instead, the tx queue is retained then the + * netif_wake_queue() call should be placed in the + * TX completion interrupt handler of the driver instead + * of here. + */ + if (!tc35815_tx_full(dev)) + netif_wake_queue(dev); +} + /* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. @@ -874,16 +1181,16 @@ static int tc35815_open(struct net_device *dev) { struct tc35815_local *lp = dev->priv; + /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. */ - - if (dev->irq == 0 || - request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) { + if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) { return -EAGAIN; } + del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); if (tc35815_init_queues(dev) != 0) { @@ -892,138 +1199,119 @@ tc35815_open(struct net_device *dev) } /* Reset the hardware here. Don't forget to set the station address. */ + spin_lock_irq(&lp->lock); tc35815_chip_init(dev); + spin_unlock_irq(&lp->lock); - lp->tbusy = 0; + /* We are now ready to accept transmit requeusts from + * the queueing layer of the networking. + */ netif_start_queue(dev); return 0; } -static void tc35815_tx_timeout(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", - dev->name, tc_readl(&tr->Tx_Stat)); - /* Try to restart the adaptor. */ - tc35815_chip_reset(dev); - tc35815_clear_queues(dev); - tc35815_chip_init(dev); - lp->tbusy=0; - spin_unlock_irqrestore(&lp->lock, flags); - dev->trans_start = jiffies; - netif_wake_queue(dev); -} - +/* This will only be invoked if your driver is _not_ in XOFF state. + * What this means is that you need not check it, and that this + * invariant will hold if you make sure that the netif_*_queue() + * calls are done at the proper times. + */ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; - - if (netif_queue_stopped(dev)) { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", - dev->name, tc_readl(&tr->Tx_Stat)); - /* Try to restart the adaptor. */ - tc35815_chip_reset(dev); - tc35815_clear_queues(dev); - tc35815_chip_init(dev); - lp->tbusy=0; - dev->trans_start = jiffies; - netif_wake_queue(dev); - } + struct TxFD *txfd; + unsigned long flags; - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, lp->tbusy), but set_bit() works as well. + /* If some error occurs while trying to transmit this + * packet, you should return '1' from this function. + * In such a case you _may not_ do anything to the + * SKB, it is still owned by the network queueing + * layer when an error is returned. This means you + * may not modify any SKB fields, you may not free + * the SKB, etc. */ - if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - dev_kfree_skb_any(skb); - } else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; - unsigned long flags; - lp->stats.tx_bytes += skb->len; + /* This is the most common case for modern hardware. + * The spinlock protects this code from the TX complete + * hardware interrupt handler. Queue flow control is + * thus managed under this lock as well. + */ + spin_lock_irqsave(&lp->lock, flags); -#ifdef __mips__ - dma_cache_wback_inv((unsigned long)buf, length); + /* failsafe... (handle txdone now if half of FDs are used) */ + if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM > + TX_FD_NUM / 2) + tc35815_txdone(dev); + + if (netif_msg_pktdata(lp)) + print_eth(skb->data); +#ifdef DEBUG + if (lp->tx_skbs[lp->tfd_start].skb) { + printk("%s: tx_skbs conflict.\n", dev->name); + panic_queues(dev); + } +#else + BUG_ON(lp->tx_skbs[lp->tfd_start].skb); #endif - - spin_lock_irqsave(&lp->lock, flags); - - /* failsafe... */ - if (lp->tfd_start != lp->tfd_end) - tc35815_txdone(dev); - - - txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf)); - - txfd->bd.BDCtl = cpu_to_le32(length); - txfd->fd.FDSystem = cpu_to_le32((__u32)skb); - txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); - - if (lp->tfd_start == lp->tfd_end) { - /* Start DMA Transmitter. */ - txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); + lp->tx_skbs[lp->tfd_start].skb = skb; + lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + + /*add to ring */ + txfd = &lp->tfd_base[lp->tfd_start]; + txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma); + txfd->bd.BDCtl = cpu_to_le32(skb->len); + txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start); + txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); + + if (lp->tfd_start == lp->tfd_end) { + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + /* Start DMA Transmitter. */ + txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); #ifdef GATHER_TXINT - txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); + txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); #endif - if (tc35815_debug > 2) { - printk("%s: starting TxFD.\n", dev->name); - dump_txfd(txfd); - if (tc35815_debug > 3) - print_eth(buf); - } - tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); - } else { - txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); - if (tc35815_debug > 2) { - printk("%s: queueing TxFD.\n", dev->name); - dump_txfd(txfd); - if (tc35815_debug > 3) - print_eth(buf); - } + if (netif_msg_tx_queued(lp)) { + printk("%s: starting TxFD.\n", dev->name); + dump_txfd(txfd); } - lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; + tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); + } else { + txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); + if (netif_msg_tx_queued(lp)) { + printk("%s: queueing TxFD.\n", dev->name); + dump_txfd(txfd); + } + } + lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; - dev->trans_start = jiffies; + dev->trans_start = jiffies; - if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) { - /* we can send another packet */ - lp->tbusy = 0; - netif_start_queue(dev); - } else { - netif_stop_queue(dev); - if (tc35815_debug > 1) - printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); - } - spin_unlock_irqrestore(&lp->lock, flags); + /* If we just used up the very last entry in the + * TX ring on this device, tell the queueing + * layer to send no more. + */ + if (tc35815_tx_full(dev)) { + if (netif_msg_tx_queued(lp)) + printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); + netif_stop_queue(dev); } + /* When the TX completion hw interrupt arrives, this + * is when the transmit statistics are updated. + */ + + spin_unlock_irqrestore(&lp->lock, flags); return 0; } #define FATAL_ERROR_INT \ (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) -static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) +static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status) { static int count; printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", dev->name, status); - if (status & Int_IntPCI) printk(" IntPCI"); if (status & Int_DmParErr) @@ -1033,110 +1321,170 @@ static void tc35815_fatal_error_interrup printk("\n"); if (count++ > 100) panic("%s: Too many fatal errors.", dev->name); - printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname); + printk(KERN_WARNING "%s: Resetting ...\n", dev->name); /* Try to restart the adaptor. */ - tc35815_chip_reset(dev); - tc35815_clear_queues(dev); - tc35815_chip_init(dev); + tc35815_restart(dev); +} + +#ifdef TC35815_NAPI +static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit) +#else +static int tc35815_do_interrupt(struct net_device *dev, u32 status) +#endif +{ + struct tc35815_local *lp = dev->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + int ret = -1; + + /* Fatal errors... */ + if (status & FATAL_ERROR_INT) { + tc35815_fatal_error_interrupt(dev, status); + return 0; + } + /* recoverable errors */ + if (status & Int_IntFDAEx) { + /* disable FDAEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Free Descriptor Area Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + ret = 0; + } + if (status & Int_IntBLEx) { + /* disable BLEx int. (until we make rooms...) */ + tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); + printk(KERN_WARNING + "%s: Buffer List Exhausted (%#x).\n", + dev->name, status); + lp->stats.rx_dropped++; + ret = 0; + } + if (status & Int_IntExBD) { + printk(KERN_WARNING + "%s: Excessive Buffer Descriptiors (%#x).\n", + dev->name, status); + lp->stats.rx_length_errors++; + ret = 0; + } + + /* normal notification */ + if (status & Int_IntMacRx) { + /* Got a packet(s). */ +#ifdef TC35815_NAPI + ret = tc35815_rx(dev, limit); +#else + tc35815_rx(dev); + ret = 0; +#endif + lp->lstats.rx_ints++; + } + if (status & Int_IntMacTx) { + /* Transmit complete. */ + lp->lstats.tx_ints++; + tc35815_txdone(dev); + netif_wake_queue(dev); + ret = 0; + } + return ret; } /* * The typical workload of the driver: - * Handle the network interface interrupts. + * Handle the network interface interrupts. */ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct tc35815_regs *tr; - struct tc35815_local *lp; - int status, boguscount = 0; - int handled = 0; - - if (dev == NULL) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); - return IRQ_NONE; - } - - tr = (struct tc35815_regs*)dev->base_addr; - lp = dev->priv; - - do { - status = tc_readl(&tr->Int_Src); - if (status == 0) - break; - handled = 1; - tc_writel(status, &tr->Int_Src); /* write to clear */ - - /* Fatal errors... */ - if (status & FATAL_ERROR_INT) { - tc35815_fatal_error_interrupt(dev, status); - break; - } - /* recoverable errors */ - if (status & Int_IntFDAEx) { - /* disable FDAEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Free Descriptor Area Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; - } - if (status & Int_IntBLEx) { - /* disable BLEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Buffer List Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; - } - if (status & Int_IntExBD) { - printk(KERN_WARNING - "%s: Excessive Buffer Descriptiors (%#x).\n", - dev->name, status); - lp->stats.rx_length_errors++; - } - /* normal notification */ - if (status & Int_IntMacRx) { - /* Got a packet(s). */ - lp->lstats.rx_ints++; - tc35815_rx(dev); - } - if (status & Int_IntMacTx) { - lp->lstats.tx_ints++; - tc35815_txdone(dev); + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; +#ifdef TC35815_NAPI + u32 dmactl = tc_readl(&tr->DMA_Ctl); + + if (!(dmactl & DMA_IntMask)) { + /* disable interrupts */ + tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); + if (netif_rx_schedule_prep(dev)) + __netif_rx_schedule(dev); + else { + printk(KERN_ERR "%s: interrupt taken in poll\n", + dev->name); + BUG(); } - } while (++boguscount < 20) ; + (void)tc_readl(&tr->Int_Src); /* flush */ + return IRQ_HANDLED; + } + return IRQ_NONE; +#else + struct tc35815_local *lp = dev->priv; + int handled; + u32 status; + + spin_lock(&lp->lock); + status = tc_readl(&tr->Int_Src); + tc_writel(status, &tr->Int_Src); /* write to clear */ + handled = tc35815_do_interrupt(dev, status); + (void)tc_readl(&tr->Int_Src); /* flush */ + spin_unlock(&lp->lock); + return IRQ_RETVAL(handled >= 0); +#endif /* TC35815_NAPI */ +} - return IRQ_RETVAL(handled); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tc35815_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + tc35815_interrupt(dev->irq, dev); + enable_irq(dev->irq); } +#endif /* We have a good packet(s), get it/them out of the buffers. */ +#ifdef TC35815_NAPI +static int +tc35815_rx(struct net_device *dev, int limit) +#else static void tc35815_rx(struct net_device *dev) +#endif { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; unsigned int fdctl; int i; int buf_free_count = 0; int fd_free_count = 0; +#ifdef TC35815_NAPI + int received = 0; +#endif while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); int pkt_len = fdctl & FD_FDLength_MASK; - struct RxFD *next_rfd; int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; +#ifdef DEBUG + struct RxFD *next_rfd; +#endif +#if (RX_CTL_CMD & Rx_StripCRC) == 0 + pkt_len -= 4; +#endif - if (tc35815_debug > 2) + if (netif_msg_rx_status(lp)) dump_rxfd(lp->rfd_cur); if (status & Rx_Good) { - /* Malloc up new buffer. */ struct sk_buff *skb; unsigned char *data; - int cur_bd, offset; - - lp->stats.rx_bytes += pkt_len; + int cur_bd; +#ifdef TC35815_USE_PACKEDBUFFER + int offset; +#endif +#ifdef TC35815_NAPI + if (--limit < 0) + break; +#endif +#ifdef TC35815_USE_PACKEDBUFFER + BUG_ON(bd_count > 2); skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", @@ -1155,25 +1503,69 @@ tc35815_rx(struct net_device *dev) while (offset < pkt_len && cur_bd < bd_count) { int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & BD_BuffLength_MASK; - void *rxbuf = - bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData)); -#ifdef __mips__ - dma_cache_inv((unsigned long)rxbuf, len); + dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData); + void *rxbuf = rxbuf_bus_to_virt(lp, dma); + if (offset + len > pkt_len) + len = pkt_len - offset; +#ifdef TC35815_DMA_SYNC_ONDEMAND + pci_dma_sync_single_for_cpu(lp->pci_dev, + dma, len, + PCI_DMA_FROMDEVICE); #endif memcpy(data + offset, rxbuf, len); +#ifdef TC35815_DMA_SYNC_ONDEMAND + pci_dma_sync_single_for_device(lp->pci_dev, + dma, len, + PCI_DMA_FROMDEVICE); +#endif offset += len; cur_bd++; } -#if 0 - print_buf(data,pkt_len); +#else /* TC35815_USE_PACKEDBUFFER */ + BUG_ON(bd_count > 1); + cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl) + & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; +#ifdef DEBUG + if (cur_bd >= RX_BUF_NUM) { + printk("%s: invalid BDID.\n", dev->name); + panic_queues(dev); + } + BUG_ON(lp->rx_skbs[cur_bd].skb_dma != + (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3)); + if (!lp->rx_skbs[cur_bd].skb) { + printk("%s: NULL skb.\n", dev->name); + panic_queues(dev); + } +#else + BUG_ON(cur_bd >= RX_BUF_NUM); #endif - if (tc35815_debug > 3) + skb = lp->rx_skbs[cur_bd].skb; + prefetch(skb->data); + lp->rx_skbs[cur_bd].skb = NULL; + lp->fbl_count--; + pci_unmap_single(lp->pci_dev, + lp->rx_skbs[cur_bd].skb_dma, + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!HAVE_DMA_RXALIGN(lp)) + memmove(skb->data, skb->data - 2, pkt_len); + data = skb_put(skb, pkt_len); +#endif /* TC35815_USE_PACKEDBUFFER */ + if (netif_msg_pktdata(lp)) print_eth(data); skb->protocol = eth_type_trans(skb, dev); +#ifdef TC35815_NAPI + netif_receive_skb(skb); + received++; +#else netif_rx(skb); +#endif + dev->last_rx = jiffies; lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { lp->stats.rx_errors++; + printk(KERN_DEBUG "%s: Rx error (status %x)\n", + dev->name, status & Rx_Stat_Mask); /* WORKAROUND: LongErr and CRCErr means Overflow. */ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { status &= ~(Rx_LongErr|Rx_CRCErr); @@ -1190,63 +1582,150 @@ #endif int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); unsigned char id = (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; - if (id >= RX_BUF_PAGES) { +#ifdef DEBUG + if (id >= RX_BUF_NUM) { printk("%s: invalid BDID.\n", dev->name); panic_queues(dev); } +#else + BUG_ON(id >= RX_BUF_NUM); +#endif /* free old buffers */ - while (lp->fbl_curid != id) { - bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl); +#ifdef TC35815_USE_PACKEDBUFFER + while (lp->fbl_curid != id) +#else + while (lp->fbl_count < RX_BUF_NUM) +#endif + { +#ifdef TC35815_USE_PACKEDBUFFER + unsigned char curid = lp->fbl_curid; +#else + unsigned char curid = + (id + 1 + lp->fbl_count) % RX_BUF_NUM; +#endif + struct BDesc *bd = &lp->fbl_ptr->bd[curid]; +#ifdef DEBUG + bdctl = le32_to_cpu(bd->BDCtl); if (bdctl & BD_CownsBD) { printk("%s: Freeing invalid BD.\n", dev->name); panic_queues(dev); } +#endif /* pass BD to controler */ +#ifndef TC35815_USE_PACKEDBUFFER + if (!lp->rx_skbs[curid].skb) { + lp->rx_skbs[curid].skb = + alloc_rxbuf_skb(dev, + lp->pci_dev, + &lp->rx_skbs[curid].skb_dma); + if (!lp->rx_skbs[curid].skb) + break; /* try on next reception */ + bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma); + } +#endif /* TC35815_USE_PACKEDBUFFER */ /* Note: BDLength was modified by chip. */ - lp->fbl_ptr->bd[lp->fbl_curid].BDCtl = - cpu_to_le32(BD_CownsBD | - (lp->fbl_curid << BD_RxBDID_SHIFT) | - PAGE_SIZE); - lp->fbl_curid = - (lp->fbl_curid + 1) % RX_BUF_PAGES; - if (tc35815_debug > 2) { + bd->BDCtl = cpu_to_le32(BD_CownsBD | + (curid << BD_RxBDID_SHIFT) | + RX_BUF_SIZE); +#ifdef TC35815_USE_PACKEDBUFFER + lp->fbl_curid = (curid + 1) % RX_BUF_NUM; + if (netif_msg_rx_status(lp)) { printk("%s: Entering new FBD %d\n", dev->name, lp->fbl_curid); dump_frfd(lp->fbl_ptr); } +#else + lp->fbl_count++; +#endif buf_free_count++; } } /* put RxFD back to controller */ - next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext)); -#ifdef __mips__ - next_rfd = (struct RxFD *)vtonocache(next_rfd); -#endif +#ifdef DEBUG + next_rfd = fd_bus_to_virt(lp, + le32_to_cpu(lp->rfd_cur->fd.FDNext)); if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { printk("%s: RxFD FDNext invalid.\n", dev->name); panic_queues(dev); } +#endif for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { /* pass FD to controler */ - lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */ +#ifdef DEBUG + lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); +#else + lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL); +#endif lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); lp->rfd_cur++; fd_free_count++; } - - lp->rfd_cur = next_rfd; + if (lp->rfd_cur > lp->rfd_limit) + lp->rfd_cur = lp->rfd_base; +#ifdef DEBUG + if (lp->rfd_cur != next_rfd) + printk("rfd_cur = %p, next_rfd %p\n", + lp->rfd_cur, next_rfd); +#endif } /* re-enable BL/FDA Exhaust interrupts. */ if (fd_free_count) { - tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En); + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + u32 en, en_old = tc_readl(&tr->Int_En); + en = en_old | Int_FDAExEn; if (buf_free_count) - tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En); + en |= Int_BLExEn; + if (en != en_old) + tc_writel(en, &tr->Int_En); } +#ifdef TC35815_NAPI + return received; +#endif } +#ifdef TC35815_NAPI +static int +tc35815_poll(struct net_device *dev, int *budget) +{ + struct tc35815_local *lp = dev->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + int limit = min(*budget, dev->quota); + int received = 0, handled; + u32 status; + + spin_lock(&lp->lock); + status = tc_readl(&tr->Int_Src); + do { + tc_writel(status, &tr->Int_Src); /* write to clear */ + + handled = tc35815_do_interrupt(dev, status, limit); + if (handled >= 0) { + received += handled; + limit -= handled; + if (limit <= 0) + break; + } + status = tc_readl(&tr->Int_Src); + } while (status); + spin_unlock(&lp->lock); + + dev->quota -= received; + *budget -= received; + if (limit <= 0) + return 1; + + netif_rx_complete(dev); + /* enable interrupts */ + tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); + return 0; +} +#endif + #ifdef NO_CHECK_CARRIER #define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) #else @@ -1265,9 +1744,17 @@ tc35815_check_tx_stat(struct net_device if (status & Tx_TxColl_MASK) lp->stats.collisions += status & Tx_TxColl_MASK; +#ifndef NO_CHECK_CARRIER + /* TX4939 does not have NCarr */ + if (lp->boardtype == TC35815_TX4939) + status &= ~Tx_NCarr; +#ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if (lp->fullduplex) + if ((lp->timer_state != asleep && lp->timer_state != lcheck) + || lp->fullduplex) status &= ~Tx_NCarr; +#endif +#endif if (!(status & TX_STA_ERR)) { /* no error. */ @@ -1283,6 +1770,15 @@ tc35815_check_tx_stat(struct net_device if (status & Tx_Under) { lp->stats.tx_fifo_errors++; msg = "Tx FIFO Underrun."; + if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) { + lp->lstats.tx_underrun++; + if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) { + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh); + msg = "Tx FIFO Underrun.Change Tx threshold to max."; + } + } } if (status & Tx_Defer) { lp->stats.tx_fifo_errors++; @@ -1306,18 +1802,19 @@ #endif lp->stats.tx_heartbeat_errors++; msg = "Signal Quality Error."; } - if (msg) + if (msg && netif_msg_tx_err(lp)) printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); } +/* This handles TX complete events posted by the device + * via interrupts. + */ static void tc35815_txdone(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; struct TxFD *txfd; unsigned int fdctl; - int num_done = 0; txfd = &lp->tfd_base[lp->tfd_end]; while (lp->tfd_start != lp->tfd_end && @@ -1325,38 +1822,61 @@ tc35815_txdone(struct net_device *dev) int status = le32_to_cpu(txfd->fd.FDStat); struct sk_buff *skb; unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); + u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem); - if (tc35815_debug > 2) { + if (netif_msg_tx_done(lp)) { printk("%s: complete TxFD.\n", dev->name); dump_txfd(txfd); } tc35815_check_tx_stat(dev, status); - skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem); + skb = fdsystem != 0xffffffff ? + lp->tx_skbs[fdsystem].skb : NULL; +#ifdef DEBUG + if (lp->tx_skbs[lp->tfd_end].skb != skb) { + printk("%s: tx_skbs mismatch.\n", dev->name); + panic_queues(dev); + } +#else + BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb); +#endif if (skb) { + lp->stats.tx_bytes += skb->len; + pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE); + lp->tx_skbs[lp->tfd_end].skb = NULL; + lp->tx_skbs[lp->tfd_end].skb_dma = 0; +#ifdef TC35815_NAPI dev_kfree_skb_any(skb); +#else + dev_kfree_skb_irq(skb); +#endif } - txfd->fd.FDSystem = cpu_to_le32(0); + txfd->fd.FDSystem = cpu_to_le32(0xffffffff); - num_done++; lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; txfd = &lp->tfd_base[lp->tfd_end]; - if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) { +#ifdef DEBUG + if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) { printk("%s: TxFD FDNext invalid.\n", dev->name); panic_queues(dev); } +#endif if (fdnext & FD_Next_EOL) { /* DMA Transmitter has been stopping... */ if (lp->tfd_end != lp->tfd_start) { + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; struct TxFD* txhead = &lp->tfd_base[head]; int qlen = (lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM; +#ifdef DEBUG if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { printk("%s: TxFD FDCtl invalid.\n", dev->name); panic_queues(dev); } +#endif /* log max queue length */ if (lp->lstats.max_tx_qlen < qlen) lp->lstats.max_tx_qlen = qlen; @@ -1367,21 +1887,23 @@ tc35815_txdone(struct net_device *dev) #ifdef GATHER_TXINT txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); #endif - if (tc35815_debug > 2) { + if (netif_msg_tx_queued(lp)) { printk("%s: start TxFD on queue.\n", dev->name); dump_txfd(txfd); } - tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); + tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); } break; } } - if (num_done > 0 && lp->tbusy) { - lp->tbusy = 0; - netif_start_queue(dev); - } + /* If we had stopped the queue due to a "tx full" + * condition, and space has now been made available, + * wake up the queue. + */ + if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev)) + netif_wake_queue(dev); } /* The inverse routine to tc35815_open(). */ @@ -1389,18 +1911,18 @@ static int tc35815_close(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - - lp->tbusy = 1; netif_stop_queue(dev); /* Flush the Tx and disable Rx here. */ + del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); free_irq(dev->irq, dev); tc35815_free_queues(dev); return 0; + } /* @@ -1410,29 +1932,29 @@ tc35815_close(struct net_device *dev) static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - unsigned long flags; - + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; if (netif_running(dev)) { - spin_lock_irqsave(&lp->lock, flags); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); - spin_unlock_irqrestore(&lp->lock, flags); } return &lp->stats; } -static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr) +static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr) { + struct tc35815_local *lp = dev->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; int cam_index = index * 6; - unsigned long cam_data; - unsigned long saved_addr; + u32 cam_data; + u32 saved_addr; saved_addr = tc_readl(&tr->CAM_Adr); - if (tc35815_debug > 1) { + if (netif_msg_hw(lp)) { int i; - printk(KERN_DEBUG "%s: CAM %d:", cardname, index); + printk(KERN_DEBUG "%s: CAM %d:", dev->name, index); for (i = 0; i < 6; i++) printk(" %02x", addr[i]); printk("\n"); @@ -1459,14 +1981,6 @@ static void tc35815_set_cam_entry(struct tc_writel(cam_data, &tr->CAM_Data); } - if (tc35815_debug > 2) { - int i; - for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { - tc_writel(i * 4, &tr->CAM_Adr); - printk("CAM 0x%x: %08lx", - i * 4, tc_readl(&tr->CAM_Data)); - } - } tc_writel(saved_addr, &tr->CAM_Adr); } @@ -1481,10 +1995,19 @@ static void tc35815_set_cam_entry(struct static void tc35815_set_multicast_list(struct net_device *dev) { - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; if (dev->flags&IFF_PROMISC) { +#ifdef WORKAROUND_100HALF_PROMISC + /* With some (all?) 100MHalf HUB, controller will hang + * if we enabled promiscuous mode before linkup... */ + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS)) + return; +#endif /* Enable promiscuous mode */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); } @@ -1506,7 +2029,7 @@ tc35815_set_multicast_list(struct net_de if (!cur_addr) break; /* entry 0,1 is reserved. */ - tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr); + tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr); ena_bits |= CAM_Ena_Bit(i + 2); } tc_writel(ena_bits, &tr->CAM_Ena); @@ -1518,122 +2041,753 @@ tc35815_set_multicast_list(struct net_de } } -static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) +static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct tc35815_local *lp = dev->priv; - unsigned long data; - unsigned long flags; + strcpy(info->driver, MODNAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(lp->pci_dev)); +} - spin_lock_irqsave(&lp->lock, flags); +static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct tc35815_local *lp = dev->priv; + spin_lock_irq(&lp->lock); + mii_ethtool_gset(&lp->mii, cmd); + spin_unlock_irq(&lp->lock); + return 0; +} - tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA); +static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct tc35815_local *lp = dev->priv; + int rc; +#if 1 /* use our negotiation method... */ + /* Verify the settings we care about. */ + if (cmd->autoneg != AUTONEG_ENABLE && + cmd->autoneg != AUTONEG_DISABLE) + return -EINVAL; + if (cmd->autoneg == AUTONEG_DISABLE && + ((cmd->speed != SPEED_100 && + cmd->speed != SPEED_10) || + (cmd->duplex != DUPLEX_HALF && + cmd->duplex != DUPLEX_FULL))) + return -EINVAL; + + /* Ok, do it to it. */ + spin_lock_irq(&lp->lock); + del_timer(&lp->timer); + tc35815_start_auto_negotiation(dev, cmd); + spin_unlock_irq(&lp->lock); + rc = 0; +#else + spin_lock_irq(&lp->lock); + rc = mii_ethtool_sset(&lp->mii, cmd); + spin_unlock_irq(&lp->lock); +#endif + return rc; +} + +static int tc35815_nway_reset(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + int rc; + spin_lock_irq(&lp->lock); + rc = mii_nway_restart(&lp->mii); + spin_unlock_irq(&lp->lock); + return rc; +} + +static u32 tc35815_get_link(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + int rc; + spin_lock_irq(&lp->lock); + rc = mii_link_ok(&lp->mii); + spin_unlock_irq(&lp->lock); + return rc; +} + +static u32 tc35815_get_msglevel(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + return lp->msg_enable; +} + +static void tc35815_set_msglevel(struct net_device *dev, u32 datum) +{ + struct tc35815_local *lp = dev->priv; + lp->msg_enable = datum; +} + +static int tc35815_get_stats_count(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + return sizeof(lp->lstats) / sizeof(int); +} + +static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) +{ + struct tc35815_local *lp = dev->priv; + data[0] = lp->lstats.max_tx_qlen; + data[1] = lp->lstats.tx_ints; + data[2] = lp->lstats.rx_ints; + data[3] = lp->lstats.tx_underrun; +} + +static struct { + const char str[ETH_GSTRING_LEN]; +} ethtool_stats_keys[] = { + { "max_tx_qlen" }, + { "tx_ints" }, + { "rx_ints" }, + { "tx_underrun" }, +}; + +static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); +} + +static const struct ethtool_ops tc35815_ethtool_ops = { + .get_drvinfo = tc35815_get_drvinfo, + .get_settings = tc35815_get_settings, + .set_settings = tc35815_set_settings, + .nway_reset = tc35815_nway_reset, + .get_link = tc35815_get_link, + .get_msglevel = tc35815_get_msglevel, + .set_msglevel = tc35815_set_msglevel, + .get_strings = tc35815_get_strings, + .get_stats_count = tc35815_get_stats_count, + .get_ethtool_stats = tc35815_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, +}; + +static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tc35815_local *lp = dev->priv; + int rc; + + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irq(&lp->lock); + rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); + spin_unlock_irq(&lp->lock); + + return rc; +} + +static int tc_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + u32 data; + tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA); while (tc_readl(&tr->MD_CA) & MD_CA_Busy) ; data = tc_readl(&tr->MD_Data); - spin_unlock_irqrestore(&lp->lock, flags); - return data; + return data & 0xffff; +} + +static void tc_mdio_write(struct net_device *dev, int phy_id, int location, + int val) +{ + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + tc_writel(val, &tr->MD_Data); + tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA); + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) + ; } -static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) +/* Auto negotiation. The scheme is very simple. We have a timer routine + * that keeps watching the auto negotiation process as it progresses. + * The DP83840 is first told to start doing it's thing, we set up the time + * and place the timer state machine in it's initial state. + * + * Here the timer peeks at the DP83840 status registers at each click to see + * if the auto negotiation has completed, we assume here that the DP83840 PHY + * will time out at some point and just tell us what (didn't) happen. For + * complete coverage we only allow so many of the ticks at this level to run, + * when this has expired we print a warning message and try another strategy. + * This "other" strategy is to force the interface into various speed/duplex + * configurations and we stop when we see a link-up condition before the + * maximum number of "peek" ticks have occurred. + * + * Once a valid link status has been detected we configure the BigMAC and + * the rest of the Happy Meal to speak the most efficient protocol we could + * get a clean link for. The priority for link configurations, highest first + * is: + * 100 Base-T Full Duplex + * 100 Base-T Half Duplex + * 10 Base-T Full Duplex + * 10 Base-T Half Duplex + * + * We start a new timer now, after a successful auto negotiation status has + * been detected. This timer just waits for the link-up bit to get set in + * the BMCR of the DP83840. When this occurs we print a kernel log message + * describing the link type in use and the fact that it is up. + * + * If a fatal error of some sort is signalled and detected in the interrupt + * service routine, and the chip is reset, or the link is ifconfig'd down + * and then back up, this entire process repeats itself all over again. + */ +/* Note: Above comments are come from sunhme driver. */ + +static int tc35815_try_next_permutation(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - unsigned long flags; + int pid = lp->phy_addr; + unsigned short bmcr; - spin_lock_irqsave(&lp->lock, flags); + bmcr = tc_mdio_read(dev, pid, MII_BMCR); - tc_writel(d, &tr->MD_Data); - tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA); - while (tc_readl(&tr->MD_CA) & MD_CA_Busy) - ; - spin_unlock_irqrestore(&lp->lock, flags); + /* Downgrade from full to half duplex. Only possible via ethtool. */ + if (bmcr & BMCR_FULLDPLX) { + bmcr &= ~BMCR_FULLDPLX; + printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + return 0; + } + + /* Downgrade from 100 to 10. */ + if (bmcr & BMCR_SPEED100) { + bmcr &= ~BMCR_SPEED100; + printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + return 0; + } + + /* We've tried everything. */ + return -1; } -static void tc35815_phy_chip_init(struct net_device *dev) +static void +tc35815_display_link_mode(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - static int first = 1; - unsigned short ctl; - - if (first) { - unsigned short id0, id1; - int count; - first = 0; - - /* first data written to the PHY will be an ID number */ - tc_phy_write(dev, 0, tr, 0, MII_CONTROL); /* ID:0 */ -#if 0 - tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL); - printk(KERN_INFO "%s: Resetting PHY...", dev->name); - while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET) - ; - printk("\n"); - tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0, - MII_CONTROL); -#endif - id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0); - id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1); - printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name, - id0, id1); - if (lp->option & TC35815_OPT_10M) { - lp->linkspeed = 10; - lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; - } else if (lp->option & TC35815_OPT_100M) { - lp->linkspeed = 100; - lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; + int pid = lp->phy_addr; + unsigned short lpa, bmcr; + char *speed = "", *duplex = ""; + + lpa = tc_mdio_read(dev, pid, MII_LPA); + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) + speed = "100Mb/s"; + else + speed = "10Mb/s"; + if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) + duplex = "Full Duplex"; + else + duplex = "Half Duplex"; + + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: Link is up at %s, %s.\n", + dev->name, speed, duplex); + printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", + dev->name, + bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); +} + +static void tc35815_display_forced_link_mode(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + unsigned short bmcr; + char *speed = "", *duplex = ""; + + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (bmcr & BMCR_SPEED100) + speed = "100Mb/s"; + else + speed = "10Mb/s"; + if (bmcr & BMCR_FULLDPLX) + duplex = "Full Duplex.\n"; + else + duplex = "Half Duplex.\n"; + + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: Link has been forced up at %s, %s", + dev->name, speed, duplex); +} + +static void tc35815_set_link_modes(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + int pid = lp->phy_addr; + unsigned short bmcr, lpa; + int speed; + + if (lp->timer_state == arbwait) { + lpa = tc_mdio_read(dev, pid, MII_LPA); + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", + dev->name, + bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); + if (!(lpa & (LPA_10HALF | LPA_10FULL | + LPA_100HALF | LPA_100FULL))) { + /* fall back to 10HALF */ + printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n", + dev->name, lpa); + lpa = LPA_10HALF; + } + if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) + lp->fullduplex = 1; + else + lp->fullduplex = 0; + if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) + speed = 100; + else + speed = 10; + } else { + /* Forcing a link mode. */ + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (bmcr & BMCR_FULLDPLX) + lp->fullduplex = 1; + else + lp->fullduplex = 0; + if (bmcr & BMCR_SPEED100) + speed = 100; + else + speed = 10; + } + + tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl); + if (lp->fullduplex) { + tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); + } else { + tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl); + } + tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl); + + /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */ + +#ifndef NO_CHECK_CARRIER + /* TX4939 does not have EnLCarr */ + if (lp->boardtype != TC35815_TX4939) { +#ifdef WORKAROUND_LOSTCAR + /* WORKAROUND: enable LostCrS only if half duplex operation */ + if (!lp->fullduplex && lp->boardtype != TC35815_TX4939) + tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl); +#endif + } +#endif + lp->mii.full_duplex = lp->fullduplex; +} + +static void tc35815_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + unsigned short bmsr, bmcr, lpa; + int restart_timer = 0; + + spin_lock_irq(&lp->lock); + + lp->timer_ticks++; + switch (lp->timer_state) { + case arbwait: + /* + * Only allow for 5 ticks, thats 10 seconds and much too + * long to wait for arbitration to complete. + */ + /* TC35815 need more times... */ + if (lp->timer_ticks >= 10) { + /* Enter force mode. */ + if (!options.doforce) { + printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," + " cable probblem?\n", dev->name); + /* Try to restart the adaptor. */ + tc35815_restart(dev); + goto out; + } + printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," + " trying force link mode\n", dev->name); + printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name, + tc_mdio_read(dev, pid, MII_BMCR), + tc_mdio_read(dev, pid, MII_BMSR)); + bmcr = BMCR_SPEED100; + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + + /* + * OK, seems we need do disable the transceiver + * for the first tick to make sure we get an + * accurate link state at the second tick. + */ + + lp->timer_state = ltrywait; + lp->timer_ticks = 0; + restart_timer = 1; } else { - /* auto negotiation */ - unsigned long neg_result; - tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL); - printk(KERN_INFO "%s: Auto Negotiation...", dev->name); - count = 0; - while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) { - if (count++ > 5000) { - printk(" failed. Assume 10Mbps\n"); - lp->linkspeed = 10; - lp->fullduplex = 0; - goto done; + /* Anything interesting happen? */ + bmsr = tc_mdio_read(dev, pid, MII_BMSR); + if (bmsr & BMSR_ANEGCOMPLETE) { + /* Just what we've been waiting for... */ + tc35815_set_link_modes(dev); + + /* + * Success, at least so far, advance our state + * engine. + */ + lp->timer_state = lupwait; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; + + case lupwait: + /* + * Auto negotiation was successful and we are awaiting a + * link up status. I have decided to let this timer run + * forever until some sort of error is signalled, reporting + * a message to the user at 10 second intervals. + */ + bmsr = tc_mdio_read(dev, pid, MII_BMSR); + if (bmsr & BMSR_LSTATUS) { + /* + * Wheee, it's up, display the link mode in use and put + * the timer to sleep. + */ + tc35815_display_link_mode(dev); + netif_carrier_on(dev); +#ifdef WORKAROUND_100HALF_PROMISC + /* delayed promiscuous enabling */ + if (dev->flags & IFF_PROMISC) + tc35815_set_multicast_list(dev); +#endif +#if 1 + lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); + lp->timer_state = lcheck; + restart_timer = 1; +#else + lp->timer_state = asleep; + restart_timer = 0; +#endif + } else { + if (lp->timer_ticks >= 10) { + printk(KERN_NOTICE "%s: Auto negotiation successful, link still " + "not completely up.\n", dev->name); + lp->timer_ticks = 0; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; + + case ltrywait: + /* + * Making the timeout here too long can make it take + * annoyingly long to attempt all of the link mode + * permutations, but then again this is essentially + * error recovery code for the most part. + */ + bmsr = tc_mdio_read(dev, pid, MII_BMSR); + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (lp->timer_ticks == 1) { + /* + * Re-enable transceiver, we'll re-enable the + * transceiver next tick, then check link state + * on the following tick. + */ + restart_timer = 1; + break; + } + if (lp->timer_ticks == 2) { + restart_timer = 1; + break; + } + if (bmsr & BMSR_LSTATUS) { + /* Force mode selection success. */ + tc35815_display_forced_link_mode(dev); + netif_carrier_on(dev); + tc35815_set_link_modes(dev); +#ifdef WORKAROUND_100HALF_PROMISC + /* delayed promiscuous enabling */ + if (dev->flags & IFF_PROMISC) + tc35815_set_multicast_list(dev); +#endif +#if 1 + lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); + lp->timer_state = lcheck; + restart_timer = 1; +#else + lp->timer_state = asleep; + restart_timer = 0; +#endif + } else { + if (lp->timer_ticks >= 4) { /* 6 seconds or so... */ + int ret; + + ret = tc35815_try_next_permutation(dev); + if (ret == -1) { + /* + * Aieee, tried them all, reset the + * chip and try all over again. + */ + printk(KERN_NOTICE "%s: Link down, " + "cable problem?\n", + dev->name); + + /* Try to restart the adaptor. */ + tc35815_restart(dev); + goto out; } - if (count % 512 == 0) - printk("."); - mdelay(1); + lp->timer_ticks = 0; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; + + case lcheck: + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + lpa = tc_mdio_read(dev, pid, MII_LPA); + if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) { + printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name, + bmcr); + } else if ((lp->saved_lpa ^ lpa) & + (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) { + printk(KERN_NOTICE "%s: link status changed" + " (BMCR %x LPA %x->%x)\n", dev->name, + bmcr, lp->saved_lpa, lpa); + } else { + /* go on */ + restart_timer = 1; + break; + } + /* Try to restart the adaptor. */ + tc35815_restart(dev); + goto out; + + case asleep: + default: + /* Can't happens.... */ + printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " + "one anyways!\n", dev->name); + restart_timer = 0; + lp->timer_ticks = 0; + lp->timer_state = asleep; /* foo on you */ + break; + } + + if (restart_timer) { + lp->timer.expires = jiffies + msecs_to_jiffies(1200); + add_timer(&lp->timer); + } +out: + spin_unlock_irq(&lp->lock); +} + +static void tc35815_start_auto_negotiation(struct net_device *dev, + struct ethtool_cmd *ep) +{ + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + unsigned short bmsr, bmcr, advertize; + int timeout; + + netif_carrier_off(dev); + bmsr = tc_mdio_read(dev, pid, MII_BMSR); + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + advertize = tc_mdio_read(dev, pid, MII_ADVERTISE); + + if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + if (options.speed || options.duplex) { + /* Advertise only specified configuration. */ + advertize &= ~(ADVERTISE_10HALF | + ADVERTISE_10FULL | + ADVERTISE_100HALF | + ADVERTISE_100FULL); + if (options.speed != 10) { + if (options.duplex != 1) + advertize |= ADVERTISE_100FULL; + if (options.duplex != 2) + advertize |= ADVERTISE_100HALF; + } + if (options.speed != 100) { + if (options.duplex != 1) + advertize |= ADVERTISE_10FULL; + if (options.duplex != 2) + advertize |= ADVERTISE_10HALF; } - printk(" done.\n"); - neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR); - if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX)) - lp->linkspeed = 100; + if (options.speed == 100) + bmcr |= BMCR_SPEED100; + else if (options.speed == 10) + bmcr &= ~BMCR_SPEED100; + if (options.duplex == 2) + bmcr |= BMCR_FULLDPLX; + else if (options.duplex == 1) + bmcr &= ~BMCR_FULLDPLX; + } else { + /* Advertise everything we can support. */ + if (bmsr & BMSR_10HALF) + advertize |= ADVERTISE_10HALF; else - lp->linkspeed = 10; - if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX)) - lp->fullduplex = 1; + advertize &= ~ADVERTISE_10HALF; + if (bmsr & BMSR_10FULL) + advertize |= ADVERTISE_10FULL; else - lp->fullduplex = 0; - done: - ; + advertize &= ~ADVERTISE_10FULL; + if (bmsr & BMSR_100HALF) + advertize |= ADVERTISE_100HALF; + else + advertize &= ~ADVERTISE_100HALF; + if (bmsr & BMSR_100FULL) + advertize |= ADVERTISE_100FULL; + else + advertize &= ~ADVERTISE_100FULL; + } + + tc_mdio_write(dev, pid, MII_ADVERTISE, advertize); + + /* Enable Auto-Negotiation, this is usually on already... */ + bmcr |= BMCR_ANENABLE; + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + + /* Restart it to make sure it is going. */ + bmcr |= BMCR_ANRESTART; + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr); + + /* BMCR_ANRESTART self clears when the process has begun. */ + timeout = 64; /* More than enough. */ + while (--timeout) { + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (!(bmcr & BMCR_ANRESTART)) + break; /* got it. */ + udelay(10); } + if (!timeout) { + printk(KERN_ERR "%s: TC35815 would not start auto " + "negotiation BMCR=0x%04x\n", + dev->name, bmcr); + printk(KERN_NOTICE "%s: Performing force link " + "detection.\n", dev->name); + goto force_link; + } else { + printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name); + lp->timer_state = arbwait; + } + } else { +force_link: + /* Force the link up, trying first a particular mode. + * Either we are here at the request of ethtool or + * because the Happy Meal would not start to autoneg. + */ + + /* Disable auto-negotiation in BMCR, enable the duplex and + * speed setting, init the timer state machine, and fire it off. + */ + if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + bmcr = BMCR_SPEED100; + } else { + if (ep->speed == SPEED_100) + bmcr = BMCR_SPEED100; + else + bmcr = 0; + if (ep->duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + } + tc_mdio_write(dev, pid, MII_BMCR, bmcr); + + /* OK, seems we need do disable the transceiver for the first + * tick to make sure we get an accurate link state at the + * second tick. + */ + lp->timer_state = ltrywait; } - ctl = 0; - if (lp->linkspeed == 100) - ctl |= MIICNTL_SPEED; - if (lp->fullduplex) - ctl |= MIICNTL_FDX; - tc_phy_write(dev, ctl, tr, 0, MII_CONTROL); + del_timer(&lp->timer); + lp->timer_ticks = 0; + lp->timer.expires = jiffies + msecs_to_jiffies(1200); + add_timer(&lp->timer); +} - if (lp->fullduplex) { - tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); +static void tc35815_find_phy(struct net_device *dev) +{ + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + unsigned short id0; + + /* find MII phy */ + for (pid = 31; pid >= 0; pid--) { + id0 = tc_mdio_read(dev, pid, MII_BMSR); + if (id0 != 0xffff && id0 != 0x0000 && + (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */ + ) { + lp->phy_addr = pid; + break; + } } + if (pid < 0) { + printk(KERN_ERR "%s: No MII Phy found.\n", + dev->name); + lp->phy_addr = pid = 0; + } + + lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1); + lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2); + if (netif_msg_hw(lp)) + printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name, + pid, lp->mii_id[0], lp->mii_id[1]); } -static void tc35815_chip_reset(struct net_device *dev) +static void tc35815_phy_chip_init(struct net_device *dev) { - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; + struct tc35815_local *lp = dev->priv; + int pid = lp->phy_addr; + unsigned short bmcr; + struct ethtool_cmd ecmd, *ep; + + /* dis-isolate if needed. */ + bmcr = tc_mdio_read(dev, pid, MII_BMCR); + if (bmcr & BMCR_ISOLATE) { + int count = 32; + printk(KERN_DEBUG "%s: unisolating...", dev->name); + tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE); + while (--count) { + if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE)) + break; + udelay(20); + } + printk(" %s.\n", count ? "done" : "failed"); + } + + if (options.speed && options.duplex) { + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100; + ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL; + ep = &ecmd; + } else { + ep = NULL; + } + tc35815_start_auto_negotiation(dev, ep); +} +static void tc35815_chip_reset(struct net_device *dev) +{ + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + int i; /* reset the controller */ tc_writel(MAC_Reset, &tr->MAC_Ctl); - while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) - ; - + udelay(4); /* 3200ns */ + i = 0; + while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) { + if (i++ > 100) { + printk(KERN_ERR "%s: MAC reset failed.\n", dev->name); + break; + } + mdelay(1); + } tc_writel(0, &tr->MAC_Ctl); /* initialize registers to default value */ @@ -1651,90 +2805,142 @@ static void tc35815_chip_reset(struct ne tc_writel(0, &tr->CAM_Ena); (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ + /* initialize internal SRAM */ + tc_writel(DMA_TestMode, &tr->DMA_Ctl); + for (i = 0; i < 0x1000; i += 4) { + tc_writel(i, &tr->CAM_Adr); + tc_writel(0, &tr->CAM_Data); + } + tc_writel(0, &tr->DMA_Ctl); } static void tc35815_chip_init(struct net_device *dev) { struct tc35815_local *lp = dev->priv; - struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; - unsigned long flags; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; unsigned long txctl = TX_CTL_CMD; tc35815_phy_chip_init(dev); /* load station address to CAM */ - tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr); + tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr); /* Enable CAM (broadcast and unicast) */ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); - spin_lock_irqsave(&lp->lock, flags); - - tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); - + /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */ + if (HAVE_DMA_RXALIGN(lp)) + tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl); + else + tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); +#ifdef TC35815_USE_PACKEDBUFFER tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ +#else + tc_writel(ETH_ZLEN, &tr->RxFragSize); +#endif tc_writel(0, &tr->TxPollCtr); /* Batch mode */ tc_writel(TX_THRESHOLD, &tr->TxThrsh); tc_writel(INT_EN_CMD, &tr->Int_En); /* set queues */ - tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas); + tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas); tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, &tr->FDA_Lim); /* * Activation method: - * First, enable eht MAC Transmitter and the DMA Receive circuits. + * First, enable the MAC Transmitter and the DMA Receive circuits. * Then enable the DMA Transmitter and the MAC Receive circuits. */ - tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ + tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ + /* start MAC transmitter */ +#ifndef NO_CHECK_CARRIER + /* TX4939 does not have EnLCarr */ + if (lp->boardtype == TC35815_TX4939) + txctl &= ~Tx_EnLCarr; +#ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if (lp->fullduplex) - txctl = TX_CTL_CMD & ~Tx_EnLCarr; + if ((lp->timer_state != asleep && lp->timer_state != lcheck) || + lp->fullduplex) + txctl &= ~Tx_EnLCarr; +#endif +#endif /* !NO_CHECK_CARRIER */ #ifdef GATHER_TXINT txctl &= ~Tx_EnComp; /* disable global tx completion int. */ #endif tc_writel(txctl, &tr->Tx_Ctl); -#if 0 /* No need to polling */ - tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ -#endif +} + +#ifdef CONFIG_PM +static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct tc35815_local *lp = dev->priv; + unsigned long flags; + + pci_save_state(pdev); + if (!netif_running(dev)) + return 0; + netif_device_detach(dev); + spin_lock_irqsave(&lp->lock, flags); + del_timer(&lp->timer); /* Kill if running */ + tc35815_chip_reset(dev); spin_unlock_irqrestore(&lp->lock, flags); + pci_set_power_state(pdev, PCI_D3hot); + return 0; } -static struct pci_driver tc35815_driver = { - .name = TC35815_MODULE_NAME, - .probe = tc35815_probe, - .remove = NULL, - .id_table = tc35815_pci_tbl, +static int tc35815_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct tc35815_local *lp = dev->priv; + unsigned long flags; + + pci_restore_state(pdev); + if (!netif_running(dev)) + return 0; + pci_set_power_state(pdev, PCI_D0); + spin_lock_irqsave(&lp->lock, flags); + tc35815_restart(dev); + spin_unlock_irqrestore(&lp->lock, flags); + netif_device_attach(dev); + return 0; +} +#endif /* CONFIG_PM */ + +static struct pci_driver tc35815_pci_driver = { + .name = MODNAME, + .id_table = tc35815_pci_tbl, + .probe = tc35815_init_one, + .remove = __devexit_p(tc35815_remove_one), +#ifdef CONFIG_PM + .suspend = tc35815_suspend, + .resume = tc35815_resume, +#endif }; +module_param_named(speed, options.speed, int, 0); +MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps"); +module_param_named(duplex, options.duplex, int, 0); +MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full"); +module_param_named(doforce, options.doforce, int, 0); +MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed"); + static int __init tc35815_init_module(void) { - return pci_register_driver(&tc35815_driver); + return pci_register_driver(&tc35815_pci_driver); } static void __exit tc35815_cleanup_module(void) { - struct net_device *next_dev; - - /* - * TODO: implement a tc35815_driver.remove hook, and - * move this code into that function. Then, delete - * all root_tc35815_dev list handling code. - */ - while (root_tc35815_dev) { - struct net_device *dev = root_tc35815_dev; - next_dev = ((struct tc35815_local *)dev->priv)->next_module; - iounmap((void *)(dev->base_addr)); - unregister_netdev(dev); - free_netdev(dev); - root_tc35815_dev = next_dev; - } - - pci_unregister_driver(&tc35815_driver); + pci_unregister_driver(&tc35815_pci_driver); } module_init(tc35815_init_module); module_exit(tc35815_cleanup_module); + +MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 9aeac76..54d4f4f 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -55,9 +55,6 @@ TODO - Implement pci_driver::suspend() and pci_driver::resume() - power management methods. - Check on 64 bit boxes. Check and fix on big endian boxes. @@ -125,6 +122,11 @@ #define MAX_CHECK_PACKET 0x8000 #define DM9801_NOISE_FLOOR 8 #define DM9802_NOISE_FLOOR 5 +#define DMFE_WOL_LINKCHANGE 0x20000000 +#define DMFE_WOL_SAMPLEPACKET 0x10000000 +#define DMFE_WOL_MAGICPACKET 0x08000000 + + #define DMFE_10MHF 0 #define DMFE_100MHF 1 #define DMFE_10MFD 4 @@ -251,6 +253,7 @@ struct dmfe_board_info { u8 wait_reset; /* Hardware failed, need to reset */ u8 dm910x_chk_mode; /* Operating mode check */ u8 first_in_callback; /* Flag to record state */ + u8 wol_mode; /* user WOL settings */ struct timer_list timer; /* System defined statistic counter */ @@ -431,6 +434,7 @@ #endif db->chip_id = ent->driver_data; db->ioaddr = pci_resource_start(pdev, 0); db->chip_revision = dev_rev; + db->wol_mode = 0; db->pdev = pdev; @@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct spin_unlock_irqrestore(&db->lock, flags); } -static void netdev_get_drvinfo(struct net_device *dev, +/* + * Ethtool interace + */ + +static void dmfe_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct dmfe_board_info *np = netdev_priv(dev); @@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct ne dev->base_addr, dev->irq); } +static int dmfe_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct dmfe_board_info *db = netdev_priv(dev); + + if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | + WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + db->wol_mode = wolinfo->wolopts; + return 0; +} + +static void dmfe_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct dmfe_board_info *db = netdev_priv(dev); + + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; + wolinfo->wolopts = db->wol_mode; + return; +} + + static const struct ethtool_ops netdev_ethtool_ops = { - .get_drvinfo = netdev_get_drvinfo, + .get_drvinfo = dmfe_ethtool_get_drvinfo, .get_link = ethtool_op_get_link, + .set_wol = dmfe_ethtool_set_wol, + .get_wol = dmfe_ethtool_get_wol, }; /* @@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); +#ifdef CONFIG_PM +static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + struct dmfe_board_info *db = netdev_priv(dev); + u32 tmp; + + /* Disable upper layer interface */ + netif_device_detach(dev); + + /* Disable Tx/Rx */ + db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); + update_cr6(db->cr6_data, dev->base_addr); + + /* Disable Interrupt */ + outl(0, dev->base_addr + DCR7); + outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5); + + /* Fre RX buffers */ + dmfe_free_rxbuffer(db); + + /* Enable WOL */ + pci_read_config_dword(pci_dev, 0x40, &tmp); + tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET); + + if (db->wol_mode & WAKE_PHY) + tmp |= DMFE_WOL_LINKCHANGE; + if (db->wol_mode & WAKE_MAGIC) + tmp |= DMFE_WOL_MAGICPACKET; + + pci_write_config_dword(pci_dev, 0x40, tmp); + + pci_enable_wake(pci_dev, PCI_D3hot, 1); + pci_enable_wake(pci_dev, PCI_D3cold, 1); + + /* Power down device*/ + pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state)); + pci_save_state(pci_dev); + + return 0; +} + +static int dmfe_resume(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + u32 tmp; + + pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); + + /* Re-initilize DM910X board */ + dmfe_init_dm910x(dev); + + /* Disable WOL */ + pci_read_config_dword(pci_dev, 0x40, &tmp); + + tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET); + pci_write_config_dword(pci_dev, 0x40, tmp); + + pci_enable_wake(pci_dev, PCI_D3hot, 0); + pci_enable_wake(pci_dev, PCI_D3cold, 0); + + /* Restart upper layer interface */ + netif_device_attach(dev); + + return 0; +} +#else +#define dmfe_suspend NULL +#define dmfe_resume NULL +#endif + static struct pci_driver dmfe_driver = { .name = "dmfe", .id_table = dmfe_pci_tbl, .probe = dmfe_init_one, .remove = __devexit_p(dmfe_remove_one), + .suspend = dmfe_suspend, + .resume = dmfe_resume }; MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index e3488d7..aafb749 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -675,7 +675,7 @@ #endif if (tp->link_change) (tp->link_change)(dev, csr5); } - if (csr5 & SytemError) { + if (csr5 & SystemError) { int error = (csr5 >> 23) & 7; /* oops, we hit a PCI error. The code produced corresponds * to the reason: @@ -745,7 +745,7 @@ #ifdef CONFIG_TULIP_NAPI TxFIFOUnderflow | TxJabber | TPLnkFail | - SytemError )) != 0); + SystemError )) != 0); #else } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index 20bd52b..b562566 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -44,8 +44,10 @@ static const unsigned char comet_miireg2 /* MII transceiver control section. Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ + MDIO protocol. + See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions") + or DP83840A data sheet for more details. + */ int tulip_mdio_read(struct net_device *dev, int phy_id, int location) { @@ -261,24 +263,56 @@ void tulip_select_media(struct net_devic u16 *reset_sequence = &((u16*)(p+3))[init_length]; int reset_length = p[2 + init_length*2]; misc_info = reset_sequence + reset_length; - if (startup) + if (startup) { + int timeout = 10; /* max 1 ms */ for (i = 0; i < reset_length; i++) iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + + /* flush posted writes */ + ioread32(ioaddr + CSR15); + + /* Sect 3.10.3 in DP83840A.pdf (p39) */ + udelay(500); + + /* Section 4.2 in DP83840A.pdf (p43) */ + /* and IEEE 802.3 "22.2.4.1.1 Reset" */ + while (timeout-- && + (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) + udelay(100); + } for (i = 0; i < init_length; i++) iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + + ioread32(ioaddr + CSR15); /* flush posted writes */ } else { u8 *init_sequence = p + 2; u8 *reset_sequence = p + 3 + init_length; int reset_length = p[2 + init_length]; misc_info = (u16*)(reset_sequence + reset_length); if (startup) { + int timeout = 10; /* max 1 ms */ iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); for (i = 0; i < reset_length; i++) iowrite32(reset_sequence[i], ioaddr + CSR12); + + /* flush posted writes */ + ioread32(ioaddr + CSR12); + + /* Sect 3.10.3 in DP83840A.pdf (p39) */ + udelay(500); + + /* Section 4.2 in DP83840A.pdf (p43) */ + /* and IEEE 802.3 "22.2.4.1.1 Reset" */ + while (timeout-- && + (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) + udelay(100); } for (i = 0; i < init_length; i++) iowrite32(init_sequence[i], ioaddr + CSR12); + + ioread32(ioaddr + CSR12); /* flush posted writes */ } + tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 25f25da..c840d2e 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -132,7 +132,7 @@ #define RxPollInt (RxIntr|RxNoBuf|RxDied /* The bits in the CSR5 status registers, mostly interrupt sources. */ enum status_bits { TimerInt = 0x800, - SytemError = 0x2000, + SystemError = 0x2000, TPLnkFail = 0x1000, TPLnkPass = 0x10, NormalIntr = 0x10000, @@ -482,8 +482,11 @@ static inline void tulip_stop_rxtx(struc udelay(10); if (!i) - printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n", - pci_name(tp->pdev)); + printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed" + " (CSR5 0x%x CSR6 0x%x)\n", + pci_name(tp->pdev), + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); } } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e3774a5..5325cb9 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -17,11 +17,11 @@ #define DRV_NAME "tulip" #ifdef CONFIG_TULIP_NAPI -#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */ +#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */ #else -#define DRV_VERSION "1.1.14" +#define DRV_VERSION "1.1.15" #endif -#define DRV_RELDATE "May 11, 2002" +#define DRV_RELDATE "Feb 27, 2007" #include diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 002a05e..3c20d51 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1148,7 +1148,7 @@ static irqreturn_t intr_handler(int irq, } /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError | + if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError | TimerInt | TxDied)) netdev_error(dev, intr_status); diff --git a/drivers/net/vioc/Makefile b/drivers/net/vioc/Makefile new file mode 100644 index 0000000..c848277 --- /dev/null +++ b/drivers/net/vioc/Makefile @@ -0,0 +1,34 @@ +################################################################################ +# +# +# Copyright(c) 2003-2006 Fabric7 Systems. 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. +# +# The full GNU General Public License is included in this distribution in the +# file called LICENSE. +# +# Contact Information: +# +# Fabric7 Systems, 1300 Crittenden Lane Suite 302 Mountain View, CA 94043 +# +################################################################################ + +obj-$(CONFIG_VIOC) += vioc.o + +vioc-objs := vioc_driver.o vioc_transmit.o vioc_receive.o vioc_api.o \ + vioc_spp.o vioc_irq.o spp.o spp_vnic.o vioc_provision.o \ + vioc_ethtool.o + diff --git a/drivers/net/vioc/driver_version.h b/drivers/net/vioc/driver_version.h new file mode 100644 index 0000000..6427a30 --- /dev/null +++ b/drivers/net/vioc/driver_version.h @@ -0,0 +1,27 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#define VIOC_DISPLAY_VERSION "VER09.00.00" diff --git a/drivers/net/vioc/f7/spp.h b/drivers/net/vioc/f7/spp.h new file mode 100644 index 0000000..10ea4ef --- /dev/null +++ b/drivers/net/vioc/f7/spp.h @@ -0,0 +1,68 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _SPP_H_ +#define _SPP_H_ + +#include "vioc_hw_registers.h" + +#define SPP_MODULE VIOC_BMC + +#define SPP_CMD_REG_BANK 15 +#define SPP_SIM_PMM_BANK 14 +#define SPP_PMM_BMC_BANK 13 + +/* communications COMMAND REGISTERS */ +#define SPP_SIM_PMM_CMDREG GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R1) +#define VIOCCP_SPP_SIM_PMM_CMDREG \ + VIOCCP_GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R1) +#define SPP_PMM_SIM_CMDREG GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R2) +#define VIOCCP_SPP_PMM_SIM_CMDREG \ + VIOCCP_GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R2) +#define SPP_PMM_BMC_HB_CMDREG GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R3) +#define SPP_PMM_BMC_SIG_CMDREG GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R4) +#define SPP_PMM_BMC_CMDREG GETRELADDR(SPP_MODULE, SPP_CMD_REG_BANK, VREG_BMC_REG_R5) + +#define SPP_BANK_ADDR(bank) GETRELADDR(SPP_MODULE, bank, VREG_BMC_REG_R0) + +#define SPP_SIM_PMM_DATA GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, VREG_BMC_REG_R0) +#define VIOCCP_SPP_SIM_PMM_DATA \ + VIOCCP_GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, VREG_BMC_REG_R0) + +/* PMM-BMC Sensor register bits */ +#define SPP_PMM_BMC_HB_SENREG GETRELADDR(SPP_MODULE, 0, VREG_BMC_SENSOR0) +#define SPP_PMM_BMC_CTL_SENREG GETRELADDR(SPP_MODULE, 0, VREG_BMC_SENSOR1) +#define SPP_PMM_BMC_SENREG GETRELADDR(SPP_MODULE, 0, VREG_BMC_SENSOR2) + +/* BMC Interrupt number used to alert PMM that message has been sent */ +#define SPP_SIM_PMM_INTR 1 +#define SPP_BANK_REGS 32 + + +#define SPP_OK 0 +#define SPP_CHKSUM_ERR 1 +#endif /* _SPP_H_ */ + diff --git a/drivers/net/vioc/f7/spp_msgdata.h b/drivers/net/vioc/f7/spp_msgdata.h new file mode 100644 index 0000000..f85bf7a --- /dev/null +++ b/drivers/net/vioc/f7/spp_msgdata.h @@ -0,0 +1,54 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _SPPMSGDATA_H_ +#define _SPPMSGDATA_H_ + +#include "spp.h" + +/* KEYs For SPP_FACILITY_VNIC */ +#define SPP_KEY_VNIC_CTL 1 +#define SPP_KEY_SET_PROV 2 + +/* Data Register Offset for VIOC ID parameter */ +#define SPP_VIOC_ID_IDX 0 +#define SPP_VIOC_ID_OFFSET GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, (VREG_BMC_REG_R0 + (SPP_VIOC_ID_IDX << 2))) +#define VIOCCP_SPP_VIOC_ID_OFFSET VIOCCP_GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, (VREG_BMC_REG_R0 + (SPP_VIOC_ID_IDX << 2))) + +/* KEYs for SPP_FACILITY_SYS */ +#define SPP_KEY_REQUEST_SIGNAL 1 + +/* Data Register Offset for RESET_TYPE parameter */ +#define SPP_UOS_RESET_TYPE_IDX 0 +#define SPP_UOS_RESET_TYPE_OFFSET GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, (VREG_BMC_REG_R0 + (SPP_UOS_RESET_TYPE_IDX << 2))) +#define VIOCCP_SPP_UOS_RESET_TYPE_OFFSET VIOCCP_GETRELADDR(SPP_MODULE, SPP_SIM_PMM_BANK, (VREG_BMC_REG_R0 + (SPP_UOS_RESET_TYPE_IDX << 2))) + +#define SPP_RESET_TYPE_REBOOT 1 +#define SPP_RESET_TYPE_SHUTDOWN 2 + +#endif /* _SPPMSGDATA_H_ */ + + diff --git a/drivers/net/vioc/f7/sppapi.h b/drivers/net/vioc/f7/sppapi.h new file mode 100644 index 0000000..bcad2fd --- /dev/null +++ b/drivers/net/vioc/f7/sppapi.h @@ -0,0 +1,240 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _SPPAPI_H_ +#define _SPPAPI_H_ + +/* + * COMMAND REGISTER is encoded as follows: + * |-------------|-------------|--------|-----|----|------------|---------| + * | chksum: | unique id: | spare: | RC: | D: | facility: | key: | + * | 31 30 29 28 | 27 26 25 24 | 23 22 | 21 | 20 | 19 18 17 16| 15 - 0 | + * |-------------|-------------|--------|-----|----|------------|---------| + */ + +#define SPP_KEY_MASK 0x0000ffff +#define SPP_KEY_SHIFT 0 +#define SPP_KEY_MASK_SHIFTED (SPP_KEY_MASK >> SPP_KEY_SHIFT) +#define SPP_FACILITY_MASK 0x000f0000 +#define SPP_FACILITY_SHIFT 16 +#define SPP_FACILITY_MASK_SHIFTED (SPP_FACILITY_MASK >> SPP_FACILITY_SHIFT) +#define SPP_D_MASK 0x00100000 +#define SPP_D_SHIFT 20 +#define SPP_D_MASK_SHIFTED (SPP_D_MASK >> SPP_D_SHIFT) +#define SPP_RC_MASK 0x00200000 +#define SPP_RC_SHIFT 21 +#define SPP_RC_MASK_SHIFTED (SPP_RC_MASK >> SPP_RC_SHIFT) +#define SPP_UNIQID_MASK 0x0f000000 +#define SPP_UNIQID_SHIFT 24 +#define SPP_UNIQID_MASK_SHIFTED (SPP_UNIQID_MASK >> SPP_UNIQID_SHIFT) +#define SPP_CHKSUM_MASK 0xf0000000 +#define SPP_CHKSUM_SHIFT 28 +#define SPP_CHKSUM_MASK_SHIFTED (SPP_CHKSUM_MASK >> SPP_CHKSUM_SHIFT) + +#define SPP_GET_KEY(m) \ + ((m & SPP_KEY_MASK) >> SPP_KEY_SHIFT) + +#define SPP_GET_FACILITY(m) \ + ((m & SPP_FACILITY_MASK) >> SPP_FACILITY_SHIFT) + +#define SPP_GET_D(m) \ + ((m & SPP_D_MASK) >> SPP_D_SHIFT) + +#define SPP_GET_RC(m) \ + ((m & SPP_D_MASK) >> SPP_D_SHIFT) + +#define SPP_GET_UNIQID(m) \ + ((m & SPP_UNIQID_MASK) >> SPP_UNIQID_SHIFT) + +#define SPP_GET_CHKSUM(m) \ + ((m & SPP_CHKSUM_MASK) >> SPP_CHKSUM_SHIFT) + +#define SPP_SET_KEY(m, key) do { \ + m = ((m & ~SPP_KEY_MASK) | ((key << SPP_KEY_SHIFT) & SPP_KEY_MASK)) ; \ +} while (0) + +#define SPP_SET_FACILITY(m, facility) do { \ + m = ((m & ~SPP_FACILITY_MASK) | ((facility << SPP_FACILITY_SHIFT) & SPP_FACILITY_MASK)) ; \ +} while (0) + +#define SPP_MBOX_FREE 0 +#define SPP_MBOX_OCCUPIED 1 + +#define SPP_MBOX_EMPTY(m) (SPP_GET_D(m) == SPP_MBOX_FREE) +#define SPP_MBOX_FULL(m) (SPP_GET_D(m) == SPP_MBOX_OCCUPIED) + +#define SPP_SET_D(m, D) do { \ + m = ((m & ~SPP_D_MASK) | ((D << SPP_D_SHIFT) & SPP_D_MASK)) ; \ +} while (0) + +#define SPP_CMD_OK 0 +#define SPP_CMD_FAIL 1 + +#define SPP_SET_RC(m, rc) do { \ + m = ((m & ~SPP_RC_MASK) | ((rc << SPP_RC_SHIFT) & SPP_RC_MASK)) ; \ +} while (0) + +#define SPP_SET_UNIQID(m, uniqid) do { \ + m = ((m & ~SPP_UNIQID_MASK) | ((uniqid << SPP_UNIQID_SHIFT) & SPP_UNIQID_MASK)) ; \ +} while (0) + + +#define SPP_SET_CHKSUM(m, chksum) do { \ + m = ((m & ~SPP_CHKSUM_MASK) | ((chksum << SPP_CHKSUM_SHIFT) & SPP_CHKSUM_MASK)) ; \ +} while (0) + + +static inline u32 spp_calc_u32_4bit_chksum(u32 w, int n) +{ + int len; + int nibbles = (n > 8) ? 8:n; + u32 cs = 0; + + for (len = 0; len < nibbles; len++) { + w = (w >> len); + cs += w & SPP_CHKSUM_MASK_SHIFTED; + } + + while (cs >> 4) + cs = (cs & SPP_CHKSUM_MASK_SHIFTED) + (cs >> 4); + + return (~cs); +} + +static inline u32 spp_calc_u32_chksum(u32 w) +{ + return (spp_calc_u32_4bit_chksum(w, 7)); +} + +static inline u32 +spp_validate_u32_chksum(u32 w) +{ + return (spp_calc_u32_4bit_chksum(w, 8) & SPP_CHKSUM_MASK_SHIFTED); +} + +static inline u32 +spp_mbox_build_cmd(u32 key, u32 facility, u32 uniqid) +{ + u32 m = 0; + u32 cs; + + SPP_SET_KEY(m, key); + SPP_SET_FACILITY(m, facility); + SPP_SET_UNIQID(m, uniqid); + SPP_SET_D(m, SPP_MBOX_OCCUPIED); + cs = spp_calc_u32_4bit_chksum(m, 7); + cs = (cs)?cs:~cs; + SPP_SET_CHKSUM(m, cs); + + return (m); +} + +static inline u32 +spp_build_key_facility(u32 key, u32 facility) +{ + u32 m = 0; + + SPP_SET_KEY(m, key); + SPP_SET_FACILITY(m, facility); + + return (m); +} + + +static inline u32 +spp_mbox_build_reply(u32 cmd, int success) +{ + u32 reply = cmd; + u32 cs; + + SPP_SET_D(reply, SPP_MBOX_FREE); + if (success == SPP_CMD_OK) + SPP_SET_RC(reply, SPP_CMD_OK); + else + SPP_SET_RC(reply, SPP_CMD_FAIL); + + cs = spp_calc_u32_4bit_chksum(reply, 7); + cs = (cs)?cs:~cs; + SPP_SET_CHKSUM(reply, cs); + + return (reply); +} + +static inline int +spp_mbox_empty(u32 m) +{ + return SPP_MBOX_EMPTY(m); +} + +static inline int +spp_mbox_full(u32 m) +{ + return SPP_MBOX_FULL(m); +} + +/* + * SPP Facilities 0 - 15 + */ + +#define SPP_FACILITY_VNIC 0 /* VNIC Provisioning */ +#define SPP_FACILITY_SYS 1 /* UOS Control */ +#define SPP_FACILITY_ISCSI_VNIC 2 /* iSCSI Initiator Provisioning */ + + +/* + * spp_msg_register() is use to install a callback - cb_fn() function, that would + * be invoked once the message with specific handle has beed received. + * The unique "handle" that associates the callback with the messages is + * key_facility parameter. + * Typically the endpoints (sender on SIM and receiver on PMM) would agree on + * the "handle" that consists of FACILITY (4 bits) and KEY (16 bits). + * The inlude spp_build_key_facility(key, facility) builds such handle. + * The parameters of callback: + * cb_nf(u32 cmd, void *data_buf, int data_buf_size, u32 timestamp), are + * cmd - an actual command value that was sent by SIM + * data_buf - pointer to up to 128 bytes (32 u32s) of message data from SIM + * data_buf_size - actual number of bytes in the message + * timestamp - a relative time/sequence number indicating when message, + * that caused the callback, was received. + * + * IMPORTANT: If the message was already waiting, at the time of spp_msg_register() + * call, the cb_fn() will be invoked in the context of spp_msg_register(). + * + */ +extern int spp_msg_register(u32 key_facility, void (*cb_fn)(u32, void *, int, u32)); + +/* + * spp_msg_unregirster() will remove the callback function, so that + * the imcoming messages with the key_facility handle will basically be + * overwriting command and data buffers. + */ + +extern void spp_msg_unregister(u32 key_facility); + +extern int read_spp_regbank32(int vioc, int bank, char *buffer); + +#endif /* _SPPAPI_H_ */ + diff --git a/drivers/net/vioc/f7/vioc_bmc_registers.h b/drivers/net/vioc/f7/vioc_bmc_registers.h new file mode 100644 index 0000000..59692aa --- /dev/null +++ b/drivers/net/vioc/f7/vioc_bmc_registers.h @@ -0,0 +1,1343 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_BMC_REGISTERS_H_ +#define _VIOC_BMC_REGISTERS_H_ + +// BMC VNIC block 0 +/* Data Register Bytes 1 and 0 for 16 bit accesses (15..0) */ +#define VREG_BMC_DATAREGB10_MASK 0x0000ffff +#define VREG_BMC_DATAREGB10_ACCESSMODE 2 +#define VREG_BMC_DATAREGB10_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGB10_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGB10_WRITEMASK 0x0000ffff +#define VREG_BMC_DATAREGB10_READMASK 0x0000ffff +#define VREG_BMC_DATAREGB10_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGB10 0x000 +#define VREG_BMC_DATAREGB10_ID 0 + +#define VVAL_BMC_DATAREGB10_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Data Register Bytes 3 and 2 for 16 bit accesses (15..0) */ +#define VREG_BMC_DATAREGB32_MASK 0x0000ffff +#define VREG_BMC_DATAREGB32_ACCESSMODE 2 +#define VREG_BMC_DATAREGB32_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGB32_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGB32_WRITEMASK 0x0000ffff +#define VREG_BMC_DATAREGB32_READMASK 0x0000ffff +#define VREG_BMC_DATAREGB32_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGB32 0x004 +#define VREG_BMC_DATAREGB32_ID 1 + +#define VVAL_BMC_DATAREGB32_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Data Register Bytes 5 and 4 for 16 bit accesses (15..0) */ +#define VREG_BMC_DATAREGB54_MASK 0x0000ffff +#define VREG_BMC_DATAREGB54_ACCESSMODE 2 +#define VREG_BMC_DATAREGB54_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGB54_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGB54_WRITEMASK 0x0000ffff +#define VREG_BMC_DATAREGB54_READMASK 0x0000ffff +#define VREG_BMC_DATAREGB54_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGB54 0x008 +#define VREG_BMC_DATAREGB54_ID 2 + +#define VVAL_BMC_DATAREGB54_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Data Register Bytes 7 and 6 for 16 bit accesses (15..0) */ +#define VREG_BMC_DATAREGB76_MASK 0x0000ffff +#define VREG_BMC_DATAREGB76_ACCESSMODE 2 +#define VREG_BMC_DATAREGB76_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGB76_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGB76_WRITEMASK 0x0000ffff +#define VREG_BMC_DATAREGB76_READMASK 0x0000ffff +#define VREG_BMC_DATAREGB76_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGB76 0x00c +#define VREG_BMC_DATAREGB76_ID 3 + +#define VVAL_BMC_DATAREGB76_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Data Register Byte 8 for 16 bit accesses (7..0) */ +#define VREG_BMC_DATAREGB8_MASK 0x000000ff +#define VREG_BMC_DATAREGB8_ACCESSMODE 2 +#define VREG_BMC_DATAREGB8_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGB8_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGB8_WRITEMASK 0x000000ff +#define VREG_BMC_DATAREGB8_READMASK 0x000000ff +#define VREG_BMC_DATAREGB8_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGB8 0x010 +#define VREG_BMC_DATAREGB8_ID 4 + +#define VVAL_BMC_DATAREGB8_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Holds last POST Code value (7..0) */ +#define VREG_BMC_POSTCODE_MASK 0x000000ff +#define VREG_BMC_POSTCODE_ACCESSMODE 1 +#define VREG_BMC_POSTCODE_HOSTPRIVILEGE 1 +#define VREG_BMC_POSTCODE_RESERVEDMASK 0x00000000 +#define VREG_BMC_POSTCODE_WRITEMASK 0x00000000 +#define VREG_BMC_POSTCODE_READMASK 0x000000ff +#define VREG_BMC_POSTCODE_CLEARMASK 0x00000000 +#define VREG_BMC_POSTCODE 0x014 +#define VREG_BMC_POSTCODE_ID 5 + + + +/* Count Register Bytes 1 and 0 for 16 bit accesses (15..0) */ +#define VREG_BMC_COUNTREGB10_MASK 0x0000ffff +#define VREG_BMC_COUNTREGB10_ACCESSMODE 2 +#define VREG_BMC_COUNTREGB10_HOSTPRIVILEGE 0 +#define VREG_BMC_COUNTREGB10_RESERVEDMASK 0x00000000 +#define VREG_BMC_COUNTREGB10_WRITEMASK 0x0000ffff +#define VREG_BMC_COUNTREGB10_READMASK 0x0000ffff +#define VREG_BMC_COUNTREGB10_CLEARMASK 0x00000000 +#define VREG_BMC_COUNTREGB10 0x018 +#define VREG_BMC_COUNTREGB10_ID 6 + +#define VVAL_BMC_COUNTREGB10_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Count Register Byte 2 for 16 bit accesses (7..0) */ +#define VREG_BMC_COUNTREGB2_MASK 0x000000ff +#define VREG_BMC_COUNTREGB2_ACCESSMODE 2 +#define VREG_BMC_COUNTREGB2_HOSTPRIVILEGE 0 +#define VREG_BMC_COUNTREGB2_RESERVEDMASK 0x00000000 +#define VREG_BMC_COUNTREGB2_WRITEMASK 0x000000ff +#define VREG_BMC_COUNTREGB2_READMASK 0x000000ff +#define VREG_BMC_COUNTREGB2_CLEARMASK 0x00000000 +#define VREG_BMC_COUNTREGB2 0x01c +#define VREG_BMC_COUNTREGB2_ID 7 + +#define VVAL_BMC_COUNTREGB2_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Addr Register Bytes 1 and 0 for 16 bit accesses (15..2) */ +#define VREG_BMC_ADDRREGB10_MASK 0x0000fffc +#define VREG_BMC_ADDRREGB10_ACCESSMODE 2 +#define VREG_BMC_ADDRREGB10_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREGB10_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREGB10_WRITEMASK 0x0000fffc +#define VREG_BMC_ADDRREGB10_READMASK 0x0000fffc +#define VREG_BMC_ADDRREGB10_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREGB10 0x020 +#define VREG_BMC_ADDRREGB10_ID 8 + + + +/* Addr Register Bytes 3 and 2 for 16 bit accesses (15..0) */ +#define VREG_BMC_ADDRREGB32_MASK 0x0000ffff +#define VREG_BMC_ADDRREGB32_ACCESSMODE 2 +#define VREG_BMC_ADDRREGB32_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREGB32_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREGB32_WRITEMASK 0x0000ffff +#define VREG_BMC_ADDRREGB32_READMASK 0x0000ffff +#define VREG_BMC_ADDRREGB32_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREGB32 0x024 +#define VREG_BMC_ADDRREGB32_ID 9 + + + +/* Addr Register Bytes 5 and 4 for 16 bit accesses (8..0) */ +#define VREG_BMC_ADDRREGB54_MASK 0x000001ff +#define VREG_BMC_ADDRREGB54_ACCESSMODE 2 +#define VREG_BMC_ADDRREGB54_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREGB54_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREGB54_WRITEMASK 0x000001ff +#define VREG_BMC_ADDRREGB54_READMASK 0x000001ff +#define VREG_BMC_ADDRREGB54_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREGB54 0x028 +#define VREG_BMC_ADDRREGB54_ID 10 + + + +/* Communication register between Host and BMC (15..0) */ +#define VREG_BMC_SENSOR_MASK 0x0000ffff +#define VREG_BMC_SENSOR_ACCESSMODE 2 +#define VREG_BMC_SENSOR_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR_WRITEMASK 0x000000ff +#define VREG_BMC_SENSOR_READMASK 0x0000ffff +#define VREG_BMC_SENSOR_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR 0x02c +#define VREG_BMC_SENSOR_ID 11 + +#define VVAL_BMC_SENSOR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of Sensor */ +#define VREG_BMC_SENSOR_SYSRESET_MASK 0x00008000 /* System Reset GPIO pin from Keyboard Controller [15..15] */ +#define VREG_BMC_SENSOR_RTS0_MASK 0x00004000 /* Request to Send bit from UART 0 [14..14] */ +#define VREG_BMC_SENSOR_TXRDY1_MASK 0x00002000 /* Uart1 Tx Ready Flag [13..13] */ +#define VREG_BMC_SENSOR_TXRDY0_MASK 0x00001000 /* Uart0 Tx Ready Flag [12..12] */ +#define VREG_BMC_SENSOR_FIFOEN1_MASK 0x00000800 /* UART1 FIFO Enabled [11..11] */ +#define VREG_BMC_SENSOR_RXEMPTY1_MASK 0x00000400 /* UART1 Receive Empty Flag [10..10] */ +#define VREG_BMC_SENSOR_FIFOEN0_MASK 0x00000200 /* UART0 FIFO Enabled [9..9] */ +#define VREG_BMC_SENSOR_RXEMPTY0_MASK 0x00000100 /* UART0 Receive Empty Flag [8..8] */ +#define VREG_BMC_SENSOR_SENSOR_MASK 0x000000ff /* Sensor Data [0..7] */ + + + + +/* If read error is detected, bits 11:4 of error address (11..0) */ +#define VREG_BMC_ERRORADDR_MASK 0x00000fff +#define VREG_BMC_ERRORADDR_ACCESSMODE 1 +#define VREG_BMC_ERRORADDR_HOSTPRIVILEGE 0 +#define VREG_BMC_ERRORADDR_RESERVEDMASK 0x00000000 +#define VREG_BMC_ERRORADDR_WRITEMASK 0x00000000 +#define VREG_BMC_ERRORADDR_READMASK 0x00000fff +#define VREG_BMC_ERRORADDR_CLEARMASK 0x00000000 +#define VREG_BMC_ERRORADDR 0x030 +#define VREG_BMC_ERRORADDR_ID 12 + /* + * The address of the 128 bit word in error can be determined as follows: + * if(ErrorAddr[11] == AddrReg[11]) BadWordAddr[39:11] = AddrReg[39:11]; + * else BadWordAddr[39:11] = AddrReg[39:11] - 1; + * BadWordAddr[10:4] = ErrorAddr[10:4]; + * BadWordAddr[3:0] = 0; + */ + +#define VVAL_BMC_ERRORADDR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* If read error is detected, expected and actual data (15..0) */ +#define VREG_BMC_ERRORDATA_MASK 0x0000ffff +#define VREG_BMC_ERRORDATA_ACCESSMODE 1 +#define VREG_BMC_ERRORDATA_HOSTPRIVILEGE 0 +#define VREG_BMC_ERRORDATA_RESERVEDMASK 0x00000000 +#define VREG_BMC_ERRORDATA_WRITEMASK 0x00000000 +#define VREG_BMC_ERRORDATA_READMASK 0x0000ffff +#define VREG_BMC_ERRORDATA_CLEARMASK 0x00000000 +#define VREG_BMC_ERRORDATA 0x034 +#define VREG_BMC_ERRORDATA_ID 13 + +#define VVAL_BMC_ERRORDATA_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of ErrorData */ +#define VREG_BMC_ERRORDATA_EXPECTED_MASK 0x0000ff00 /* Expected data for read operation [8..15] */ +#define VREG_BMC_ERRORDATA_ACTUAL_MASK 0x000000ff /* Actual data returned for read operation [0..7] */ + +/* Indicates which byte, or bytes, did not match expected data (15..0) */ +#define VREG_BMC_ERRBYTEMASK_MASK 0x0000ffff +#define VREG_BMC_ERRBYTEMASK_ACCESSMODE 1 +#define VREG_BMC_ERRBYTEMASK_HOSTPRIVILEGE 0 +#define VREG_BMC_ERRBYTEMASK_RESERVEDMASK 0x00000000 +#define VREG_BMC_ERRBYTEMASK_WRITEMASK 0x00000000 +#define VREG_BMC_ERRBYTEMASK_READMASK 0x0000ffff +#define VREG_BMC_ERRBYTEMASK_CLEARMASK 0x00000000 +#define VREG_BMC_ERRBYTEMASK 0x038 +#define VREG_BMC_ERRBYTEMASK_ID 14 + /* + * If more than one bit is set in the ErrByteMask then multiple bytes were in error + * The expected and actual data value returned correspond to the leftmost bad byte + * in the 128 bit data word. + */ + +#define VVAL_BMC_ERRBYTEMASK_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Command (7..0) */ +#define VREG_BMC_CMDREG_MASK 0x000000ff +#define VREG_BMC_CMDREG_ACCESSMODE 2 +#define VREG_BMC_CMDREG_HOSTPRIVILEGE 0 +#define VREG_BMC_CMDREG_RESERVEDMASK 0x00000000 +#define VREG_BMC_CMDREG_WRITEMASK 0x000000ff +#define VREG_BMC_CMDREG_READMASK 0x000000ff +#define VREG_BMC_CMDREG_CLEARMASK 0x00000078 +#define VREG_BMC_CMDREG 0x03c +#define VREG_BMC_CMDREG_ID 15 + /* Multiple Status bits can be asserted independently */ + +#define VVAL_BMC_CMDREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of CmdReg */ +#define VREG_BMC_CMDREG_VALID_MASK 0x00000080 /* Set to 1 to start operation, HW clears to 0 when complete [7..7] */ +#define VREG_BMC_CMDREG_STATUS_MASK 0x00000078 /* Completion status [3..6] */ +#define VVAL_BMC_CMDREG_STATUS_HTCKERR 0x40 /* Comparison Failed during read operation */ +#define VVAL_BMC_CMDREG_STATUS_BADCMD 0x20 /* Unknown command */ +#define VVAL_BMC_CMDREG_STATUS_RINGERR 0x10 /* Ring operation failed */ +#define VVAL_BMC_CMDREG_STATUS_BADMODID 0x8 /* Ring Address had unknown Module ID */ +#define VREG_BMC_CMDREG_COMMAND_MASK 0x00000007 /* Command to execute [0..2] */ +#define VVAL_BMC_CMDREG_COMMAND_READWORD 0x0 /* Read a single word from memory or the ring */ +#define VVAL_BMC_CMDREG_COMMAND_WRITEWORD 0x1 /* Write a single word to memory or the ring */ +#define VVAL_BMC_CMDREG_COMMAND_READBLOCK 0x2 /* Read a block of memory and compare to a constant value */ +#define VVAL_BMC_CMDREG_COMMAND_WRITEBLOCK 0x3 /* Write a block of memory to a constant value */ +#define VVAL_BMC_CMDREG_COMMAND_READLFSR 0x4 /* Read a block of memory and compare to LFSR value */ +#define VVAL_BMC_CMDREG_COMMAND_WRITELFSR 0x5 /* Write a block of memory to LFSR value */ +#define VVAL_BMC_CMDREG_COMMAND_RESV6 0x6 /* Reserved */ +#define VVAL_BMC_CMDREG_COMMAND_RESV7 0x7 /* Reserved */ + +/* Low order 32-bits of 41-bit address (31..2) */ +#define VREG_BMC_ADDRREGLO_MASK 0xfffffffc +#define VREG_BMC_ADDRREGLO_ACCESSMODE 2 +#define VREG_BMC_ADDRREGLO_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREGLO_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREGLO_WRITEMASK 0xfffffffc +#define VREG_BMC_ADDRREGLO_READMASK 0xfffffffc +#define VREG_BMC_ADDRREGLO_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREGLO 0x040 +#define VREG_BMC_ADDRREGLO_ID 16 + +#define VVAL_BMC_ADDRREGLO_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* High Order 9-bits of 41-bit address (8..0) */ +#define VREG_BMC_ADDRREGHI_MASK 0x000001ff +#define VREG_BMC_ADDRREGHI_ACCESSMODE 2 +#define VREG_BMC_ADDRREGHI_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREGHI_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREGHI_WRITEMASK 0x000001ff +#define VREG_BMC_ADDRREGHI_READMASK 0x000001ff +#define VREG_BMC_ADDRREGHI_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREGHI 0x044 +#define VREG_BMC_ADDRREGHI_ID 17 + +#define VVAL_BMC_ADDRREGHI_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* 24-Bit Count register (23..0) */ +#define VREG_BMC_COUNTREG_MASK 0x00ffffff +#define VREG_BMC_COUNTREG_ACCESSMODE 2 +#define VREG_BMC_COUNTREG_HOSTPRIVILEGE 0 +#define VREG_BMC_COUNTREG_RESERVEDMASK 0x00000000 +#define VREG_BMC_COUNTREG_WRITEMASK 0x00ffffff +#define VREG_BMC_COUNTREG_READMASK 0x00ffffff +#define VREG_BMC_COUNTREG_CLEARMASK 0x00000000 +#define VREG_BMC_COUNTREG 0x048 +#define VREG_BMC_COUNTREG_ID 18 + +#define VVAL_BMC_COUNTREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Low order 32-bits for 72-bit data (31..0) */ +#define VREG_BMC_DATAREGLO_MASK 0xffffffff +#define VREG_BMC_DATAREGLO_ACCESSMODE 2 +#define VREG_BMC_DATAREGLO_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGLO_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGLO_WRITEMASK 0xffffffff +#define VREG_BMC_DATAREGLO_READMASK 0xffffffff +#define VREG_BMC_DATAREGLO_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGLO 0x050 +#define VREG_BMC_DATAREGLO_ID 20 + +#define VVAL_BMC_DATAREGLO_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Middle 32-Bits for 72-bit data (31..0) */ +#define VREG_BMC_DATAREGMID_MASK 0xffffffff +#define VREG_BMC_DATAREGMID_ACCESSMODE 2 +#define VREG_BMC_DATAREGMID_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGMID_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGMID_WRITEMASK 0xffffffff +#define VREG_BMC_DATAREGMID_READMASK 0xffffffff +#define VREG_BMC_DATAREGMID_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGMID 0x054 +#define VREG_BMC_DATAREGMID_ID 21 + +#define VVAL_BMC_DATAREGMID_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* High order 8-Bits for 72-bit data (7..0) */ +#define VREG_BMC_DATAREGHI_MASK 0x000000ff +#define VREG_BMC_DATAREGHI_ACCESSMODE 2 +#define VREG_BMC_DATAREGHI_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREGHI_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREGHI_WRITEMASK 0x000000ff +#define VREG_BMC_DATAREGHI_READMASK 0x000000ff +#define VREG_BMC_DATAREGHI_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREGHI 0x058 +#define VREG_BMC_DATAREGHI_ID 22 + +#define VVAL_BMC_DATAREGHI_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Full Data Register for 72 bit accesses (31..0) */ +#define VREG_BMC_DATAREG_MASK 0xffffffff +#define VREG_BMC_DATAREG_ACCESSMODE 2 +#define VREG_BMC_DATAREG_HOSTPRIVILEGE 0 +#define VREG_BMC_DATAREG_RESERVEDMASK 0x00000000 +#define VREG_BMC_DATAREG_WRITEMASK 0xffffffff +#define VREG_BMC_DATAREG_READMASK 0xffffffff +#define VREG_BMC_DATAREG_CLEARMASK 0x00000000 +#define VREG_BMC_DATAREG 0x060 +#define VREG_BMC_DATAREG_ID 24 + +/* Full Addr Register for 41 bit accesses (31..0) */ +#define VREG_BMC_ADDRREG_MASK 0xffffffff +#define VREG_BMC_ADDRREG_ACCESSMODE 2 +#define VREG_BMC_ADDRREG_HOSTPRIVILEGE 0 +#define VREG_BMC_ADDRREG_RESERVEDMASK 0x00000000 +#define VREG_BMC_ADDRREG_WRITEMASK 0xffffffff +#define VREG_BMC_ADDRREG_READMASK 0xffffffff +#define VREG_BMC_ADDRREG_CLEARMASK 0x00000000 +#define VREG_BMC_ADDRREG 0x070 +#define VREG_BMC_ADDRREG_ID 28 + + + +/* Global Enable and Status bits (31..0) */ +#define VREG_BMC_GLOBAL_MASK 0xffffffff +#define VREG_BMC_GLOBAL_ACCESSMODE 2 +#define VREG_BMC_GLOBAL_HOSTPRIVILEGE 1 +#define VREG_BMC_GLOBAL_RESERVEDMASK 0xff473e0e +#define VREG_BMC_GLOBAL_WRITEMASK 0x0000c1f0 +#define VREG_BMC_GLOBAL_READMASK 0x00b8c1f1 +#define VREG_BMC_GLOBAL_CLEARMASK 0x00000000 +#define VREG_BMC_GLOBAL 0x100 +#define VREG_BMC_GLOBAL_ID 64 + +#define VVAL_BMC_GLOBAL_DEFAULT 0x30 /* Reset by hreset: Reset with UART and KBRD enabled */ +/* Subfields of Global */ +#define VREG_BMC_GLOBAL_RESV0_MASK 0xff000000 /* Reserved [24..31] */ +#define VREG_BMC_GLOBAL_HTINIT_MASK 0x00800000 /* HT Interface Initialization Complete [23..23] */ +#define VREG_BMC_GLOBAL_RESV0A_MASK 0x00400000 /* Reserved [22..22] */ +#define VREG_BMC_GLOBAL_C6SYNC_MASK 0x00200000 /* C6 Rx Syncs received [21..21] */ +#define VREG_BMC_GLOBAL_C6IDLE_MASK 0x00100000 /* C6 Rx Idles received [20..20] */ +#define VREG_BMC_GLOBAL_C6READY_MASK 0x00080000 /* C6 Rx Ready received [19..19] */ +#define VREG_BMC_GLOBAL_RESV1_MASK 0x00070000 /* Reserved [16..18] */ +#define VREG_BMC_GLOBAL_VIOCEN_MASK 0x00008000 /* Master VIOC Enable bit [15..15] */ +#define VREG_BMC_GLOBAL_LEGAPICEN_MASK 0x00004000 /* Legacy IOAPIC Enable bit [14..14] */ +#define VREG_BMC_GLOBAL_RESV2_MASK 0x00003e00 /* Reserved [9..13] */ +#define VREG_BMC_GLOBAL_APICCLKEN_MASK 0x00000100 /* Enables VIOC to drive APIC bus clock [8..8] */ +#define VREG_BMC_GLOBAL_HTEN_MASK 0x00000080 /* HT interface Enable bit [7..7] */ +#define VREG_BMC_GLOBAL_CSIXEN_MASK 0x00000040 /* CSIX interface Enable bit [6..6] */ +#define VREG_BMC_GLOBAL_KBRDEN_MASK 0x00000020 /* Emulated Keyboard Register Enable bit [5..5] */ +#define VREG_BMC_GLOBAL_UARTEN_MASK 0x00000010 /* Emulated UART Enable bit [4..4] */ +#define VREG_BMC_GLOBAL_RESV3_MASK 0x0000000e /* Reserved [1..3] */ +#define VREG_BMC_GLOBAL_SOFTRESET_MASK 0x00000001 /* VIOC Soft Reset: HW clears bit after reset is complete [0..0] */ + + + + +/* Nonprivileged Debug Control and Status Bits (31..0) */ +#define VREG_BMC_DEBUG_MASK 0xffffffff +#define VREG_BMC_DEBUG_ACCESSMODE 2 +#define VREG_BMC_DEBUG_HOSTPRIVILEGE 1 +#define VREG_BMC_DEBUG_RESERVEDMASK 0xffff0000 +#define VREG_BMC_DEBUG_WRITEMASK 0x0000ffff +#define VREG_BMC_DEBUG_READMASK 0x0000ffff +#define VREG_BMC_DEBUG_CLEARMASK 0x00000000 +#define VREG_BMC_DEBUG 0x104 +#define VREG_BMC_DEBUG_ID 65 + +#define VVAL_BMC_DEBUG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of Debug */ +#define VREG_BMC_DEBUG_RESV0_MASK 0xffff0000 /* Reserved [16..31] */ +#define VREG_BMC_DEBUG_DEBUGHI_MASK 0x0000ff00 /* Select bits to appear on high half of Debug port [8..15] */ +#define VREG_BMC_DEBUG_DEBUGLO_MASK 0x000000ff /* Select bits to appear on low half of Debug port [0..7] */ + + + + +/* Privileged Debug Control and Status Bits (31..0) */ +#define VREG_BMC_DEBUGPRIV_MASK 0xffffffff +#define VREG_BMC_DEBUGPRIV_ACCESSMODE 2 +#define VREG_BMC_DEBUGPRIV_HOSTPRIVILEGE 0 +#define VREG_BMC_DEBUGPRIV_RESERVEDMASK 0x1fffffff +#define VREG_BMC_DEBUGPRIV_WRITEMASK 0xe0000000 +#define VREG_BMC_DEBUGPRIV_READMASK 0xe0000000 +#define VREG_BMC_DEBUGPRIV_CLEARMASK 0x00000000 +#define VREG_BMC_DEBUGPRIV 0x108 +#define VREG_BMC_DEBUGPRIV_ID 66 + +#define VVAL_BMC_DEBUGPRIV_DEFAULT 0x0 /* Reset by hreset: Resets to 0 */ +/* Subfields of DebugPriv */ +#define VREG_BMC_DEBUGPRIV_DISABLE_MASK 0x80000000 /* When set disables access to privileged registers from Host CPU [31..31] */ +#define VREG_BMC_DEBUGPRIV_C6_INTLOOP_MASK 0x40000000 /* Enable CSIX Internal Loopback on egress to ingress [30..30] */ +#define VREG_BMC_DEBUGPRIV_C6_EXTLOOP_MASK 0x20000000 /* Enable CSIX External Loopback on ingress to egress [29..29] */ +#define VREG_BMC_DEBUGPRIV_RESV0_MASK 0x1fffffff /* Reserved [0..28] */ + + + + +/* HT Receive Clock A DCM control (31..0) */ +#define VREG_BMC_HTRXACLK_MASK 0xffffffff +#define VREG_BMC_HTRXACLK_ACCESSMODE 2 +#define VREG_BMC_HTRXACLK_HOSTPRIVILEGE 0 +#define VREG_BMC_HTRXACLK_RESERVEDMASK 0xffff7e00 +#define VREG_BMC_HTRXACLK_WRITEMASK 0x000000ff +#define VREG_BMC_HTRXACLK_READMASK 0x000081ff +#define VREG_BMC_HTRXACLK_CLEARMASK 0x00000000 +#define VREG_BMC_HTRXACLK 0x110 +#define VREG_BMC_HTRXACLK_ID 68 + +/* Subfields of HTRxAClk */ +#define VREG_BMC_HTRXACLK_RESV0_MASK 0xffff0000 /* Reserved [16..31] */ +#define VREG_BMC_HTRXACLK_DONE_MASK 0x00008000 /* indicates that the DCM has completed the previous operation [15..15] */ +#define VREG_BMC_HTRXACLK_RESV1_MASK 0x00007e00 /* Reserved [9..14] */ +#define VREG_BMC_HTRXACLK_SAMPLE_MASK 0x00000100 /* Clock value sampled with current phase shift [8..8] */ +#define VREG_BMC_HTRXACLK_PHASE_MASK 0x000000ff /* 8 bit phase shift value [0..7] */ + + + + +/* HT Receive Clock B DCM control (31..0) */ +#define VREG_BMC_HTRXBCLK_MASK 0xffffffff +#define VREG_BMC_HTRXBCLK_ACCESSMODE 2 +#define VREG_BMC_HTRXBCLK_HOSTPRIVILEGE 0 +#define VREG_BMC_HTRXBCLK_RESERVEDMASK 0xffff7e00 +#define VREG_BMC_HTRXBCLK_WRITEMASK 0x000000ff +#define VREG_BMC_HTRXBCLK_READMASK 0x000081ff +#define VREG_BMC_HTRXBCLK_CLEARMASK 0x00000000 +#define VREG_BMC_HTRXBCLK 0x114 +#define VREG_BMC_HTRXBCLK_ID 69 + +/* Subfields of HTRxBClk */ +#define VREG_BMC_HTRXBCLK_RESV0_MASK 0xffff0000 /* Reserved [16..31] */ +#define VREG_BMC_HTRXBCLK_DONE_MASK 0x00008000 /* indicates that the DCM has completed the previous operation [15..15] */ +#define VREG_BMC_HTRXBCLK_RESV1_MASK 0x00007e00 /* Reserved [9..14] */ +#define VREG_BMC_HTRXBCLK_SAMPLE_MASK 0x00000100 /* Clock value sampled with current phase shift [8..8] */ +#define VREG_BMC_HTRXBCLK_PHASE_MASK 0x000000ff /* 8 bit phase shift value [0..7] */ + + + + +/* HT Transmit Clock DCM control (31..0) */ +#define VREG_BMC_HTTXCLK_MASK 0xffffffff +#define VREG_BMC_HTTXCLK_ACCESSMODE 2 +#define VREG_BMC_HTTXCLK_HOSTPRIVILEGE 0 +#define VREG_BMC_HTTXCLK_RESERVEDMASK 0xffff7e00 +#define VREG_BMC_HTTXCLK_WRITEMASK 0x000000ff +#define VREG_BMC_HTTXCLK_READMASK 0x000081ff +#define VREG_BMC_HTTXCLK_CLEARMASK 0x00000000 +#define VREG_BMC_HTTXCLK 0x118 +#define VREG_BMC_HTTXCLK_ID 70 + +/* Subfields of HTTxClk */ +#define VREG_BMC_HTTXCLK_RESV0_MASK 0xffff0000 /* Reserved [16..31] */ +#define VREG_BMC_HTTXCLK_DONE_MASK 0x00008000 /* indicates that the DCM has completed the previous operation [15..15] */ +#define VREG_BMC_HTTXCLK_RESV1_MASK 0x00007e00 /* Reserved [9..14] */ +#define VREG_BMC_HTTXCLK_SAMPLE_MASK 0x00000100 /* Clock value sampled with current phase shift [8..8] */ +#define VREG_BMC_HTTXCLK_PHASE_MASK 0x000000ff /* 8 bit phase shift value [0..7] */ + + + + +/* Sensor bit 0 (0..0) */ +#define VREG_BMC_SENSOR0_MASK 0x00000001 +#define VREG_BMC_SENSOR0_ACCESSMODE 2 +#define VREG_BMC_SENSOR0_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR0_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR0_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR0_READMASK 0x00000001 +#define VREG_BMC_SENSOR0_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR0 0x120 +#define VREG_BMC_SENSOR0_ID 72 + +#define VVAL_BMC_SENSOR0_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 1 (0..0) */ +#define VREG_BMC_SENSOR1_MASK 0x00000001 +#define VREG_BMC_SENSOR1_ACCESSMODE 2 +#define VREG_BMC_SENSOR1_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR1_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR1_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR1_READMASK 0x00000001 +#define VREG_BMC_SENSOR1_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR1 0x124 +#define VREG_BMC_SENSOR1_ID 73 + +#define VVAL_BMC_SENSOR1_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 2 (0..0) */ +#define VREG_BMC_SENSOR2_MASK 0x00000001 +#define VREG_BMC_SENSOR2_ACCESSMODE 2 +#define VREG_BMC_SENSOR2_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR2_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR2_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR2_READMASK 0x00000001 +#define VREG_BMC_SENSOR2_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR2 0x128 +#define VREG_BMC_SENSOR2_ID 74 + +#define VVAL_BMC_SENSOR2_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 3 (0..0) */ +#define VREG_BMC_SENSOR3_MASK 0x00000001 +#define VREG_BMC_SENSOR3_ACCESSMODE 2 +#define VREG_BMC_SENSOR3_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR3_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR3_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR3_READMASK 0x00000001 +#define VREG_BMC_SENSOR3_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR3 0x12c +#define VREG_BMC_SENSOR3_ID 75 + +#define VVAL_BMC_SENSOR3_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 4 (0..0) */ +#define VREG_BMC_SENSOR4_MASK 0x00000001 +#define VREG_BMC_SENSOR4_ACCESSMODE 2 +#define VREG_BMC_SENSOR4_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR4_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR4_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR4_READMASK 0x00000001 +#define VREG_BMC_SENSOR4_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR4 0x130 +#define VREG_BMC_SENSOR4_ID 76 + +#define VVAL_BMC_SENSOR4_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 5 (0..0) */ +#define VREG_BMC_SENSOR5_MASK 0x00000001 +#define VREG_BMC_SENSOR5_ACCESSMODE 2 +#define VREG_BMC_SENSOR5_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR5_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR5_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR5_READMASK 0x00000001 +#define VREG_BMC_SENSOR5_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR5 0x134 +#define VREG_BMC_SENSOR5_ID 77 + +#define VVAL_BMC_SENSOR5_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 6 (0..0) */ +#define VREG_BMC_SENSOR6_MASK 0x00000001 +#define VREG_BMC_SENSOR6_ACCESSMODE 2 +#define VREG_BMC_SENSOR6_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR6_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR6_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR6_READMASK 0x00000001 +#define VREG_BMC_SENSOR6_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR6 0x138 +#define VREG_BMC_SENSOR6_ID 78 + +#define VVAL_BMC_SENSOR6_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Sensor bit 7 (0..0) */ +#define VREG_BMC_SENSOR7_MASK 0x00000001 +#define VREG_BMC_SENSOR7_ACCESSMODE 2 +#define VREG_BMC_SENSOR7_HOSTPRIVILEGE 1 +#define VREG_BMC_SENSOR7_RESERVEDMASK 0x00000000 +#define VREG_BMC_SENSOR7_WRITEMASK 0x00000001 +#define VREG_BMC_SENSOR7_READMASK 0x00000001 +#define VREG_BMC_SENSOR7_CLEARMASK 0x00000000 +#define VREG_BMC_SENSOR7 0x13c +#define VREG_BMC_SENSOR7_ID 79 + +#define VVAL_BMC_SENSOR7_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Request Register (15..0) */ +#define VREG_BMC_INTRREQ_MASK 0x0000ffff +#define VREG_BMC_INTRREQ_ACCESSMODE 2 +#define VREG_BMC_INTRREQ_HOSTPRIVILEGE 1 +#define VREG_BMC_INTRREQ_RESERVEDMASK 0x00000000 +#define VREG_BMC_INTRREQ_WRITEMASK 0x0000ffff +#define VREG_BMC_INTRREQ_READMASK 0x0000ffff +#define VREG_BMC_INTRREQ_CLEARMASK 0x00000000 +#define VREG_BMC_INTRREQ 0x140 +#define VREG_BMC_INTRREQ_ID 80 + +#define VVAL_BMC_INTRREQ_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Status Register (31..0) */ +#define VREG_BMC_INTRSTATUS_MASK 0xffffffff +#define VREG_BMC_INTRSTATUS_ACCESSMODE 2 +#define VREG_BMC_INTRSTATUS_HOSTPRIVILEGE 1 +#define VREG_BMC_INTRSTATUS_RESERVEDMASK 0xfffc0000 +#define VREG_BMC_INTRSTATUS_WRITEMASK 0x0003ffff +#define VREG_BMC_INTRSTATUS_READMASK 0x0003ffff +#define VREG_BMC_INTRSTATUS_CLEARMASK 0x0003ffff +#define VREG_BMC_INTRSTATUS 0x144 +#define VREG_BMC_INTRSTATUS_ID 81 + +#define VVAL_BMC_INTRSTATUS_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of IntrStatus */ +#define VREG_BMC_INTRSTATUS_RSVD_MASK 0xfffc0000 /* Reserved [18..31] */ +#define VREG_BMC_INTRSTATUS_NONFATAL_MASK 0x00020000 /* NonFatal error was signalled [17..17] */ +#define VREG_BMC_INTRSTATUS_FATAL_MASK 0x00010000 /* Fatal error was signalled [16..16] */ +#define VREG_BMC_INTRSTATUS_INTR_MASK 0x0000ffff /* Programmed Interrupt was signalled [0..15] */ + + + + +/* NonFatal Error Status (31..0) */ +#define VREG_BMC_INTRERRSTAT_MASK 0xffffffff +#define VREG_BMC_INTRERRSTAT_ACCESSMODE 2 +#define VREG_BMC_INTRERRSTAT_HOSTPRIVILEGE 1 +#define VREG_BMC_INTRERRSTAT_RESERVEDMASK 0xfffffffe +#define VREG_BMC_INTRERRSTAT_WRITEMASK 0x00000001 +#define VREG_BMC_INTRERRSTAT_READMASK 0x00000001 +#define VREG_BMC_INTRERRSTAT_CLEARMASK 0x00000001 +#define VREG_BMC_INTRERRSTAT 0x150 +#define VREG_BMC_INTRERRSTAT_ID 84 + +#define VVAL_BMC_INTRERRSTAT_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of IntrErrStat */ +#define VREG_BMC_INTRERRSTAT_RSVD_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_BMC_INTRERRSTAT_ERR1_MASK 0x00000001 /* Example - Details to be filled in [0..0] */ + + + + +/* Fatal Error Status (31..0) */ +#define VREG_BMC_NMIERRSTAT_MASK 0xffffffff +#define VREG_BMC_NMIERRSTAT_ACCESSMODE 2 +#define VREG_BMC_NMIERRSTAT_HOSTPRIVILEGE 1 +#define VREG_BMC_NMIERRSTAT_RESERVEDMASK 0xfffffffe +#define VREG_BMC_NMIERRSTAT_WRITEMASK 0x00000001 +#define VREG_BMC_NMIERRSTAT_READMASK 0x00000001 +#define VREG_BMC_NMIERRSTAT_CLEARMASK 0x00000001 +#define VREG_BMC_NMIERRSTAT 0x154 +#define VREG_BMC_NMIERRSTAT_ID 85 + +#define VVAL_BMC_NMIERRSTAT_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of NMIErrStat */ +#define VREG_BMC_NMIERRSTAT_RSVD_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_BMC_NMIERRSTAT_ERR1_MASK 0x00000001 /* Example - Details to be filled in [0..0] */ + + + + +/* First NonFatal Error (31..0) */ +#define VREG_BMC_FRSTINTRERR_MASK 0xffffffff +#define VREG_BMC_FRSTINTRERR_ACCESSMODE 2 +#define VREG_BMC_FRSTINTRERR_HOSTPRIVILEGE 1 +#define VREG_BMC_FRSTINTRERR_RESERVEDMASK 0xfffffffe +#define VREG_BMC_FRSTINTRERR_WRITEMASK 0x00000001 +#define VREG_BMC_FRSTINTRERR_READMASK 0x00000001 +#define VREG_BMC_FRSTINTRERR_CLEARMASK 0x00000001 +#define VREG_BMC_FRSTINTRERR 0x158 +#define VREG_BMC_FRSTINTRERR_ID 86 + +#define VVAL_BMC_FRSTINTRERR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of FrstIntrErr */ +#define VREG_BMC_FRSTINTRERR_RSVD_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_BMC_FRSTINTRERR_ERR1_MASK 0x00000001 /* Example - Details to be filled in [0..0] */ + + + + +/* First Fatal Error (31..0) */ +#define VREG_BMC_FRSTNMIERR_MASK 0xffffffff +#define VREG_BMC_FRSTNMIERR_ACCESSMODE 2 +#define VREG_BMC_FRSTNMIERR_HOSTPRIVILEGE 1 +#define VREG_BMC_FRSTNMIERR_RESERVEDMASK 0xfffffffe +#define VREG_BMC_FRSTNMIERR_WRITEMASK 0x00000001 +#define VREG_BMC_FRSTNMIERR_READMASK 0x00000001 +#define VREG_BMC_FRSTNMIERR_CLEARMASK 0x00000001 +#define VREG_BMC_FRSTNMIERR 0x15c +#define VREG_BMC_FRSTNMIERR_ID 87 + +#define VVAL_BMC_FRSTNMIERR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of FrstNMIErr */ +#define VREG_BMC_FRSTNMIERR_RSVD_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_BMC_FRSTNMIERR_ERR1_MASK 0x00000001 /* Example - Details to be filled in [0..0] */ + + + + +/* Fabric configuration Register (31..0) */ +#define VREG_BMC_FABRIC_MASK 0xffffffff +#define VREG_BMC_FABRIC_ACCESSMODE 2 +#define VREG_BMC_FABRIC_HOSTPRIVILEGE 1 +#define VREG_BMC_FABRIC_RESERVEDMASK 0xfffffff0 +#define VREG_BMC_FABRIC_WRITEMASK 0x0000000f +#define VREG_BMC_FABRIC_READMASK 0x0000000f +#define VREG_BMC_FABRIC_CLEARMASK 0x00000000 +#define VREG_BMC_FABRIC 0x200 +#define VREG_BMC_FABRIC_ID 128 + +#define VVAL_BMC_FABRIC_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of Fabric */ +#define VREG_BMC_FABRIC_RESV0_MASK 0xfffffff0 /* Reserved [4..31] */ +#define VREG_BMC_FABRIC_PORT_MASK 0x0000000f /* Fabric Port Address [0..3] */ + + + + +/* VIOC Manager configuration Register (31..0) */ +#define VREG_BMC_VMGRCFG_MASK 0xffffffff +#define VREG_BMC_VMGRCFG_ACCESSMODE 2 +#define VREG_BMC_VMGRCFG_HOSTPRIVILEGE 0 +#define VREG_BMC_VMGRCFG_RESERVEDMASK 0xfffffffe +#define VREG_BMC_VMGRCFG_WRITEMASK 0x00000001 +#define VREG_BMC_VMGRCFG_READMASK 0x00000001 +#define VREG_BMC_VMGRCFG_CLEARMASK 0x00000000 +#define VREG_BMC_VMGRCFG 0x210 +#define VREG_BMC_VMGRCFG_ID 132 + +#define VVAL_BMC_VMGRCFG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of VMgrCfg */ +#define VREG_BMC_VMGRCFG_RESV0_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_BMC_VMGRCFG_MGIDOFFSET_MASK 0x00000001 /* Enables CSIX MGID Offset [0..0] */ + + + + +/* VIOC Manager PCI configuration Register 0 (31..0) */ +#define VREG_BMC_VMGRPCICFG0_MASK 0xffffffff +#define VREG_BMC_VMGRPCICFG0_ACCESSMODE 2 +#define VREG_BMC_VMGRPCICFG0_HOSTPRIVILEGE 0 +#define VREG_BMC_VMGRPCICFG0_RESERVEDMASK 0x7f000000 +#define VREG_BMC_VMGRPCICFG0_WRITEMASK 0x80ffffff +#define VREG_BMC_VMGRPCICFG0_READMASK 0x80ffffff +#define VREG_BMC_VMGRPCICFG0_CLEARMASK 0x00000000 +#define VREG_BMC_VMGRPCICFG0 0x214 +#define VREG_BMC_VMGRPCICFG0_ID 133 + +#define VVAL_BMC_VMGRPCICFG0_DEFAULT 0x80088000 /* Reset by hreset: Reset to Enabled */ +/* Subfields of VMgrPCICfg0 */ +#define VREG_BMC_VMGRPCICFG0_MSIXEN_MASK 0x80000000 /* Enable MSI-X Configuration Registers [31..31] */ +#define VREG_BMC_VMGRPCICFG0_RESV0_MASK 0x7f000000 /* Reserved [24..30] */ +#define VREG_BMC_VMGRPCICFG0_CLASSCODE_MASK 0x00ffffff /* Class Code to expose for Function 0 [0..23] */ + + + + +/* Base address for Uart 0 (15..0) */ +#define VREG_BMC_UART0BASE_MASK 0x0000ffff +#define VREG_BMC_UART0BASE_ACCESSMODE 2 +#define VREG_BMC_UART0BASE_HOSTPRIVILEGE 1 +#define VREG_BMC_UART0BASE_RESERVEDMASK 0x00000007 +#define VREG_BMC_UART0BASE_WRITEMASK 0x0000fff8 +#define VREG_BMC_UART0BASE_READMASK 0x0000fff8 +#define VREG_BMC_UART0BASE_CLEARMASK 0x00000000 +#define VREG_BMC_UART0BASE 0x300 +#define VREG_BMC_UART0BASE_ID 192 + +#define VVAL_BMC_UART0BASE_DEFAULT 0x3f8 /* Reset by hreset: Default is the legacy COM1 port address */ +/* Subfields of UART0Base */ +#define VREG_BMC_UART0BASE_ADDR_MASK 0x0000fff8 /* UART0 Base Addr [3..15] */ +#define VREG_BMC_UART0BASE_RSV1_MASK 0x00000007 /* Reserved - read as 0 [0..2] */ + + + + +/* IRQ number to be used by Uart 0 (3..0) */ +#define VREG_BMC_UART0IRQ_MASK 0x0000000f +#define VREG_BMC_UART0IRQ_ACCESSMODE 2 +#define VREG_BMC_UART0IRQ_HOSTPRIVILEGE 1 +#define VREG_BMC_UART0IRQ_RESERVEDMASK 0x00000000 +#define VREG_BMC_UART0IRQ_WRITEMASK 0x0000000f +#define VREG_BMC_UART0IRQ_READMASK 0x0000000f +#define VREG_BMC_UART0IRQ_CLEARMASK 0x00000000 +#define VREG_BMC_UART0IRQ 0x304 +#define VREG_BMC_UART0IRQ_ID 193 + +#define VVAL_BMC_UART0IRQ_DEFAULT 0x4 /* Reset by hreset: Default is the legacy COM1 IRQ */ + + +/* Send (write) and Receive (read) uart data register (15..0) */ +#define VREG_BMC_UART0DATA_MASK 0x0000ffff +#define VREG_BMC_UART0DATA_ACCESSMODE 1 +#define VREG_BMC_UART0DATA_HOSTPRIVILEGE 1 +#define VREG_BMC_UART0DATA_RESERVEDMASK 0x0000cfff +#define VREG_BMC_UART0DATA_WRITEMASK 0x00000000 +#define VREG_BMC_UART0DATA_READMASK 0x00003000 +#define VREG_BMC_UART0DATA_CLEARMASK 0x00000000 +#define VREG_BMC_UART0DATA 0x308 +#define VREG_BMC_UART0DATA_ID 194 + +#define VVAL_BMC_UART0DATA_DEFAULT 0x0 /* Reset by hreset: Default is 0 */ +/* Subfields of UART0Data */ +#define VREG_BMC_UART0DATA_RSV1_MASK 0x0000c000 /* Reserved - read as 0 [14..15] */ +#define VREG_BMC_UART0DATA_TXRDY1_MASK 0x00002000 /* Uart1 Tx Ready Flag [13..13] */ +#define VREG_BMC_UART0DATA_TXRDY0_MASK 0x00001000 /* Uart0 Tx Ready Flag [12..12] */ +#define VREG_BMC_UART0DATA_RSV0_MASK 0x00000f00 /* Reserved - read as 0 [8..11] */ +#define VREG_BMC_UART0DATA_DATA_MASK 0x000000ff /* UART Data Register [0..7] */ + + + + +/* Base address for Uart 1 (15..0) */ +#define VREG_BMC_UART1BASE_MASK 0x0000ffff +#define VREG_BMC_UART1BASE_ACCESSMODE 2 +#define VREG_BMC_UART1BASE_HOSTPRIVILEGE 1 +#define VREG_BMC_UART1BASE_RESERVEDMASK 0x00000007 +#define VREG_BMC_UART1BASE_WRITEMASK 0x0000fff8 +#define VREG_BMC_UART1BASE_READMASK 0x0000fff8 +#define VREG_BMC_UART1BASE_CLEARMASK 0x00000000 +#define VREG_BMC_UART1BASE 0x310 +#define VREG_BMC_UART1BASE_ID 196 + +#define VVAL_BMC_UART1BASE_DEFAULT 0x2f8 /* Reset by hreset: Default is the legacy COM2 port address */ +/* Subfields of UART1Base */ +#define VREG_BMC_UART1BASE_ADDR_MASK 0x0000fff8 /* UART1 Base Addr [3..15] */ +#define VREG_BMC_UART1BASE_RSV1_MASK 0x00000007 /* Reserved - read as 0 [0..2] */ + + + + +/* IRQ number to be used by Uart 1 (3..0) */ +#define VREG_BMC_UART1IRQ_MASK 0x0000000f +#define VREG_BMC_UART1IRQ_ACCESSMODE 2 +#define VREG_BMC_UART1IRQ_HOSTPRIVILEGE 1 +#define VREG_BMC_UART1IRQ_RESERVEDMASK 0x00000000 +#define VREG_BMC_UART1IRQ_WRITEMASK 0x0000000f +#define VREG_BMC_UART1IRQ_READMASK 0x0000000f +#define VREG_BMC_UART1IRQ_CLEARMASK 0x00000000 +#define VREG_BMC_UART1IRQ 0x314 +#define VREG_BMC_UART1IRQ_ID 197 + +#define VVAL_BMC_UART1IRQ_DEFAULT 0x3 /* Reset by hreset: Default is the legacy COM2 IRQ */ + + +/* Send (write) and Receive (read) uart data register (15..0) */ +#define VREG_BMC_UART1DATA_MASK 0x0000ffff +#define VREG_BMC_UART1DATA_ACCESSMODE 1 +#define VREG_BMC_UART1DATA_HOSTPRIVILEGE 1 +#define VREG_BMC_UART1DATA_RESERVEDMASK 0x0000cfff +#define VREG_BMC_UART1DATA_WRITEMASK 0x00000000 +#define VREG_BMC_UART1DATA_READMASK 0x00003000 +#define VREG_BMC_UART1DATA_CLEARMASK 0x00000000 +#define VREG_BMC_UART1DATA 0x318 +#define VREG_BMC_UART1DATA_ID 198 + +#define VVAL_BMC_UART1DATA_DEFAULT 0x0 /* Reset by hreset: Default is 0 */ +/* Subfields of UART1Data */ +#define VREG_BMC_UART1DATA_RSV1_MASK 0x0000c000 /* Reserved - read as 0 [14..15] */ +#define VREG_BMC_UART1DATA_TXRDY1_MASK 0x00002000 /* Uart1 Tx Ready Flag [13..13] */ +#define VREG_BMC_UART1DATA_TXRDY0_MASK 0x00001000 /* Uart0 Tx Ready Flag [12..12] */ +#define VREG_BMC_UART1DATA_RSV0_MASK 0x00000f00 /* Reserved - read as 0 [8..11] */ +#define VREG_BMC_UART1DATA_DATA_MASK 0x000000ff /* UART Data Register [0..7] */ + + + + +/* VNIC Queue Enable register (31..0) */ +#define VREG_BMC_VNIC_CFG_MASK 0xffffffff +#define VREG_BMC_VNIC_CFG_ACCESSMODE 2 +#define VREG_BMC_VNIC_CFG_HOSTPRIVILEGE 1 +#define VREG_BMC_VNIC_CFG_RESERVEDMASK 0xfffffffc +#define VREG_BMC_VNIC_CFG_WRITEMASK 0x00000003 +#define VREG_BMC_VNIC_CFG_READMASK 0x00000003 +#define VREG_BMC_VNIC_CFG_CLEARMASK 0x00000000 +#define VREG_BMC_VNIC_CFG 0x800 +#define VREG_BMC_VNIC_CFG_ID 512 + /* + * This register is repeated for each VNIC. + * Bits 15:12 of the address indicate the VNIC ID + */ + +#define VVAL_BMC_VNIC_CFG_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of VNIC_CFG */ +#define VREG_BMC_VNIC_CFG_RSV1_MASK 0xfffffffc /* Reserved - read as 0 [2..31] */ +#define VREG_BMC_VNIC_CFG_PROMISCUOUS_MASK 0x00000002 /* [1..1] */ +#define VREG_BMC_VNIC_CFG_ENABLE_MASK 0x00000001 /* [0..0] */ + + + + +/* VNIC Enable Register (15..0) */ +#define VREG_BMC_VNIC_EN_MASK 0x0000ffff +#define VREG_BMC_VNIC_EN_ACCESSMODE 2 +#define VREG_BMC_VNIC_EN_HOSTPRIVILEGE 0 +#define VREG_BMC_VNIC_EN_RESERVEDMASK 0x00000000 +#define VREG_BMC_VNIC_EN_WRITEMASK 0x0000ffff +#define VREG_BMC_VNIC_EN_READMASK 0x0000ffff +#define VREG_BMC_VNIC_EN_CLEARMASK 0x00000000 +#define VREG_BMC_VNIC_EN 0x804 +#define VREG_BMC_VNIC_EN_ID 513 + /* + * This register is privileged. The SIM writes this register to + * provision VNICs for the partition + */ + +#define VVAL_BMC_VNIC_EN_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of VNIC_EN */ +#define VREG_BMC_VNIC_EN_VNIC0_MASK 0x00000001 /* Enable VNIC 0 [0..0] */ +#define VREG_BMC_VNIC_EN_VNIC1_MASK 0x00000002 /* Enable VNIC 1 [1..1] */ +#define VREG_BMC_VNIC_EN_VNIC2_MASK 0x00000004 /* Enable VNIC 2 [2..2] */ +#define VREG_BMC_VNIC_EN_VNIC3_MASK 0x00000008 /* Enable VNIC 3 [3..3] */ +#define VREG_BMC_VNIC_EN_VNIC4_MASK 0x00000010 /* Enable VNIC 4 [4..4] */ +#define VREG_BMC_VNIC_EN_VNIC5_MASK 0x00000020 /* Enable VNIC 5 [5..5] */ +#define VREG_BMC_VNIC_EN_VNIC6_MASK 0x00000040 /* Enable VNIC 6 [6..6] */ +#define VREG_BMC_VNIC_EN_VNIC7_MASK 0x00000080 /* Enable VNIC 7 [7..7] */ +#define VREG_BMC_VNIC_EN_VNIC8_MASK 0x00000100 /* Enable VNIC 8 [8..8] */ +#define VREG_BMC_VNIC_EN_VNIC9_MASK 0x00000200 /* Enable VNIC 9 [9..9] */ +#define VREG_BMC_VNIC_EN_VNIC10_MASK 0x00000400 /* Enable VNIC 10 [10..10] */ +#define VREG_BMC_VNIC_EN_VNIC11_MASK 0x00000800 /* Enable VNIC 11 [11..11] */ +#define VREG_BMC_VNIC_EN_VNIC12_MASK 0x00001000 /* Enable VNIC 12 [12..12] */ +#define VREG_BMC_VNIC_EN_VNIC13_MASK 0x00002000 /* Enable VNIC 13 [13..13] */ +#define VREG_BMC_VNIC_EN_VNIC14_MASK 0x00004000 /* Enable VNIC 14 [14..14] */ +#define VREG_BMC_VNIC_EN_VNIC15_MASK 0x00008000 /* Enable VNIC 15 [15..15] */ + + + + +/* PORT Enable Register (15..0) */ +#define VREG_BMC_PORT_EN_MASK 0x0000ffff +#define VREG_BMC_PORT_EN_ACCESSMODE 2 +#define VREG_BMC_PORT_EN_HOSTPRIVILEGE 0 +#define VREG_BMC_PORT_EN_RESERVEDMASK 0x00000000 +#define VREG_BMC_PORT_EN_WRITEMASK 0x0000ffff +#define VREG_BMC_PORT_EN_READMASK 0x0000ffff +#define VREG_BMC_PORT_EN_CLEARMASK 0x00000000 +#define VREG_BMC_PORT_EN 0x808 +#define VREG_BMC_PORT_EN_ID 514 + /* + * This register is privileged. The SIM writes this register to + * provision PORTs for the partition + */ + +#define VVAL_BMC_PORT_EN_DEFAULT 0xffff /* Reset by hreset: Reset enable all ports */ +/* Subfields of PORT_EN */ +#define VREG_BMC_PORT_EN_PORT0_MASK 0x00000001 /* Enable PORT 0 [0..0] */ +#define VREG_BMC_PORT_EN_PORT1_MASK 0x00000002 /* Enable PORT 1 [1..1] */ +#define VREG_BMC_PORT_EN_PORT2_MASK 0x00000004 /* Enable PORT 2 [2..2] */ +#define VREG_BMC_PORT_EN_PORT3_MASK 0x00000008 /* Enable PORT 3 [3..3] */ +#define VREG_BMC_PORT_EN_PORT4_MASK 0x00000010 /* Enable PORT 4 [4..4] */ +#define VREG_BMC_PORT_EN_PORT5_MASK 0x00000020 /* Enable PORT 5 [5..5] */ +#define VREG_BMC_PORT_EN_PORT6_MASK 0x00000040 /* Enable PORT 6 [6..6] */ +#define VREG_BMC_PORT_EN_PORT7_MASK 0x00000080 /* Enable PORT 7 [7..7] */ +#define VREG_BMC_PORT_EN_PORT8_MASK 0x00000100 /* Enable PORT 8 [8..8] */ +#define VREG_BMC_PORT_EN_PORT9_MASK 0x00000200 /* Enable PORT 9 [9..9] */ +#define VREG_BMC_PORT_EN_PORT10_MASK 0x00000400 /* Enable PORT 10 [10..10] */ +#define VREG_BMC_PORT_EN_PORT11_MASK 0x00000800 /* Enable PORT 11 [11..11] */ +#define VREG_BMC_PORT_EN_PORT12_MASK 0x00001000 /* Enable PORT 12 [12..12] */ +#define VREG_BMC_PORT_EN_PORT13_MASK 0x00002000 /* Enable PORT 13 [13..13] */ +#define VREG_BMC_PORT_EN_PORT14_MASK 0x00004000 /* Enable PORT 14 [14..14] */ +#define VREG_BMC_PORT_EN_PORT15_MASK 0x00008000 /* Enable PORT 15 [15..15] */ + + + + +/* General Scratchpad space. 32 Registers/VNIC (31..0) */ +#define VREG_BMC_REG_MASK 0xffffffff +#define VREG_BMC_REG_ACCESSMODE 2 +#define VREG_BMC_REG_HOSTPRIVILEGE 1 +#define VREG_BMC_REG_RESERVEDMASK 0x00000000 +#define VREG_BMC_REG_WRITEMASK 0xffffffff +#define VREG_BMC_REG_READMASK 0xffffffff +#define VREG_BMC_REG_CLEARMASK 0x00000000 +#define VREG_BMC_REG 0x900 +#define VREG_BMC_REG_ID 576 + +#define VREG_BMC_REG_R0 0x900 +#define VREG_BMC_REG_R1 0x904 +#define VREG_BMC_REG_R2 0x908 +#define VREG_BMC_REG_R3 0x90C +#define VREG_BMC_REG_R4 0x910 +#define VREG_BMC_REG_R5 0x914 +#define VREG_BMC_REG_R6 0x918 +#define VREG_BMC_REG_R7 0x91C +#define VREG_BMC_REG_R8 0x920 +#define VREG_BMC_REG_R9 0x924 +#define VREG_BMC_REG_R10 0x928 +#define VREG_BMC_REG_R11 0x92C +#define VREG_BMC_REG_R12 0x930 +#define VREG_BMC_REG_R13 0x934 +#define VREG_BMC_REG_R14 0x938 +#define VREG_BMC_REG_R15 0x93C +#define VREG_BMC_REG_R16 0x940 +#define VREG_BMC_REG_R17 0x944 +#define VREG_BMC_REG_R18 0x948 +#define VREG_BMC_REG_R19 0x94C +#define VREG_BMC_REG_R20 0x950 +#define VREG_BMC_REG_R21 0x954 +#define VREG_BMC_REG_R22 0x958 +#define VREG_BMC_REG_R23 0x95C +#define VREG_BMC_REG_R24 0x960 +#define VREG_BMC_REG_R25 0x964 +#define VREG_BMC_REG_R26 0x968 +#define VREG_BMC_REG_R27 0x96C +#define VREG_BMC_REG_R28 0x970 +#define VREG_BMC_REG_R29 0x974 +#define VREG_BMC_REG_R30 0x978 +#define VREG_BMC_REG_R31 0x97C + + +/* POST Code history registers (31..0) */ +#define VREG_BMC_POST_MASK 0xffffffff +#define VREG_BMC_POST_ACCESSMODE 1 +#define VREG_BMC_POST_HOSTPRIVILEGE 1 +#define VREG_BMC_POST_RESERVEDMASK 0x00000000 +#define VREG_BMC_POST_WRITEMASK 0x00000000 +#define VREG_BMC_POST_READMASK 0xffffffff +#define VREG_BMC_POST_CLEARMASK 0x00000000 +#define VREG_BMC_POST 0xc00 +#define VREG_BMC_POST_ID 768 + +#define VREG_BMC_POST_R0 0xC00 +#define VREG_BMC_POST_R1 0xC04 +#define VREG_BMC_POST_R2 0xC08 +#define VREG_BMC_POST_R3 0xC0C +#define VREG_BMC_POST_R4 0xC10 +#define VREG_BMC_POST_R5 0xC14 +#define VREG_BMC_POST_R6 0xC18 +#define VREG_BMC_POST_R7 0xC1C +#define VREG_BMC_POST_R8 0xC20 +#define VREG_BMC_POST_R9 0xC24 +#define VREG_BMC_POST_R10 0xC28 +#define VREG_BMC_POST_R11 0xC2C +#define VREG_BMC_POST_R12 0xC30 +#define VREG_BMC_POST_R13 0xC34 +#define VREG_BMC_POST_R14 0xC38 +#define VREG_BMC_POST_R15 0xC3C +#define VREG_BMC_POST_R16 0xC40 +#define VREG_BMC_POST_R17 0xC44 +#define VREG_BMC_POST_R18 0xC48 +#define VREG_BMC_POST_R19 0xC4C +#define VREG_BMC_POST_R20 0xC50 +#define VREG_BMC_POST_R21 0xC54 +#define VREG_BMC_POST_R22 0xC58 +#define VREG_BMC_POST_R23 0xC5C +#define VREG_BMC_POST_R24 0xC60 +#define VREG_BMC_POST_R25 0xC64 +#define VREG_BMC_POST_R26 0xC68 +#define VREG_BMC_POST_R27 0xC6C +#define VREG_BMC_POST_R28 0xC70 +#define VREG_BMC_POST_R29 0xC74 +#define VREG_BMC_POST_R30 0xC78 +#define VREG_BMC_POST_R31 0xC7C +#define VREG_BMC_POST_R32 0xC80 +#define VREG_BMC_POST_R33 0xC84 +#define VREG_BMC_POST_R34 0xC88 +#define VREG_BMC_POST_R35 0xC8C +#define VREG_BMC_POST_R36 0xC90 +#define VREG_BMC_POST_R37 0xC94 +#define VREG_BMC_POST_R38 0xC98 +#define VREG_BMC_POST_R39 0xC9C +#define VREG_BMC_POST_R40 0xCA0 +#define VREG_BMC_POST_R41 0xCA4 +#define VREG_BMC_POST_R42 0xCA8 +#define VREG_BMC_POST_R43 0xCAC +#define VREG_BMC_POST_R44 0xCB0 +#define VREG_BMC_POST_R45 0xCB4 +#define VREG_BMC_POST_R46 0xCB8 +#define VREG_BMC_POST_R47 0xCBC +#define VREG_BMC_POST_R48 0xCC0 +#define VREG_BMC_POST_R49 0xCC4 +#define VREG_BMC_POST_R50 0xCC8 +#define VREG_BMC_POST_R51 0xCCC +#define VREG_BMC_POST_R52 0xCD0 +#define VREG_BMC_POST_R53 0xCD4 +#define VREG_BMC_POST_R54 0xCD8 +#define VREG_BMC_POST_R55 0xCDC +#define VREG_BMC_POST_R56 0xCE0 +#define VREG_BMC_POST_R57 0xCE4 +#define VREG_BMC_POST_R58 0xCE8 +#define VREG_BMC_POST_R59 0xCEC +#define VREG_BMC_POST_R60 0xCF0 +#define VREG_BMC_POST_R61 0xCF4 +#define VREG_BMC_POST_R62 0xCF8 +#define VREG_BMC_POST_R63 0xCFC +#define VREG_BMC_POST_R64 0xD00 +#define VREG_BMC_POST_R65 0xD04 +#define VREG_BMC_POST_R66 0xD08 +#define VREG_BMC_POST_R67 0xD0C +#define VREG_BMC_POST_R68 0xD10 +#define VREG_BMC_POST_R69 0xD14 +#define VREG_BMC_POST_R70 0xD18 +#define VREG_BMC_POST_R71 0xD1C +#define VREG_BMC_POST_R72 0xD20 +#define VREG_BMC_POST_R73 0xD24 +#define VREG_BMC_POST_R74 0xD28 +#define VREG_BMC_POST_R75 0xD2C +#define VREG_BMC_POST_R76 0xD30 +#define VREG_BMC_POST_R77 0xD34 +#define VREG_BMC_POST_R78 0xD38 +#define VREG_BMC_POST_R79 0xD3C +#define VREG_BMC_POST_R80 0xD40 +#define VREG_BMC_POST_R81 0xD44 +#define VREG_BMC_POST_R82 0xD48 +#define VREG_BMC_POST_R83 0xD4C +#define VREG_BMC_POST_R84 0xD50 +#define VREG_BMC_POST_R85 0xD54 +#define VREG_BMC_POST_R86 0xD58 +#define VREG_BMC_POST_R87 0xD5C +#define VREG_BMC_POST_R88 0xD60 +#define VREG_BMC_POST_R89 0xD64 +#define VREG_BMC_POST_R90 0xD68 +#define VREG_BMC_POST_R91 0xD6C +#define VREG_BMC_POST_R92 0xD70 +#define VREG_BMC_POST_R93 0xD74 +#define VREG_BMC_POST_R94 0xD78 +#define VREG_BMC_POST_R95 0xD7C +#define VREG_BMC_POST_R96 0xD80 +#define VREG_BMC_POST_R97 0xD84 +#define VREG_BMC_POST_R98 0xD88 +#define VREG_BMC_POST_R99 0xD8C +#define VREG_BMC_POST_R100 0xD90 +#define VREG_BMC_POST_R101 0xD94 +#define VREG_BMC_POST_R102 0xD98 +#define VREG_BMC_POST_R103 0xD9C +#define VREG_BMC_POST_R104 0xDA0 +#define VREG_BMC_POST_R105 0xDA4 +#define VREG_BMC_POST_R106 0xDA8 +#define VREG_BMC_POST_R107 0xDAC +#define VREG_BMC_POST_R108 0xDB0 +#define VREG_BMC_POST_R109 0xDB4 +#define VREG_BMC_POST_R110 0xDB8 +#define VREG_BMC_POST_R111 0xDBC +#define VREG_BMC_POST_R112 0xDC0 +#define VREG_BMC_POST_R113 0xDC4 +#define VREG_BMC_POST_R114 0xDC8 +#define VREG_BMC_POST_R115 0xDCC +#define VREG_BMC_POST_R116 0xDD0 +#define VREG_BMC_POST_R117 0xDD4 +#define VREG_BMC_POST_R118 0xDD8 +#define VREG_BMC_POST_R119 0xDDC +#define VREG_BMC_POST_R120 0xDE0 +#define VREG_BMC_POST_R121 0xDE4 +#define VREG_BMC_POST_R122 0xDE8 +#define VREG_BMC_POST_R123 0xDEC +#define VREG_BMC_POST_R124 0xDF0 +#define VREG_BMC_POST_R125 0xDF4 +#define VREG_BMC_POST_R126 0xDF8 +#define VREG_BMC_POST_R127 0xDFC +#define VREG_BMC_POST_R128 0xE00 +#define VREG_BMC_POST_R129 0xE04 +#define VREG_BMC_POST_R130 0xE08 +#define VREG_BMC_POST_R131 0xE0C +#define VREG_BMC_POST_R132 0xE10 +#define VREG_BMC_POST_R133 0xE14 +#define VREG_BMC_POST_R134 0xE18 +#define VREG_BMC_POST_R135 0xE1C +#define VREG_BMC_POST_R136 0xE20 +#define VREG_BMC_POST_R137 0xE24 +#define VREG_BMC_POST_R138 0xE28 +#define VREG_BMC_POST_R139 0xE2C +#define VREG_BMC_POST_R140 0xE30 +#define VREG_BMC_POST_R141 0xE34 +#define VREG_BMC_POST_R142 0xE38 +#define VREG_BMC_POST_R143 0xE3C +#define VREG_BMC_POST_R144 0xE40 +#define VREG_BMC_POST_R145 0xE44 +#define VREG_BMC_POST_R146 0xE48 +#define VREG_BMC_POST_R147 0xE4C +#define VREG_BMC_POST_R148 0xE50 +#define VREG_BMC_POST_R149 0xE54 +#define VREG_BMC_POST_R150 0xE58 +#define VREG_BMC_POST_R151 0xE5C +#define VREG_BMC_POST_R152 0xE60 +#define VREG_BMC_POST_R153 0xE64 +#define VREG_BMC_POST_R154 0xE68 +#define VREG_BMC_POST_R155 0xE6C +#define VREG_BMC_POST_R156 0xE70 +#define VREG_BMC_POST_R157 0xE74 +#define VREG_BMC_POST_R158 0xE78 +#define VREG_BMC_POST_R159 0xE7C +#define VREG_BMC_POST_R160 0xE80 +#define VREG_BMC_POST_R161 0xE84 +#define VREG_BMC_POST_R162 0xE88 +#define VREG_BMC_POST_R163 0xE8C +#define VREG_BMC_POST_R164 0xE90 +#define VREG_BMC_POST_R165 0xE94 +#define VREG_BMC_POST_R166 0xE98 +#define VREG_BMC_POST_R167 0xE9C +#define VREG_BMC_POST_R168 0xEA0 +#define VREG_BMC_POST_R169 0xEA4 +#define VREG_BMC_POST_R170 0xEA8 +#define VREG_BMC_POST_R171 0xEAC +#define VREG_BMC_POST_R172 0xEB0 +#define VREG_BMC_POST_R173 0xEB4 +#define VREG_BMC_POST_R174 0xEB8 +#define VREG_BMC_POST_R175 0xEBC +#define VREG_BMC_POST_R176 0xEC0 +#define VREG_BMC_POST_R177 0xEC4 +#define VREG_BMC_POST_R178 0xEC8 +#define VREG_BMC_POST_R179 0xECC +#define VREG_BMC_POST_R180 0xED0 +#define VREG_BMC_POST_R181 0xED4 +#define VREG_BMC_POST_R182 0xED8 +#define VREG_BMC_POST_R183 0xEDC +#define VREG_BMC_POST_R184 0xEE0 +#define VREG_BMC_POST_R185 0xEE4 +#define VREG_BMC_POST_R186 0xEE8 +#define VREG_BMC_POST_R187 0xEEC +#define VREG_BMC_POST_R188 0xEF0 +#define VREG_BMC_POST_R189 0xEF4 +#define VREG_BMC_POST_R190 0xEF8 +#define VREG_BMC_POST_R191 0xEFC +#define VREG_BMC_POST_R192 0xF00 +#define VREG_BMC_POST_R193 0xF04 +#define VREG_BMC_POST_R194 0xF08 +#define VREG_BMC_POST_R195 0xF0C +#define VREG_BMC_POST_R196 0xF10 +#define VREG_BMC_POST_R197 0xF14 +#define VREG_BMC_POST_R198 0xF18 +#define VREG_BMC_POST_R199 0xF1C +#define VREG_BMC_POST_R200 0xF20 +#define VREG_BMC_POST_R201 0xF24 +#define VREG_BMC_POST_R202 0xF28 +#define VREG_BMC_POST_R203 0xF2C +#define VREG_BMC_POST_R204 0xF30 +#define VREG_BMC_POST_R205 0xF34 +#define VREG_BMC_POST_R206 0xF38 +#define VREG_BMC_POST_R207 0xF3C +#define VREG_BMC_POST_R208 0xF40 +#define VREG_BMC_POST_R209 0xF44 +#define VREG_BMC_POST_R210 0xF48 +#define VREG_BMC_POST_R211 0xF4C +#define VREG_BMC_POST_R212 0xF50 +#define VREG_BMC_POST_R213 0xF54 +#define VREG_BMC_POST_R214 0xF58 +#define VREG_BMC_POST_R215 0xF5C +#define VREG_BMC_POST_R216 0xF60 +#define VREG_BMC_POST_R217 0xF64 +#define VREG_BMC_POST_R218 0xF68 +#define VREG_BMC_POST_R219 0xF6C +#define VREG_BMC_POST_R220 0xF70 +#define VREG_BMC_POST_R221 0xF74 +#define VREG_BMC_POST_R222 0xF78 +#define VREG_BMC_POST_R223 0xF7C +#define VREG_BMC_POST_R224 0xF80 +#define VREG_BMC_POST_R225 0xF84 +#define VREG_BMC_POST_R226 0xF88 +#define VREG_BMC_POST_R227 0xF8C +#define VREG_BMC_POST_R228 0xF90 +#define VREG_BMC_POST_R229 0xF94 +#define VREG_BMC_POST_R230 0xF98 +#define VREG_BMC_POST_R231 0xF9C +#define VREG_BMC_POST_R232 0xFA0 +#define VREG_BMC_POST_R233 0xFA4 +#define VREG_BMC_POST_R234 0xFA8 +#define VREG_BMC_POST_R235 0xFAC +#define VREG_BMC_POST_R236 0xFB0 +#define VREG_BMC_POST_R237 0xFB4 +#define VREG_BMC_POST_R238 0xFB8 +#define VREG_BMC_POST_R239 0xFBC +#define VREG_BMC_POST_R240 0xFC0 +#define VREG_BMC_POST_R241 0xFC4 +#define VREG_BMC_POST_R242 0xFC8 +#define VREG_BMC_POST_R243 0xFCC +#define VREG_BMC_POST_R244 0xFD0 +#define VREG_BMC_POST_R245 0xFD4 +#define VREG_BMC_POST_R246 0xFD8 +#define VREG_BMC_POST_R247 0xFDC +#define VREG_BMC_POST_R248 0xFE0 +#define VREG_BMC_POST_R249 0xFE4 +#define VREG_BMC_POST_R250 0xFE8 +#define VREG_BMC_POST_R251 0xFEC +#define VREG_BMC_POST_R252 0xFF0 +#define VREG_BMC_POST_R253 0xFF4 +#define VREG_BMC_POST_R254 0xFF8 +#define VREG_BMC_POST_R255 0xFFC + +#endif /* _VNIC_BMC_REGISTERS_H_ */ + diff --git a/drivers/net/vioc/f7/vioc_ht_registers.h b/drivers/net/vioc/f7/vioc_ht_registers.h new file mode 100644 index 0000000..0874473 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_ht_registers.h @@ -0,0 +1,771 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_HT_REGISTERS_H_ +#define _VIOC_HT_REGISTERS_H_ +/* + * HyperTransport Configuration Register Designators + * Register addresses are offsets from the VIOCs base Config Space address + * which is defined as 0xFDFE000000 + */ +/* Module HT:4 */ + +/* Device and Vendor ID (31..0) */ +#define VREG_HT_ID_MASK 0xffffffff +#define VREG_HT_ID_ACCESSMODE 1 +#define VREG_HT_ID_HOSTPRIVILEGE 1 +#define VREG_HT_ID_RESERVEDMASK 0x00000000 +#define VREG_HT_ID_WRITEMASK 0x00000000 +#define VREG_HT_ID_READMASK 0xffffffff +#define VREG_HT_ID_CLEARMASK 0x00000000 +#define VREG_HT_ID 0x000 +#define VREG_HT_ID_ID 0 + /* Device Header */ + +#define VVAL_HT_ID_DEFAULT 0x1fab7 /* Reset by hreset: Private Device ID and Vendor ID */ +/* Subfields of ID */ +#define VREG_HT_ID_DEVID_MASK 0xffff0000 /* Device ID = 0x0001 [16..31] */ +#define VREG_HT_ID_VENDORID_MASK 0x0000ffff /* Vendor ID = 0xFAB7 [0..15] */ + + + + +/* Command and Status register (31..0) */ +#define VREG_HT_CMD_MASK 0xffffffff +#define VREG_HT_CMD_ACCESSMODE 2 +#define VREG_HT_CMD_HOSTPRIVILEGE 1 +#define VREG_HT_CMD_RESERVEDMASK 0x06e7fab8 +#define VREG_HT_CMD_WRITEMASK 0xf9000146 +#define VREG_HT_CMD_READMASK 0xf9180547 +#define VREG_HT_CMD_CLEARMASK 0xf9000000 +#define VREG_HT_CMD 0x004 +#define VREG_HT_CMD_ID 1 + +#define VVAL_HT_CMD_DEFAULT 0x100000 /* Reset by hreset: */ +/* Subfields of Cmd */ +#define VREG_HT_CMD_DATAERR_MASK 0x80000000 /* Data Error Detected [31..31] */ +#define VREG_HT_CMD_SYSERR_MASK 0x40000000 /* Signalled System Error [30..30] */ +#define VREG_HT_CMD_RCVMSTRABRT_MASK 0x20000000 /* Received a Master Abort [29..29] */ +#define VREG_HT_CMD_RCVTGTABRT_MASK 0x10000000 /* Received a Target Abort [28..28] */ +#define VREG_HT_CMD_SIGTGTABRT_MASK 0x08000000 /* Signalled a Target Abort [27..27] */ +#define VREG_HT_CMD_RSV1_MASK 0x06000000 /* Reserved - read as 0 [25..26] */ +#define VREG_HT_CMD_MSTRDATAERR_MASK 0x01000000 /* Master Data Error [24..24] */ +#define VREG_HT_CMD_RSV2_MASK 0x00e00000 /* Reserved - read as 0 [21..23] */ +#define VREG_HT_CMD_CAPLIST_MASK 0x00100000 /* Capabilities List Present - always 1 [20..20] */ +#define VREG_HT_CMD_INTSTATUS_MASK 0x00080000 /* Legacy Interrupt Status - always 0 [19..19] */ +#define VREG_HT_CMD_RSV3_MASK 0x00070000 /* Reserved - read as 0 [16..18] */ +#define VREG_HT_CMD_RSV4_MASK 0x0000f800 /* Reserved - read as 0 [11..15] */ +#define VREG_HT_CMD_INTDISABLE_MASK 0x00000400 /* Legacy Interrupt disable - always 0 [10..10] */ +#define VREG_HT_CMD_RSV5_MASK 0x00000200 /* Reserved - read as 0 [9..9] */ +#define VREG_HT_CMD_SERREN_MASK 0x00000100 /* Enable Sync flood on error [8..8] */ +#define VREG_HT_CMD_RSV6_MASK 0x00000080 /* Reserved - read as 0 [7..7] */ +#define VREG_HT_CMD_DERRRSP_MASK 0x00000040 /* Data Error Response [6..6] */ +#define VREG_HT_CMD_RSV7_MASK 0x00000038 /* Reserved - read as 0 [3..5] */ +#define VREG_HT_CMD_BUSMSTREN_MASK 0x00000004 /* Bus Master Enable [2..2] */ +#define VREG_HT_CMD_MEMSPACEEN_MASK 0x00000002 /* Memory Space Enable [1..1] */ +#define VREG_HT_CMD_IOSPACEEN_MASK 0x00000001 /* IO Space Enable [0..0] */ + + + + +/* Class Code and Revision ID (31..0) */ +#define VREG_HT_CLASSREV_MASK 0xffffffff +#define VREG_HT_CLASSREV_ACCESSMODE 1 +#define VREG_HT_CLASSREV_HOSTPRIVILEGE 1 +#define VREG_HT_CLASSREV_RESERVEDMASK 0x00000000 +#define VREG_HT_CLASSREV_WRITEMASK 0x00000000 +#define VREG_HT_CLASSREV_READMASK 0xffffffff +#define VREG_HT_CLASSREV_CLEARMASK 0x00000000 +#define VREG_HT_CLASSREV 0x008 +#define VREG_HT_CLASSREV_ID 2 + +#define VVAL_HT_CLASSREV_DEFAULT 0x8800001 /* Reset by hreset: Hardwired */ +/* Subfields of ClassRev */ +#define VREG_HT_CLASSREV_CLASS_MASK 0xffffff00 /* Class Code = 0x088000 [8..31] */ +#define VREG_HT_CLASSREV_REVID_MASK 0x000000ff /* Revision ID = 0x01 [0..7] */ + + + + +/* Cache Line Size register - not implemented (31..0) */ +#define VREG_HT_CACHELSZ_MASK 0xffffffff +#define VREG_HT_CACHELSZ_ACCESSMODE 1 +#define VREG_HT_CACHELSZ_HOSTPRIVILEGE 1 +#define VREG_HT_CACHELSZ_RESERVEDMASK 0x00000000 +#define VREG_HT_CACHELSZ_WRITEMASK 0x00000000 +#define VREG_HT_CACHELSZ_READMASK 0xffffffff +#define VREG_HT_CACHELSZ_CLEARMASK 0x00000000 +#define VREG_HT_CACHELSZ 0x00c +#define VREG_HT_CACHELSZ_ID 3 + +#define VVAL_HT_CACHELSZ_DEFAULT 0x800000 /* Reset by hreset: Default value */ +/* Subfields of CacheLSz */ +#define VREG_HT_CACHELSZ_BIST_MASK 0xff000000 /* BIST [24..31] */ +#define VREG_HT_CACHELSZ_MULTIFUNC_MASK 0x00800000 /* MultiFunction Device Flag [23..23] */ +#define VREG_HT_CACHELSZ_HDRTYPE_MASK 0x007f0000 /* Header Type [16..22] */ +#define VREG_HT_CACHELSZ_LATTIMER_MASK 0x0000ff00 /* Latency Timer [8..15] */ +#define VREG_HT_CACHELSZ_LINESZ_MASK 0x000000ff /* Cache Line Size [0..7] */ + + + + +/* Bits 31:0 of Memory Base Address - bits 23:0 are ignored and assumed to be 0 (31..0) */ +#define VREG_HT_MEMBASEADDR_LO_MASK 0xffffffff +#define VREG_HT_MEMBASEADDR_LO_ACCESSMODE 2 +#define VREG_HT_MEMBASEADDR_LO_HOSTPRIVILEGE 1 +#define VREG_HT_MEMBASEADDR_LO_RESERVEDMASK 0x00000000 +#define VREG_HT_MEMBASEADDR_LO_WRITEMASK 0xffffffff +#define VREG_HT_MEMBASEADDR_LO_READMASK 0xffffffff +#define VREG_HT_MEMBASEADDR_LO_CLEARMASK 0x00000000 +#define VREG_HT_MEMBASEADDR_LO 0x010 +#define VREG_HT_MEMBASEADDR_LO_ID 4 + +#define VVAL_HT_MEMBASEADDR_LO_DEFAULT 0x4 /* Reset by hreset: Reset to 0 */ + + +/* Bits 63:32 of Memory Base Address - bits 63:40 are ignored (31..0) */ +#define VREG_HT_MEMBASEADDR_HI_MASK 0xffffffff +#define VREG_HT_MEMBASEADDR_HI_ACCESSMODE 2 +#define VREG_HT_MEMBASEADDR_HI_HOSTPRIVILEGE 1 +#define VREG_HT_MEMBASEADDR_HI_RESERVEDMASK 0x00000000 +#define VREG_HT_MEMBASEADDR_HI_WRITEMASK 0xffffffff +#define VREG_HT_MEMBASEADDR_HI_READMASK 0xffffffff +#define VREG_HT_MEMBASEADDR_HI_CLEARMASK 0x00000000 +#define VREG_HT_MEMBASEADDR_HI 0x014 +#define VREG_HT_MEMBASEADDR_HI_ID 5 + +#define VVAL_HT_MEMBASEADDR_HI_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Pointer to Capability List (7..0) */ +#define VREG_HT_CAPPTR_MASK 0x000000ff +#define VREG_HT_CAPPTR_ACCESSMODE 1 +#define VREG_HT_CAPPTR_HOSTPRIVILEGE 1 +#define VREG_HT_CAPPTR_RESERVEDMASK 0x00000000 +#define VREG_HT_CAPPTR_WRITEMASK 0x00000000 +#define VREG_HT_CAPPTR_READMASK 0x000000ff +#define VREG_HT_CAPPTR_CLEARMASK 0x00000000 +#define VREG_HT_CAPPTR 0x034 +#define VREG_HT_CAPPTR_ID 13 + +#define VVAL_HT_CAPPTR_DEFAULT 0x40 /* Reset by hreset: */ + + +/* Sub rev ID for experimental versions of the part (7..0) */ +#define VREG_HT_EXPREV_MASK 0x000000ff +#define VREG_HT_EXPREV_ACCESSMODE 2 +#define VREG_HT_EXPREV_HOSTPRIVILEGE 1 +#define VREG_HT_EXPREV_RESERVEDMASK 0x00000000 +#define VREG_HT_EXPREV_WRITEMASK 0x000000ff +#define VREG_HT_EXPREV_READMASK 0x000000ff +#define VREG_HT_EXPREV_CLEARMASK 0x00000000 +#define VREG_HT_EXPREV 0x038 +#define VREG_HT_EXPREV_ID 14 + +#define VVAL_HT_EXPREV_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Line - RW scratchpad register (15..0) */ +#define VREG_HT_INT_MASK 0x0000ffff +#define VREG_HT_INT_ACCESSMODE 2 +#define VREG_HT_INT_HOSTPRIVILEGE 1 +#define VREG_HT_INT_RESERVEDMASK 0x00000000 +#define VREG_HT_INT_WRITEMASK 0x000000ff +#define VREG_HT_INT_READMASK 0x0000ffff +#define VREG_HT_INT_CLEARMASK 0x00000000 +#define VREG_HT_INT 0x03c +#define VREG_HT_INT_ID 15 + +#define VVAL_HT_INT_DEFAULT 0x100 /* Reset by hreset: Reset to 100 */ +/* Subfields of Int */ +#define VREG_HT_INT_PIN_MASK 0x0000ff00 /* Interrupt pin used by Function [8..15] */ +#define VREG_HT_INT_LINE_MASK 0x000000ff /* Interrupt Line assigned by Function BIOS [0..7] */ + + + + +/* Command and Capability Register (31..0) */ +#define VREG_HT_CAP0_MASK 0xffffffff +#define VREG_HT_CAP0_ACCESSMODE 2 +#define VREG_HT_CAP0_HOSTPRIVILEGE 1 +#define VREG_HT_CAP0_RESERVEDMASK 0x00000000 +#define VREG_HT_CAP0_WRITEMASK 0x101f0000 +#define VREG_HT_CAP0_READMASK 0xffffffff +#define VREG_HT_CAP0_CLEARMASK 0x00000000 +#define VREG_HT_CAP0 0x040 +#define VREG_HT_CAP0_ID 16 + /* Capability Header */ + +#define VVAL_HT_CAP0_DEFAULT 0x806008 /* Reset by hreset: */ +/* Subfields of Cap0 */ +#define VREG_HT_CAP0_TYPESLV_MASK 0xe0000000 /* Capability Type Field. Slave = 0x0 [29..31] */ +#define VREG_HT_CAP0_DROPUNINIT_MASK 0x10000000 /* Drop on Uninitialized Link. [28..28] */ +#define VREG_HT_CAP0_DIR_MASK 0x08000000 /* Default Direction. Ignored on cave. [27..27] */ +#define VREG_HT_CAP0_MSTRHOST_MASK 0x04000000 /* Indicates which link is path to master host bridge [26..26] */ +#define VREG_HT_CAP0_UNITCNT_MASK 0x03e00000 /* Number of UnitIDs required by this device [21..25] */ +#define VREG_HT_CAP0_BASEUNITID_MASK 0x001f0000 /* Base UnitID. Lowest numbered UnitID belonging to this device [16..20] */ +#define VREG_HT_CAP0_CAPPTR_MASK 0x0000ff00 /* Pointer to next Capability Block = 0x60 [8..15] */ +#define VREG_HT_CAP0_CAPID_MASK 0x000000ff /* Capability ID = 0x08 [0..7] */ + + + + +/* Link0 Config and Control Register (31..0) */ +#define VREG_HT_CAP1_MASK 0xffffffff +#define VREG_HT_CAP1_ACCESSMODE 2 +#define VREG_HT_CAP1_HOSTPRIVILEGE 1 +#define VREG_HT_CAP1_RESERVEDMASK 0x00000001 +#define VREG_HT_CAP1_WRITEMASK 0x77000f0a +#define VREG_HT_CAP1_READMASK 0xfffffffe +#define VREG_HT_CAP1_CLEARMASK 0x00000f00 +#define VREG_HT_CAP1 0x044 +#define VREG_HT_CAP1_ID 17 + +#define VVAL_HT_CAP1_DEFAULT 0x110000 /* Reset by hreset: Reset value */ +/* Subfields of Cap1 */ +#define VREG_HT_CAP1_CFG_DWFCOUTEN_MASK 0x80000000 /* Double Word Flow Control Out enable [31..31] */ +#define VREG_HT_CAP1_CFG_LWIDTHOUT_MASK 0x70000000 /* Link width to use for Output [28..30] */ +#define VREG_HT_CAP1_CFG_DWFCINEN_MASK 0x08000000 /* Double Word Flow Control In enable [27..27] */ +#define VREG_HT_CAP1_CFG_LWIDTHIN_MASK 0x07000000 /* Link width to use for Input [24..26] */ +#define VREG_HT_CAP1_CFG_DWFCOUT_MASK 0x00800000 /* Double Word Flow Control Out [23..23] */ +#define VREG_HT_CAP1_CFG_MAXWIDTHOUT_MASK 0x00700000 /* Maximum Link width of output port [20..22] */ +#define VREG_HT_CAP1_CFG_DWFCIN_MASK 0x00080000 /* Double Word Flow Control In [19..19] */ +#define VREG_HT_CAP1_CFG_MAXWIDTHIN_MASK 0x00070000 /* Maximum Link width of input port [16..18] */ +#define VREG_HT_CAP1_CTL_64BEN_MASK 0x00008000 /* Enable 64 bit addressing [15..15] */ +#define VREG_HT_CAP1_CTL_EXTCTLTIME_MASK 0x00004000 /* Assert CTL for 50 uSec after LDTSTOP [14..14] */ +#define VREG_HT_CAP1_CTL_LDTSTOPTE_MASK 0x00002000 /* Tristate link during LDTSTOP [13..13] */ +#define VREG_HT_CAP1_CTL_ISOCFCEN_MASK 0x00001000 /* Isochronous Flow Control Enable [12..12] */ +#define VREG_HT_CAP1_CTL_CRCERROR_MASK 0x00000f00 /* CRC Error [8..11] */ +#define VREG_HT_CAP1_CTL_XMITOFF_MASK 0x00000080 /* Transmitter Off - SW can set, not clear [7..7] */ +#define VREG_HT_CAP1_CTL_ENDOFCHAIN_MASK 0x00000040 /* End of Chain - SW can set, not clear [6..6] */ +#define VREG_HT_CAP1_CTL_INITDONE_MASK 0x00000020 /* Asserted when Initialization is complete [5..5] */ +#define VREG_HT_CAP1_CTL_LINKFAIL_MASK 0x00000010 /* Set if a Failure is detected on the link [4..4] */ +#define VREG_HT_CAP1_CTL_FRCCRCERR_MASK 0x00000008 /* Force CRC errors [3..3] */ +#define VREG_HT_CAP1_CTL_CRCTEST_MASK 0x00000004 /* Start CRC Test [2..2] */ +#define VREG_HT_CAP1_CTL_CRCFLOODEN_MASK 0x00000002 /* Generate Sync flood on CRC error [1..1] */ +#define VREG_HT_CAP1_CTL_RSV1_MASK 0x00000001 /* Reserved [0..0] */ + + + + +/* Link1 Config and Control Register (31..0) */ +#define VREG_HT_CAP2_MASK 0xffffffff +#define VREG_HT_CAP2_ACCESSMODE 1 +#define VREG_HT_CAP2_HOSTPRIVILEGE 1 +#define VREG_HT_CAP2_RESERVEDMASK 0x00000000 +#define VREG_HT_CAP2_WRITEMASK 0x00000000 +#define VREG_HT_CAP2_READMASK 0xffffffff +#define VREG_HT_CAP2_CLEARMASK 0x00000000 +#define VREG_HT_CAP2 0x048 +#define VREG_HT_CAP2_ID 18 + +#define VVAL_HT_CAP2_DEFAULT 0xd0 /* Reset by hreset: There is no second link */ +/* Subfields of Cap2 */ +#define VREG_HT_CAP2_CFG_DWFCOUTEN_MASK 0x80000000 /* Double Word Flow Control Out enable [31..31] */ +#define VREG_HT_CAP2_CFG_LWIDTHOUT_MASK 0x70000000 /* Link width to use for Output [28..30] */ +#define VREG_HT_CAP2_CFG_DWFCINEN_MASK 0x08000000 /* Double Word Flow Control In enable [27..27] */ +#define VREG_HT_CAP2_CFG_LWIDTHIN_MASK 0x07000000 /* Link width to use for Input [24..26] */ +#define VREG_HT_CAP2_CFG_DWFCOUT_MASK 0x00800000 /* Double Word Flow Control Out [23..23] */ +#define VREG_HT_CAP2_CFG_MAXWIDTHOUT_MASK 0x00700000 /* Maximum Link width of output port [20..22] */ +#define VREG_HT_CAP2_CFG_DWFCIN_MASK 0x00080000 /* Double Word Flow Control In [19..19] */ +#define VREG_HT_CAP2_CFG_MAXWIDTHIN_MASK 0x00070000 /* Maximum Link width of input port [16..18] */ +#define VREG_HT_CAP2_CTL_64BEN_MASK 0x00008000 /* Enable 64 bit addressing [15..15] */ +#define VREG_HT_CAP2_CTL_EXTCTLTIME_MASK 0x00004000 /* Assert CTL for 50 uSec after LDTSTOP [14..14] */ +#define VREG_HT_CAP2_CTL_LDTSTOPTE_MASK 0x00002000 /* Tristate link during LDTSTOP [13..13] */ +#define VREG_HT_CAP2_CTL_ISOCFCEN_MASK 0x00001000 /* Isochronous Flow Control Enable [12..12] */ +#define VREG_HT_CAP2_CTL_CRCERROR_MASK 0x00000f00 /* CRC Error [8..11] */ +#define VREG_HT_CAP2_CTL_XMITOFF_MASK 0x00000080 /* Transmitter Off [7..7] */ +#define VREG_HT_CAP2_CTL_ENDOFCHAIN_MASK 0x00000040 /* End of Chain [6..6] */ +#define VREG_HT_CAP2_CTL_INITDONE_MASK 0x00000020 /* Asserted when Initialization is complete [5..5] */ +#define VREG_HT_CAP2_CTL_LINKFAIL_MASK 0x00000010 /* Set if a Failure is detected on the link [4..4] */ +#define VREG_HT_CAP2_CTL_FRCCRCERR_MASK 0x00000008 /* Force CRC errors [3..3] */ +#define VREG_HT_CAP2_CTL_CRCTEST_MASK 0x00000004 /* Start CRC Test [2..2] */ +#define VREG_HT_CAP2_CTL_CRCFLOODEN_MASK 0x00000002 /* Generate Sync flood on CRC error [1..1] */ +#define VREG_HT_CAP2_CTL_RSV1_MASK 0x00000001 /* Reserved [0..0] */ + + + + +/* , Word 3 of Capability Block (31..0) */ +#define VREG_HT_CAP3_MASK 0xffffffff +#define VREG_HT_CAP3_ACCESSMODE 2 +#define VREG_HT_CAP3_HOSTPRIVILEGE 1 +#define VREG_HT_CAP3_RESERVEDMASK 0x00000000 +#define VREG_HT_CAP3_WRITEMASK 0x00006f00 +#define VREG_HT_CAP3_READMASK 0xffffffff +#define VREG_HT_CAP3_CLEARMASK 0x00006000 +#define VREG_HT_CAP3 0x04c +#define VREG_HT_CAP3_ID 19 + +#define VVAL_HT_CAP3_DEFAULT 0x50025 /* Reset by hreset: HT link rev 1.05, 200 and 400 MHz only */ +/* Subfields of Cap3 */ +#define VREG_HT_CAP3_FREQCAP_MASK 0xffff0000 /* Frequencies supported by device [16..31] */ +#define VREG_HT_CAP3_CTLTIMEOUT_MASK 0x00008000 /* CTL Timeout Error Detected [15..15] */ +#define VREG_HT_CAP3_EOCERR_MASK 0x00004000 /* End of Chain Error Detected [14..14] */ +#define VREG_HT_CAP3_OVFLERR_MASK 0x00002000 /* Buffer Overflow Error Detected [13..13] */ +#define VREG_HT_CAP3_PROTERR_MASK 0x00001000 /* Protocol Error Detected [12..12] */ +#define VREG_HT_CAP3_LINKFREQ_MASK 0x00000f00 /* Link Frequency Control [8..11] */ +#define VVAL_HT_CAP3_LINKFREQ_200 0x0 /* 200 Mhz */ +#define VVAL_HT_CAP3_LINKFREQ_400 0x200 /* 400 Mhz */ +#define VREG_HT_CAP3_MAJORREV_MASK 0x000000e0 /* Major HT revision level - 1 [5..7] */ +#define VREG_HT_CAP3_MINORREV_MASK 0x0000001f /* Minor HT revision level - .05 [0..4] */ + + + + +/* Word 4 of Capability Block (31..0) */ +#define VREG_HT_CAP4_MASK 0xffffffff +#define VREG_HT_CAP4_ACCESSMODE 1 +#define VREG_HT_CAP4_HOSTPRIVILEGE 1 +#define VREG_HT_CAP4_RESERVEDMASK 0x00000000 +#define VREG_HT_CAP4_WRITEMASK 0x00000000 +#define VREG_HT_CAP4_READMASK 0xffffffff +#define VREG_HT_CAP4_CLEARMASK 0x00000000 +#define VREG_HT_CAP4 0x050 +#define VREG_HT_CAP4_ID 20 + +#define VVAL_HT_CAP4_DEFAULT 0x0 /* Reset by hreset: No extra features */ + + +/* Word 4 of Capability Block (31..0) */ +#define VREG_HT_CAP5_MASK 0xffffffff +#define VREG_HT_CAP5_ACCESSMODE 2 +#define VREG_HT_CAP5_HOSTPRIVILEGE 1 +#define VREG_HT_CAP5_RESERVEDMASK 0x00000000 +#define VREG_HT_CAP5_WRITEMASK 0x7a7affff +#define VREG_HT_CAP5_READMASK 0xffffffff +#define VREG_HT_CAP5_CLEARMASK 0x02000000 +#define VREG_HT_CAP5 0x054 +#define VREG_HT_CAP5_ID 21 + +#define VVAL_HT_CAP5_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of Cap5 */ +#define VREG_HT_CAP5_SERRNFEEN_MASK 0x80000000 /* System Error Non-Fatal Interrupt Enable [31..31] */ +#define VREG_HT_CAP5_CRCNFEEN_MASK 0x40000000 /* CRC Error Non-Fatal Interrupt Enable [30..30] */ +#define VREG_HT_CAP5_RSPNFEEN_MASK 0x20000000 /* Response Error Non-Fatal Interrupt Enable [29..29] */ +#define VREG_HT_CAP5_EOCNFEEN_MASK 0x10000000 /* End of Chain Error Non-Fatal Interrupt Enable [28..28] */ +#define VREG_HT_CAP5_OVFLNFEEN_MASK 0x08000000 /* Overflow Error Non-Fatal Interrupt Enable [27..27] */ +#define VREG_HT_CAP5_PROTNFEEN_MASK 0x04000000 /* Protocol Error Non-Fatal Interrupt Enable [26..26] */ +#define VREG_HT_CAP5_RSPERROR_MASK 0x02000000 /* Set to indicate Response Error received [25..25] */ +#define VREG_HT_CAP5_CHAINFAIL_MASK 0x01000000 /* Set to indicate Sync flood received [24..24] */ +#define VREG_HT_CAP5_SERRFEEN_MASK 0x00800000 /* System Error Fatal Interrupt Enable [23..23] */ +#define VREG_HT_CAP5_CRCFEEN_MASK 0x00400000 /* CRC Error Fatal Interrupt Enable [22..22] */ +#define VREG_HT_CAP5_RSPFEEN_MASK 0x00200000 /* Response Error Fatal Interrupt Enable [21..21] */ +#define VREG_HT_CAP5_EOCFEEN_MASK 0x00100000 /* End of Chain Error Fatal Interrupt Enable [20..20] */ +#define VREG_HT_CAP5_OVFLFEEN_MASK 0x00080000 /* Overflow Error Fatal Interrupt Enable [19..19] */ +#define VREG_HT_CAP5_PROTFEEN_MASK 0x00040000 /* Protocol Error Fatal Interrupt Enable [18..18] */ +#define VREG_HT_CAP5_OVFLFLDEN_MASK 0x00020000 /* Overflow Error Flood Enable [17..17] */ +#define VREG_HT_CAP5_PROTFLDEN_MASK 0x00010000 /* Protocol Error Flood Enable [16..16] */ +#define VREG_HT_CAP5_SCRATCH_MASK 0x0000ffff /* Enumeration Scratchpad register [0..15] */ + + + +/* + * MSIX Table Structure + * One table entry is described here. + * There are a total of 19 table entries. + */ +/* Module MSIXTBL:96 */ + +/* MSIX PBA Structure - ReadOnly */ +/* Module MSIXPBA:97 */ + +/* MSI-X Discovery And Configuration Capability Block (31..0) */ +#define VREG_HT_MSIXCAP0_MASK 0xffffffff +#define VREG_HT_MSIXCAP0_ACCESSMODE 2 +#define VREG_HT_MSIXCAP0_HOSTPRIVILEGE 1 +#define VREG_HT_MSIXCAP0_RESERVEDMASK 0x38000000 +#define VREG_HT_MSIXCAP0_WRITEMASK 0xc0000000 +#define VREG_HT_MSIXCAP0_READMASK 0xc7ffffff +#define VREG_HT_MSIXCAP0_CLEARMASK 0x00000000 +#define VREG_HT_MSIXCAP0 0x060 +#define VREG_HT_MSIXCAP0_ID 24 + +#define VVAL_HT_MSIXCAP0_DEFAULT 0x120011 /* Reset by hreset: Reset value */ +/* Subfields of MsixCap0 */ +#define VREG_HT_MSIXCAP0_MSIX_EN_MASK 0x80000000 /* Enable MSI-X function [31..31] */ +#define VREG_HT_MSIXCAP0_FUNCMASK_MASK 0x40000000 /* Mask all MSI-X interrupts [30..30] */ +#define VREG_HT_MSIXCAP0_RSVD_MASK 0x38000000 /* Reserved [27..29] */ +#define VREG_HT_MSIXCAP0_TBLSIZE_MASK 0x07ff0000 /* MSI-X Table Size [16..26] */ +#define VREG_HT_MSIXCAP0_NEXT_MASK 0x0000ff00 /* pointer to next capability block [8..15] */ +#define VREG_HT_MSIXCAP0_ID_MASK 0x000000ff /* 0x11 MSI-X ID [0..7] */ + + + + +/* MSI-X Discovery And Configuration Capability Block (31..0) */ +#define VREG_HT_MSIXCAP1_MASK 0xffffffff +#define VREG_HT_MSIXCAP1_ACCESSMODE 2 +#define VREG_HT_MSIXCAP1_HOSTPRIVILEGE 1 +#define VREG_HT_MSIXCAP1_RESERVEDMASK 0x00000000 +#define VREG_HT_MSIXCAP1_WRITEMASK 0x00000000 +#define VREG_HT_MSIXCAP1_READMASK 0xffffffff +#define VREG_HT_MSIXCAP1_CLEARMASK 0x00000000 +#define VREG_HT_MSIXCAP1 0x064 +#define VREG_HT_MSIXCAP1_ID 25 + +#define VVAL_HT_MSIXCAP1_DEFAULT 0x600000 /* Reset by hreset: Reset value */ +/* Subfields of MsixCap1 */ +#define VREG_HT_MSIXCAP1_TBLOFFSET_MASK 0xfffffff8 /* Offset to MSI-X Table [3..31] */ +#define VREG_HT_MSIXCAP1_TBLBIR_MASK 0x00000007 /* BAR Index for Table [0..2] */ + + + + +/* MSI-X Discovery And Configuration Capability Block (31..0) */ +#define VREG_HT_MSIXCAP2_MASK 0xffffffff +#define VREG_HT_MSIXCAP2_ACCESSMODE 2 +#define VREG_HT_MSIXCAP2_HOSTPRIVILEGE 1 +#define VREG_HT_MSIXCAP2_RESERVEDMASK 0x00000000 +#define VREG_HT_MSIXCAP2_WRITEMASK 0x00000000 +#define VREG_HT_MSIXCAP2_READMASK 0xffffffff +#define VREG_HT_MSIXCAP2_CLEARMASK 0x00000000 +#define VREG_HT_MSIXCAP2 0x068 +#define VREG_HT_MSIXCAP2_ID 26 + +#define VVAL_HT_MSIXCAP2_DEFAULT 0x610000 /* Reset by hreset: Reset value */ +/* Subfields of MsixCap2 */ +#define VREG_HT_MSIXCAP2_PBAOFFSET_MASK 0xfffffff8 /* Offset to MSI-X Table [3..31] */ +#define VREG_HT_MSIXCAP2_PBABIR_MASK 0x00000007 /* BAR Index for Table [0..2] */ + + + + +/* Device and Vendor ID (31..0) */ +#define VREG_HT_ID_1_MASK 0xffffffff +#define VREG_HT_ID_1_ACCESSMODE 1 +#define VREG_HT_ID_1_HOSTPRIVILEGE 1 +#define VREG_HT_ID_1_RESERVEDMASK 0x00000000 +#define VREG_HT_ID_1_WRITEMASK 0x00000000 +#define VREG_HT_ID_1_READMASK 0xffffffff +#define VREG_HT_ID_1_CLEARMASK 0x00000000 +#define VREG_HT_ID_1 0x100 +#define VREG_HT_ID_1_ID 64 + /* Device Header */ + +#define VVAL_HT_ID_1_DEFAULT 0x9fab7 /* Reset by hreset: Private Device ID and Vendor ID */ +/* Subfields of ID_1 */ +#define VREG_HT_ID_1_DEVID_MASK 0xffff0000 /* Device ID = 0x0001 [16..31] */ +#define VREG_HT_ID_1_VENDORID_MASK 0x0000ffff /* Vendor ID = 0xFAB7 [0..15] */ + + + + +/* Command and Status register (31..0) */ +#define VREG_HT_CMD_1_MASK 0xffffffff +#define VREG_HT_CMD_1_ACCESSMODE 1 +#define VREG_HT_CMD_1_HOSTPRIVILEGE 1 +#define VREG_HT_CMD_1_RESERVEDMASK 0x00000000 +#define VREG_HT_CMD_1_WRITEMASK 0x00000000 +#define VREG_HT_CMD_1_READMASK 0xffffffff +#define VREG_HT_CMD_1_CLEARMASK 0x00000000 +#define VREG_HT_CMD_1 0x104 +#define VREG_HT_CMD_1_ID 65 + +#define VVAL_HT_CMD_1_DEFAULT 0x0 /* Reset by hreset: */ + + +/* Class Code and Revision ID (31..0) */ +#define VREG_HT_CLASSREV_1_MASK 0xffffffff +#define VREG_HT_CLASSREV_1_ACCESSMODE 1 +#define VREG_HT_CLASSREV_1_HOSTPRIVILEGE 1 +#define VREG_HT_CLASSREV_1_RESERVEDMASK 0x00000000 +#define VREG_HT_CLASSREV_1_WRITEMASK 0x00000000 +#define VREG_HT_CLASSREV_1_READMASK 0xffffffff +#define VREG_HT_CLASSREV_1_CLEARMASK 0x00000000 +#define VREG_HT_CLASSREV_1 0x108 +#define VREG_HT_CLASSREV_1_ID 66 + +#define VVAL_HT_CLASSREV_1_DEFAULT 0x8800001 /* Reset by hreset: Hardwired */ +/* Subfields of ClassRev_1 */ +#define VREG_HT_CLASSREV_1_CLASS_MASK 0xffffff00 /* Class Code = 0x088000 [8..31] */ +#define VREG_HT_CLASSREV_1_REVID_MASK 0x000000ff /* Revision ID = 0x01 [0..7] */ + + + + +/* Cache Line Size register - not implemented (31..0) */ +#define VREG_HT_CACHELSZ_1_MASK 0xffffffff +#define VREG_HT_CACHELSZ_1_ACCESSMODE 1 +#define VREG_HT_CACHELSZ_1_HOSTPRIVILEGE 1 +#define VREG_HT_CACHELSZ_1_RESERVEDMASK 0x00000000 +#define VREG_HT_CACHELSZ_1_WRITEMASK 0x00000000 +#define VREG_HT_CACHELSZ_1_READMASK 0xffffffff +#define VREG_HT_CACHELSZ_1_CLEARMASK 0x00000000 +#define VREG_HT_CACHELSZ_1 0x10c +#define VREG_HT_CACHELSZ_1_ID 67 + +#define VVAL_HT_CACHELSZ_1_DEFAULT 0x0 /* Reset by hreset: Default value */ + + +/* Hardwired to 0, No memory space (31..0) */ +#define VREG_HT_MBADDR_LO_1_MASK 0xffffffff +#define VREG_HT_MBADDR_LO_1_ACCESSMODE 1 +#define VREG_HT_MBADDR_LO_1_HOSTPRIVILEGE 1 +#define VREG_HT_MBADDR_LO_1_RESERVEDMASK 0x00000000 +#define VREG_HT_MBADDR_LO_1_WRITEMASK 0x00000000 +#define VREG_HT_MBADDR_LO_1_READMASK 0xffffffff +#define VREG_HT_MBADDR_LO_1_CLEARMASK 0x00000000 +#define VREG_HT_MBADDR_LO_1 0x110 +#define VREG_HT_MBADDR_LO_1_ID 68 + +#define VVAL_HT_MBADDR_LO_1_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Line - RW scratchpad register (15..0) */ +#define VREG_HT_INT_1_MASK 0x0000ffff +#define VREG_HT_INT_1_ACCESSMODE 2 +#define VREG_HT_INT_1_HOSTPRIVILEGE 1 +#define VREG_HT_INT_1_RESERVEDMASK 0x00000000 +#define VREG_HT_INT_1_WRITEMASK 0x000000ff +#define VREG_HT_INT_1_READMASK 0x0000ffff +#define VREG_HT_INT_1_CLEARMASK 0x00000000 +#define VREG_HT_INT_1 0x13c +#define VREG_HT_INT_1_ID 79 + +#define VVAL_HT_INT_1_DEFAULT 0x200 /* Reset by hreset: Reset to 200 */ +/* Subfields of Int_1 */ +#define VREG_HT_INT_1_PIN_MASK 0x0000ff00 /* Interrupt pin used by Function [8..15] */ +#define VREG_HT_INT_1_LINE_MASK 0x000000ff /* Interrupt Line assigned by Function BIOS [0..7] */ + + + + +/* Device and Vendor ID (31..0) */ +#define VREG_HT_ID_2_MASK 0xffffffff +#define VREG_HT_ID_2_ACCESSMODE 1 +#define VREG_HT_ID_2_HOSTPRIVILEGE 1 +#define VREG_HT_ID_2_RESERVEDMASK 0x00000000 +#define VREG_HT_ID_2_WRITEMASK 0x00000000 +#define VREG_HT_ID_2_READMASK 0xffffffff +#define VREG_HT_ID_2_CLEARMASK 0x00000000 +#define VREG_HT_ID_2 0x200 +#define VREG_HT_ID_2_ID 128 + /* Device Header */ + +#define VVAL_HT_ID_2_DEFAULT 0x9fab7 /* Reset by hreset: Private Device ID and Vendor ID */ +/* Subfields of ID_2 */ +#define VREG_HT_ID_2_DEVID_MASK 0xffff0000 /* Device ID = 0x0001 [16..31] */ +#define VREG_HT_ID_2_VENDORID_MASK 0x0000ffff /* Vendor ID = 0xFAB7 [0..15] */ + + + + +/* Command and Status register (31..0) */ +#define VREG_HT_CMD_2_MASK 0xffffffff +#define VREG_HT_CMD_2_ACCESSMODE 1 +#define VREG_HT_CMD_2_HOSTPRIVILEGE 1 +#define VREG_HT_CMD_2_RESERVEDMASK 0x00000000 +#define VREG_HT_CMD_2_WRITEMASK 0x00000000 +#define VREG_HT_CMD_2_READMASK 0xffffffff +#define VREG_HT_CMD_2_CLEARMASK 0x00000000 +#define VREG_HT_CMD_2 0x204 +#define VREG_HT_CMD_2_ID 129 + +#define VVAL_HT_CMD_2_DEFAULT 0x0 /* Reset by hreset: */ + + +/* Class Code and Revision ID (31..0) */ +#define VREG_HT_CLASSREV_2_MASK 0xffffffff +#define VREG_HT_CLASSREV_2_ACCESSMODE 1 +#define VREG_HT_CLASSREV_2_HOSTPRIVILEGE 1 +#define VREG_HT_CLASSREV_2_RESERVEDMASK 0x00000000 +#define VREG_HT_CLASSREV_2_WRITEMASK 0x00000000 +#define VREG_HT_CLASSREV_2_READMASK 0xffffffff +#define VREG_HT_CLASSREV_2_CLEARMASK 0x00000000 +#define VREG_HT_CLASSREV_2 0x208 +#define VREG_HT_CLASSREV_2_ID 130 + +#define VVAL_HT_CLASSREV_2_DEFAULT 0x8800001 /* Reset by hreset: Hardwired */ +/* Subfields of ClassRev_2 */ +#define VREG_HT_CLASSREV_2_CLASS_MASK 0xffffff00 /* Class Code = 0x088000 [8..31] */ +#define VREG_HT_CLASSREV_2_REVID_MASK 0x000000ff /* Revision ID = 0x01 [0..7] */ + + + + +/* Cache Line Size register - not implemented (31..0) */ +#define VREG_HT_CACHELSZ_2_MASK 0xffffffff +#define VREG_HT_CACHELSZ_2_ACCESSMODE 1 +#define VREG_HT_CACHELSZ_2_HOSTPRIVILEGE 1 +#define VREG_HT_CACHELSZ_2_RESERVEDMASK 0x00000000 +#define VREG_HT_CACHELSZ_2_WRITEMASK 0x00000000 +#define VREG_HT_CACHELSZ_2_READMASK 0xffffffff +#define VREG_HT_CACHELSZ_2_CLEARMASK 0x00000000 +#define VREG_HT_CACHELSZ_2 0x20c +#define VREG_HT_CACHELSZ_2_ID 131 + +#define VVAL_HT_CACHELSZ_2_DEFAULT 0x0 /* Reset by hreset: Default value */ + + +/* Hardwired to 0, No memory space (31..0) */ +#define VREG_HT_MBADDR_LO_2_MASK 0xffffffff +#define VREG_HT_MBADDR_LO_2_ACCESSMODE 1 +#define VREG_HT_MBADDR_LO_2_HOSTPRIVILEGE 1 +#define VREG_HT_MBADDR_LO_2_RESERVEDMASK 0x00000000 +#define VREG_HT_MBADDR_LO_2_WRITEMASK 0x00000000 +#define VREG_HT_MBADDR_LO_2_READMASK 0xffffffff +#define VREG_HT_MBADDR_LO_2_CLEARMASK 0x00000000 +#define VREG_HT_MBADDR_LO_2 0x210 +#define VREG_HT_MBADDR_LO_2_ID 132 + +#define VVAL_HT_MBADDR_LO_2_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Line - RW scratchpad register (15..0) */ +#define VREG_HT_INT_2_MASK 0x0000ffff +#define VREG_HT_INT_2_ACCESSMODE 2 +#define VREG_HT_INT_2_HOSTPRIVILEGE 1 +#define VREG_HT_INT_2_RESERVEDMASK 0x00000000 +#define VREG_HT_INT_2_WRITEMASK 0x000000ff +#define VREG_HT_INT_2_READMASK 0x0000ffff +#define VREG_HT_INT_2_CLEARMASK 0x00000000 +#define VREG_HT_INT_2 0x23c +#define VREG_HT_INT_2_ID 143 + +#define VVAL_HT_INT_2_DEFAULT 0x300 /* Reset by hreset: Reset to 300 */ +/* Subfields of Int_2 */ +#define VREG_HT_INT_2_PIN_MASK 0x0000ff00 /* Interrupt pin used by Function [8..15] */ +#define VREG_HT_INT_2_LINE_MASK 0x000000ff /* Interrupt Line assigned by Function BIOS [0..7] */ + + + + +/* Device and Vendor ID (31..0) */ +#define VREG_HT_ID_3_MASK 0xffffffff +#define VREG_HT_ID_3_ACCESSMODE 1 +#define VREG_HT_ID_3_HOSTPRIVILEGE 1 +#define VREG_HT_ID_3_RESERVEDMASK 0x00000000 +#define VREG_HT_ID_3_WRITEMASK 0x00000000 +#define VREG_HT_ID_3_READMASK 0xffffffff +#define VREG_HT_ID_3_CLEARMASK 0x00000000 +#define VREG_HT_ID_3 0x300 +#define VREG_HT_ID_3_ID 192 + /* Device Header */ + +#define VVAL_HT_ID_3_DEFAULT 0x9fab7 /* Reset by hreset: Private Device ID and Vendor ID */ +/* Subfields of ID_3 */ +#define VREG_HT_ID_3_DEVID_MASK 0xffff0000 /* Device ID = 0x0001 [16..31] */ +#define VREG_HT_ID_3_VENDORID_MASK 0x0000ffff /* Vendor ID = 0xFAB7 [0..15] */ + + + + +/* Command and Status register (31..0) */ +#define VREG_HT_CMD_3_MASK 0xffffffff +#define VREG_HT_CMD_3_ACCESSMODE 1 +#define VREG_HT_CMD_3_HOSTPRIVILEGE 1 +#define VREG_HT_CMD_3_RESERVEDMASK 0x00000000 +#define VREG_HT_CMD_3_WRITEMASK 0x00000000 +#define VREG_HT_CMD_3_READMASK 0xffffffff +#define VREG_HT_CMD_3_CLEARMASK 0x00000000 +#define VREG_HT_CMD_3 0x304 +#define VREG_HT_CMD_3_ID 193 + +#define VVAL_HT_CMD_3_DEFAULT 0x0 /* Reset by hreset: */ + + +/* Class Code and Revision ID (31..0) */ +#define VREG_HT_CLASSREV_3_MASK 0xffffffff +#define VREG_HT_CLASSREV_3_ACCESSMODE 1 +#define VREG_HT_CLASSREV_3_HOSTPRIVILEGE 1 +#define VREG_HT_CLASSREV_3_RESERVEDMASK 0x00000000 +#define VREG_HT_CLASSREV_3_WRITEMASK 0x00000000 +#define VREG_HT_CLASSREV_3_READMASK 0xffffffff +#define VREG_HT_CLASSREV_3_CLEARMASK 0x00000000 +#define VREG_HT_CLASSREV_3 0x308 +#define VREG_HT_CLASSREV_3_ID 194 + +#define VVAL_HT_CLASSREV_3_DEFAULT 0x8800001 /* Reset by hreset: Hardwired */ +/* Subfields of ClassRev_3 */ +#define VREG_HT_CLASSREV_3_CLASS_MASK 0xffffff00 /* Class Code = 0x088000 [8..31] */ +#define VREG_HT_CLASSREV_3_REVID_MASK 0x000000ff /* Revision ID = 0x01 [0..7] */ + + + + +/* Cache Line Size register - not implemented (31..0) */ +#define VREG_HT_CACHELSZ_3_MASK 0xffffffff +#define VREG_HT_CACHELSZ_3_ACCESSMODE 1 +#define VREG_HT_CACHELSZ_3_HOSTPRIVILEGE 1 +#define VREG_HT_CACHELSZ_3_RESERVEDMASK 0x00000000 +#define VREG_HT_CACHELSZ_3_WRITEMASK 0x00000000 +#define VREG_HT_CACHELSZ_3_READMASK 0xffffffff +#define VREG_HT_CACHELSZ_3_CLEARMASK 0x00000000 +#define VREG_HT_CACHELSZ_3 0x30c +#define VREG_HT_CACHELSZ_3_ID 195 + +#define VVAL_HT_CACHELSZ_3_DEFAULT 0x0 /* Reset by hreset: Default value */ + + +/* Hardwired to 0, No memory space (31..0) */ +#define VREG_HT_MBADDR_LO_3_MASK 0xffffffff +#define VREG_HT_MBADDR_LO_3_ACCESSMODE 1 +#define VREG_HT_MBADDR_LO_3_HOSTPRIVILEGE 1 +#define VREG_HT_MBADDR_LO_3_RESERVEDMASK 0x00000000 +#define VREG_HT_MBADDR_LO_3_WRITEMASK 0x00000000 +#define VREG_HT_MBADDR_LO_3_READMASK 0xffffffff +#define VREG_HT_MBADDR_LO_3_CLEARMASK 0x00000000 +#define VREG_HT_MBADDR_LO_3 0x310 +#define VREG_HT_MBADDR_LO_3_ID 196 + +#define VVAL_HT_MBADDR_LO_3_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Interrupt Line - RW scratchpad register (15..0) */ +#define VREG_HT_INT_3_MASK 0x0000ffff +#define VREG_HT_INT_3_ACCESSMODE 2 +#define VREG_HT_INT_3_HOSTPRIVILEGE 1 +#define VREG_HT_INT_3_RESERVEDMASK 0x00000000 +#define VREG_HT_INT_3_WRITEMASK 0x000000ff +#define VREG_HT_INT_3_READMASK 0x0000ffff +#define VREG_HT_INT_3_CLEARMASK 0x00000000 +#define VREG_HT_INT_3 0x33c +#define VREG_HT_INT_3_ID 207 + +#define VVAL_HT_INT_3_DEFAULT 0x400 /* Reset by hreset: Reset to 400 */ +/* Subfields of Int_3 */ +#define VREG_HT_INT_3_PIN_MASK 0x0000ff00 /* Interrupt pin used by Function [8..15] */ +#define VREG_HT_INT_3_LINE_MASK 0x000000ff /* Interrupt Line assigned by Function BIOS [0..7] */ + + + + +/* Collection of internal SRAM parity error (31..0) */ +#define VREG_HT_PARERR_MASK 0xffffffff +#define VREG_HT_PARERR_ACCESSMODE 3 +#define VREG_HT_PARERR_HOSTPRIVILEGE 1 +#define VREG_HT_PARERR_RESERVEDMASK 0x00000000 +#define VREG_HT_PARERR_WRITEMASK 0xffffffff +#define VREG_HT_PARERR_READMASK 0xffffffff +#define VREG_HT_PARERR_CLEARMASK 0xffffffff +#define VREG_HT_PARERR 0x700 +#define VREG_HT_PARERR_ID 448 + +#define VVAL_HT_PARERR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + +#endif /* _VIOC_HT_REGISTERS_H_ */ diff --git a/drivers/net/vioc/f7/vioc_hw_registers.h b/drivers/net/vioc/f7/vioc_hw_registers.h new file mode 100644 index 0000000..58379b6 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_hw_registers.h @@ -0,0 +1,160 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_HW_REGISTERS_H_ +#define _VIOC_HW_REGISTERS_H_ + +/* Constructs a relative address, independent of PCI base address */ +#define GETRELADDR(module, vnic, reg) \ + (u64) (((module & 0xFF) << 16) | ((vnic & 0xF) << 12) | (reg & 0xFFC)) + +#include + +#ifdef __cplusplus +extern "C" { +#endif +#define VIOC_RESERVED_00 0x00 +#define VIOC_BMC 0x01 /* BMC Interface Module */ +#define VIOC_SIM 0x02 /* SIM Interface Module */ +#define VIOC_RESERVED_03 0x03 +#define VIOC_HT 0x04 /* HT Target Module */ +#define VIOC_TCAM 0x05 /* TCAM read/write interface Module */ +#define VIOC_DRAM 0x06 /* DRAM Interface Module */ +#define VIOC_C6RX 0x07 /* CSIX Receive Module */ +#define VIOC_C6FPU 0x08 /* CSIX Frame Parser Unit Module */ +#define VIOC_F7LE 0x09 /* F7 Lookup Engine Module */ + +#define VIOC_RESERVED_0A 0x0A +#define VIOC_RESERVED_0B 0x0B +#define VIOC_RESERVED_0C 0x0C +#define VIOC_RESERVED_0D 0x0D +#define VIOC_RESERVED_0E 0x0E +#define VIOC_RESERVED_0F 0x0F +#define VIOC_VING 0x10 /* VIOC Ingress Module */ +#define VIOC_IHCU 0x11 /* Ingress Host Control Unit Module */ +#define VIOC_PERFMON 0x12 /* Performance Counter and Statistics */ +#define VIOC_RESERVED_13 0x13 +#define VIOC_RESERVED_14 0x14 +#define VIOC_APIC 0x15 /* IO APIC Configuration Registers */ +#define VIOC_RESERVED_16 0x16 +#define VIOC_RESERVED_17 0x17 +#define VIOC_RESERVED_18 0x18 +#define VIOC_RESERVED_19 0x19 +#define VIOC_RESERVED_1A 0x1A +#define VIOC_RESERVED_1B 0x1B +#define VIOC_RESERVED_1C 0x1C +#define VIOC_RESERVED_1D 0x1D +#define VIOC_RESERVED_1E 0x1E +#define VIOC_RESERVED_1F 0x1F +#define VIOC_VENG 0x20 /* VIOC Egress Module */ +#define VIOC_RESERVED_21 0x21 +#define VIOC_RESERVED_22 0x22 +#define VIOC_RESERVED_23 0x23 +#define VIOC_RESERVED_24 0x24 +#define VIOC_RESERVED_25 0x25 +#define VIOC_RESERVED_26 0x26 +#define VIOC_RESERVED_27 0x27 +#define VIOC_RESERVED_28 0x28 +#define VIOC_RESERVED_29 0x29 +#define VIOC_RESERVED_2A 0x2A +#define VIOC_RESERVED_2B 0x2B +#define VIOC_RESERVED_2C 0x2C +#define VIOC_RESERVED_2D 0x2D +#define VIOC_RESERVED_2E 0x2E +#define VIOC_RESERVED_2F 0x2F +#define VIOC_VARB 0x30 /* VIOC Arbiter Module */ +#define VIOC_RESERVED_31 0x31 +#define VIOC_RESERVED_32 0x32 +#define VIOC_RESERVED_33 0x33 +#define VIOC_RESERVED_34 0x34 +#define VIOC_RESERVED_35 0x35 +#define VIOC_RESERVED_36 0x36 +#define VIOC_RESERVED_37 0x37 +#define VIOC_RESERVED_38 0x38 +#define VIOC_RESERVED_39 0x39 +#define VIOC_RESERVED_3A 0x3A +#define VIOC_RESERVED_3B 0x3B +#define VIOC_RESERVED_3C 0x3C +#define VIOC_RESERVED_3D 0x3D +#define VIOC_RESERVED_3E 0x3E +#define VIOC_RESERVED_3F 0x3F +#define VIOC_F7MP 0x40 /* F7MP Control Module */ +#define VIOC_RESERVED_41 0x41 +#define VIOC_RESERVED_42 0x42 +#define VIOC_RESERVED_43 0x43 +#define VIOC_RESERVED_44 0x44 +#define VIOC_RESERVED_45 0x45 +#define VIOC_RESERVED_46 0x46 +#define VIOC_RESERVED_47 0x47 +#define VIOC_RESERVED_48 0x48 +#define VIOC_RESERVED_49 0x49 +#define VIOC_RESERVED_4A 0x4A +#define VIOC_RESERVED_4B 0x4B +#define VIOC_RESERVED_4C 0x4C +#define VIOC_RESERVED_4D 0x4D +#define VIOC_RESERVED_4E 0x4E +#define VIOC_RESERVED_4F 0x4F +#define VIOC_RESERVED_50 0x50 +#define VIOC_RESERVED_51 0x51 +#define VIOC_RESERVED_52 0x52 +#define VIOC_RESERVED_53 0x53 +#define VIOC_RESERVED_54 0x54 +#define VIOC_RESERVED_55 0x55 +#define VIOC_RESERVED_56 0x56 +#define VIOC_RESERVED_57 0x57 +#define VIOC_RESERVED_58 0x58 +#define VIOC_RESERVED_59 0x59 +#define VIOC_RESERVED_5A 0x5A +#define VIOC_RESERVED_5B 0x5B +#define VIOC_RESERVED_5C 0x5C +#define VIOC_RESERVED_5D 0x5D +#define VIOC_RESERVED_5E 0x5E +#define VIOC_RESERVED_5F 0x5F +#define VIOC_MSIXTBL 0x60 /* MSIX Table Structure */ +#define VIOC_MSIXPBA 0x61 /* MSIX Pending Bit Array Structure */ + + + +#define VIOC_MAX_VNICS 16 +#define VIOC_MAX_MODULES 98 +#if !defined(VIOC_MAX_VIOCS) // can be overridden +#define VIOC_MAX_VIOCS 4 +#endif /* VIOC_MAX_VIOS */ +#define VIOC_MAX_VNIC_REGISTERS 1023 +#ifdef __cplusplus +} +#endif + +#include "vioc_ihcu_registers.h" +#include "vioc_bmc_registers.h" +#include "vioc_ht_registers.h" +#include "vioc_msi_registers.h" +#include "vioc_le_registers.h" +#include "vioc_ving_registers.h" +#include "vioc_veng_registers.h" + +#endif /* _VIOC_HW_REGISTERS_H_ */ diff --git a/drivers/net/vioc/f7/vioc_ihcu_registers.h b/drivers/net/vioc/f7/vioc_ihcu_registers.h new file mode 100644 index 0000000..1992088 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_ihcu_registers.h @@ -0,0 +1,550 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_IHCU_REGISTERS_H_ +#define _VIOC_IHCU_REGISTERS_H_ + +/* Module IHCU:17 */ + +/* Collection of internal SRAM parity error (31..0) */ +#define VREG_IHCU_PARERR_MASK 0xffffffff +#define VREG_IHCU_PARERR_ACCESSMODE 2 +#define VREG_IHCU_PARERR_HOSTPRIVILEGE 1 +#define VREG_IHCU_PARERR_RESERVEDMASK 0xfffff800 +#define VREG_IHCU_PARERR_WRITEMASK 0x000007ff +#define VREG_IHCU_PARERR_READMASK 0x000007ff +#define VREG_IHCU_PARERR_CLEARMASK 0x000007ff +#define VREG_IHCU_PARERR 0x100 +#define VREG_IHCU_PARERR_ID 64 + +#define VVAL_IHCU_PARERR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of ParErr */ +#define VREG_IHCU_PARERR_RESV0_MASK 0xfffff800 /* Unused [11..31] */ +#define VREG_IHCU_PARERR_MCTHREAD0_MASK 0x00000400 /* Bank 0 of Multicast Thread RAM [10..10] */ +#define VREG_IHCU_PARERR_MCTHREAD1_MASK 0x00000200 /* Bank 0 of Multicast Thread RAM [9..9] */ +#define VREG_IHCU_PARERR_RXCOFF_MASK 0x00000100 /* RxC Offset RAM [8..8] */ +#define VREG_IHCU_PARERR_RXCPTR_MASK 0x00000080 /* RxC Current Pointer [7..7] */ +#define VREG_IHCU_PARERR_RXDQMAP_MASK 0x00000040 /* RxD to VNIC Q reverse map RAM [6..6] */ +#define VREG_IHCU_PARERR_VNICQRXD_MASK 0x00000020 /* VNIC Q to RxD map RAM [5..5] */ +#define VREG_IHCU_PARERR_RXDBUFLEN_MASK 0x00000010 /* RxD Buffer Length RAM [4..4] */ +#define VREG_IHCU_PARERR_VNICQRXC_MASK 0x00000008 /* VNIC Q to RxC map RAM [3..3] */ +#define VREG_IHCU_PARERR_RXCBALO_MASK 0x00000004 /* RxC Base Address SRAM [2..2] */ +#define VREG_IHCU_PARERR_RXCBAHI_MASK 0x00000002 /* RxC Base Address SRAM [1..1] */ +#define VREG_IHCU_PARERR_THMEM_MASK 0x00000001 /* Thread state Memory RAM [0..0] */ + + + + +/* RxD Queue Definition - Base address (31..0) */ +#define VREG_IHCU_RXD_W0_MASK 0xffffffff +#define VREG_IHCU_RXD_W0_ACCESSMODE 2 +#define VREG_IHCU_RXD_W0_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXD_W0_RESERVEDMASK 0x0000003f +#define VREG_IHCU_RXD_W0_WRITEMASK 0xffffffc0 +#define VREG_IHCU_RXD_W0_READMASK 0xffffffc0 +#define VREG_IHCU_RXD_W0_CLEARMASK 0x00000000 +#define VREG_IHCU_RXD_W0 0x200 +#define VREG_IHCU_RXD_W0_ID 128 + +/* Subfields of RxD_W0 */ +#define VREG_IHCU_RXD_W0_BA_LO_MASK 0xffffffc0 /* Bits 31:6 of the RxD ring base address [6..31] */ +#define VREG_IHCU_RXD_W0_RSV_MASK 0x0000003f /* Reserved [0..5] */ + + +#define VREG_IHCU_RXD_W0_R0 0x200 +#define VREG_IHCU_RXD_W0_R1 0x210 +#define VREG_IHCU_RXD_W0_R2 0x220 +#define VREG_IHCU_RXD_W0_R3 0x230 +#define VREG_IHCU_RXD_W0_R4 0x240 +#define VREG_IHCU_RXD_W0_R5 0x250 +#define VREG_IHCU_RXD_W0_R6 0x260 +#define VREG_IHCU_RXD_W0_R7 0x270 +#define VREG_IHCU_RXD_W0_R8 0x280 +#define VREG_IHCU_RXD_W0_R9 0x290 +#define VREG_IHCU_RXD_W0_R10 0x2A0 +#define VREG_IHCU_RXD_W0_R11 0x2B0 +#define VREG_IHCU_RXD_W0_R12 0x2C0 +#define VREG_IHCU_RXD_W0_R13 0x2D0 +#define VREG_IHCU_RXD_W0_R14 0x2E0 +#define VREG_IHCU_RXD_W0_R15 0x2F0 + + +/* RxD Queue Definition (31..0) */ +#define VREG_IHCU_RXD_W1_MASK 0xffffffff +#define VREG_IHCU_RXD_W1_ACCESSMODE 2 +#define VREG_IHCU_RXD_W1_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXD_W1_RESERVEDMASK 0xff000000 +#define VREG_IHCU_RXD_W1_WRITEMASK 0x00ffffff +#define VREG_IHCU_RXD_W1_READMASK 0x00ffffff +#define VREG_IHCU_RXD_W1_CLEARMASK 0x00000000 +#define VREG_IHCU_RXD_W1 0x204 +#define VREG_IHCU_RXD_W1_ID 129 + +/* Subfields of RxD_W1 */ +#define VREG_IHCU_RXD_W1_RSV1_MASK 0xff000000 /* Reserved [24..31] */ +#define VREG_IHCU_RXD_W1_SIZE_MASK 0x00ffff00 /* Number of descriptors in the queue [8..23] */ +#define VREG_IHCU_RXD_W1_BA_HI_MASK 0x000000ff /* Bits 39:32 of base address [0..7] */ + + +#define VREG_IHCU_RXD_W1_R0 0x204 +#define VREG_IHCU_RXD_W1_R1 0x214 +#define VREG_IHCU_RXD_W1_R2 0x224 +#define VREG_IHCU_RXD_W1_R3 0x234 +#define VREG_IHCU_RXD_W1_R4 0x244 +#define VREG_IHCU_RXD_W1_R5 0x254 +#define VREG_IHCU_RXD_W1_R6 0x264 +#define VREG_IHCU_RXD_W1_R7 0x274 +#define VREG_IHCU_RXD_W1_R8 0x284 +#define VREG_IHCU_RXD_W1_R9 0x294 +#define VREG_IHCU_RXD_W1_R10 0x2A4 +#define VREG_IHCU_RXD_W1_R11 0x2B4 +#define VREG_IHCU_RXD_W1_R12 0x2C4 +#define VREG_IHCU_RXD_W1_R13 0x2D4 +#define VREG_IHCU_RXD_W1_R14 0x2E4 +#define VREG_IHCU_RXD_W1_R15 0x2F4 + + +/* RxD Queue Definition (31..0) */ +#define VREG_IHCU_RXD_W2_MASK 0xffffffff +#define VREG_IHCU_RXD_W2_ACCESSMODE 2 +#define VREG_IHCU_RXD_W2_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXD_W2_RESERVEDMASK 0xffffc000 +#define VREG_IHCU_RXD_W2_WRITEMASK 0x00003fff +#define VREG_IHCU_RXD_W2_READMASK 0x00003fff +#define VREG_IHCU_RXD_W2_CLEARMASK 0x00000000 +#define VREG_IHCU_RXD_W2 0x208 +#define VREG_IHCU_RXD_W2_ID 130 + +/* Subfields of RxD_W2 */ +#define VREG_IHCU_RXD_W2_RSV1_MASK 0xffff0000 /* Reserved [16..31] */ +#define VREG_IHCU_RXD_W2_RSV2_MASK 0x0000c000 /* Reserved [14..15] */ +#define VREG_IHCU_RXD_W2_BUFSIZE_MASK 0x00003fff /* Size of queued buffers, in bytes [0..13] */ + + +#define VREG_IHCU_RXD_W2_R0 0x208 +#define VREG_IHCU_RXD_W2_R1 0x218 +#define VREG_IHCU_RXD_W2_R2 0x228 +#define VREG_IHCU_RXD_W2_R3 0x238 +#define VREG_IHCU_RXD_W2_R4 0x248 +#define VREG_IHCU_RXD_W2_R5 0x258 +#define VREG_IHCU_RXD_W2_R6 0x268 +#define VREG_IHCU_RXD_W2_R7 0x278 +#define VREG_IHCU_RXD_W2_R8 0x288 +#define VREG_IHCU_RXD_W2_R9 0x298 +#define VREG_IHCU_RXD_W2_R10 0x2A8 +#define VREG_IHCU_RXD_W2_R11 0x2B8 +#define VREG_IHCU_RXD_W2_R12 0x2C8 +#define VREG_IHCU_RXD_W2_R13 0x2D8 +#define VREG_IHCU_RXD_W2_R14 0x2E8 +#define VREG_IHCU_RXD_W2_R15 0x2F8 + + +/* RxD Queue Status (31..0) */ +#define VREG_IHCU_RXD_W3_MASK 0xffffffff +#define VREG_IHCU_RXD_W3_ACCESSMODE 2 +#define VREG_IHCU_RXD_W3_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXD_W3_RESERVEDMASK 0x7fffc000 +#define VREG_IHCU_RXD_W3_WRITEMASK 0x80000000 +#define VREG_IHCU_RXD_W3_READMASK 0x80003fff +#define VREG_IHCU_RXD_W3_CLEARMASK 0x00000000 +#define VREG_IHCU_RXD_W3 0x20c +#define VREG_IHCU_RXD_W3_ID 131 + /* Any packets arriving to a Paused RxD will be dropped */ + +/* Subfields of RxD_W3 */ +#define VREG_IHCU_RXD_W3_PAUSEREQ_MASK 0x80000000 /* Temporarily stop enqeueing on this RxD [31..31] */ +#define VREG_IHCU_RXD_W3_RSV1_MASK 0x7fffc000 /* Reserved [14..30] */ +#define VREG_IHCU_RXD_W3_CURRRDPTR_MASK 0x00003fff /* Offset in RxD of NEXT descriptor to be used [0..13] */ + + +#define VREG_IHCU_RXD_W3_R0 0x20C +#define VREG_IHCU_RXD_W3_R1 0x21C +#define VREG_IHCU_RXD_W3_R2 0x22C +#define VREG_IHCU_RXD_W3_R3 0x23C +#define VREG_IHCU_RXD_W3_R4 0x24C +#define VREG_IHCU_RXD_W3_R5 0x25C +#define VREG_IHCU_RXD_W3_R6 0x26C +#define VREG_IHCU_RXD_W3_R7 0x27C +#define VREG_IHCU_RXD_W3_R8 0x28C +#define VREG_IHCU_RXD_W3_R9 0x29C +#define VREG_IHCU_RXD_W3_R10 0x2AC +#define VREG_IHCU_RXD_W3_R11 0x2BC +#define VREG_IHCU_RXD_W3_R12 0x2CC +#define VREG_IHCU_RXD_W3_R13 0x2DC +#define VREG_IHCU_RXD_W3_R14 0x2EC +#define VREG_IHCU_RXD_W3_R15 0x2FC + + +/* RxC Queue Definition - Base address (31..0) */ +#define VREG_IHCU_RXC_LO_MASK 0xffffffff +#define VREG_IHCU_RXC_LO_ACCESSMODE 2 +#define VREG_IHCU_RXC_LO_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXC_LO_RESERVEDMASK 0x0000003f +#define VREG_IHCU_RXC_LO_WRITEMASK 0xffffffc0 +#define VREG_IHCU_RXC_LO_READMASK 0xffffffc0 +#define VREG_IHCU_RXC_LO_CLEARMASK 0x00000000 +#define VREG_IHCU_RXC_LO 0x400 +#define VREG_IHCU_RXC_LO_ID 256 + +/* Subfields of RxC_Lo */ +#define VREG_IHCU_RXC_LO_BA_LO_MASK 0xffffffc0 /* Bits 31:6 of base address [6..31] */ +#define VREG_IHCU_RXC_LO_RSV_MASK 0x0000003f /* Reserved [0..5] */ + + +#define VREG_IHCU_RXC_LO_R0 0x400 +#define VREG_IHCU_RXC_LO_R1 0x410 +#define VREG_IHCU_RXC_LO_R2 0x420 +#define VREG_IHCU_RXC_LO_R3 0x430 +#define VREG_IHCU_RXC_LO_R4 0x440 +#define VREG_IHCU_RXC_LO_R5 0x450 +#define VREG_IHCU_RXC_LO_R6 0x460 +#define VREG_IHCU_RXC_LO_R7 0x470 +#define VREG_IHCU_RXC_LO_R8 0x480 +#define VREG_IHCU_RXC_LO_R9 0x490 +#define VREG_IHCU_RXC_LO_R10 0x4A0 +#define VREG_IHCU_RXC_LO_R11 0x4B0 +#define VREG_IHCU_RXC_LO_R12 0x4C0 +#define VREG_IHCU_RXC_LO_R13 0x4D0 +#define VREG_IHCU_RXC_LO_R14 0x4E0 +#define VREG_IHCU_RXC_LO_R15 0x4F0 + + +/* RxC Queue Definition (31..0) */ +#define VREG_IHCU_RXC_HI_MASK 0xffffffff +#define VREG_IHCU_RXC_HI_ACCESSMODE 2 +#define VREG_IHCU_RXC_HI_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXC_HI_RESERVEDMASK 0xff000000 +#define VREG_IHCU_RXC_HI_WRITEMASK 0x00ffffff +#define VREG_IHCU_RXC_HI_READMASK 0x00ffffff +#define VREG_IHCU_RXC_HI_CLEARMASK 0x00000000 +#define VREG_IHCU_RXC_HI 0x404 +#define VREG_IHCU_RXC_HI_ID 257 + +/* Subfields of RxC_Hi */ +#define VREG_IHCU_RXC_HI_RSV1_MASK 0xff000000 /* Reserved [24..31] */ +#define VREG_IHCU_RXC_HI_SIZE_MASK 0x00ffff00 /* Number of descriptors in the queue [8..23] */ +#define VREG_IHCU_RXC_HI_BA_HI_MASK 0x000000ff /* Bits 39:32 of base address [0..7] */ + + +#define VREG_IHCU_RXC_HI_R0 0x404 +#define VREG_IHCU_RXC_HI_R1 0x414 +#define VREG_IHCU_RXC_HI_R2 0x424 +#define VREG_IHCU_RXC_HI_R3 0x434 +#define VREG_IHCU_RXC_HI_R4 0x444 +#define VREG_IHCU_RXC_HI_R5 0x454 +#define VREG_IHCU_RXC_HI_R6 0x464 +#define VREG_IHCU_RXC_HI_R7 0x474 +#define VREG_IHCU_RXC_HI_R8 0x484 +#define VREG_IHCU_RXC_HI_R9 0x494 +#define VREG_IHCU_RXC_HI_R10 0x4A4 +#define VREG_IHCU_RXC_HI_R11 0x4B4 +#define VREG_IHCU_RXC_HI_R12 0x4C4 +#define VREG_IHCU_RXC_HI_R13 0x4D4 +#define VREG_IHCU_RXC_HI_R14 0x4E4 +#define VREG_IHCU_RXC_HI_R15 0x4F4 + + +/* RxC Queue Definition - Interrupt (3..0) */ +#define VREG_IHCU_RXC_INT_MASK 0x0000000f +#define VREG_IHCU_RXC_INT_ACCESSMODE 2 +#define VREG_IHCU_RXC_INT_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXC_INT_RESERVEDMASK 0x00000000 +#define VREG_IHCU_RXC_INT_WRITEMASK 0x0000000f +#define VREG_IHCU_RXC_INT_READMASK 0x0000000f +#define VREG_IHCU_RXC_INT_CLEARMASK 0x00000000 +#define VREG_IHCU_RXC_INT 0x408 +#define VREG_IHCU_RXC_INT_ID 258 + /* RxC_Int specifies which interrupt will get sent for this completion queue */ + +#define VREG_IHCU_RXC_INT_R0 0x408 +#define VREG_IHCU_RXC_INT_R1 0x418 +#define VREG_IHCU_RXC_INT_R2 0x428 +#define VREG_IHCU_RXC_INT_R3 0x438 +#define VREG_IHCU_RXC_INT_R4 0x448 +#define VREG_IHCU_RXC_INT_R5 0x458 +#define VREG_IHCU_RXC_INT_R6 0x468 +#define VREG_IHCU_RXC_INT_R7 0x478 +#define VREG_IHCU_RXC_INT_R8 0x488 +#define VREG_IHCU_RXC_INT_R9 0x498 +#define VREG_IHCU_RXC_INT_R10 0x4A8 +#define VREG_IHCU_RXC_INT_R11 0x4B8 +#define VREG_IHCU_RXC_INT_R12 0x4C8 +#define VREG_IHCU_RXC_INT_R13 0x4D8 +#define VREG_IHCU_RXC_INT_R14 0x4E8 +#define VREG_IHCU_RXC_INT_R15 0x4F8 + + +/* Minimum time to wait between checking RxD queue state (12..0) */ +#define VREG_IHCU_SLEEPTIME_MASK 0x00001fff +#define VREG_IHCU_SLEEPTIME_ACCESSMODE 2 +#define VREG_IHCU_SLEEPTIME_HOSTPRIVILEGE 1 +#define VREG_IHCU_SLEEPTIME_RESERVEDMASK 0x00000000 +#define VREG_IHCU_SLEEPTIME_WRITEMASK 0x00001fff +#define VREG_IHCU_SLEEPTIME_READMASK 0x00001fff +#define VREG_IHCU_SLEEPTIME_CLEARMASK 0x00000000 +#define VREG_IHCU_SLEEPTIME 0x500 +#define VREG_IHCU_SLEEPTIME_ID 320 + /* + * When an RxD queue runs out of buffers the VIOC goes to sleep on that queue. + * When a new SOP cell arrives the VIOC will check to see if new buffers + * have been posted. If another cell arrives within the interval + * indicated by SleepTime, the VIOC will just drop the cell. + * SleepTime is specified in unit of cell time. + */ + +#define VVAL_IHCU_SLEEPTIME_DEFAULT 0x1e /* Reset by sreset: Reset to 30 */ + + +/* Addr[31:6] for Interrupt Status Block Write (31..0) */ +#define VREG_IHCU_INTRSTATADDRLO_MASK 0xffffffff +#define VREG_IHCU_INTRSTATADDRLO_ACCESSMODE 2 +#define VREG_IHCU_INTRSTATADDRLO_HOSTPRIVILEGE 1 +#define VREG_IHCU_INTRSTATADDRLO_RESERVEDMASK 0x00000000 +#define VREG_IHCU_INTRSTATADDRLO_WRITEMASK 0xffffffff +#define VREG_IHCU_INTRSTATADDRLO_READMASK 0xffffffff +#define VREG_IHCU_INTRSTATADDRLO_CLEARMASK 0x00000000 +#define VREG_IHCU_INTRSTATADDRLO 0x508 +#define VREG_IHCU_INTRSTATADDRLO_ID 322 + +#define VVAL_IHCU_INTRSTATADDRLO_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Addr[39:32] for Interrupt Status Block Write (7..0) */ +#define VREG_IHCU_INTRSTATADDRHI_MASK 0x000000ff +#define VREG_IHCU_INTRSTATADDRHI_ACCESSMODE 2 +#define VREG_IHCU_INTRSTATADDRHI_HOSTPRIVILEGE 1 +#define VREG_IHCU_INTRSTATADDRHI_RESERVEDMASK 0x00000000 +#define VREG_IHCU_INTRSTATADDRHI_WRITEMASK 0x000000ff +#define VREG_IHCU_INTRSTATADDRHI_READMASK 0x000000ff +#define VREG_IHCU_INTRSTATADDRHI_CLEARMASK 0x00000000 +#define VREG_IHCU_INTRSTATADDRHI 0x50c +#define VREG_IHCU_INTRSTATADDRHI_ID 323 + +#define VVAL_IHCU_INTRSTATADDRHI_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Enable bits for RxD Queues (15..0) */ +#define VREG_IHCU_RXDQEN_MASK 0x0000ffff +#define VREG_IHCU_RXDQEN_ACCESSMODE 2 +#define VREG_IHCU_RXDQEN_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXDQEN_RESERVEDMASK 0x00000000 +#define VREG_IHCU_RXDQEN_WRITEMASK 0x0000ffff +#define VREG_IHCU_RXDQEN_READMASK 0x0000ffff +#define VREG_IHCU_RXDQEN_CLEARMASK 0x00000000 +#define VREG_IHCU_RXDQEN 0x510 +#define VREG_IHCU_RXDQEN_ID 324 + +#define VVAL_IHCU_RXDQEN_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of RxDQEn */ +#define VREG_IHCU_RXDQEN_RXD15_MASK 0x00008000 /* Enable RxD15 [15..15] */ +#define VREG_IHCU_RXDQEN_RXD14_MASK 0x00004000 /* Enable RxD14 [14..14] */ +#define VREG_IHCU_RXDQEN_RXD13_MASK 0x00002000 /* Enable RxD13 [13..13] */ +#define VREG_IHCU_RXDQEN_RXD12_MASK 0x00001000 /* Enable RxD12 [12..12] */ +#define VREG_IHCU_RXDQEN_RXD11_MASK 0x00000800 /* Enable RxD11 [11..11] */ +#define VREG_IHCU_RXDQEN_RXD10_MASK 0x00000400 /* Enable RxD10 [10..10] */ +#define VREG_IHCU_RXDQEN_RXD9_MASK 0x00000200 /* Enable RxD9 [9..9] */ +#define VREG_IHCU_RXDQEN_RXD8_MASK 0x00000100 /* Enable RxD8 [8..8] */ +#define VREG_IHCU_RXDQEN_RXD7_MASK 0x00000080 /* Enable RxD7 [7..7] */ +#define VREG_IHCU_RXDQEN_RXD6_MASK 0x00000040 /* Enable RxD6 [6..6] */ +#define VREG_IHCU_RXDQEN_RXD5_MASK 0x00000020 /* Enable RxD5 [5..5] */ +#define VREG_IHCU_RXDQEN_RXD4_MASK 0x00000010 /* Enable RxD4 [4..4] */ +#define VREG_IHCU_RXDQEN_RXD3_MASK 0x00000008 /* Enable RxD3 [3..3] */ +#define VREG_IHCU_RXDQEN_RXD2_MASK 0x00000004 /* Enable RxD2 [2..2] */ +#define VREG_IHCU_RXDQEN_RXD1_MASK 0x00000002 /* Enable RxD1 [1..1] */ +#define VREG_IHCU_RXDQEN_RXD0_MASK 0x00000001 /* Enable RxD0 [0..0] */ + +/* Map of VNIC to RxD Queues (31..0) */ +#define VREG_IHCU_VNICRXDMAP_MASK 0xffffffff +#define VREG_IHCU_VNICRXDMAP_ACCESSMODE 2 +#define VREG_IHCU_VNICRXDMAP_HOSTPRIVILEGE 1 +#define VREG_IHCU_VNICRXDMAP_RESERVEDMASK 0x70707070 +#define VREG_IHCU_VNICRXDMAP_WRITEMASK 0x8f8f8f8f +#define VREG_IHCU_VNICRXDMAP_READMASK 0x8f8f8f8f +#define VREG_IHCU_VNICRXDMAP_CLEARMASK 0x00000000 +#define VREG_IHCU_VNICRXDMAP 0x810 +#define VREG_IHCU_VNICRXDMAP_ID 516 + +/* Subfields of VNICRxDMap */ +#define VREG_IHCU_VNICRXDMAP_P3_MASK 0x80000000 /* Set to 1 if 4th RxD is provisioned [31..31] */ +#define VREG_IHCU_VNICRXDMAP_RSV3_MASK 0x70000000 /* Reserved [28..30] */ +#define VREG_IHCU_VNICRXDMAP_RXD3_MASK 0x0f000000 /* RxD to use for 4th mapping [24..27] */ +#define VREG_IHCU_VNICRXDMAP_P2_MASK 0x00800000 /* Set to 1 if 3rd RxD is provisioned [23..23] */ +#define VREG_IHCU_VNICRXDMAP_RSV2_MASK 0x00700000 /* Reserved [20..22] */ +#define VREG_IHCU_VNICRXDMAP_RXD2_MASK 0x000f0000 /* RxD to use for 3rd mapping [16..19] */ +#define VREG_IHCU_VNICRXDMAP_P1_MASK 0x00008000 /* Set to 1 if 2nd RxD is provisioned [15..15] */ +#define VREG_IHCU_VNICRXDMAP_RSV1_MASK 0x00007000 /* Reserved [12..14] */ +#define VREG_IHCU_VNICRXDMAP_RXD1_MASK 0x00000f00 /* RxD to use for 2nd mapping [8..11] */ +#define VREG_IHCU_VNICRXDMAP_P0_MASK 0x00000080 /* Set to 1 if 1st RxD is provisioned [7..7] */ +#define VREG_IHCU_VNICRXDMAP_RSV0_MASK 0x00000070 /* Reserved [4..6] */ +#define VREG_IHCU_VNICRXDMAP_RXD0_MASK 0x0000000f /* RxD to use for 1st mapping [0..3] */ + + + + +/* Map of VNIC to RxC Queue (31..0) */ +#define VREG_IHCU_VNICRXCMAP_MASK 0xffffffff +#define VREG_IHCU_VNICRXCMAP_ACCESSMODE 2 +#define VREG_IHCU_VNICRXCMAP_HOSTPRIVILEGE 1 +#define VREG_IHCU_VNICRXCMAP_RESERVEDMASK 0x00000000 +#define VREG_IHCU_VNICRXCMAP_WRITEMASK 0xffffffff +#define VREG_IHCU_VNICRXCMAP_READMASK 0xffffffff +#define VREG_IHCU_VNICRXCMAP_CLEARMASK 0x00000000 +#define VREG_IHCU_VNICRXCMAP 0x820 +#define VREG_IHCU_VNICRXCMAP_ID 520 + + + +/* Timer register for RxC Interrupt generation (31..0) */ +#define VREG_IHCU_RXCINTTIMER_MASK 0xffffffff +#define VREG_IHCU_RXCINTTIMER_ACCESSMODE 2 +#define VREG_IHCU_RXCINTTIMER_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXCINTTIMER_RESERVEDMASK 0x00000000 +#define VREG_IHCU_RXCINTTIMER_WRITEMASK 0x0000ffff +#define VREG_IHCU_RXCINTTIMER_READMASK 0xffffffff +#define VREG_IHCU_RXCINTTIMER_CLEARMASK 0x00000000 +#define VREG_IHCU_RXCINTTIMER 0x900 +#define VREG_IHCU_RXCINTTIMER_ID 576 + +/* Subfields of RxCIntTimer */ +#define VREG_IHCU_RXCINTTIMER_CURR_MASK 0xffff0000 /* Current Count [16..31] */ +#define VREG_IHCU_RXCINTTIMER_TERM_MASK 0x0000ffff /* Terminal Count [0..15] */ + + +#define VREG_IHCU_RXCINTTIMER_R0 0x900 +#define VREG_IHCU_RXCINTTIMER_R1 0x904 +#define VREG_IHCU_RXCINTTIMER_R2 0x908 +#define VREG_IHCU_RXCINTTIMER_R3 0x90C +#define VREG_IHCU_RXCINTTIMER_R4 0x910 +#define VREG_IHCU_RXCINTTIMER_R5 0x914 +#define VREG_IHCU_RXCINTTIMER_R6 0x918 +#define VREG_IHCU_RXCINTTIMER_R7 0x91C +#define VREG_IHCU_RXCINTTIMER_R8 0x920 +#define VREG_IHCU_RXCINTTIMER_R9 0x924 +#define VREG_IHCU_RXCINTTIMER_R10 0x928 +#define VREG_IHCU_RXCINTTIMER_R11 0x92C +#define VREG_IHCU_RXCINTTIMER_R12 0x930 +#define VREG_IHCU_RXCINTTIMER_R13 0x934 +#define VREG_IHCU_RXCINTTIMER_R14 0x938 +#define VREG_IHCU_RXCINTTIMER_R15 0x93C + + +/* Packet Count register for RxC Interrupt generation (31..0) */ +#define VREG_IHCU_RXCINTPKTCNT_MASK 0xffffffff +#define VREG_IHCU_RXCINTPKTCNT_ACCESSMODE 2 +#define VREG_IHCU_RXCINTPKTCNT_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXCINTPKTCNT_RESERVEDMASK 0x00000000 +#define VREG_IHCU_RXCINTPKTCNT_WRITEMASK 0x0000ffff +#define VREG_IHCU_RXCINTPKTCNT_READMASK 0xffffffff +#define VREG_IHCU_RXCINTPKTCNT_CLEARMASK 0x00000000 +#define VREG_IHCU_RXCINTPKTCNT 0x940 +#define VREG_IHCU_RXCINTPKTCNT_ID 592 + +/* Subfields of RxCIntPktCnt */ +#define VREG_IHCU_RXCINTPKTCNT_CURR_MASK 0xffff0000 /* Current Count [16..31] */ +#define VREG_IHCU_RXCINTPKTCNT_TERM_MASK 0x0000ffff /* Terminal Count [0..15] */ + + +#define VREG_IHCU_RXCINTPKTCNT_R0 0x940 +#define VREG_IHCU_RXCINTPKTCNT_R1 0x944 +#define VREG_IHCU_RXCINTPKTCNT_R2 0x948 +#define VREG_IHCU_RXCINTPKTCNT_R3 0x94C +#define VREG_IHCU_RXCINTPKTCNT_R4 0x950 +#define VREG_IHCU_RXCINTPKTCNT_R5 0x954 +#define VREG_IHCU_RXCINTPKTCNT_R6 0x958 +#define VREG_IHCU_RXCINTPKTCNT_R7 0x95C +#define VREG_IHCU_RXCINTPKTCNT_R8 0x960 +#define VREG_IHCU_RXCINTPKTCNT_R9 0x964 +#define VREG_IHCU_RXCINTPKTCNT_R10 0x968 +#define VREG_IHCU_RXCINTPKTCNT_R11 0x96C +#define VREG_IHCU_RXCINTPKTCNT_R12 0x970 +#define VREG_IHCU_RXCINTPKTCNT_R13 0x974 +#define VREG_IHCU_RXCINTPKTCNT_R14 0x978 +#define VREG_IHCU_RXCINTPKTCNT_R15 0x97C + + +/* Control register for RxC Interrupt generation (31..0) */ +#define VREG_IHCU_RXCINTCTL_MASK 0xffffffff +#define VREG_IHCU_RXCINTCTL_ACCESSMODE 2 +#define VREG_IHCU_RXCINTCTL_HOSTPRIVILEGE 1 +#define VREG_IHCU_RXCINTCTL_RESERVEDMASK 0xfffffffc +#define VREG_IHCU_RXCINTCTL_WRITEMASK 0x00000003 +#define VREG_IHCU_RXCINTCTL_READMASK 0x00000003 +#define VREG_IHCU_RXCINTCTL_CLEARMASK 0x00000000 +#define VREG_IHCU_RXCINTCTL 0x980 +#define VREG_IHCU_RXCINTCTL_ID 608 + +#define VVAL_IHCU_RXCINTCTL_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of RxCIntCtl */ +#define VREG_IHCU_RXCINTCTL_RSV_MASK 0xfffffffc /* Reserved [2..31] */ +#define VREG_IHCU_RXCINTCTL_CLRPEND_MASK 0x00000002 /* Clear MSI-X Pending bit [1..1] */ +#define VREG_IHCU_RXCINTCTL_MASK_MASK 0x00000001 /* Mask Rx Interrupts [0..0] */ + + +#define VREG_IHCU_RXCINTCTL_R0 0x980 +#define VREG_IHCU_RXCINTCTL_R1 0x984 +#define VREG_IHCU_RXCINTCTL_R2 0x988 +#define VREG_IHCU_RXCINTCTL_R3 0x98C +#define VREG_IHCU_RXCINTCTL_R4 0x990 +#define VREG_IHCU_RXCINTCTL_R5 0x994 +#define VREG_IHCU_RXCINTCTL_R6 0x998 +#define VREG_IHCU_RXCINTCTL_R7 0x99C +#define VREG_IHCU_RXCINTCTL_R8 0x9A0 +#define VREG_IHCU_RXCINTCTL_R9 0x9A4 +#define VREG_IHCU_RXCINTCTL_R10 0x9A8 +#define VREG_IHCU_RXCINTCTL_R11 0x9AC +#define VREG_IHCU_RXCINTCTL_R12 0x9B0 +#define VREG_IHCU_RXCINTCTL_R13 0x9B4 +#define VREG_IHCU_RXCINTCTL_R14 0x9B8 +#define VREG_IHCU_RXCINTCTL_R15 0x9BC + + +/* Diagnostic Shared memory Read Address register (12..0) */ +#define VREG_IHCU_DIAGADDR_MASK 0x00001fff +#define VREG_IHCU_DIAGADDR_ACCESSMODE 2 +#define VREG_IHCU_DIAGADDR_HOSTPRIVILEGE 1 +#define VREG_IHCU_DIAGADDR_RESERVEDMASK 0x00000000 +#define VREG_IHCU_DIAGADDR_WRITEMASK 0x00001fff +#define VREG_IHCU_DIAGADDR_READMASK 0x00001fff +#define VREG_IHCU_DIAGADDR_CLEARMASK 0x00000000 +#define VREG_IHCU_DIAGADDR 0xf00 +#define VREG_IHCU_DIAGADDR_ID 960 + +#define VVAL_IHCU_DIAGADDR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + +/* Diagnostic read result register (31..0) */ +#define VREG_IHCU_DIAGRESULT_MASK 0xffffffff +#define VREG_IHCU_DIAGRESULT_ACCESSMODE 1 +#define VREG_IHCU_DIAGRESULT_HOSTPRIVILEGE 1 +#define VREG_IHCU_DIAGRESULT_RESERVEDMASK 0x00000000 +#define VREG_IHCU_DIAGRESULT_WRITEMASK 0x00000000 +#define VREG_IHCU_DIAGRESULT_READMASK 0xffffffff +#define VREG_IHCU_DIAGRESULT_CLEARMASK 0x00000000 +#define VREG_IHCU_DIAGRESULT 0xf04 +#define VREG_IHCU_DIAGRESULT_ID 961 + +#endif /* _VIOC_IHCU_REGISTERS_H_ */ + diff --git a/drivers/net/vioc/f7/vioc_le_registers.h b/drivers/net/vioc/f7/vioc_le_registers.h new file mode 100644 index 0000000..9f51431 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_le_registers.h @@ -0,0 +1,241 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_LE_REGISTERS_H_ +#define _VIOC_LE_REGISTERS_H_ + +// F7LE + +/* Combined 72 bit Address and Command Register (31..0) */ +#define VREG_F7LE_ADDRCMD_MASK 0xffffffff +#define VREG_F7LE_ADDRCMD_ACCESSMODE 2 +#define VREG_F7LE_ADDRCMD_HOSTPRIVILEGE 0 +#define VREG_F7LE_ADDRCMD_RESERVEDMASK 0x00000000 +#define VREG_F7LE_ADDRCMD_WRITEMASK 0xffffffff +#define VREG_F7LE_ADDRCMD_READMASK 0xffffffff +#define VREG_F7LE_ADDRCMD_CLEARMASK 0x00000000 +#define VREG_F7LE_ADDRCMD 0x000 +#define VREG_F7LE_ADDRCMD_ID 0 + +#define VVAL_F7LE_ADDRCMD_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Full Addr Register for 72-bit accesses (31..0) */ +#define VREG_F7LE_DATAREG_MASK 0xffffffff +#define VREG_F7LE_DATAREG_ACCESSMODE 2 +#define VREG_F7LE_DATAREG_HOSTPRIVILEGE 0 +#define VREG_F7LE_DATAREG_RESERVEDMASK 0x00000000 +#define VREG_F7LE_DATAREG_WRITEMASK 0xffffffff +#define VREG_F7LE_DATAREG_READMASK 0xffffffff +#define VREG_F7LE_DATAREG_CLEARMASK 0x00000000 +#define VREG_F7LE_DATAREG 0x004 +#define VREG_F7LE_DATAREG_ID 1 + +#define VVAL_F7LE_DATAREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Full 72 bit ReadData Register for 72-bit accesses (31..0) */ +#define VREG_F7LE_RDDATAREG_MASK 0xffffffff +#define VREG_F7LE_RDDATAREG_ACCESSMODE 2 +#define VREG_F7LE_RDDATAREG_HOSTPRIVILEGE 0 +#define VREG_F7LE_RDDATAREG_RESERVEDMASK 0x00000000 +#define VREG_F7LE_RDDATAREG_WRITEMASK 0xffffffff +#define VREG_F7LE_RDDATAREG_READMASK 0xffffffff +#define VREG_F7LE_RDDATAREG_CLEARMASK 0x00000000 +#define VREG_F7LE_RDDATAREG 0x008 +#define VREG_F7LE_RDDATAREG_ID 2 + +#define VVAL_F7LE_RDDATAREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Address for Diagnostic accesses to TCAM and SRAM (31..0) */ +#define VREG_F7LE_ADDRREG_MASK 0xffffffff +#define VREG_F7LE_ADDRREG_ACCESSMODE 2 +#define VREG_F7LE_ADDRREG_HOSTPRIVILEGE 0 +#define VREG_F7LE_ADDRREG_RESERVEDMASK 0x00000000 +#define VREG_F7LE_ADDRREG_WRITEMASK 0xffffffff +#define VREG_F7LE_ADDRREG_READMASK 0xffffffff +#define VREG_F7LE_ADDRREG_CLEARMASK 0x00000000 +#define VREG_F7LE_ADDRREG 0x010 +#define VREG_F7LE_ADDRREG_ID 4 + +#define VVAL_F7LE_ADDRREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of AddrReg */ +#define VREG_F7LE_ADDRREG_RSVD0_MASK 0xffe00000 /* Reserved [21..31] */ +#define VREG_F7LE_ADDRREG_ARRAY_MASK 0x00180000 /* Select array to access [19..20] */ +#define VVAL_F7LE_ADDRREG_ARRAY_TCAMDATA 0x0 /* TCAM Data array */ +#define VVAL_F7LE_ADDRREG_ARRAY_TCAMMASK 0x80000 /* TCAM Mask array */ +#define VVAL_F7LE_ADDRREG_ARRAY_SRAM 0x100000 /* SRAM */ +#define VVAL_F7LE_ADDRREG_ARRAY_REGS 0x180000 /* TCAM internal registers */ +#define VREG_F7LE_ADDRREG_ADDRESS_MASK 0x0007ffff /* Address [0..18] */ + + + + +/* Command and Status for diagnostic accesses (31..0) */ +#define VREG_F7LE_CMDREG_MASK 0xffffffff +#define VREG_F7LE_CMDREG_ACCESSMODE 2 +#define VREG_F7LE_CMDREG_HOSTPRIVILEGE 0 +#define VREG_F7LE_CMDREG_RESERVEDMASK 0x00000000 +#define VREG_F7LE_CMDREG_WRITEMASK 0xffffff00 +#define VREG_F7LE_CMDREG_READMASK 0xffffffff +#define VREG_F7LE_CMDREG_CLEARMASK 0x00000000 +#define VREG_F7LE_CMDREG 0x014 +#define VREG_F7LE_CMDREG_ID 5 + /* + * Writing this register causes a diagnostic access to be performed + * Allows arbitrary parity pattern to be used for write or lookup. + * Bits 15:8 of the command register are used in place of the HW generated parity + */ + +#define VVAL_F7LE_CMDREG_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of CmdReg */ +#define VREG_F7LE_CMDREG_CMD_MASK 0xc0000000 /* Type of operation [30..31] */ +#define VVAL_F7LE_CMDREG_CMD_READ 0x0 /* Read Operation */ +#define VVAL_F7LE_CMDREG_CMD_LOOKUP 0x40000000 /* Lookup Operation */ +#define VVAL_F7LE_CMDREG_CMD_WRITE 0x80000000 /* Write Operation */ +#define VREG_F7LE_CMDREG_FRCPAR_MASK 0x20000000 /* Bypass HW parity generation [29..29] */ +#define VREG_F7LE_CMDREG_RSVD0_MASK 0x1fff0000 /* Unused [16..28] */ +#define VREG_F7LE_CMDREG_WRPARITY_MASK 0x0000ff00 /* Parity bits to be used for raw write operations. [8..15] */ +#define VREG_F7LE_CMDREG_RDPARITY_MASK 0x000000ff /* Raw Parity bits returned from Read operation [0..7] */ + + + + +/* Low order 32-bits of 72 bit data for 32 bit accesses (31..0) */ +#define VREG_F7LE_DATAREGLO_MASK 0xffffffff +#define VREG_F7LE_DATAREGLO_ACCESSMODE 2 +#define VREG_F7LE_DATAREGLO_HOSTPRIVILEGE 0 +#define VREG_F7LE_DATAREGLO_RESERVEDMASK 0x00000000 +#define VREG_F7LE_DATAREGLO_WRITEMASK 0xffffffff +#define VREG_F7LE_DATAREGLO_READMASK 0xffffffff +#define VREG_F7LE_DATAREGLO_CLEARMASK 0x00000000 +#define VREG_F7LE_DATAREGLO 0x020 +#define VREG_F7LE_DATAREGLO_ID 8 + +#define VVAL_F7LE_DATAREGLO_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Middle 32-bits of 72 bit data for 32 bit accesses (31..0) */ +#define VREG_F7LE_DATAREGMID_MASK 0xffffffff +#define VREG_F7LE_DATAREGMID_ACCESSMODE 2 +#define VREG_F7LE_DATAREGMID_HOSTPRIVILEGE 0 +#define VREG_F7LE_DATAREGMID_RESERVEDMASK 0x00000000 +#define VREG_F7LE_DATAREGMID_WRITEMASK 0xffffffff +#define VREG_F7LE_DATAREGMID_READMASK 0xffffffff +#define VREG_F7LE_DATAREGMID_CLEARMASK 0x00000000 +#define VREG_F7LE_DATAREGMID 0x024 +#define VREG_F7LE_DATAREGMID_ID 9 + +#define VVAL_F7LE_DATAREGMID_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Unused (7..0) */ +#define VREG_F7LE_DATAREGHI_MASK 0x000000ff +#define VREG_F7LE_DATAREGHI_ACCESSMODE 2 +#define VREG_F7LE_DATAREGHI_HOSTPRIVILEGE 0 +#define VREG_F7LE_DATAREGHI_RESERVEDMASK 0x00000000 +#define VREG_F7LE_DATAREGHI_WRITEMASK 0x000000ff +#define VREG_F7LE_DATAREGHI_READMASK 0x000000ff +#define VREG_F7LE_DATAREGHI_CLEARMASK 0x00000000 +#define VREG_F7LE_DATAREGHI 0x02c +#define VREG_F7LE_DATAREGHI_ID 11 + +#define VVAL_F7LE_DATAREGHI_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Low order 32-bits of 72 bit RdData for 32 bit accesses (31..0) */ +#define VREG_F7LE_RDDATAREGLO_MASK 0xffffffff +#define VREG_F7LE_RDDATAREGLO_ACCESSMODE 1 +#define VREG_F7LE_RDDATAREGLO_HOSTPRIVILEGE 0 +#define VREG_F7LE_RDDATAREGLO_RESERVEDMASK 0x00000000 +#define VREG_F7LE_RDDATAREGLO_WRITEMASK 0x00000000 +#define VREG_F7LE_RDDATAREGLO_READMASK 0xffffffff +#define VREG_F7LE_RDDATAREGLO_CLEARMASK 0x00000000 +#define VREG_F7LE_RDDATAREGLO 0x030 +#define VREG_F7LE_RDDATAREGLO_ID 12 + +#define VVAL_F7LE_RDDATAREGLO_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Middle 32-bits of 72 bit RdData for 32 bit accesses (31..0) */ +#define VREG_F7LE_RDDATAREGMID_MASK 0xffffffff +#define VREG_F7LE_RDDATAREGMID_ACCESSMODE 1 +#define VREG_F7LE_RDDATAREGMID_HOSTPRIVILEGE 0 +#define VREG_F7LE_RDDATAREGMID_RESERVEDMASK 0x00000000 +#define VREG_F7LE_RDDATAREGMID_WRITEMASK 0x00000000 +#define VREG_F7LE_RDDATAREGMID_READMASK 0xffffffff +#define VREG_F7LE_RDDATAREGMID_CLEARMASK 0x00000000 +#define VREG_F7LE_RDDATAREGMID 0x034 +#define VREG_F7LE_RDDATAREGMID_ID 13 + +#define VVAL_F7LE_RDDATAREGMID_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + + +/* Status bits from read result (7..0) */ +#define VREG_F7LE_RDDATAREGHI_MASK 0x000000ff +#define VREG_F7LE_RDDATAREGHI_ACCESSMODE 1 +#define VREG_F7LE_RDDATAREGHI_HOSTPRIVILEGE 0 +#define VREG_F7LE_RDDATAREGHI_RESERVEDMASK 0x00000000 +#define VREG_F7LE_RDDATAREGHI_WRITEMASK 0x00000000 +#define VREG_F7LE_RDDATAREGHI_READMASK 0x000000ff +#define VREG_F7LE_RDDATAREGHI_CLEARMASK 0x00000000 +#define VREG_F7LE_RDDATAREGHI 0x03c +#define VREG_F7LE_RDDATAREGHI_ID 15 + +#define VVAL_F7LE_RDDATAREGHI_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of RdDataRegHi */ +#define VREG_F7LE_RDDATAREGHI_DONE_MASK 0x00000080 /* FLD_RDONLY, HW clears when read is started, sets when done [7..7] */ +#define VREG_F7LE_RDDATAREGHI_LOOKUP_MASK 0x00000040 /* FLD_RDONLY, Result data is from a lookup (1) or Read (0) [6..6] */ +#define VREG_F7LE_RDDATAREGHI_MATCH_MASK 0x00000020 /* FLD_RDONLY, On a lookup asserted if TCAM indicated match [5..5] */ +#define VREG_F7LE_RDDATAREGHI_PARERR_MASK 0x00000010 /* FLD_RDONLY, HW Detected a parity error on the response data [4..4] */ +#define VREG_F7LE_RDDATAREGHI_RSVD0_MASK 0x0000000f /* Reserved [0..3] */ + + + + +/* TCAM initialization control register (31..0) */ +#define VREG_F7LE_INIT_MASK 0xffffffff +#define VREG_F7LE_INIT_ACCESSMODE 2 +#define VREG_F7LE_INIT_HOSTPRIVILEGE 0 +#define VREG_F7LE_INIT_RESERVEDMASK 0x7cfe0000 +#define VREG_F7LE_INIT_WRITEMASK 0x0301ffff +#define VREG_F7LE_INIT_READMASK 0x8301ffff +#define VREG_F7LE_INIT_CLEARMASK 0x00000000 +#define VREG_F7LE_INIT 0x040 +#define VREG_F7LE_INIT_ID 16 + +#define VVAL_F7LE_INIT_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ +/* Subfields of Init */ +#define VREG_F7LE_INIT_DONE_MASK 0x80000000 /* Read Only: TCAM initialization Sequence is complete [31..31] */ +#define VREG_F7LE_INIT_RESV0_MASK 0x7c000000 /* Reserved [26..30] */ +#define VREG_F7LE_INIT_STOP_MASK 0x02000000 /* 1 causes VIOC to stop TCAM initialization [25..25] */ +#define VREG_F7LE_INIT_START_MASK 0x01000000 /* 1 causes VIOC to initialize TCAM. HW clears after starting [24..24] */ +#define VREG_F7LE_INIT_RESV1_MASK 0x00fe0000 /* Reserved [17..23] */ +#define VREG_F7LE_INIT_COUNT_MASK 0x0001ffff /* Number of TCAM data or mask entries to clear [0..16] */ + +#endif /* _VIOC_LE_REGISTERS_H_ */ diff --git a/drivers/net/vioc/f7/vioc_msi_registers.h b/drivers/net/vioc/f7/vioc_msi_registers.h new file mode 100644 index 0000000..eeba048 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_msi_registers.h @@ -0,0 +1,111 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_MSI_REGISTERS_H_ +#define _VIOC_MSI_REGISTERS_H_ + +/* + * MSIX Table Structure + * One table entry is described here. + * There are a total of 19 table entries. + */ +/* Module MSIXTBL:96 */ + +/* Low half of MSI-X Address (31..0) */ +#define VREG_MSIXTBL_ADDRLOW_MASK 0xffffffff +#define VREG_MSIXTBL_ADDRLOW_ACCESSMODE 2 +#define VREG_MSIXTBL_ADDRLOW_HOSTPRIVILEGE 1 +#define VREG_MSIXTBL_ADDRLOW_RESERVEDMASK 0x00000000 +#define VREG_MSIXTBL_ADDRLOW_WRITEMASK 0xffffffff +#define VREG_MSIXTBL_ADDRLOW_READMASK 0xffffffff +#define VREG_MSIXTBL_ADDRLOW_CLEARMASK 0x00000000 +#define VREG_MSIXTBL_ADDRLOW 0x000 +#define VREG_MSIXTBL_ADDRLOW_ID 0 + + + +/* High half of MSI-X Address (31..0) */ +#define VREG_MSIXTBL_ADDRHIGH_MASK 0xffffffff +#define VREG_MSIXTBL_ADDRHIGH_ACCESSMODE 2 +#define VREG_MSIXTBL_ADDRHIGH_HOSTPRIVILEGE 1 +#define VREG_MSIXTBL_ADDRHIGH_RESERVEDMASK 0x00000000 +#define VREG_MSIXTBL_ADDRHIGH_WRITEMASK 0xffffffff +#define VREG_MSIXTBL_ADDRHIGH_READMASK 0xffffffff +#define VREG_MSIXTBL_ADDRHIGH_CLEARMASK 0x00000000 +#define VREG_MSIXTBL_ADDRHIGH 0x004 +#define VREG_MSIXTBL_ADDRHIGH_ID 1 + + + +/* MSI_X Data (31..0) */ +#define VREG_MSIXTBL_DATA_MASK 0xffffffff +#define VREG_MSIXTBL_DATA_ACCESSMODE 2 +#define VREG_MSIXTBL_DATA_HOSTPRIVILEGE 1 +#define VREG_MSIXTBL_DATA_RESERVEDMASK 0x00000000 +#define VREG_MSIXTBL_DATA_WRITEMASK 0xffffffff +#define VREG_MSIXTBL_DATA_READMASK 0xffffffff +#define VREG_MSIXTBL_DATA_CLEARMASK 0x00000000 +#define VREG_MSIXTBL_DATA 0x008 +#define VREG_MSIXTBL_DATA_ID 2 + + + +/* MSI_X Control (31..0) */ +#define VREG_MSIXTBL_CNTL_MASK 0xffffffff +#define VREG_MSIXTBL_CNTL_ACCESSMODE 2 +#define VREG_MSIXTBL_CNTL_HOSTPRIVILEGE 1 +#define VREG_MSIXTBL_CNTL_RESERVEDMASK 0xfffffffe +#define VREG_MSIXTBL_CNTL_WRITEMASK 0x00000001 +#define VREG_MSIXTBL_CNTL_READMASK 0x00000001 +#define VREG_MSIXTBL_CNTL_CLEARMASK 0x00000000 +#define VREG_MSIXTBL_CNTL 0x00c +#define VREG_MSIXTBL_CNTL_ID 3 + +/* Subfields of Cntl */ +#define VREG_MSIXTBL_CNTL_RSVD_MASK 0xfffffffe /* Reserved [1..31] */ +#define VREG_MSIXTBL_CNTL_MASK_MASK 0x00000001 /* Interrupt Mask [0..0] */ + + +/* MSIX PBA Structure - ReadOnly */ +/* Module MSIXPBA:97 */ + +// MSIXPBA one VNIC block + + +/* Bit vector of pending interrupts (18..0) */ +#define VREG_MSIXPBA_PENDING_MASK 0x0007ffff +#define VREG_MSIXPBA_PENDING_ACCESSMODE 1 +#define VREG_MSIXPBA_PENDING_HOSTPRIVILEGE 1 +#define VREG_MSIXPBA_PENDING_RESERVEDMASK 0x00000000 +#define VREG_MSIXPBA_PENDING_WRITEMASK 0x00000000 +#define VREG_MSIXPBA_PENDING_READMASK 0x0007ffff +#define VREG_MSIXPBA_PENDING_CLEARMASK 0x00000000 +#define VREG_MSIXPBA_PENDING 0x000 +#define VREG_MSIXPBA_PENDING_ID 0 + +#endif /* _VIOC_MSI_REGISTERS_H_ */ + diff --git a/drivers/net/vioc/f7/vioc_pkts_defs.h b/drivers/net/vioc/f7/vioc_pkts_defs.h new file mode 100644 index 0000000..62c0091 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_pkts_defs.h @@ -0,0 +1,853 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _VIOC_PKTS_H_ +#define _VIOC_PKTS_H_ +/* Fabric7 Fabric Packet Format */ +struct vioc_f7pf { + + /* 30..31: Encapsulation Version */ + u32 enVer: 2; +#define VIOC_F7PF_VERSION0 0x0 /* Version 0 */ +#define VIOC_F7PF_VERSION1 0x1 /* Version 1 */ +#define VIOC_F7PF_ENCAPRESERVED2 0x2 /* reserved */ +#define VIOC_F7PF_ENCAPRESERVED3 0x3 /* reserved */ + + /* 29..29: Multicast Flag */ + u32 mc: 1; +#define VIOC_F7PF_UNICASTPKT 0x0 /* Unicast Packet */ +#define VIOC_F7PF_MULTICASTPKT 0x1 /* Multicast Packet */ + + /* 28..28: No Touch Flag */ + u32 noTouch: 1; +#define VIOC_F7PF_FLAGTOUCH 0x0 /* Indicates Normal VIOC Processing */ +#define VIOC_F7PF_FLAGNOTOUCH 0x1 /* Privileged mode, skips VIOC Processing (SIM only) */ + + /* 26..27: Drop Precedence */ + u32 f7DP: 2; + + /* 24..25: Class of Service (Fabric Priority) */ + u32 f7COS: 2; +#define VIOC_F7PF_PRIORITY0 0x0 /* Priority for VIOCCP */ +#define VIOC_F7PF_PRIORITY1 0x1 /* Reserved1 */ +#define VIOC_F7PF_PRIORITY2 0x2 /* Reserved2 */ +#define VIOC_F7PF_PRIORITY3 0x3 /* Priority for all other traffic */ + + /* 16..23: Encapsulation Tag */ + u32 enTag: 8; + /* All other encap values are reserved */ +#define VIOC_F7PF_ET_NULL 0x0 /* Null Encapsulation Tag (Invalid ) */ +#define VIOC_F7PF_ET_VIOCCP 0x1 /* Encap for VIOC Control Protocol Requests */ +#define VIOC_F7PF_ET_VIOCCP_RESP 0x2 /* Encap for VIOC Control Protocol Responses */ +#define VIOC_F7PF_ET_VNIC_DIAG 0x8 /* Encap for VNIC Driver Diagnostics */ +#define VIOC_F7PF_ET_ETH 0x10 /* Ethernet Frame */ +#define VIOC_F7PF_ET_ETH_F7MP 0x11 /* Ethernet Frame with F7MP payload */ +#define VIOC_F7PF_ET_ETH_IPV4 0x12 /* Ethernet Frame with IP payload */ +#define VIOC_F7PF_ET_ETH_IPV4_CKS 0x13 /* Ethernet Frame with IP payload */ +#define VIOC_F7PF_ET_ETH_CONTROL 0x18 /* Ethernet BPDU, LACP Control Protocol */ +#define VIOC_F7PF_ET_MPLS 0x20 /* MPLS transit, no Ethernet encap */ +#define VIOC_F7PF_ET_IPV4 0x30 /* IPV4, no Ethernet encap */ +#define VIOC_F7PF_ET_F7MP 0xf7 /* F7MP, no Ethernet encap */ + + /* 14..15: Key Length */ + u32 ekLen: 2; + + /* 0..13: Packet Length */ + u32 pktLen: 14; + + /* 10..15: Destination Fabric address */ + u16 dstFabAddr: 6; + + /* 4..9: Destination Sub Address */ + u16 dstSubAddr: 6; + + /* 0..3: Reserved */ + u16 reserved_uni: 4; + + /* 10..15: Source Fabric address */ + u16 srcFabAddr: 6; + + /* 4..9: Source Sub Address */ + u16 srcSubAddr: 6; + + /* 0..3: Source Priority */ + u16 priority: 4; + + /* 0..15: Logical Interface Identifier */ + u16 lifID: 16; +#define VIOC_F7PF_LOCAL_LIFID_MIN 0x0 /* Local LIF ( Card-Level ) Min Value */ +#define VIOC_F7PF_LOCAL_LIFID_MAX 0xbfff /* Local LIF ( Card-Level ) Max Value */ +#define VIOC_F7PF_GLOBAL_LIFID_MIN 0xc000 /* Global LIF Min Value */ +#define VIOC_F7PF_GLOBAL_LIFID_MAX 0xffff /* Global LIF Max Value */ +}; + +struct vioc_f7pf_w { + u32 word_0; + + /* Encapsulation Version */ +# define VIOC_F7PF_ENVER_WORD 0 +# define VIOC_F7PF_ENVER_MASK 0xc0000000 +# define VIOC_F7PF_ENVER_SHIFT 30 +#ifndef GET_VIOC_F7PF_ENVER +# define GET_VIOC_F7PF_ENVER(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENVER_MASK)) +#endif +#ifndef GET_VIOC_F7PF_ENVER_SHIFTED +# define GET_VIOC_F7PF_ENVER_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENVER_MASK))>>VIOC_F7PF_ENVER_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_ENVER +# define GET_NTOH_VIOC_F7PF_ENVER(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENVER_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_ENVER_SHIFTED +# define GET_NTOH_VIOC_F7PF_ENVER_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENVER_MASK))>>VIOC_F7PF_ENVER_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_ENVER +# define SET_VIOC_F7PF_ENVER(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_ENVER_MASK)) +#endif +#ifndef SET_VIOC_F7PF_ENVER_SHIFTED +# define SET_VIOC_F7PF_ENVER_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_ENVER_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_ENVER +# define SET_HTON_VIOC_F7PF_ENVER(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_ENVER_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_ENVER_SHIFTED +# define SET_HTON_VIOC_F7PF_ENVER_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_ENVER_MASK)) +#endif + /* Version 0 (0x0<<30) */ +# define VIOC_F7PF_Version0_W 0x00000000 + /* Version 1 (0x1<<30) */ +# define VIOC_F7PF_Version1_W 0x40000000 + /* reserved (0x2<<30) */ +# define VIOC_F7PF_EncapReserved2_W 0x80000000 + /* reserved (0x3<<30) */ +# define VIOC_F7PF_EncapReserved3_W 0xc0000000 + + /* Multicast Flag */ +# define VIOC_F7PF_MC_WORD 0 +# define VIOC_F7PF_MC_MASK 0x20000000 +# define VIOC_F7PF_MC_SHIFT 29 +#ifndef GET_VIOC_F7PF_MC +# define GET_VIOC_F7PF_MC(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_MC_MASK)) +#endif +#ifndef GET_VIOC_F7PF_MC_SHIFTED +# define GET_VIOC_F7PF_MC_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_MC_MASK))>>VIOC_F7PF_MC_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_MC +# define GET_NTOH_VIOC_F7PF_MC(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_MC_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_MC_SHIFTED +# define GET_NTOH_VIOC_F7PF_MC_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_MC_MASK))>>VIOC_F7PF_MC_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_MC +# define SET_VIOC_F7PF_MC(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_MC_MASK)) +#endif +#ifndef SET_VIOC_F7PF_MC_SHIFTED +# define SET_VIOC_F7PF_MC_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_MC_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_MC +# define SET_HTON_VIOC_F7PF_MC(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_MC_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_MC_SHIFTED +# define SET_HTON_VIOC_F7PF_MC_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_MC_MASK)) +#endif + /* Unicast Packet (0x0<<29) */ +# define VIOC_F7PF_UnicastPkt_W 0x00000000 + /* Multicast Packet (0x1<<29) */ +# define VIOC_F7PF_MulticastPkt_W 0x20000000 + + /* No Touch Flag */ +# define VIOC_F7PF_NOTOUCH_WORD 0 +# define VIOC_F7PF_NOTOUCH_MASK 0x10000000 +# define VIOC_F7PF_NOTOUCH_SHIFT 28 +#ifndef GET_VIOC_F7PF_NOTOUCH +# define GET_VIOC_F7PF_NOTOUCH(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_NOTOUCH_MASK)) +#endif +#ifndef GET_VIOC_F7PF_NOTOUCH_SHIFTED +# define GET_VIOC_F7PF_NOTOUCH_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_NOTOUCH_MASK))>>VIOC_F7PF_NOTOUCH_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_NOTOUCH +# define GET_NTOH_VIOC_F7PF_NOTOUCH(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_NOTOUCH_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_NOTOUCH_SHIFTED +# define GET_NTOH_VIOC_F7PF_NOTOUCH_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_NOTOUCH_MASK))>>VIOC_F7PF_NOTOUCH_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_NOTOUCH +# define SET_VIOC_F7PF_NOTOUCH(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_NOTOUCH_MASK)) +#endif +#ifndef SET_VIOC_F7PF_NOTOUCH_SHIFTED +# define SET_VIOC_F7PF_NOTOUCH_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_NOTOUCH_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_NOTOUCH +# define SET_HTON_VIOC_F7PF_NOTOUCH(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_NOTOUCH_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_NOTOUCH_SHIFTED +# define SET_HTON_VIOC_F7PF_NOTOUCH_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_NOTOUCH_MASK)) +#endif + /* Indicates Normal VIOC Processing (0x0<<28) */ +# define VIOC_F7PF_FlagTouch_W 0x00000000 + /* Privileged mode, skips VIOC Processing (SIM only) (0x1<<28) */ +# define VIOC_F7PF_FlagNoTouch_W 0x10000000 + + /* Drop Precedence */ +# define VIOC_F7PF_F7DP_WORD 0 +# define VIOC_F7PF_F7DP_MASK 0x0c000000 +# define VIOC_F7PF_F7DP_SHIFT 26 +#ifndef GET_VIOC_F7PF_F7DP +# define GET_VIOC_F7PF_F7DP(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7DP_MASK)) +#endif +#ifndef GET_VIOC_F7PF_F7DP_SHIFTED +# define GET_VIOC_F7PF_F7DP_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7DP_MASK))>>VIOC_F7PF_F7DP_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_F7DP +# define GET_NTOH_VIOC_F7PF_F7DP(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7DP_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_F7DP_SHIFTED +# define GET_NTOH_VIOC_F7PF_F7DP_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7DP_MASK))>>VIOC_F7PF_F7DP_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_F7DP +# define SET_VIOC_F7PF_F7DP(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_F7DP_MASK)) +#endif +#ifndef SET_VIOC_F7PF_F7DP_SHIFTED +# define SET_VIOC_F7PF_F7DP_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_F7DP_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_F7DP +# define SET_HTON_VIOC_F7PF_F7DP(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_F7DP_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_F7DP_SHIFTED +# define SET_HTON_VIOC_F7PF_F7DP_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_F7DP_MASK)) +#endif + + /* Class of Service (Fabric Priority) */ +# define VIOC_F7PF_F7COS_WORD 0 +# define VIOC_F7PF_F7COS_MASK 0x03000000 +# define VIOC_F7PF_F7COS_SHIFT 24 +#ifndef GET_VIOC_F7PF_F7COS +# define GET_VIOC_F7PF_F7COS(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7COS_MASK)) +#endif +#ifndef GET_VIOC_F7PF_F7COS_SHIFTED +# define GET_VIOC_F7PF_F7COS_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7COS_MASK))>>VIOC_F7PF_F7COS_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_F7COS +# define GET_NTOH_VIOC_F7PF_F7COS(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7COS_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_F7COS_SHIFTED +# define GET_NTOH_VIOC_F7PF_F7COS_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_F7COS_MASK))>>VIOC_F7PF_F7COS_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_F7COS +# define SET_VIOC_F7PF_F7COS(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_F7COS_MASK)) +#endif +#ifndef SET_VIOC_F7PF_F7COS_SHIFTED +# define SET_VIOC_F7PF_F7COS_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_F7COS_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_F7COS +# define SET_HTON_VIOC_F7PF_F7COS(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_F7COS_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_F7COS_SHIFTED +# define SET_HTON_VIOC_F7PF_F7COS_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_F7COS_MASK)) +#endif + /* Priority for VIOCCP (0x0<<24) */ +# define VIOC_F7PF_Priority0_W 0x00000000 + /* Reserved1 (0x1<<24) */ +# define VIOC_F7PF_Priority1_W 0x01000000 + /* Reserved2 (0x2<<24) */ +# define VIOC_F7PF_Priority2_W 0x02000000 + /* Priority for all other traffic (0x3<<24) */ +# define VIOC_F7PF_Priority3_W 0x03000000 + + /* Encapsulation Tag */ +# define VIOC_F7PF_ENTAG_WORD 0 +# define VIOC_F7PF_ENTAG_MASK 0x00ff0000 +# define VIOC_F7PF_ENTAG_SHIFT 16 +#ifndef GET_VIOC_F7PF_ENTAG +# define GET_VIOC_F7PF_ENTAG(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENTAG_MASK)) +#endif +#ifndef GET_VIOC_F7PF_ENTAG_SHIFTED +# define GET_VIOC_F7PF_ENTAG_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENTAG_MASK))>>VIOC_F7PF_ENTAG_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_ENTAG +# define GET_NTOH_VIOC_F7PF_ENTAG(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENTAG_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_ENTAG_SHIFTED +# define GET_NTOH_VIOC_F7PF_ENTAG_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_ENTAG_MASK))>>VIOC_F7PF_ENTAG_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_ENTAG +# define SET_VIOC_F7PF_ENTAG(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_ENTAG_MASK)) +#endif +#ifndef SET_VIOC_F7PF_ENTAG_SHIFTED +# define SET_VIOC_F7PF_ENTAG_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_ENTAG_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_ENTAG +# define SET_HTON_VIOC_F7PF_ENTAG(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_ENTAG_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_ENTAG_SHIFTED +# define SET_HTON_VIOC_F7PF_ENTAG_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_ENTAG_MASK)) +#endif + /* Null Encapsulation Tag (Invalid ) (0x0<<16) */ +# define VIOC_F7PF_ET_NULL_W 0x00000000 + /* Encap for VIOC Control Protocol Requests (0x1<<16) */ +# define VIOC_F7PF_ET_VIOCCP_W 0x00010000 + /* Encap for VIOC Control Protocol Responses (0x2<<16) */ +# define VIOC_F7PF_ET_VIOCCP_RESP_W 0x00020000 + /* Encap for VNIC Driver Diagnostics (0x8<<16) */ +# define VIOC_F7PF_ET_VNIC_DIAG_W 0x00080000 + /* Ethernet Frame (0x10<<16) */ +# define VIOC_F7PF_ET_ETH_W 0x00100000 + /* Ethernet Frame with F7MP payload (0x11<<16) */ +# define VIOC_F7PF_ET_ETH_F7MP_W 0x00110000 + /* Ethernet Frame with IP payload (0x12<<16) */ +# define VIOC_F7PF_ET_ETH_IPV4_W 0x00120000 + /* Ethernet Frame with IP payload (0x13<<16) */ +# define VIOC_F7PF_ET_ETH_IPV4_CKS_W 0x00130000 + /* Ethernet BPDU, LACP Control Protocol (0x18<<16) */ +# define VIOC_F7PF_ET_ETH_CONTROL_W 0x00180000 + /* MPLS transit, no Ethernet encap (0x20<<16) */ +# define VIOC_F7PF_ET_MPLS_W 0x00200000 + /* IPV4, no Ethernet encap (0x30<<16) */ +# define VIOC_F7PF_ET_IPV4_W 0x00300000 + /* F7MP, no Ethernet encap (0xf7<<16) */ +# define VIOC_F7PF_ET_F7MP_W 0x00f70000 + + /* Key Length */ +# define VIOC_F7PF_EKLEN_WORD 0 +# define VIOC_F7PF_EKLEN_MASK 0x0000c000 +# define VIOC_F7PF_EKLEN_SHIFT 14 +#ifndef GET_VIOC_F7PF_EKLEN +# define GET_VIOC_F7PF_EKLEN(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_EKLEN_MASK)) +#endif +#ifndef GET_VIOC_F7PF_EKLEN_SHIFTED +# define GET_VIOC_F7PF_EKLEN_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_EKLEN_MASK))>>VIOC_F7PF_EKLEN_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_EKLEN +# define GET_NTOH_VIOC_F7PF_EKLEN(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_EKLEN_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_EKLEN_SHIFTED +# define GET_NTOH_VIOC_F7PF_EKLEN_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_EKLEN_MASK))>>VIOC_F7PF_EKLEN_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_EKLEN +# define SET_VIOC_F7PF_EKLEN(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_EKLEN_MASK)) +#endif +#ifndef SET_VIOC_F7PF_EKLEN_SHIFTED +# define SET_VIOC_F7PF_EKLEN_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_EKLEN_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_EKLEN +# define SET_HTON_VIOC_F7PF_EKLEN(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_EKLEN_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_EKLEN_SHIFTED +# define SET_HTON_VIOC_F7PF_EKLEN_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_EKLEN_MASK)) +#endif + + /* Packet Length */ +# define VIOC_F7PF_PKTLEN_WORD 0 +# define VIOC_F7PF_PKTLEN_MASK 0x00003fff +# define VIOC_F7PF_PKTLEN_SHIFT 0 +#ifndef GET_VIOC_F7PF_PKTLEN +# define GET_VIOC_F7PF_PKTLEN(p) \ + ((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_PKTLEN_MASK)) +#endif +#ifndef GET_VIOC_F7PF_PKTLEN_SHIFTED +# define GET_VIOC_F7PF_PKTLEN_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_PKTLEN_MASK))>>VIOC_F7PF_PKTLEN_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_PKTLEN +# define GET_NTOH_VIOC_F7PF_PKTLEN(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_PKTLEN_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_PKTLEN_SHIFTED +# define GET_NTOH_VIOC_F7PF_PKTLEN_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_0)&(VIOC_F7PF_PKTLEN_MASK))>>VIOC_F7PF_PKTLEN_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_PKTLEN +# define SET_VIOC_F7PF_PKTLEN(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= (val & VIOC_F7PF_PKTLEN_MASK)) +#endif +#ifndef SET_VIOC_F7PF_PKTLEN_SHIFTED +# define SET_VIOC_F7PF_PKTLEN_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= ((val<word_0) &= (~VIOC_F7PF_PKTLEN_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_PKTLEN +# define SET_HTON_VIOC_F7PF_PKTLEN(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl(val & VIOC_F7PF_PKTLEN_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_PKTLEN_SHIFTED +# define SET_HTON_VIOC_F7PF_PKTLEN_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VIOC_F7PF_PKTLEN_MASK)) +#endif + + u32 word_1; + + /* Destination Fabric address */ +# define VIOC_F7PF_DSTFABADDR_WORD 1 +# define VIOC_F7PF_DSTFABADDR_MASK 0xfc000000 +# define VIOC_F7PF_DSTFABADDR_SHIFT 26 +#ifndef GET_VIOC_F7PF_DSTFABADDR +# define GET_VIOC_F7PF_DSTFABADDR(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTFABADDR_MASK)) +#endif +#ifndef GET_VIOC_F7PF_DSTFABADDR_SHIFTED +# define GET_VIOC_F7PF_DSTFABADDR_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTFABADDR_MASK))>>VIOC_F7PF_DSTFABADDR_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_DSTFABADDR +# define GET_NTOH_VIOC_F7PF_DSTFABADDR(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTFABADDR_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_DSTFABADDR_SHIFTED +# define GET_NTOH_VIOC_F7PF_DSTFABADDR_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTFABADDR_MASK))>>VIOC_F7PF_DSTFABADDR_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_DSTFABADDR +# define SET_VIOC_F7PF_DSTFABADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_DSTFABADDR_MASK)) +#endif +#ifndef SET_VIOC_F7PF_DSTFABADDR_SHIFTED +# define SET_VIOC_F7PF_DSTFABADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_DSTFABADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_DSTFABADDR +# define SET_HTON_VIOC_F7PF_DSTFABADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_DSTFABADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_DSTFABADDR_SHIFTED +# define SET_HTON_VIOC_F7PF_DSTFABADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_DSTFABADDR_MASK)) +#endif + + /* Destination Sub Address */ +# define VIOC_F7PF_DSTSUBADDR_WORD 1 +# define VIOC_F7PF_DSTSUBADDR_MASK 0x03f00000 +# define VIOC_F7PF_DSTSUBADDR_SHIFT 20 +#ifndef GET_VIOC_F7PF_DSTSUBADDR +# define GET_VIOC_F7PF_DSTSUBADDR(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTSUBADDR_MASK)) +#endif +#ifndef GET_VIOC_F7PF_DSTSUBADDR_SHIFTED +# define GET_VIOC_F7PF_DSTSUBADDR_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTSUBADDR_MASK))>>VIOC_F7PF_DSTSUBADDR_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_DSTSUBADDR +# define GET_NTOH_VIOC_F7PF_DSTSUBADDR(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTSUBADDR_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_DSTSUBADDR_SHIFTED +# define GET_NTOH_VIOC_F7PF_DSTSUBADDR_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_DSTSUBADDR_MASK))>>VIOC_F7PF_DSTSUBADDR_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_DSTSUBADDR +# define SET_VIOC_F7PF_DSTSUBADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_DSTSUBADDR_MASK)) +#endif +#ifndef SET_VIOC_F7PF_DSTSUBADDR_SHIFTED +# define SET_VIOC_F7PF_DSTSUBADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_DSTSUBADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_DSTSUBADDR +# define SET_HTON_VIOC_F7PF_DSTSUBADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_DSTSUBADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_DSTSUBADDR_SHIFTED +# define SET_HTON_VIOC_F7PF_DSTSUBADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_DSTSUBADDR_MASK)) +#endif + + /* Reserved */ +# define VIOC_F7PF_RESERVED_UNI_WORD 1 +# define VIOC_F7PF_RESERVED_UNI_MASK 0x000f0000 +# define VIOC_F7PF_RESERVED_UNI_SHIFT 16 +#ifndef GET_VIOC_F7PF_RESERVED_UNI +# define GET_VIOC_F7PF_RESERVED_UNI(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_RESERVED_UNI_MASK)) +#endif +#ifndef GET_VIOC_F7PF_RESERVED_UNI_SHIFTED +# define GET_VIOC_F7PF_RESERVED_UNI_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_RESERVED_UNI_MASK))>>VIOC_F7PF_RESERVED_UNI_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_RESERVED_UNI +# define GET_NTOH_VIOC_F7PF_RESERVED_UNI(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_RESERVED_UNI_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_RESERVED_UNI_SHIFTED +# define GET_NTOH_VIOC_F7PF_RESERVED_UNI_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_RESERVED_UNI_MASK))>>VIOC_F7PF_RESERVED_UNI_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_RESERVED_UNI +# define SET_VIOC_F7PF_RESERVED_UNI(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_RESERVED_UNI_MASK)) +#endif +#ifndef SET_VIOC_F7PF_RESERVED_UNI_SHIFTED +# define SET_VIOC_F7PF_RESERVED_UNI_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_RESERVED_UNI_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_RESERVED_UNI +# define SET_HTON_VIOC_F7PF_RESERVED_UNI(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_RESERVED_UNI_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_RESERVED_UNI_SHIFTED +# define SET_HTON_VIOC_F7PF_RESERVED_UNI_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_RESERVED_UNI_MASK)) +#endif + + /* Source Fabric address */ +# define VIOC_F7PF_SRCFABADDR_WORD 1 +# define VIOC_F7PF_SRCFABADDR_MASK 0x0000fc00 +# define VIOC_F7PF_SRCFABADDR_SHIFT 10 +#ifndef GET_VIOC_F7PF_SRCFABADDR +# define GET_VIOC_F7PF_SRCFABADDR(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCFABADDR_MASK)) +#endif +#ifndef GET_VIOC_F7PF_SRCFABADDR_SHIFTED +# define GET_VIOC_F7PF_SRCFABADDR_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCFABADDR_MASK))>>VIOC_F7PF_SRCFABADDR_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_SRCFABADDR +# define GET_NTOH_VIOC_F7PF_SRCFABADDR(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCFABADDR_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_SRCFABADDR_SHIFTED +# define GET_NTOH_VIOC_F7PF_SRCFABADDR_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCFABADDR_MASK))>>VIOC_F7PF_SRCFABADDR_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_SRCFABADDR +# define SET_VIOC_F7PF_SRCFABADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_SRCFABADDR_MASK)) +#endif +#ifndef SET_VIOC_F7PF_SRCFABADDR_SHIFTED +# define SET_VIOC_F7PF_SRCFABADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_SRCFABADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_SRCFABADDR +# define SET_HTON_VIOC_F7PF_SRCFABADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_SRCFABADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_SRCFABADDR_SHIFTED +# define SET_HTON_VIOC_F7PF_SRCFABADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_SRCFABADDR_MASK)) +#endif + + /* Source Sub Address */ +# define VIOC_F7PF_SRCSUBADDR_WORD 1 +# define VIOC_F7PF_SRCSUBADDR_MASK 0x000003f0 +# define VIOC_F7PF_SRCSUBADDR_SHIFT 4 +#ifndef GET_VIOC_F7PF_SRCSUBADDR +# define GET_VIOC_F7PF_SRCSUBADDR(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCSUBADDR_MASK)) +#endif +#ifndef GET_VIOC_F7PF_SRCSUBADDR_SHIFTED +# define GET_VIOC_F7PF_SRCSUBADDR_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCSUBADDR_MASK))>>VIOC_F7PF_SRCSUBADDR_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_SRCSUBADDR +# define GET_NTOH_VIOC_F7PF_SRCSUBADDR(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCSUBADDR_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_SRCSUBADDR_SHIFTED +# define GET_NTOH_VIOC_F7PF_SRCSUBADDR_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_SRCSUBADDR_MASK))>>VIOC_F7PF_SRCSUBADDR_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_SRCSUBADDR +# define SET_VIOC_F7PF_SRCSUBADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_SRCSUBADDR_MASK)) +#endif +#ifndef SET_VIOC_F7PF_SRCSUBADDR_SHIFTED +# define SET_VIOC_F7PF_SRCSUBADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_SRCSUBADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_SRCSUBADDR +# define SET_HTON_VIOC_F7PF_SRCSUBADDR(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_SRCSUBADDR_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_SRCSUBADDR_SHIFTED +# define SET_HTON_VIOC_F7PF_SRCSUBADDR_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_SRCSUBADDR_MASK)) +#endif + + /* Source Priority */ +# define VIOC_F7PF_PRIORITY_WORD 1 +# define VIOC_F7PF_PRIORITY_MASK 0x0000000f +# define VIOC_F7PF_PRIORITY_SHIFT 0 +#ifndef GET_VIOC_F7PF_PRIORITY +# define GET_VIOC_F7PF_PRIORITY(p) \ + ((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_PRIORITY_MASK)) +#endif +#ifndef GET_VIOC_F7PF_PRIORITY_SHIFTED +# define GET_VIOC_F7PF_PRIORITY_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_PRIORITY_MASK))>>VIOC_F7PF_PRIORITY_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_PRIORITY +# define GET_NTOH_VIOC_F7PF_PRIORITY(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_PRIORITY_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_PRIORITY_SHIFTED +# define GET_NTOH_VIOC_F7PF_PRIORITY_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_1)&(VIOC_F7PF_PRIORITY_MASK))>>VIOC_F7PF_PRIORITY_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_PRIORITY +# define SET_VIOC_F7PF_PRIORITY(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= (val & VIOC_F7PF_PRIORITY_MASK)) +#endif +#ifndef SET_VIOC_F7PF_PRIORITY_SHIFTED +# define SET_VIOC_F7PF_PRIORITY_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= ((val<word_1) &= (~VIOC_F7PF_PRIORITY_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_PRIORITY +# define SET_HTON_VIOC_F7PF_PRIORITY(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl(val & VIOC_F7PF_PRIORITY_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_PRIORITY_SHIFTED +# define SET_HTON_VIOC_F7PF_PRIORITY_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VIOC_F7PF_PRIORITY_MASK)) +#endif + + u32 word_2; + + /* Logical Interface Identifier */ +# define VIOC_F7PF_LIFID_WORD 2 +# define VIOC_F7PF_LIFID_MASK 0xffff0000 +# define VIOC_F7PF_LIFID_SHIFT 16 +#ifndef GET_VIOC_F7PF_LIFID +# define GET_VIOC_F7PF_LIFID(p) \ + ((((struct vioc_f7pf_w *)p)->word_2)&(VIOC_F7PF_LIFID_MASK)) +#endif +#ifndef GET_VIOC_F7PF_LIFID_SHIFTED +# define GET_VIOC_F7PF_LIFID_SHIFTED(p) \ + (((((struct vioc_f7pf_w *)p)->word_2)&(VIOC_F7PF_LIFID_MASK))>>VIOC_F7PF_LIFID_SHIFT) +#endif +#ifndef GET_NTOH_VIOC_F7PF_LIFID +# define GET_NTOH_VIOC_F7PF_LIFID(p) \ + (ntohl(((struct vioc_f7pf_w *)p)->word_2)&(VIOC_F7PF_LIFID_MASK)) +#endif +#ifndef GET_NTOH_VIOC_F7PF_LIFID_SHIFTED +# define GET_NTOH_VIOC_F7PF_LIFID_SHIFTED(p) \ + ((ntohl(((struct vioc_f7pf_w *)p)->word_2)&(VIOC_F7PF_LIFID_MASK))>>VIOC_F7PF_LIFID_SHIFT) +#endif +#ifndef SET_VIOC_F7PF_LIFID +# define SET_VIOC_F7PF_LIFID(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_2) |= (val & VIOC_F7PF_LIFID_MASK)) +#endif +#ifndef SET_VIOC_F7PF_LIFID_SHIFTED +# define SET_VIOC_F7PF_LIFID_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_2) |= ((val<word_2) &= (~VIOC_F7PF_LIFID_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_LIFID +# define SET_HTON_VIOC_F7PF_LIFID(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_2) |= htonl(val & VIOC_F7PF_LIFID_MASK)) +#endif +#ifndef SET_HTON_VIOC_F7PF_LIFID_SHIFTED +# define SET_HTON_VIOC_F7PF_LIFID_SHIFTED(p,val) \ + ((((struct vioc_f7pf_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VIOC_F7PF_LIFID_MASK)) +#endif + /* Local LIF ( Card-Level ) Min Value (0x0<<16) */ +# define VIOC_F7PF_LOCAL_LIFID_MIN_W 0x00000000 + /* Local LIF ( Card-Level ) Max Value (0xbfff<<16) */ +# define VIOC_F7PF_LOCAL_LIFID_MAX_W 0xbfff0000 + /* Global LIF Min Value (0xc000<<16) */ +# define VIOC_F7PF_GLOBAL_LIFID_MIN_W 0xc0000000 + /* Global LIF Max Value (0xffff<<16) */ +# define VIOC_F7PF_GLOBAL_LIFID_MAX_W 0xffff0000 + +}; + + +extern void vioc_f7pf_copyin(struct vioc_f7pf *p, const u32 *mp); +extern void vioc_f7pf_copyout(const struct vioc_f7pf *p, u32 *mp); + + +#endif /* _VIOC_PKTS_H_ */ + diff --git a/drivers/net/vioc/f7/vioc_veng_registers.h b/drivers/net/vioc/f7/vioc_veng_registers.h new file mode 100644 index 0000000..3c5fdd6 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_veng_registers.h @@ -0,0 +1,299 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_VENG_REGISTERS_H_ +#define _VIOC_VENG_REGISTERS_H_ + +// VENG +/* Fabric Priority Map (15..0) */ +#define VREG_VENG_PRIMAP_MASK 0x0000ffff +#define VREG_VENG_PRIMAP_ACCESSMODE 2 +#define VREG_VENG_PRIMAP_HOSTPRIVILEGE 0 +#define VREG_VENG_PRIMAP_RESERVEDMASK 0x0000cccc +#define VREG_VENG_PRIMAP_WRITEMASK 0x00003333 +#define VREG_VENG_PRIMAP_READMASK 0x00003333 +#define VREG_VENG_PRIMAP_CLEARMASK 0x00000000 +#define VREG_VENG_PRIMAP 0x000 +#define VREG_VENG_PRIMAP_ID 0 + +#define VVAL_VENG_PRIMAP_DEFAULT 0x3210 /* Reset by hreset: Reset to identity mapping */ +/* Subfields of PriMap */ +#define VREG_VENG_PRIMAP_RSVD3_MASK 0x0000c000 /* Reserved [14..15] */ +#define VREG_VENG_PRIMAP_P3_MASK 0x00003000 /* Map for Priority 3 [12..13] */ +#define VREG_VENG_PRIMAP_RSVD2_MASK 0x00000c00 /* Reserved [10..11] */ +#define VREG_VENG_PRIMAP_P2_MASK 0x00000300 /* Map for Priority 2 [8..9] */ +#define VREG_VENG_PRIMAP_RSVD1_MASK 0x000000c0 /* Reserved [6..7] */ +#define VREG_VENG_PRIMAP_P1_MASK 0x00000030 /* Map for Priority 1 [4..5] */ +#define VREG_VENG_PRIMAP_RSVD0_MASK 0x0000000c /* Reserved [2..3] */ +#define VREG_VENG_PRIMAP_P0_MASK 0x00000003 /* Map for Priority 0 [0..1] */ + +/* 32-bit low bytes of VNIC MAC Address (31..0) */ +#define VREG_VENG_MACADDRLO_MASK 0xffffffff +#define VREG_VENG_MACADDRLO_ACCESSMODE 2 +#define VREG_VENG_MACADDRLO_HOSTPRIVILEGE 0 +#define VREG_VENG_MACADDRLO_RESERVEDMASK 0x00000000 +#define VREG_VENG_MACADDRLO_WRITEMASK 0xffffffff +#define VREG_VENG_MACADDRLO_READMASK 0xffffffff +#define VREG_VENG_MACADDRLO_CLEARMASK 0x00000000 +#define VREG_VENG_MACADDRLO 0x010 +#define VREG_VENG_MACADDRLO_ID 4 + +/* 16-bit high bytes of VNIC MAC Address (15..0) */ +#define VREG_VENG_MACADDRHI_MASK 0x0000ffff +#define VREG_VENG_MACADDRHI_ACCESSMODE 2 +#define VREG_VENG_MACADDRHI_HOSTPRIVILEGE 0 +#define VREG_VENG_MACADDRHI_RESERVEDMASK 0x00000000 +#define VREG_VENG_MACADDRHI_WRITEMASK 0x0000ffff +#define VREG_VENG_MACADDRHI_READMASK 0x0000ffff +#define VREG_VENG_MACADDRHI_CLEARMASK 0x00000000 +#define VREG_VENG_MACADDRHI 0x014 +#define VREG_VENG_MACADDRHI_ID 5 + +/* VLAN Tag (13..0) */ +#define VREG_VENG_VLANTAG_MASK 0x00003fff +#define VREG_VENG_VLANTAG_ACCESSMODE 2 +#define VREG_VENG_VLANTAG_HOSTPRIVILEGE 0 +#define VREG_VENG_VLANTAG_RESERVEDMASK 0x00000000 +#define VREG_VENG_VLANTAG_WRITEMASK 0x00003fff +#define VREG_VENG_VLANTAG_READMASK 0x00003fff +#define VREG_VENG_VLANTAG_CLEARMASK 0x00000000 +#define VREG_VENG_VLANTAG 0x018 +#define VREG_VENG_VLANTAG_ID 6 + +/* Min transmit bandwidth (31..0) */ +#define VREG_VENG_TXMINBW_MASK 0xffffffff +#define VREG_VENG_TXMINBW_ACCESSMODE 2 +#define VREG_VENG_TXMINBW_HOSTPRIVILEGE 0 +#define VREG_VENG_TXMINBW_RESERVEDMASK 0x3fffff80 +#define VREG_VENG_TXMINBW_WRITEMASK 0xc000007f +#define VREG_VENG_TXMINBW_READMASK 0xc000007f +#define VREG_VENG_TXMINBW_CLEARMASK 0x00000000 +#define VREG_VENG_TXMINBW 0x020 +#define VREG_VENG_TXMINBW_ID 8 + /* Units is 100Mbps of F7 payload */ + +#define VVAL_VENG_TXMINBW_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of TxMinBW */ +#define VREG_VENG_TXMINBW_DP_MASK 0xc0000000 /* Drop Precedence [30..31] */ +#define VREG_VENG_TXMINBW_RSVD_MASK 0x3fffff80 /* Reserved [7..29] */ +#define VREG_VENG_TXMINBW_MINBW_MASK 0x0000007f /* Bandwidth in 100Mbps [0..6] */ + +/* Max transmit bandwidth (31..0) */ +#define VREG_VENG_TXMAXBW_MASK 0xffffffff +#define VREG_VENG_TXMAXBW_ACCESSMODE 2 +#define VREG_VENG_TXMAXBW_HOSTPRIVILEGE 0 +#define VREG_VENG_TXMAXBW_RESERVEDMASK 0x3fffff80 +#define VREG_VENG_TXMAXBW_WRITEMASK 0xc000007f +#define VREG_VENG_TXMAXBW_READMASK 0xc000007f +#define VREG_VENG_TXMAXBW_CLEARMASK 0x00000000 +#define VREG_VENG_TXMAXBW 0x024 +#define VREG_VENG_TXMAXBW_ID 9 + /* Units is 100Mbps of F7 payload */ + +#define VVAL_VENG_TXMAXBW_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of TxMaxBW */ +#define VREG_VENG_TXMAXBW_DP_MASK 0xc0000000 /* Drop Precedence [30..31] */ +#define VREG_VENG_TXMAXBW_RSVD_MASK 0x3fffff80 /* Reserved [7..29] */ +#define VREG_VENG_TXMAXBW_MAXBW_MASK 0x0000007f /* Bandwidth in 100Mbps [0..6] */ + +/* Weight for arbitration among VNIC Tx Queues (5..0) */ +#define VREG_VENG_TXWRR_MASK 0x0000003f +#define VREG_VENG_TXWRR_ACCESSMODE 2 +#define VREG_VENG_TXWRR_HOSTPRIVILEGE 0 +#define VREG_VENG_TXWRR_RESERVEDMASK 0x00000000 +#define VREG_VENG_TXWRR_WRITEMASK 0x0000003f +#define VREG_VENG_TXWRR_READMASK 0x0000003f +#define VREG_VENG_TXWRR_CLEARMASK 0x00000000 +#define VREG_VENG_TXWRR 0x028 +#define VREG_VENG_TXWRR_ID 10 + +#define VVAL_VENG_TXWRR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Tx Interrupt Control Register (15..0) */ +#define VREG_VENG_TXINTCTL_MASK 0x0000ffff +#define VREG_VENG_TXINTCTL_ACCESSMODE 2 +#define VREG_VENG_TXINTCTL_HOSTPRIVILEGE 1 +#define VREG_VENG_TXINTCTL_RESERVEDMASK 0x00007ff0 +#define VREG_VENG_TXINTCTL_WRITEMASK 0x0000800f +#define VREG_VENG_TXINTCTL_READMASK 0x0000800f +#define VREG_VENG_TXINTCTL_CLEARMASK 0x00000000 +#define VREG_VENG_TXINTCTL 0x040 +#define VREG_VENG_TXINTCTL_ID 16 + +#define VVAL_VENG_TXINTCTL_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of TxIntCtl */ +#define VREG_VENG_TXINTCTL_INTONEMPTY_MASK 0x00008000 /* When asserted send interrupt on transition to Empty [15..15] */ +#define VREG_VENG_TXINTCTL_RSVD0_MASK 0x00007ff0 /* Unused [4..14] */ +#define VREG_VENG_TXINTCTL_INTNUM_MASK 0x0000000f /* Interrupt number to send [0..3] */ + + + + +/* Blast cell counter (31..0) */ +#define VREG_VENG_CNTR_BLAST_V0_MASK 0xffffffff +#define VREG_VENG_CNTR_BLAST_V0_ACCESSMODE 1 +#define VREG_VENG_CNTR_BLAST_V0_HOSTPRIVILEGE 1 +#define VREG_VENG_CNTR_BLAST_V0_RESERVEDMASK 0x00000000 +#define VREG_VENG_CNTR_BLAST_V0_WRITEMASK 0x00000000 +#define VREG_VENG_CNTR_BLAST_V0_READMASK 0xffffffff +#define VREG_VENG_CNTR_BLAST_V0_CLEARMASK 0x00000000 +#define VREG_VENG_CNTR_BLAST_V0 0x050 +#define VREG_VENG_CNTR_BLAST_V0_ID 20 + +#define VVAL_VENG_CNTR_BLAST_V0_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* C6tx cell counter (31..0) */ +#define VREG_VENG_CNTR_C6TXPHY_V0_MASK 0xffffffff +#define VREG_VENG_CNTR_C6TXPHY_V0_ACCESSMODE 1 +#define VREG_VENG_CNTR_C6TXPHY_V0_HOSTPRIVILEGE 1 +#define VREG_VENG_CNTR_C6TXPHY_V0_RESERVEDMASK 0x00000000 +#define VREG_VENG_CNTR_C6TXPHY_V0_WRITEMASK 0x00000000 +#define VREG_VENG_CNTR_C6TXPHY_V0_READMASK 0xffffffff +#define VREG_VENG_CNTR_C6TXPHY_V0_CLEARMASK 0x00000000 +#define VREG_VENG_CNTR_C6TXPHY_V0 0x054 +#define VREG_VENG_CNTR_C6TXPHY_V0_ID 21 + +#define VVAL_VENG_CNTR_C6TXPHY_V0_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* TxD Queue Definition - Base address (31..0) */ +#define VREG_VENG_TXD_W0_MASK 0xffffffff +#define VREG_VENG_TXD_W0_ACCESSMODE 2 +#define VREG_VENG_TXD_W0_HOSTPRIVILEGE 1 +#define VREG_VENG_TXD_W0_RESERVEDMASK 0x0000003f +#define VREG_VENG_TXD_W0_WRITEMASK 0xffffffc0 +#define VREG_VENG_TXD_W0_READMASK 0xffffffc0 +#define VREG_VENG_TXD_W0_CLEARMASK 0x00000000 +#define VREG_VENG_TXD_W0 0x100 +#define VREG_VENG_TXD_W0_ID 64 + +/* Subfields of TxD_W0 */ +#define VREG_VENG_TXD_W0_BA_LO_MASK 0xffffffc0 /* Bits 31:6 of the TxD ring base address [6..31] */ +#define VREG_VENG_TXD_W0_RSV_MASK 0x0000003f /* Reserved [0..5] */ + + + + +/* TxD Queue Definition (31..0) */ +#define VREG_VENG_TXD_W1_MASK 0xffffffff +#define VREG_VENG_TXD_W1_ACCESSMODE 2 +#define VREG_VENG_TXD_W1_HOSTPRIVILEGE 1 +#define VREG_VENG_TXD_W1_RESERVEDMASK 0xff000000 +#define VREG_VENG_TXD_W1_WRITEMASK 0x00ffffff +#define VREG_VENG_TXD_W1_READMASK 0x00ffffff +#define VREG_VENG_TXD_W1_CLEARMASK 0x00000000 +#define VREG_VENG_TXD_W1 0x104 +#define VREG_VENG_TXD_W1_ID 65 + +/* Subfields of TxD_W1 */ +#define VREG_VENG_TXD_W1_RSV1_MASK 0xff000000 /* Reserved [24..31] */ +#define VREG_VENG_TXD_W1_SIZE_MASK 0x00ffff00 /* Number of descriptors in the queue [8..23] */ +#define VREG_VENG_TXD_W1_BA_HI_MASK 0x000000ff /* Bits 39:32 of base address [0..7] */ + + + + +/* TxD Queue Status (31..0) */ +#define VREG_VENG_TXD_CTL_MASK 0xffffffff +#define VREG_VENG_TXD_CTL_ACCESSMODE 2 +#define VREG_VENG_TXD_CTL_HOSTPRIVILEGE 1 +#define VREG_VENG_TXD_CTL_RESERVEDMASK 0xc000fc38 +#define VREG_VENG_TXD_CTL_WRITEMASK 0x000000c7 +#define VREG_VENG_TXD_CTL_READMASK 0x3fff03c7 +#define VREG_VENG_TXD_CTL_CLEARMASK 0x000000c0 +#define VREG_VENG_TXD_CTL 0x108 +#define VREG_VENG_TXD_CTL_ID 66 + /* + * When 1 causes the Q to transition from Empty to Active. + * HW clears this bit after the transition + */ + +/* Subfields of TxD_Ctl */ +#define VREG_VENG_TXD_CTL_RSV1_MASK 0xc0000000 /* Reserved [30..31] */ +#define VREG_VENG_TXD_CTL_CURRRDPTR_MASK 0x3fff0000 /* Offset in TxD of NEXT descriptor to be used [16..29] */ +#define VREG_VENG_TXD_CTL_RSV2_MASK 0x0000fc00 /* Reserved [10..15] */ +#define VREG_VENG_TXD_CTL_TXSTATE_MASK 0x00000300 /* VNIC Tx State [8..9] */ +#define VVAL_VENG_TXD_CTL_TXSTATE_DISABLED 0x0 /* Disabled */ +#define VVAL_VENG_TXD_CTL_TXSTATE_PAUSED 0x100 /* Paused */ +#define VVAL_VENG_TXD_CTL_TXSTATE_EMPTY 0x200 /* Empty */ +#define VVAL_VENG_TXD_CTL_TXSTATE_ACTIVE 0x300 /* Active */ +#define VREG_VENG_TXD_CTL_ERROR_MASK 0x00000080 /* Error detected while processing ring [7..7] */ +#define VREG_VENG_TXD_CTL_INVDESC_MASK 0x00000040 /* An Invalid descriptor found mid packet [6..6] */ +#define VREG_VENG_TXD_CTL_RSV3_MASK 0x00000038 /* Reserved [3..5] */ +#define VREG_VENG_TXD_CTL_QENABLE_MASK 0x00000004 /* Enable/Disable the Tx Q [2..2] */ +#define VREG_VENG_TXD_CTL_QPAUSE_MASK 0x00000002 /* Force the Q to Pause state [1..1] */ +#define VREG_VENG_TXD_CTL_QRING_MASK 0x00000001 /* Ring the doorbell for the Queue [0..0] */ + +/* VNIC Transmit Q Control Register (31..0) */ +#define VREG_VENG_TXQ_CFG_MASK 0xffffffff +#define VREG_VENG_TXQ_CFG_ACCESSMODE 2 +#define VREG_VENG_TXQ_CFG_HOSTPRIVILEGE 0 +#define VREG_VENG_TXQ_CFG_RESERVEDMASK 0xfffff8ff +#define VREG_VENG_TXQ_CFG_WRITEMASK 0x00000700 +#define VREG_VENG_TXQ_CFG_READMASK 0x00000700 +#define VREG_VENG_TXQ_CFG_CLEARMASK 0x00000000 +#define VREG_VENG_TXQ_CFG 0x10c +#define VREG_VENG_TXQ_CFG_ID 67 + +#define VVAL_VENG_TXQ_CFG_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of TxQ_Cfg */ +#define VREG_VENG_TXQ_CFG_RSVD0_MASK 0xfffff800 /* Reserved [11..31] */ +#define VREG_VENG_TXQ_CFG_O_MASK 0x00000400 /* Override the COS field from the packet header [10..10] */ +#define VREG_VENG_TXQ_CFG_PRI_MASK 0x00000300 /* Fabric Priority to be used [8..9] */ +#define VREG_VENG_TXQ_CFG_RSVD2_MASK 0x000000ff /* Reserved [0..7] */ + + + + +/* Base address of LAG Table (31..0) */ +#define VREG_VENG_LAGTBLBASE_MASK 0xffffffff +#define VREG_VENG_LAGTBLBASE_ACCESSMODE 2 +#define VREG_VENG_LAGTBLBASE_HOSTPRIVILEGE 0 +#define VREG_VENG_LAGTBLBASE_RESERVEDMASK 0x00000000 +#define VREG_VENG_LAGTBLBASE_WRITEMASK 0xffffffff +#define VREG_VENG_LAGTBLBASE_READMASK 0xffffffff +#define VREG_VENG_LAGTBLBASE_CLEARMASK 0x00000000 +#define VREG_VENG_LAGTBLBASE 0x400 +#define VREG_VENG_LAGTBLBASE_ID 256 + + +/* Collection of internal SRAM parity error (31..0) */ +#define VREG_VENG_PARERR_MASK 0xffffffff +#define VREG_VENG_PARERR_ACCESSMODE 3 +#define VREG_VENG_PARERR_HOSTPRIVILEGE 1 +#define VREG_VENG_PARERR_RESERVEDMASK 0x00000000 +#define VREG_VENG_PARERR_WRITEMASK 0xffffffff +#define VREG_VENG_PARERR_READMASK 0xffffffff +#define VREG_VENG_PARERR_CLEARMASK 0xffffffff +#define VREG_VENG_PARERR 0xf00 +#define VREG_VENG_PARERR_ID 960 + +#define VVAL_VENG_PARERR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + +#endif /* _VIOC_VENG_REGISTERS_H_ */ diff --git a/drivers/net/vioc/f7/vioc_ving_registers.h b/drivers/net/vioc/f7/vioc_ving_registers.h new file mode 100644 index 0000000..7258215 --- /dev/null +++ b/drivers/net/vioc/f7/vioc_ving_registers.h @@ -0,0 +1,327 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VIOC_VING_REGISTERS_H_ +#define _VIOC_VIOG_REGISTERS_H_ + +/* Module VING:16 */ + +/* Priority 0 flow control threshold for Shared Memory (8..0) */ +#define VREG_VING_BUFTH1_MASK 0x000001ff +#define VREG_VING_BUFTH1_ACCESSMODE 2 +#define VREG_VING_BUFTH1_HOSTPRIVILEGE 1 +#define VREG_VING_BUFTH1_RESERVEDMASK 0x00000000 +#define VREG_VING_BUFTH1_WRITEMASK 0x000001ff +#define VREG_VING_BUFTH1_READMASK 0x000001ff +#define VREG_VING_BUFTH1_CLEARMASK 0x00000000 +#define VREG_VING_BUFTH1 0x000 +#define VREG_VING_BUFTH1_ID 0 + +#define VVAL_VING_BUFTH1_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Priority 1 flow control threshold for Shared Memory (8..0) */ +#define VREG_VING_BUFTH2_MASK 0x000001ff +#define VREG_VING_BUFTH2_ACCESSMODE 2 +#define VREG_VING_BUFTH2_HOSTPRIVILEGE 1 +#define VREG_VING_BUFTH2_RESERVEDMASK 0x00000000 +#define VREG_VING_BUFTH2_WRITEMASK 0x000001ff +#define VREG_VING_BUFTH2_READMASK 0x000001ff +#define VREG_VING_BUFTH2_CLEARMASK 0x00000000 +#define VREG_VING_BUFTH2 0x004 +#define VREG_VING_BUFTH2_ID 1 + +#define VVAL_VING_BUFTH2_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Priority 2 flow control threshold for Shared Memory (8..0) */ +#define VREG_VING_BUFTH3_MASK 0x000001ff +#define VREG_VING_BUFTH3_ACCESSMODE 2 +#define VREG_VING_BUFTH3_HOSTPRIVILEGE 1 +#define VREG_VING_BUFTH3_RESERVEDMASK 0x00000000 +#define VREG_VING_BUFTH3_WRITEMASK 0x000001ff +#define VREG_VING_BUFTH3_READMASK 0x000001ff +#define VREG_VING_BUFTH3_CLEARMASK 0x00000000 +#define VREG_VING_BUFTH3 0x008 +#define VREG_VING_BUFTH3_ID 2 + +#define VVAL_VING_BUFTH3_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Priority 3 flow control threshold for Shared Memory (8..0) */ +#define VREG_VING_BUFTH4_MASK 0x000001ff +#define VREG_VING_BUFTH4_ACCESSMODE 2 +#define VREG_VING_BUFTH4_HOSTPRIVILEGE 1 +#define VREG_VING_BUFTH4_RESERVEDMASK 0x00000000 +#define VREG_VING_BUFTH4_WRITEMASK 0x000001ff +#define VREG_VING_BUFTH4_READMASK 0x000001ff +#define VREG_VING_BUFTH4_CLEARMASK 0x00000000 +#define VREG_VING_BUFTH4 0x00c +#define VREG_VING_BUFTH4_ID 3 + +#define VVAL_VING_BUFTH4_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Number of MC bufs remaining before drop Class 0 (8..0) */ +#define VREG_VING_MCDROPTH1_MASK 0x000001ff +#define VREG_VING_MCDROPTH1_ACCESSMODE 2 +#define VREG_VING_MCDROPTH1_HOSTPRIVILEGE 1 +#define VREG_VING_MCDROPTH1_RESERVEDMASK 0x00000000 +#define VREG_VING_MCDROPTH1_WRITEMASK 0x000001ff +#define VREG_VING_MCDROPTH1_READMASK 0x000001ff +#define VREG_VING_MCDROPTH1_CLEARMASK 0x00000000 +#define VREG_VING_MCDROPTH1 0x010 +#define VREG_VING_MCDROPTH1_ID 4 + +#define VVAL_VING_MCDROPTH1_DEFAULT 0x100 /* Reset by sreset: Reset to 256 */ + + +/* Number of MC bufs remaining before drop Class 1 (8..0) */ +#define VREG_VING_MCDROPTH2_MASK 0x000001ff +#define VREG_VING_MCDROPTH2_ACCESSMODE 2 +#define VREG_VING_MCDROPTH2_HOSTPRIVILEGE 1 +#define VREG_VING_MCDROPTH2_RESERVEDMASK 0x00000000 +#define VREG_VING_MCDROPTH2_WRITEMASK 0x000001ff +#define VREG_VING_MCDROPTH2_READMASK 0x000001ff +#define VREG_VING_MCDROPTH2_CLEARMASK 0x00000000 +#define VREG_VING_MCDROPTH2 0x014 +#define VREG_VING_MCDROPTH2_ID 5 + +#define VVAL_VING_MCDROPTH2_DEFAULT 0xc8 /* Reset by sreset: Reset to 200 */ + + +/* Number of MC bufs remaining before drop Class 2 (8..0) */ +#define VREG_VING_MCDROPTH3_MASK 0x000001ff +#define VREG_VING_MCDROPTH3_ACCESSMODE 2 +#define VREG_VING_MCDROPTH3_HOSTPRIVILEGE 1 +#define VREG_VING_MCDROPTH3_RESERVEDMASK 0x00000000 +#define VREG_VING_MCDROPTH3_WRITEMASK 0x000001ff +#define VREG_VING_MCDROPTH3_READMASK 0x000001ff +#define VREG_VING_MCDROPTH3_CLEARMASK 0x00000000 +#define VREG_VING_MCDROPTH3 0x018 +#define VREG_VING_MCDROPTH3_ID 6 + +#define VVAL_VING_MCDROPTH3_DEFAULT 0x96 /* Reset by sreset: Reset to 150 */ + + +/* Number of MC bufs remaining before drop Class 3 (8..0) */ +#define VREG_VING_MCDROPTH4_MASK 0x000001ff +#define VREG_VING_MCDROPTH4_ACCESSMODE 2 +#define VREG_VING_MCDROPTH4_HOSTPRIVILEGE 1 +#define VREG_VING_MCDROPTH4_RESERVEDMASK 0x00000000 +#define VREG_VING_MCDROPTH4_WRITEMASK 0x000001ff +#define VREG_VING_MCDROPTH4_READMASK 0x000001ff +#define VREG_VING_MCDROPTH4_CLEARMASK 0x00000000 +#define VREG_VING_MCDROPTH4 0x01c +#define VREG_VING_MCDROPTH4_ID 7 + +#define VVAL_VING_MCDROPTH4_DEFAULT 0x80 /* Reset by sreset: Reset to 128 */ + + +/* Count of Cells arriving at inglcu (31..0) */ +#define VREG_VING_CNTR_CELLS_MASK 0xffffffff +#define VREG_VING_CNTR_CELLS_ACCESSMODE 1 +#define VREG_VING_CNTR_CELLS_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_CELLS_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_CELLS_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_CELLS_READMASK 0xffffffff +#define VREG_VING_CNTR_CELLS_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_CELLS 0x100 +#define VREG_VING_CNTR_CELLS_ID 64 + +#define VVAL_VING_CNTR_CELLS_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of Cells queued in Shared Memory (31..0) */ +#define VREG_VING_CNTR_CELLSQUEUED_MASK 0xffffffff +#define VREG_VING_CNTR_CELLSQUEUED_ACCESSMODE 1 +#define VREG_VING_CNTR_CELLSQUEUED_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_CELLSQUEUED_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_CELLSQUEUED_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_CELLSQUEUED_READMASK 0xffffffff +#define VREG_VING_CNTR_CELLSQUEUED_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_CELLSQUEUED 0x104 +#define VREG_VING_CNTR_CELLSQUEUED_ID 65 + +#define VVAL_VING_CNTR_CELLSQUEUED_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of SOP Cells queued in Shared Memory (31..0) */ +#define VREG_VING_CNTR_PKTSQUEUED_MASK 0xffffffff +#define VREG_VING_CNTR_PKTSQUEUED_ACCESSMODE 1 +#define VREG_VING_CNTR_PKTSQUEUED_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_PKTSQUEUED_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_PKTSQUEUED_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_PKTSQUEUED_READMASK 0xffffffff +#define VREG_VING_CNTR_PKTSQUEUED_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_PKTSQUEUED 0x108 +#define VREG_VING_CNTR_PKTSQUEUED_ID 66 + +#define VVAL_VING_CNTR_PKTSQUEUED_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of Packets Dropped because VNIC q is not enabled (31..0) */ +#define VREG_VING_CNTR_DROPNOQUEUE_MASK 0xffffffff +#define VREG_VING_CNTR_DROPNOQUEUE_ACCESSMODE 1 +#define VREG_VING_CNTR_DROPNOQUEUE_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_DROPNOQUEUE_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_DROPNOQUEUE_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_DROPNOQUEUE_READMASK 0xffffffff +#define VREG_VING_CNTR_DROPNOQUEUE_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_DROPNOQUEUE 0x10c +#define VREG_VING_CNTR_DROPNOQUEUE_ID 67 + +#define VVAL_VING_CNTR_DROPNOQUEUE_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of Packets Dropped because MC lookup failed (31..0) */ +#define VREG_VING_CNTR_DROPMCLOOKUP_MASK 0xffffffff +#define VREG_VING_CNTR_DROPMCLOOKUP_ACCESSMODE 1 +#define VREG_VING_CNTR_DROPMCLOOKUP_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_DROPMCLOOKUP_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_DROPMCLOOKUP_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_DROPMCLOOKUP_READMASK 0xffffffff +#define VREG_VING_CNTR_DROPMCLOOKUP_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_DROPMCLOOKUP 0x110 +#define VREG_VING_CNTR_DROPMCLOOKUP_ID 68 + +#define VVAL_VING_CNTR_DROPMCLOOKUP_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of cells Dropped because of cell CRC Error (31..0) */ +#define VREG_VING_CNTR_C6RXCRCERR_MASK 0xffffffff +#define VREG_VING_CNTR_C6RXCRCERR_ACCESSMODE 1 +#define VREG_VING_CNTR_C6RXCRCERR_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_C6RXCRCERR_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_C6RXCRCERR_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_C6RXCRCERR_READMASK 0xffffffff +#define VREG_VING_CNTR_C6RXCRCERR_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_C6RXCRCERR 0x114 +#define VREG_VING_CNTR_C6RXCRCERR_ID 69 + +#define VVAL_VING_CNTR_C6RXCRCERR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of cells Dropped because of cell HPar Error (31..0) */ +#define VREG_VING_CNTR_C6RXHPARERR_MASK 0xffffffff +#define VREG_VING_CNTR_C6RXHPARERR_ACCESSMODE 1 +#define VREG_VING_CNTR_C6RXHPARERR_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_C6RXHPARERR_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_C6RXHPARERR_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_C6RXHPARERR_READMASK 0xffffffff +#define VREG_VING_CNTR_C6RXHPARERR_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_C6RXHPARERR 0x118 +#define VREG_VING_CNTR_C6RXHPARERR_ID 70 + +#define VVAL_VING_CNTR_C6RXHPARERR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of cells Dropped because of cell VPar Error (31..0) */ +#define VREG_VING_CNTR_C6RXVPARERR_MASK 0xffffffff +#define VREG_VING_CNTR_C6RXVPARERR_ACCESSMODE 1 +#define VREG_VING_CNTR_C6RXVPARERR_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_C6RXVPARERR_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_C6RXVPARERR_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_C6RXVPARERR_READMASK 0xffffffff +#define VREG_VING_CNTR_C6RXVPARERR_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_C6RXVPARERR 0x11c +#define VREG_VING_CNTR_C6RXVPARERR_ID 71 + +#define VVAL_VING_CNTR_C6RXVPARERR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Count of cells Dropped because of Framing Error (31..0) */ +#define VREG_VING_CNTR_C6RXFRAMEERR_MASK 0xffffffff +#define VREG_VING_CNTR_C6RXFRAMEERR_ACCESSMODE 1 +#define VREG_VING_CNTR_C6RXFRAMEERR_HOSTPRIVILEGE 1 +#define VREG_VING_CNTR_C6RXFRAMEERR_RESERVEDMASK 0x00000000 +#define VREG_VING_CNTR_C6RXFRAMEERR_WRITEMASK 0x00000000 +#define VREG_VING_CNTR_C6RXFRAMEERR_READMASK 0xffffffff +#define VREG_VING_CNTR_C6RXFRAMEERR_CLEARMASK 0x00000000 +#define VREG_VING_CNTR_C6RXFRAMEERR 0x120 +#define VREG_VING_CNTR_C6RXFRAMEERR_ID 72 + +#define VVAL_VING_CNTR_C6RXFRAMEERR_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ + + +/* Maximum Bandwidth allowed for this VNIC (31..0) */ +#define VREG_VING_MAXBW_MASK 0xffffffff +#define VREG_VING_MAXBW_ACCESSMODE 2 +#define VREG_VING_MAXBW_HOSTPRIVILEGE 0 +#define VREG_VING_MAXBW_RESERVEDMASK 0xf0000080 +#define VREG_VING_MAXBW_WRITEMASK 0x0fffff7f +#define VREG_VING_MAXBW_READMASK 0x0fffff7f +#define VREG_VING_MAXBW_CLEARMASK 0x00000000 +#define VREG_VING_MAXBW 0x200 +#define VREG_VING_MAXBW_ID 128 + +#define VVAL_VING_MAXBW_DEFAULT 0x0 /* Reset by hreset: 0 means no limit is enforced */ +/* Subfields of MaxBW */ +#define VREG_VING_MAXBW_RSV0_MASK 0xf0000000 /* Reserved [28..31] */ +#define VREG_VING_MAXBW_CBS_MASK 0x0fffff00 /* Committed Burst Size in 64 bytes [8..27] */ +#define VREG_VING_MAXBW_RSV1_MASK 0x00000080 /* Reserved [7..7] */ +#define VREG_VING_MAXBW_CIR_MASK 0x0000007f /* Committed Information Rate in 100 Mbps [0..6] */ + + + + +/* Context Scrub Control Register (31..0) */ +#define VREG_VING_CONTEXTSCRUB_MASK 0xffffffff +#define VREG_VING_CONTEXTSCRUB_ACCESSMODE 2 +#define VREG_VING_CONTEXTSCRUB_HOSTPRIVILEGE 1 +#define VREG_VING_CONTEXTSCRUB_RESERVEDMASK 0x7fffffe0 +#define VREG_VING_CONTEXTSCRUB_WRITEMASK 0x8000001f +#define VREG_VING_CONTEXTSCRUB_READMASK 0x8000001f +#define VREG_VING_CONTEXTSCRUB_CLEARMASK 0x00000000 +#define VREG_VING_CONTEXTSCRUB 0x300 +#define VREG_VING_CONTEXTSCRUB_ID 192 + +#define VVAL_VING_CONTEXTSCRUB_DEFAULT 0x0 /* Reset by sreset: Reset to 0 */ +/* Subfields of ContextScrub */ +#define VREG_VING_CONTEXTSCRUB_ENABLE_MASK 0x80000000 /* Enable Context Scrubber [31..31] */ +#define VREG_VING_CONTEXTSCRUB_RSV0_MASK 0x7fffffe0 /* Reserved [5..30] */ +#define VREG_VING_CONTEXTSCRUB_RATE_MASK 0x0000001f /* Scrub Rate - .3 sec to 10 sec [0..4] */ + + + + +/* Collection of internal SRAM parity error (31..0) */ +#define VREG_VING_PARERR_MASK 0xffffffff +#define VREG_VING_PARERR_ACCESSMODE 3 +#define VREG_VING_PARERR_HOSTPRIVILEGE 1 +#define VREG_VING_PARERR_RESERVEDMASK 0x00000000 +#define VREG_VING_PARERR_WRITEMASK 0xffffffff +#define VREG_VING_PARERR_READMASK 0xffffffff +#define VREG_VING_PARERR_CLEARMASK 0xffffffff +#define VREG_VING_PARERR 0xf00 +#define VREG_VING_PARERR_ID 960 + +#define VVAL_VING_PARERR_DEFAULT 0x0 /* Reset by hreset: Reset to 0 */ + +#endif /* VIOC_VING_REGISTERS_H_ */ + + diff --git a/drivers/net/vioc/f7/vnic_defs.h b/drivers/net/vioc/f7/vnic_defs.h new file mode 100644 index 0000000..cfe3ab9 --- /dev/null +++ b/drivers/net/vioc/f7/vnic_defs.h @@ -0,0 +1,2168 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ + +#ifndef _VNIC_H_ +#define _VNIC_H_ + +struct tx_pktBufDesc_Phys_w { + u32 word_0; + + /* Lower 32-Bits of 40-Bit Phys addr of buffer */ +# define VNIC_TX_BUFADDR_LO_WORD 0 +# define VNIC_TX_BUFADDR_LO_MASK 0xffffffff +# define VNIC_TX_BUFADDR_LO_SHIFT 0 +#ifndef GET_VNIC_TX_BUFADDR_LO +# define GET_VNIC_TX_BUFADDR_LO(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TX_BUFADDR_LO_MASK)) +#endif +#ifndef GET_VNIC_TX_BUFADDR_LO_SHIFTED +# define GET_VNIC_TX_BUFADDR_LO_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TX_BUFADDR_LO_MASK))>>VNIC_TX_BUFADDR_LO_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFADDR_LO +# define GET_NTOH_VNIC_TX_BUFADDR_LO(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TX_BUFADDR_LO_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFADDR_LO_SHIFTED +# define GET_NTOH_VNIC_TX_BUFADDR_LO_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TX_BUFADDR_LO_MASK))>>VNIC_TX_BUFADDR_LO_SHIFT) +#endif +#ifndef SET_VNIC_TX_BUFADDR_LO +# define SET_VNIC_TX_BUFADDR_LO(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_0) |= (val & VNIC_TX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_VNIC_TX_BUFADDR_LO_SHIFTED +# define SET_VNIC_TX_BUFADDR_LO_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_TX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFADDR_LO +# define SET_HTON_VNIC_TX_BUFADDR_LO(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_0) |= htonl(val & VNIC_TX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFADDR_LO_SHIFTED +# define SET_HTON_VNIC_TX_BUFADDR_LO_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_TX_BUFADDR_LO_MASK)) +#endif + + u32 word_1; + + /* SW makes descriptor usable by VIOC HW */ +# define VNIC_TX_HANDED_WORD 1 +# define VNIC_TX_HANDED_MASK 0x80000000 +# define VNIC_TX_HANDED_SHIFT 31 +#ifndef GET_VNIC_TX_HANDED +# define GET_VNIC_TX_HANDED(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_HANDED_MASK)) +#endif +#ifndef GET_VNIC_TX_HANDED_SHIFTED +# define GET_VNIC_TX_HANDED_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_HANDED_MASK))>>VNIC_TX_HANDED_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_HANDED +# define GET_NTOH_VNIC_TX_HANDED(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_HANDED_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_HANDED_SHIFTED +# define GET_NTOH_VNIC_TX_HANDED_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_HANDED_MASK))>>VNIC_TX_HANDED_SHIFT) +#endif +#ifndef SET_VNIC_TX_HANDED +# define SET_VNIC_TX_HANDED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_HANDED_MASK)) +#endif +#ifndef SET_VNIC_TX_HANDED_SHIFTED +# define SET_VNIC_TX_HANDED_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_HANDED_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_HANDED +# define SET_HTON_VNIC_TX_HANDED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_HANDED_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_HANDED_SHIFTED +# define SET_HTON_VNIC_TX_HANDED_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_HANDED_MASK)) +#endif + /* Handed to VIOC HW (0x1<<31) */ +# define VNIC_TX_HANDED_HW_W 0x80000000 + + /* indicates the validiti of the sts field */ +# define VNIC_TX_VALID_WORD 1 +# define VNIC_TX_VALID_MASK 0x40000000 +# define VNIC_TX_VALID_SHIFT 30 +#ifndef GET_VNIC_TX_VALID +# define GET_VNIC_TX_VALID(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_VALID_MASK)) +#endif +#ifndef GET_VNIC_TX_VALID_SHIFTED +# define GET_VNIC_TX_VALID_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_VALID_MASK))>>VNIC_TX_VALID_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_VALID +# define GET_NTOH_VNIC_TX_VALID(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_VALID_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_VALID_SHIFTED +# define GET_NTOH_VNIC_TX_VALID_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_VALID_MASK))>>VNIC_TX_VALID_SHIFT) +#endif +#ifndef SET_VNIC_TX_VALID +# define SET_VNIC_TX_VALID(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_VALID_MASK)) +#endif +#ifndef SET_VNIC_TX_VALID_SHIFTED +# define SET_VNIC_TX_VALID_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_VALID_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_VALID +# define SET_HTON_VNIC_TX_VALID(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_VALID_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_VALID_SHIFTED +# define SET_HTON_VNIC_TX_VALID_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_VALID_MASK)) +#endif + /* sts field is valid (0x1<<30) */ +# define VNIC_TX_VALID_W 0x40000000 + + /* status set by VIOC HW after handling descriptor */ +# define VNIC_TX_STS_WORD 1 +# define VNIC_TX_STS_MASK 0x38000000 +# define VNIC_TX_STS_SHIFT 27 +#ifndef GET_VNIC_TX_STS +# define GET_VNIC_TX_STS(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_STS_MASK)) +#endif +#ifndef GET_VNIC_TX_STS_SHIFTED +# define GET_VNIC_TX_STS_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_STS_MASK))>>VNIC_TX_STS_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_STS +# define GET_NTOH_VNIC_TX_STS(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_STS_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_STS_SHIFTED +# define GET_NTOH_VNIC_TX_STS_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_STS_MASK))>>VNIC_TX_STS_SHIFT) +#endif +#ifndef SET_VNIC_TX_STS +# define SET_VNIC_TX_STS(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_STS_MASK)) +#endif +#ifndef SET_VNIC_TX_STS_SHIFTED +# define SET_VNIC_TX_STS_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_STS_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_STS +# define SET_HTON_VNIC_TX_STS(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_STS_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_STS_SHIFTED +# define SET_HTON_VNIC_TX_STS_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_STS_MASK)) +#endif + /* Transmit successful; (0x0<<27) */ +# define VNIC_TX_TX_OK_W 0x00000000 + /* SOP too short (0x1<<27) */ +# define VNIC_TX_RUNT_SOP_W 0x08000000 + /* SOP framing error (0x2<<27) */ +# define VNIC_TX_SOP_FRAME_ERR_W 0x10000000 + /* MOP framing error (0x3<<27) */ +# define VNIC_TX_MOP_FRAME_ERR_W 0x18000000 + /* MOP framing error (0x4<<27) */ +# define VNIC_TX_LENGTH_ERR_W 0x20000000 + + /* Reserved */ +# define VNIC_TX_RSRVD_WORD 1 +# define VNIC_TX_RSRVD_MASK 0x04000000 +# define VNIC_TX_RSRVD_SHIFT 26 +#ifndef GET_VNIC_TX_RSRVD +# define GET_VNIC_TX_RSRVD(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_RSRVD_MASK)) +#endif +#ifndef GET_VNIC_TX_RSRVD_SHIFTED +# define GET_VNIC_TX_RSRVD_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_RSRVD_MASK))>>VNIC_TX_RSRVD_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_RSRVD +# define GET_NTOH_VNIC_TX_RSRVD(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_RSRVD_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_RSRVD_SHIFTED +# define GET_NTOH_VNIC_TX_RSRVD_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_RSRVD_MASK))>>VNIC_TX_RSRVD_SHIFT) +#endif +#ifndef SET_VNIC_TX_RSRVD +# define SET_VNIC_TX_RSRVD(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_RSRVD_MASK)) +#endif +#ifndef SET_VNIC_TX_RSRVD_SHIFTED +# define SET_VNIC_TX_RSRVD_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_RSRVD_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_RSRVD +# define SET_HTON_VNIC_TX_RSRVD(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_RSRVD_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_RSRVD_SHIFTED +# define SET_HTON_VNIC_TX_RSRVD_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_RSRVD_MASK)) +#endif + /* Reserved (0x0<<26) */ +# define VNIC_TX_RSRVD_W 0x00000000 + + /* Transmit interrupt request */ +# define VNIC_TX_INTR_REQ_WORD 1 +# define VNIC_TX_INTR_REQ_MASK 0x02000000 +# define VNIC_TX_INTR_REQ_SHIFT 25 +#ifndef GET_VNIC_TX_INTR_REQ +# define GET_VNIC_TX_INTR_REQ(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_INTR_REQ_MASK)) +#endif +#ifndef GET_VNIC_TX_INTR_REQ_SHIFTED +# define GET_VNIC_TX_INTR_REQ_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_INTR_REQ_MASK))>>VNIC_TX_INTR_REQ_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_INTR_REQ +# define GET_NTOH_VNIC_TX_INTR_REQ(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_INTR_REQ_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_INTR_REQ_SHIFTED +# define GET_NTOH_VNIC_TX_INTR_REQ_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_INTR_REQ_MASK))>>VNIC_TX_INTR_REQ_SHIFT) +#endif +#ifndef SET_VNIC_TX_INTR_REQ +# define SET_VNIC_TX_INTR_REQ(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_INTR_REQ_MASK)) +#endif +#ifndef SET_VNIC_TX_INTR_REQ_SHIFTED +# define SET_VNIC_TX_INTR_REQ_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_INTR_REQ_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_INTR_REQ +# define SET_HTON_VNIC_TX_INTR_REQ(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_INTR_REQ_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_INTR_REQ_SHIFTED +# define SET_HTON_VNIC_TX_INTR_REQ_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_INTR_REQ_MASK)) +#endif + /* Yes, Interrupt on xmt complete (0x1<<25) */ +# define VNIC_TX_INTR_W 0x02000000 + + /* Checksum trailer request */ +# define VNIC_TX_IP_CKSUM_REQ_WORD 1 +# define VNIC_TX_IP_CKSUM_REQ_MASK 0x01000000 +# define VNIC_TX_IP_CKSUM_REQ_SHIFT 24 +#ifndef GET_VNIC_TX_IP_CKSUM_REQ +# define GET_VNIC_TX_IP_CKSUM_REQ(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif +#ifndef GET_VNIC_TX_IP_CKSUM_REQ_SHIFTED +# define GET_VNIC_TX_IP_CKSUM_REQ_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_IP_CKSUM_REQ_MASK))>>VNIC_TX_IP_CKSUM_REQ_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_IP_CKSUM_REQ +# define GET_NTOH_VNIC_TX_IP_CKSUM_REQ(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_IP_CKSUM_REQ_SHIFTED +# define GET_NTOH_VNIC_TX_IP_CKSUM_REQ_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_IP_CKSUM_REQ_MASK))>>VNIC_TX_IP_CKSUM_REQ_SHIFT) +#endif +#ifndef SET_VNIC_TX_IP_CKSUM_REQ +# define SET_VNIC_TX_IP_CKSUM_REQ(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif +#ifndef SET_VNIC_TX_IP_CKSUM_REQ_SHIFTED +# define SET_VNIC_TX_IP_CKSUM_REQ_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_IP_CKSUM_REQ +# define SET_HTON_VNIC_TX_IP_CKSUM_REQ(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_IP_CKSUM_REQ_SHIFTED +# define SET_HTON_VNIC_TX_IP_CKSUM_REQ_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_IP_CKSUM_REQ_MASK)) +#endif + /* Yes (0x1<<24) */ +# define VNIC_TX_IP_CKSUM_W 0x01000000 + + /* first segment of the pkt */ +# define VNIC_TX_SOP_WORD 1 +# define VNIC_TX_SOP_MASK 0x00800000 +# define VNIC_TX_SOP_SHIFT 23 +#ifndef GET_VNIC_TX_SOP +# define GET_VNIC_TX_SOP(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_SOP_MASK)) +#endif +#ifndef GET_VNIC_TX_SOP_SHIFTED +# define GET_VNIC_TX_SOP_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_SOP_MASK))>>VNIC_TX_SOP_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_SOP +# define GET_NTOH_VNIC_TX_SOP(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_SOP_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_SOP_SHIFTED +# define GET_NTOH_VNIC_TX_SOP_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_SOP_MASK))>>VNIC_TX_SOP_SHIFT) +#endif +#ifndef SET_VNIC_TX_SOP +# define SET_VNIC_TX_SOP(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_SOP_MASK)) +#endif +#ifndef SET_VNIC_TX_SOP_SHIFTED +# define SET_VNIC_TX_SOP_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_SOP_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_SOP +# define SET_HTON_VNIC_TX_SOP(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_SOP_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_SOP_SHIFTED +# define SET_HTON_VNIC_TX_SOP_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_SOP_MASK)) +#endif + /* Yes (0x1<<23) */ +# define VNIC_TX_SOP_W 0x00800000 + + /* last segment of the pkt */ +# define VNIC_TX_EOP_WORD 1 +# define VNIC_TX_EOP_MASK 0x00400000 +# define VNIC_TX_EOP_SHIFT 22 +#ifndef GET_VNIC_TX_EOP +# define GET_VNIC_TX_EOP(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_EOP_MASK)) +#endif +#ifndef GET_VNIC_TX_EOP_SHIFTED +# define GET_VNIC_TX_EOP_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_EOP_MASK))>>VNIC_TX_EOP_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_EOP +# define GET_NTOH_VNIC_TX_EOP(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_EOP_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_EOP_SHIFTED +# define GET_NTOH_VNIC_TX_EOP_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_EOP_MASK))>>VNIC_TX_EOP_SHIFT) +#endif +#ifndef SET_VNIC_TX_EOP +# define SET_VNIC_TX_EOP(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_EOP_MASK)) +#endif +#ifndef SET_VNIC_TX_EOP_SHIFTED +# define SET_VNIC_TX_EOP_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_EOP_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_EOP +# define SET_HTON_VNIC_TX_EOP(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_EOP_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_EOP_SHIFTED +# define SET_HTON_VNIC_TX_EOP_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_EOP_MASK)) +#endif + /* Yes (0x1<<22) */ +# define VNIC_TX_EOP_W 0x00400000 + + /* 14-Bits length in bytes to transmit */ +# define VNIC_TX_BUFLEN_WORD 1 +# define VNIC_TX_BUFLEN_MASK 0x003fff00 +# define VNIC_TX_BUFLEN_SHIFT 8 +#ifndef GET_VNIC_TX_BUFLEN +# define GET_VNIC_TX_BUFLEN(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFLEN_MASK)) +#endif +#ifndef GET_VNIC_TX_BUFLEN_SHIFTED +# define GET_VNIC_TX_BUFLEN_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFLEN_MASK))>>VNIC_TX_BUFLEN_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFLEN +# define GET_NTOH_VNIC_TX_BUFLEN(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFLEN_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFLEN_SHIFTED +# define GET_NTOH_VNIC_TX_BUFLEN_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFLEN_MASK))>>VNIC_TX_BUFLEN_SHIFT) +#endif +#ifndef SET_VNIC_TX_BUFLEN +# define SET_VNIC_TX_BUFLEN(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_BUFLEN_MASK)) +#endif +#ifndef SET_VNIC_TX_BUFLEN_SHIFTED +# define SET_VNIC_TX_BUFLEN_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_BUFLEN_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFLEN +# define SET_HTON_VNIC_TX_BUFLEN(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_BUFLEN_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFLEN_SHIFTED +# define SET_HTON_VNIC_TX_BUFLEN_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_BUFLEN_MASK)) +#endif + + /* Top 8-Bits of 40-Bit Phys address of buffer */ +# define VNIC_TX_BUFADDR_HI_WORD 1 +# define VNIC_TX_BUFADDR_HI_MASK 0x000000ff +# define VNIC_TX_BUFADDR_HI_SHIFT 0 +#ifndef GET_VNIC_TX_BUFADDR_HI +# define GET_VNIC_TX_BUFADDR_HI(p) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFADDR_HI_MASK)) +#endif +#ifndef GET_VNIC_TX_BUFADDR_HI_SHIFTED +# define GET_VNIC_TX_BUFADDR_HI_SHIFTED(p) \ + (((((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFADDR_HI_MASK))>>VNIC_TX_BUFADDR_HI_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFADDR_HI +# define GET_NTOH_VNIC_TX_BUFADDR_HI(p) \ + (ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFADDR_HI_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TX_BUFADDR_HI_SHIFTED +# define GET_NTOH_VNIC_TX_BUFADDR_HI_SHIFTED(p) \ + ((ntohl(((struct tx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TX_BUFADDR_HI_MASK))>>VNIC_TX_BUFADDR_HI_SHIFT) +#endif +#ifndef SET_VNIC_TX_BUFADDR_HI +# define SET_VNIC_TX_BUFADDR_HI(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_VNIC_TX_BUFADDR_HI_SHIFTED +# define SET_VNIC_TX_BUFADDR_HI_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFADDR_HI +# define SET_HTON_VNIC_TX_BUFADDR_HI(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_HTON_VNIC_TX_BUFADDR_HI_SHIFTED +# define SET_HTON_VNIC_TX_BUFADDR_HI_SHIFTED(p,val) \ + ((((struct tx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TX_BUFADDR_HI_MASK)) +#endif + +}; + +struct txd_pktBufDesc_Phys_w { + u32 word_0; + + /* RESERVED */ +# define VNIC_TXD_UNUSED0_WORD 0 +# define VNIC_TXD_UNUSED0_MASK 0xffffffff +# define VNIC_TXD_UNUSED0_SHIFT 0 +#ifndef GET_VNIC_TXD_UNUSED0 +# define GET_VNIC_TXD_UNUSED0(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TXD_UNUSED0_MASK)) +#endif +#ifndef GET_VNIC_TXD_UNUSED0_SHIFTED +# define GET_VNIC_TXD_UNUSED0_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TXD_UNUSED0_MASK))>>VNIC_TXD_UNUSED0_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED0 +# define GET_NTOH_VNIC_TXD_UNUSED0(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TXD_UNUSED0_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED0_SHIFTED +# define GET_NTOH_VNIC_TXD_UNUSED0_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_TXD_UNUSED0_MASK))>>VNIC_TXD_UNUSED0_SHIFT) +#endif +#ifndef SET_VNIC_TXD_UNUSED0 +# define SET_VNIC_TXD_UNUSED0(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_0) |= (val & VNIC_TXD_UNUSED0_MASK)) +#endif +#ifndef SET_VNIC_TXD_UNUSED0_SHIFTED +# define SET_VNIC_TXD_UNUSED0_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_TXD_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED0 +# define SET_HTON_VNIC_TXD_UNUSED0(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_0) |= htonl(val & VNIC_TXD_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED0_SHIFTED +# define SET_HTON_VNIC_TXD_UNUSED0_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_TXD_UNUSED0_MASK)) +#endif + + u32 word_1; + + /* Ownership of the descriptor */ +# define VNIC_TXD_OWNED_WORD 1 +# define VNIC_TXD_OWNED_MASK 0x80000000 +# define VNIC_TXD_OWNED_SHIFT 31 +#ifndef GET_VNIC_TXD_OWNED +# define GET_VNIC_TXD_OWNED(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_OWNED_MASK)) +#endif +#ifndef GET_VNIC_TXD_OWNED_SHIFTED +# define GET_VNIC_TXD_OWNED_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_OWNED_MASK))>>VNIC_TXD_OWNED_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_OWNED +# define GET_NTOH_VNIC_TXD_OWNED(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_OWNED_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_OWNED_SHIFTED +# define GET_NTOH_VNIC_TXD_OWNED_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_OWNED_MASK))>>VNIC_TXD_OWNED_SHIFT) +#endif +#ifndef SET_VNIC_TXD_OWNED +# define SET_VNIC_TXD_OWNED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_OWNED_MASK)) +#endif +#ifndef SET_VNIC_TXD_OWNED_SHIFTED +# define SET_VNIC_TXD_OWNED_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_OWNED_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_OWNED +# define SET_HTON_VNIC_TXD_OWNED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_OWNED_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_OWNED_SHIFTED +# define SET_HTON_VNIC_TXD_OWNED_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_OWNED_MASK)) +#endif + /* Desc Active, Owned by HW (0x1<<31) */ +# define VNIC_TXD_OWNED_HW_W 0x80000000 + + /* Determines status of the operation posted */ +# define VNIC_TXD_STATUS_WORD 1 +# define VNIC_TXD_STATUS_MASK 0x40000000 +# define VNIC_TXD_STATUS_SHIFT 30 +#ifndef GET_VNIC_TXD_STATUS +# define GET_VNIC_TXD_STATUS(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_STATUS_MASK)) +#endif +#ifndef GET_VNIC_TXD_STATUS_SHIFTED +# define GET_VNIC_TXD_STATUS_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_STATUS_MASK))>>VNIC_TXD_STATUS_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_STATUS +# define GET_NTOH_VNIC_TXD_STATUS(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_STATUS_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_STATUS_SHIFTED +# define GET_NTOH_VNIC_TXD_STATUS_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_STATUS_MASK))>>VNIC_TXD_STATUS_SHIFT) +#endif +#ifndef SET_VNIC_TXD_STATUS +# define SET_VNIC_TXD_STATUS(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_STATUS_MASK)) +#endif +#ifndef SET_VNIC_TXD_STATUS_SHIFTED +# define SET_VNIC_TXD_STATUS_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_STATUS_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_STATUS +# define SET_HTON_VNIC_TXD_STATUS(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_STATUS_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_STATUS_SHIFTED +# define SET_HTON_VNIC_TXD_STATUS_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_STATUS_MASK)) +#endif + /* Posted, posted to VIOC (0x1<<30) */ +# define VNIC_TXD_STATUS_POSTED_W 0x40000000 + + /* RESERVED */ +# define VNIC_TXD_UNUSED1_WORD 1 +# define VNIC_TXD_UNUSED1_MASK 0x3e000000 +# define VNIC_TXD_UNUSED1_SHIFT 25 +#ifndef GET_VNIC_TXD_UNUSED1 +# define GET_VNIC_TXD_UNUSED1(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED1_MASK)) +#endif +#ifndef GET_VNIC_TXD_UNUSED1_SHIFTED +# define GET_VNIC_TXD_UNUSED1_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED1_MASK))>>VNIC_TXD_UNUSED1_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED1 +# define GET_NTOH_VNIC_TXD_UNUSED1(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED1_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED1_SHIFTED +# define GET_NTOH_VNIC_TXD_UNUSED1_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED1_MASK))>>VNIC_TXD_UNUSED1_SHIFT) +#endif +#ifndef SET_VNIC_TXD_UNUSED1 +# define SET_VNIC_TXD_UNUSED1(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_UNUSED1_MASK)) +#endif +#ifndef SET_VNIC_TXD_UNUSED1_SHIFTED +# define SET_VNIC_TXD_UNUSED1_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED1 +# define SET_HTON_VNIC_TXD_UNUSED1(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED1_SHIFTED +# define SET_HTON_VNIC_TXD_UNUSED1_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_UNUSED1_MASK)) +#endif + + /* VIOC transmit continuation */ +# define VNIC_TXD_CONTINUATION_WORD 1 +# define VNIC_TXD_CONTINUATION_MASK 0x01000000 +# define VNIC_TXD_CONTINUATION_SHIFT 24 +#ifndef GET_VNIC_TXD_CONTINUATION +# define GET_VNIC_TXD_CONTINUATION(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_CONTINUATION_MASK)) +#endif +#ifndef GET_VNIC_TXD_CONTINUATION_SHIFTED +# define GET_VNIC_TXD_CONTINUATION_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_CONTINUATION_MASK))>>VNIC_TXD_CONTINUATION_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_CONTINUATION +# define GET_NTOH_VNIC_TXD_CONTINUATION(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_CONTINUATION_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_CONTINUATION_SHIFTED +# define GET_NTOH_VNIC_TXD_CONTINUATION_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_CONTINUATION_MASK))>>VNIC_TXD_CONTINUATION_SHIFT) +#endif +#ifndef SET_VNIC_TXD_CONTINUATION +# define SET_VNIC_TXD_CONTINUATION(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_CONTINUATION_MASK)) +#endif +#ifndef SET_VNIC_TXD_CONTINUATION_SHIFTED +# define SET_VNIC_TXD_CONTINUATION_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_CONTINUATION_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_CONTINUATION +# define SET_HTON_VNIC_TXD_CONTINUATION(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_CONTINUATION_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_CONTINUATION_SHIFTED +# define SET_HTON_VNIC_TXD_CONTINUATION_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_CONTINUATION_MASK)) +#endif + /* Next desc being proc (0x1<<24) */ +# define VNIC_TXD_CONT_ON_W 0x01000000 + + /* RESERVED */ +# define VNIC_TXD_UNUSED2_WORD 1 +# define VNIC_TXD_UNUSED2_MASK 0x00ffff00 +# define VNIC_TXD_UNUSED2_SHIFT 8 +#ifndef GET_VNIC_TXD_UNUSED2 +# define GET_VNIC_TXD_UNUSED2(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED2_MASK)) +#endif +#ifndef GET_VNIC_TXD_UNUSED2_SHIFTED +# define GET_VNIC_TXD_UNUSED2_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED2_MASK))>>VNIC_TXD_UNUSED2_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED2 +# define GET_NTOH_VNIC_TXD_UNUSED2(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED2_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED2_SHIFTED +# define GET_NTOH_VNIC_TXD_UNUSED2_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED2_MASK))>>VNIC_TXD_UNUSED2_SHIFT) +#endif +#ifndef SET_VNIC_TXD_UNUSED2 +# define SET_VNIC_TXD_UNUSED2(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_UNUSED2_MASK)) +#endif +#ifndef SET_VNIC_TXD_UNUSED2_SHIFTED +# define SET_VNIC_TXD_UNUSED2_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_UNUSED2_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED2 +# define SET_HTON_VNIC_TXD_UNUSED2(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_UNUSED2_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED2_SHIFTED +# define SET_HTON_VNIC_TXD_UNUSED2_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_UNUSED2_MASK)) +#endif + + /* RESERVED */ +# define VNIC_TXD_UNUSED3_WORD 1 +# define VNIC_TXD_UNUSED3_MASK 0x000000ff +# define VNIC_TXD_UNUSED3_SHIFT 0 +#ifndef GET_VNIC_TXD_UNUSED3 +# define GET_VNIC_TXD_UNUSED3(p) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED3_MASK)) +#endif +#ifndef GET_VNIC_TXD_UNUSED3_SHIFTED +# define GET_VNIC_TXD_UNUSED3_SHIFTED(p) \ + (((((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED3_MASK))>>VNIC_TXD_UNUSED3_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED3 +# define GET_NTOH_VNIC_TXD_UNUSED3(p) \ + (ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED3_MASK)) +#endif +#ifndef GET_NTOH_VNIC_TXD_UNUSED3_SHIFTED +# define GET_NTOH_VNIC_TXD_UNUSED3_SHIFTED(p) \ + ((ntohl(((struct txd_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_TXD_UNUSED3_MASK))>>VNIC_TXD_UNUSED3_SHIFT) +#endif +#ifndef SET_VNIC_TXD_UNUSED3 +# define SET_VNIC_TXD_UNUSED3(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_TXD_UNUSED3_MASK)) +#endif +#ifndef SET_VNIC_TXD_UNUSED3_SHIFTED +# define SET_VNIC_TXD_UNUSED3_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_TXD_UNUSED3_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED3 +# define SET_HTON_VNIC_TXD_UNUSED3(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_TXD_UNUSED3_MASK)) +#endif +#ifndef SET_HTON_VNIC_TXD_UNUSED3_SHIFTED +# define SET_HTON_VNIC_TXD_UNUSED3_SHIFTED(p,val) \ + ((((struct txd_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_TXD_UNUSED3_MASK)) +#endif + +}; + +struct rx_pktBufDesc_Phys_w { + u32 word_0; + + /* Lo 32-Bits of 40-Bit Phys addr of buffer */ +# define VNIC_RX_BUFADDR_LO_WORD 0 +# define VNIC_RX_BUFADDR_LO_MASK 0xffffffff +# define VNIC_RX_BUFADDR_LO_SHIFT 0 +#ifndef GET_VNIC_RX_BUFADDR_LO +# define GET_VNIC_RX_BUFADDR_LO(p) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_RX_BUFADDR_LO_MASK)) +#endif +#ifndef GET_VNIC_RX_BUFADDR_LO_SHIFTED +# define GET_VNIC_RX_BUFADDR_LO_SHIFTED(p) \ + (((((struct rx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_RX_BUFADDR_LO_MASK))>>VNIC_RX_BUFADDR_LO_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RX_BUFADDR_LO +# define GET_NTOH_VNIC_RX_BUFADDR_LO(p) \ + (ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_RX_BUFADDR_LO_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RX_BUFADDR_LO_SHIFTED +# define GET_NTOH_VNIC_RX_BUFADDR_LO_SHIFTED(p) \ + ((ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_0)&(VNIC_RX_BUFADDR_LO_MASK))>>VNIC_RX_BUFADDR_LO_SHIFT) +#endif +#ifndef SET_VNIC_RX_BUFADDR_LO +# define SET_VNIC_RX_BUFADDR_LO(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_0) |= (val & VNIC_RX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_VNIC_RX_BUFADDR_LO_SHIFTED +# define SET_VNIC_RX_BUFADDR_LO_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_RX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_BUFADDR_LO +# define SET_HTON_VNIC_RX_BUFADDR_LO(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_0) |= htonl(val & VNIC_RX_BUFADDR_LO_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_BUFADDR_LO_SHIFTED +# define SET_HTON_VNIC_RX_BUFADDR_LO_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_RX_BUFADDR_LO_MASK)) +#endif + + u32 word_1; + + /* Determines ownership of the descriptor */ +# define VNIC_RX_OWNED_WORD 1 +# define VNIC_RX_OWNED_MASK 0x80000000 +# define VNIC_RX_OWNED_SHIFT 31 +#ifndef GET_VNIC_RX_OWNED +# define GET_VNIC_RX_OWNED(p) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_OWNED_MASK)) +#endif +#ifndef GET_VNIC_RX_OWNED_SHIFTED +# define GET_VNIC_RX_OWNED_SHIFTED(p) \ + (((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_OWNED_MASK))>>VNIC_RX_OWNED_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RX_OWNED +# define GET_NTOH_VNIC_RX_OWNED(p) \ + (ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_OWNED_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RX_OWNED_SHIFTED +# define GET_NTOH_VNIC_RX_OWNED_SHIFTED(p) \ + ((ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_OWNED_MASK))>>VNIC_RX_OWNED_SHIFT) +#endif +#ifndef SET_VNIC_RX_OWNED +# define SET_VNIC_RX_OWNED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_RX_OWNED_MASK)) +#endif +#ifndef SET_VNIC_RX_OWNED_SHIFTED +# define SET_VNIC_RX_OWNED_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_RX_OWNED_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_OWNED +# define SET_HTON_VNIC_RX_OWNED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_RX_OWNED_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_OWNED_SHIFTED +# define SET_HTON_VNIC_RX_OWNED_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_RX_OWNED_MASK)) +#endif + /* VIOC HW (0x1<<31) */ +# define VNIC_RX_OWNED_HW_W 0x80000000 + + /* RESERVED */ +# define VNIC_RX_UNUSED0_WORD 1 +# define VNIC_RX_UNUSED0_MASK 0x7f000000 +# define VNIC_RX_UNUSED0_SHIFT 24 +#ifndef GET_VNIC_RX_UNUSED0 +# define GET_VNIC_RX_UNUSED0(p) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED0_MASK)) +#endif +#ifndef GET_VNIC_RX_UNUSED0_SHIFTED +# define GET_VNIC_RX_UNUSED0_SHIFTED(p) \ + (((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED0_MASK))>>VNIC_RX_UNUSED0_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RX_UNUSED0 +# define GET_NTOH_VNIC_RX_UNUSED0(p) \ + (ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED0_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RX_UNUSED0_SHIFTED +# define GET_NTOH_VNIC_RX_UNUSED0_SHIFTED(p) \ + ((ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED0_MASK))>>VNIC_RX_UNUSED0_SHIFT) +#endif +#ifndef SET_VNIC_RX_UNUSED0 +# define SET_VNIC_RX_UNUSED0(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_RX_UNUSED0_MASK)) +#endif +#ifndef SET_VNIC_RX_UNUSED0_SHIFTED +# define SET_VNIC_RX_UNUSED0_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_RX_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_UNUSED0 +# define SET_HTON_VNIC_RX_UNUSED0(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_RX_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_UNUSED0_SHIFTED +# define SET_HTON_VNIC_RX_UNUSED0_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_RX_UNUSED0_MASK)) +#endif + + /* RESERVED */ +# define VNIC_RX_UNUSED1_WORD 1 +# define VNIC_RX_UNUSED1_MASK 0x00ffff00 +# define VNIC_RX_UNUSED1_SHIFT 8 +#ifndef GET_VNIC_RX_UNUSED1 +# define GET_VNIC_RX_UNUSED1(p) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED1_MASK)) +#endif +#ifndef GET_VNIC_RX_UNUSED1_SHIFTED +# define GET_VNIC_RX_UNUSED1_SHIFTED(p) \ + (((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED1_MASK))>>VNIC_RX_UNUSED1_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RX_UNUSED1 +# define GET_NTOH_VNIC_RX_UNUSED1(p) \ + (ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED1_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RX_UNUSED1_SHIFTED +# define GET_NTOH_VNIC_RX_UNUSED1_SHIFTED(p) \ + ((ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_UNUSED1_MASK))>>VNIC_RX_UNUSED1_SHIFT) +#endif +#ifndef SET_VNIC_RX_UNUSED1 +# define SET_VNIC_RX_UNUSED1(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_RX_UNUSED1_MASK)) +#endif +#ifndef SET_VNIC_RX_UNUSED1_SHIFTED +# define SET_VNIC_RX_UNUSED1_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_RX_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_UNUSED1 +# define SET_HTON_VNIC_RX_UNUSED1(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_RX_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_UNUSED1_SHIFTED +# define SET_HTON_VNIC_RX_UNUSED1_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_RX_UNUSED1_MASK)) +#endif + + /* Hi 8-Bits of 40-Bit Phy address of buffer */ +# define VNIC_RX_BUFADDR_HI_WORD 1 +# define VNIC_RX_BUFADDR_HI_MASK 0x000000ff +# define VNIC_RX_BUFADDR_HI_SHIFT 0 +#ifndef GET_VNIC_RX_BUFADDR_HI +# define GET_VNIC_RX_BUFADDR_HI(p) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_BUFADDR_HI_MASK)) +#endif +#ifndef GET_VNIC_RX_BUFADDR_HI_SHIFTED +# define GET_VNIC_RX_BUFADDR_HI_SHIFTED(p) \ + (((((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_BUFADDR_HI_MASK))>>VNIC_RX_BUFADDR_HI_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RX_BUFADDR_HI +# define GET_NTOH_VNIC_RX_BUFADDR_HI(p) \ + (ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_BUFADDR_HI_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RX_BUFADDR_HI_SHIFTED +# define GET_NTOH_VNIC_RX_BUFADDR_HI_SHIFTED(p) \ + ((ntohl(((struct rx_pktBufDesc_Phys_w *)p)->word_1)&(VNIC_RX_BUFADDR_HI_MASK))>>VNIC_RX_BUFADDR_HI_SHIFT) +#endif +#ifndef SET_VNIC_RX_BUFADDR_HI +# define SET_VNIC_RX_BUFADDR_HI(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= (val & VNIC_RX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_VNIC_RX_BUFADDR_HI_SHIFTED +# define SET_VNIC_RX_BUFADDR_HI_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_RX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_BUFADDR_HI +# define SET_HTON_VNIC_RX_BUFADDR_HI(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_RX_BUFADDR_HI_MASK)) +#endif +#ifndef SET_HTON_VNIC_RX_BUFADDR_HI_SHIFTED +# define SET_HTON_VNIC_RX_BUFADDR_HI_SHIFTED(p,val) \ + ((((struct rx_pktBufDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_RX_BUFADDR_HI_MASK)) +#endif + +}; + +struct rxc_pktDesc_Phys_w { + u32 word_0; + + /* Descriptor INDEX on the rx ring */ +# define VNIC_RXC_IDX_WORD 0 +# define VNIC_RXC_IDX_MASK 0xffff0000 +# define VNIC_RXC_IDX_SHIFT 16 +#ifndef GET_VNIC_RXC_IDX +# define GET_VNIC_RXC_IDX(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_IDX_MASK)) +#endif +#ifndef GET_VNIC_RXC_IDX_SHIFTED +# define GET_VNIC_RXC_IDX_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_IDX_MASK))>>VNIC_RXC_IDX_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_IDX +# define GET_NTOH_VNIC_RXC_IDX(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_IDX_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_IDX_SHIFTED +# define GET_NTOH_VNIC_RXC_IDX_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_IDX_MASK))>>VNIC_RXC_IDX_SHIFT) +#endif +#ifndef SET_VNIC_RXC_IDX +# define SET_VNIC_RXC_IDX(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= (val & VNIC_RXC_IDX_MASK)) +#endif +#ifndef SET_VNIC_RXC_IDX_SHIFTED +# define SET_VNIC_RXC_IDX_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_RXC_IDX_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_IDX +# define SET_HTON_VNIC_RXC_IDX(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= htonl(val & VNIC_RXC_IDX_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_IDX_SHIFTED +# define SET_HTON_VNIC_RXC_IDX_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_RXC_IDX_MASK)) +#endif + + /* Unique opaque ID for pkt in rx ring */ +# define VNIC_RXC_PKT_ID_WORD 0 +# define VNIC_RXC_PKT_ID_MASK 0x0000ffff +# define VNIC_RXC_PKT_ID_SHIFT 0 +#ifndef GET_VNIC_RXC_PKT_ID +# define GET_VNIC_RXC_PKT_ID(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_PKT_ID_MASK)) +#endif +#ifndef GET_VNIC_RXC_PKT_ID_SHIFTED +# define GET_VNIC_RXC_PKT_ID_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_PKT_ID_MASK))>>VNIC_RXC_PKT_ID_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_PKT_ID +# define GET_NTOH_VNIC_RXC_PKT_ID(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_PKT_ID_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_PKT_ID_SHIFTED +# define GET_NTOH_VNIC_RXC_PKT_ID_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_0)&(VNIC_RXC_PKT_ID_MASK))>>VNIC_RXC_PKT_ID_SHIFT) +#endif +#ifndef SET_VNIC_RXC_PKT_ID +# define SET_VNIC_RXC_PKT_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= (val & VNIC_RXC_PKT_ID_MASK)) +#endif +#ifndef SET_VNIC_RXC_PKT_ID_SHIFTED +# define SET_VNIC_RXC_PKT_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_RXC_PKT_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_PKT_ID +# define SET_HTON_VNIC_RXC_PKT_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= htonl(val & VNIC_RXC_PKT_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_PKT_ID_SHIFTED +# define SET_HTON_VNIC_RXC_PKT_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_RXC_PKT_ID_MASK)) +#endif + + u32 word_1; + + /* 16-bit IP checksum or 32-Bit CRC chksum */ +# define VNIC_RXC_CKSUM_WORD 1 +# define VNIC_RXC_CKSUM_MASK 0xffffffff +# define VNIC_RXC_CKSUM_SHIFT 0 +#ifndef GET_VNIC_RXC_CKSUM +# define GET_VNIC_RXC_CKSUM(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_1)&(VNIC_RXC_CKSUM_MASK)) +#endif +#ifndef GET_VNIC_RXC_CKSUM_SHIFTED +# define GET_VNIC_RXC_CKSUM_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_1)&(VNIC_RXC_CKSUM_MASK))>>VNIC_RXC_CKSUM_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_CKSUM +# define GET_NTOH_VNIC_RXC_CKSUM(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_1)&(VNIC_RXC_CKSUM_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_CKSUM_SHIFTED +# define GET_NTOH_VNIC_RXC_CKSUM_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_1)&(VNIC_RXC_CKSUM_MASK))>>VNIC_RXC_CKSUM_SHIFT) +#endif +#ifndef SET_VNIC_RXC_CKSUM +# define SET_VNIC_RXC_CKSUM(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_1) |= (val & VNIC_RXC_CKSUM_MASK)) +#endif +#ifndef SET_VNIC_RXC_CKSUM_SHIFTED +# define SET_VNIC_RXC_CKSUM_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_1) |= ((val<word_1) &= (~VNIC_RXC_CKSUM_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_CKSUM +# define SET_HTON_VNIC_RXC_CKSUM(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_1) |= htonl(val & VNIC_RXC_CKSUM_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_CKSUM_SHIFTED +# define SET_HTON_VNIC_RXC_CKSUM_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_1) |= htonl((val<word_1) &= htonl(~VNIC_RXC_CKSUM_MASK)) +#endif + + u32 word_2; + + /* VNIC id of packet buffer */ +# define VNIC_RXC_VNIC_ID_WORD 2 +# define VNIC_RXC_VNIC_ID_MASK 0xf0000000 +# define VNIC_RXC_VNIC_ID_SHIFT 28 +#ifndef GET_VNIC_RXC_VNIC_ID +# define GET_VNIC_RXC_VNIC_ID(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_ID_MASK)) +#endif +#ifndef GET_VNIC_RXC_VNIC_ID_SHIFTED +# define GET_VNIC_RXC_VNIC_ID_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_ID_MASK))>>VNIC_RXC_VNIC_ID_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_VNIC_ID +# define GET_NTOH_VNIC_RXC_VNIC_ID(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_ID_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_VNIC_ID_SHIFTED +# define GET_NTOH_VNIC_RXC_VNIC_ID_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_ID_MASK))>>VNIC_RXC_VNIC_ID_SHIFT) +#endif +#ifndef SET_VNIC_RXC_VNIC_ID +# define SET_VNIC_RXC_VNIC_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= (val & VNIC_RXC_VNIC_ID_MASK)) +#endif +#ifndef SET_VNIC_RXC_VNIC_ID_SHIFTED +# define SET_VNIC_RXC_VNIC_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= ((val<word_2) &= (~VNIC_RXC_VNIC_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_VNIC_ID +# define SET_HTON_VNIC_RXC_VNIC_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl(val & VNIC_RXC_VNIC_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_VNIC_ID_SHIFTED +# define SET_HTON_VNIC_RXC_VNIC_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VNIC_RXC_VNIC_ID_MASK)) +#endif + + /* RESERVED */ +# define VNIC_RXC_UNUSED1_WORD 2 +# define VNIC_RXC_UNUSED1_MASK 0x0c000000 +# define VNIC_RXC_UNUSED1_SHIFT 26 +#ifndef GET_VNIC_RXC_UNUSED1 +# define GET_VNIC_RXC_UNUSED1(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED1_MASK)) +#endif +#ifndef GET_VNIC_RXC_UNUSED1_SHIFTED +# define GET_VNIC_RXC_UNUSED1_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED1_MASK))>>VNIC_RXC_UNUSED1_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED1 +# define GET_NTOH_VNIC_RXC_UNUSED1(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED1_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED1_SHIFTED +# define GET_NTOH_VNIC_RXC_UNUSED1_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED1_MASK))>>VNIC_RXC_UNUSED1_SHIFT) +#endif +#ifndef SET_VNIC_RXC_UNUSED1 +# define SET_VNIC_RXC_UNUSED1(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= (val & VNIC_RXC_UNUSED1_MASK)) +#endif +#ifndef SET_VNIC_RXC_UNUSED1_SHIFTED +# define SET_VNIC_RXC_UNUSED1_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= ((val<word_2) &= (~VNIC_RXC_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED1 +# define SET_HTON_VNIC_RXC_UNUSED1(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl(val & VNIC_RXC_UNUSED1_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED1_SHIFTED +# define SET_HTON_VNIC_RXC_UNUSED1_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VNIC_RXC_UNUSED1_MASK)) +#endif + + /* Queue number within VNIC */ +# define VNIC_RXC_VNIC_Q_WORD 2 +# define VNIC_RXC_VNIC_Q_MASK 0x03000000 +# define VNIC_RXC_VNIC_Q_SHIFT 24 +#ifndef GET_VNIC_RXC_VNIC_Q +# define GET_VNIC_RXC_VNIC_Q(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_Q_MASK)) +#endif +#ifndef GET_VNIC_RXC_VNIC_Q_SHIFTED +# define GET_VNIC_RXC_VNIC_Q_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_Q_MASK))>>VNIC_RXC_VNIC_Q_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_VNIC_Q +# define GET_NTOH_VNIC_RXC_VNIC_Q(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_Q_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_VNIC_Q_SHIFTED +# define GET_NTOH_VNIC_RXC_VNIC_Q_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_VNIC_Q_MASK))>>VNIC_RXC_VNIC_Q_SHIFT) +#endif +#ifndef SET_VNIC_RXC_VNIC_Q +# define SET_VNIC_RXC_VNIC_Q(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= (val & VNIC_RXC_VNIC_Q_MASK)) +#endif +#ifndef SET_VNIC_RXC_VNIC_Q_SHIFTED +# define SET_VNIC_RXC_VNIC_Q_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= ((val<word_2) &= (~VNIC_RXC_VNIC_Q_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_VNIC_Q +# define SET_HTON_VNIC_RXC_VNIC_Q(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl(val & VNIC_RXC_VNIC_Q_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_VNIC_Q_SHIFTED +# define SET_HTON_VNIC_RXC_VNIC_Q_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VNIC_RXC_VNIC_Q_MASK)) +#endif + + /* Encapsulation Tag from F7 Header */ +# define VNIC_RXC_ENTAG_WORD 2 +# define VNIC_RXC_ENTAG_MASK 0x00ff0000 +# define VNIC_RXC_ENTAG_SHIFT 16 +#ifndef GET_VNIC_RXC_ENTAG +# define GET_VNIC_RXC_ENTAG(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_ENTAG_MASK)) +#endif +#ifndef GET_VNIC_RXC_ENTAG_SHIFTED +# define GET_VNIC_RXC_ENTAG_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_ENTAG_MASK))>>VNIC_RXC_ENTAG_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_ENTAG +# define GET_NTOH_VNIC_RXC_ENTAG(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_ENTAG_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_ENTAG_SHIFTED +# define GET_NTOH_VNIC_RXC_ENTAG_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_ENTAG_MASK))>>VNIC_RXC_ENTAG_SHIFT) +#endif +#ifndef SET_VNIC_RXC_ENTAG +# define SET_VNIC_RXC_ENTAG(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= (val & VNIC_RXC_ENTAG_MASK)) +#endif +#ifndef SET_VNIC_RXC_ENTAG_SHIFTED +# define SET_VNIC_RXC_ENTAG_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= ((val<word_2) &= (~VNIC_RXC_ENTAG_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_ENTAG +# define SET_HTON_VNIC_RXC_ENTAG(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl(val & VNIC_RXC_ENTAG_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_ENTAG_SHIFTED +# define SET_HTON_VNIC_RXC_ENTAG_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VNIC_RXC_ENTAG_MASK)) +#endif + + /* RESERVED */ +# define VNIC_RXC_UNUSED2_WORD 2 +# define VNIC_RXC_UNUSED2_MASK 0x0000ffff +# define VNIC_RXC_UNUSED2_SHIFT 0 +#ifndef GET_VNIC_RXC_UNUSED2 +# define GET_VNIC_RXC_UNUSED2(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED2_MASK)) +#endif +#ifndef GET_VNIC_RXC_UNUSED2_SHIFTED +# define GET_VNIC_RXC_UNUSED2_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED2_MASK))>>VNIC_RXC_UNUSED2_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED2 +# define GET_NTOH_VNIC_RXC_UNUSED2(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED2_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED2_SHIFTED +# define GET_NTOH_VNIC_RXC_UNUSED2_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_2)&(VNIC_RXC_UNUSED2_MASK))>>VNIC_RXC_UNUSED2_SHIFT) +#endif +#ifndef SET_VNIC_RXC_UNUSED2 +# define SET_VNIC_RXC_UNUSED2(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= (val & VNIC_RXC_UNUSED2_MASK)) +#endif +#ifndef SET_VNIC_RXC_UNUSED2_SHIFTED +# define SET_VNIC_RXC_UNUSED2_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= ((val<word_2) &= (~VNIC_RXC_UNUSED2_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED2 +# define SET_HTON_VNIC_RXC_UNUSED2(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl(val & VNIC_RXC_UNUSED2_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED2_SHIFTED +# define SET_HTON_VNIC_RXC_UNUSED2_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_2) |= htonl((val<word_2) &= htonl(~VNIC_RXC_UNUSED2_MASK)) +#endif + + u32 word_3; + + /* Flag set when operation completed by HW */ +# define VNIC_RXC_FLAGGED_WORD 3 +# define VNIC_RXC_FLAGGED_MASK 0x80000000 +# define VNIC_RXC_FLAGGED_SHIFT 31 +#ifndef GET_VNIC_RXC_FLAGGED +# define GET_VNIC_RXC_FLAGGED(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FLAGGED_MASK)) +#endif +#ifndef GET_VNIC_RXC_FLAGGED_SHIFTED +# define GET_VNIC_RXC_FLAGGED_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FLAGGED_MASK))>>VNIC_RXC_FLAGGED_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_FLAGGED +# define GET_NTOH_VNIC_RXC_FLAGGED(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FLAGGED_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_FLAGGED_SHIFTED +# define GET_NTOH_VNIC_RXC_FLAGGED_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FLAGGED_MASK))>>VNIC_RXC_FLAGGED_SHIFT) +#endif +#ifndef SET_VNIC_RXC_FLAGGED +# define SET_VNIC_RXC_FLAGGED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_FLAGGED_MASK)) +#endif +#ifndef SET_VNIC_RXC_FLAGGED_SHIFTED +# define SET_VNIC_RXC_FLAGGED_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_FLAGGED_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_FLAGGED +# define SET_HTON_VNIC_RXC_FLAGGED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_FLAGGED_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_FLAGGED_SHIFTED +# define SET_HTON_VNIC_RXC_FLAGGED_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_FLAGGED_MASK)) +#endif + /* Done, oper completed by VIOC (0x1<<31) */ +# define VNIC_RXC_FLAGGED_HW_W 0x80000000 + + /* Flag signalling reception of a VIOCP packet */ +# define VNIC_RXC_IS_VIOCP_WORD 3 +# define VNIC_RXC_IS_VIOCP_MASK 0x40000000 +# define VNIC_RXC_IS_VIOCP_SHIFT 30 +#ifndef GET_VNIC_RXC_IS_VIOCP +# define GET_VNIC_RXC_IS_VIOCP(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_IS_VIOCP_MASK)) +#endif +#ifndef GET_VNIC_RXC_IS_VIOCP_SHIFTED +# define GET_VNIC_RXC_IS_VIOCP_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_IS_VIOCP_MASK))>>VNIC_RXC_IS_VIOCP_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_IS_VIOCP +# define GET_NTOH_VNIC_RXC_IS_VIOCP(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_IS_VIOCP_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_IS_VIOCP_SHIFTED +# define GET_NTOH_VNIC_RXC_IS_VIOCP_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_IS_VIOCP_MASK))>>VNIC_RXC_IS_VIOCP_SHIFT) +#endif +#ifndef SET_VNIC_RXC_IS_VIOCP +# define SET_VNIC_RXC_IS_VIOCP(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_IS_VIOCP_MASK)) +#endif +#ifndef SET_VNIC_RXC_IS_VIOCP_SHIFTED +# define SET_VNIC_RXC_IS_VIOCP_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_IS_VIOCP_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_IS_VIOCP +# define SET_HTON_VNIC_RXC_IS_VIOCP(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_IS_VIOCP_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_IS_VIOCP_SHIFTED +# define SET_HTON_VNIC_RXC_IS_VIOCP_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_IS_VIOCP_MASK)) +#endif + /* Buffer is VIOCP bit mask (0x1<<30) */ +# define VNIC_RXC_ISVIOCPMASK_W 0x40000000 + /* VIOCP packet (0x1<<30) */ +# define VNIC_RXC_ISVIOCP_W 0x40000000 + + /* Status Flag signalling bad packet length */ +# define VNIC_RXC_BADLENGTH_WORD 3 +# define VNIC_RXC_BADLENGTH_MASK 0x20000000 +# define VNIC_RXC_BADLENGTH_SHIFT 29 +#ifndef GET_VNIC_RXC_BADLENGTH +# define GET_VNIC_RXC_BADLENGTH(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADLENGTH_MASK)) +#endif +#ifndef GET_VNIC_RXC_BADLENGTH_SHIFTED +# define GET_VNIC_RXC_BADLENGTH_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADLENGTH_MASK))>>VNIC_RXC_BADLENGTH_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADLENGTH +# define GET_NTOH_VNIC_RXC_BADLENGTH(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADLENGTH_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADLENGTH_SHIFTED +# define GET_NTOH_VNIC_RXC_BADLENGTH_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADLENGTH_MASK))>>VNIC_RXC_BADLENGTH_SHIFT) +#endif +#ifndef SET_VNIC_RXC_BADLENGTH +# define SET_VNIC_RXC_BADLENGTH(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_BADLENGTH_MASK)) +#endif +#ifndef SET_VNIC_RXC_BADLENGTH_SHIFTED +# define SET_VNIC_RXC_BADLENGTH_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_BADLENGTH_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADLENGTH +# define SET_HTON_VNIC_RXC_BADLENGTH(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_BADLENGTH_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADLENGTH_SHIFTED +# define SET_HTON_VNIC_RXC_BADLENGTH_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_BADLENGTH_MASK)) +#endif + /* Bad Length (0x1<<29) */ +# define VNIC_RXC_ISBADLENGTH_W 0x20000000 + + /* Status Flag signalling bad packet CRC */ +# define VNIC_RXC_BADCRC_WORD 3 +# define VNIC_RXC_BADCRC_MASK 0x10000000 +# define VNIC_RXC_BADCRC_SHIFT 28 +#ifndef GET_VNIC_RXC_BADCRC +# define GET_VNIC_RXC_BADCRC(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADCRC_MASK)) +#endif +#ifndef GET_VNIC_RXC_BADCRC_SHIFTED +# define GET_VNIC_RXC_BADCRC_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADCRC_MASK))>>VNIC_RXC_BADCRC_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADCRC +# define GET_NTOH_VNIC_RXC_BADCRC(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADCRC_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADCRC_SHIFTED +# define GET_NTOH_VNIC_RXC_BADCRC_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADCRC_MASK))>>VNIC_RXC_BADCRC_SHIFT) +#endif +#ifndef SET_VNIC_RXC_BADCRC +# define SET_VNIC_RXC_BADCRC(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_BADCRC_MASK)) +#endif +#ifndef SET_VNIC_RXC_BADCRC_SHIFTED +# define SET_VNIC_RXC_BADCRC_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_BADCRC_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADCRC +# define SET_HTON_VNIC_RXC_BADCRC(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_BADCRC_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADCRC_SHIFTED +# define SET_HTON_VNIC_RXC_BADCRC_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_BADCRC_MASK)) +#endif + /* Bad CRC (0x1<<28) */ +# define VNIC_RXC_ISBADCRC_W 0x10000000 + + /* RESERVED */ +# define VNIC_RXC_UNUSED3_WORD 3 +# define VNIC_RXC_UNUSED3_MASK 0x08000000 +# define VNIC_RXC_UNUSED3_SHIFT 27 +#ifndef GET_VNIC_RXC_UNUSED3 +# define GET_VNIC_RXC_UNUSED3(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED3_MASK)) +#endif +#ifndef GET_VNIC_RXC_UNUSED3_SHIFTED +# define GET_VNIC_RXC_UNUSED3_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED3_MASK))>>VNIC_RXC_UNUSED3_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED3 +# define GET_NTOH_VNIC_RXC_UNUSED3(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED3_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED3_SHIFTED +# define GET_NTOH_VNIC_RXC_UNUSED3_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED3_MASK))>>VNIC_RXC_UNUSED3_SHIFT) +#endif +#ifndef SET_VNIC_RXC_UNUSED3 +# define SET_VNIC_RXC_UNUSED3(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_UNUSED3_MASK)) +#endif +#ifndef SET_VNIC_RXC_UNUSED3_SHIFTED +# define SET_VNIC_RXC_UNUSED3_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_UNUSED3_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED3 +# define SET_HTON_VNIC_RXC_UNUSED3(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_UNUSED3_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED3_SHIFTED +# define SET_HTON_VNIC_RXC_UNUSED3_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_UNUSED3_MASK)) +#endif + + /* Status Flag signalling bad Shared Memory Parity */ +# define VNIC_RXC_BADSMPARITY_WORD 3 +# define VNIC_RXC_BADSMPARITY_MASK 0x04000000 +# define VNIC_RXC_BADSMPARITY_SHIFT 26 +#ifndef GET_VNIC_RXC_BADSMPARITY +# define GET_VNIC_RXC_BADSMPARITY(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADSMPARITY_MASK)) +#endif +#ifndef GET_VNIC_RXC_BADSMPARITY_SHIFTED +# define GET_VNIC_RXC_BADSMPARITY_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADSMPARITY_MASK))>>VNIC_RXC_BADSMPARITY_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADSMPARITY +# define GET_NTOH_VNIC_RXC_BADSMPARITY(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADSMPARITY_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_BADSMPARITY_SHIFTED +# define GET_NTOH_VNIC_RXC_BADSMPARITY_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_BADSMPARITY_MASK))>>VNIC_RXC_BADSMPARITY_SHIFT) +#endif +#ifndef SET_VNIC_RXC_BADSMPARITY +# define SET_VNIC_RXC_BADSMPARITY(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_BADSMPARITY_MASK)) +#endif +#ifndef SET_VNIC_RXC_BADSMPARITY_SHIFTED +# define SET_VNIC_RXC_BADSMPARITY_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_BADSMPARITY_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADSMPARITY +# define SET_HTON_VNIC_RXC_BADSMPARITY(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_BADSMPARITY_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_BADSMPARITY_SHIFTED +# define SET_HTON_VNIC_RXC_BADSMPARITY_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_BADSMPARITY_MASK)) +#endif + /* Bad Shared Memory Parity (0x1<<26) */ +# define VNIC_RXC_ISBADSMPARITY_W 0x04000000 + + /* Status Flag signalling aborted packet */ +# define VNIC_RXC_PKTABORT_WORD 3 +# define VNIC_RXC_PKTABORT_MASK 0x02000000 +# define VNIC_RXC_PKTABORT_SHIFT 25 +#ifndef GET_VNIC_RXC_PKTABORT +# define GET_VNIC_RXC_PKTABORT(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_PKTABORT_MASK)) +#endif +#ifndef GET_VNIC_RXC_PKTABORT_SHIFTED +# define GET_VNIC_RXC_PKTABORT_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_PKTABORT_MASK))>>VNIC_RXC_PKTABORT_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_PKTABORT +# define GET_NTOH_VNIC_RXC_PKTABORT(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_PKTABORT_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_PKTABORT_SHIFTED +# define GET_NTOH_VNIC_RXC_PKTABORT_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_PKTABORT_MASK))>>VNIC_RXC_PKTABORT_SHIFT) +#endif +#ifndef SET_VNIC_RXC_PKTABORT +# define SET_VNIC_RXC_PKTABORT(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_PKTABORT_MASK)) +#endif +#ifndef SET_VNIC_RXC_PKTABORT_SHIFTED +# define SET_VNIC_RXC_PKTABORT_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_PKTABORT_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_PKTABORT +# define SET_HTON_VNIC_RXC_PKTABORT(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_PKTABORT_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_PKTABORT_SHIFTED +# define SET_HTON_VNIC_RXC_PKTABORT_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_PKTABORT_MASK)) +#endif + /* Packet aborted (0x1<<25) */ +# define VNIC_RXC_ISPKTABORT_W 0x02000000 + + /* RESERVED */ +# define VNIC_RXC_UNUSED4_WORD 3 +# define VNIC_RXC_UNUSED4_MASK 0x01000000 +# define VNIC_RXC_UNUSED4_SHIFT 24 +#ifndef GET_VNIC_RXC_UNUSED4 +# define GET_VNIC_RXC_UNUSED4(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED4_MASK)) +#endif +#ifndef GET_VNIC_RXC_UNUSED4_SHIFTED +# define GET_VNIC_RXC_UNUSED4_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED4_MASK))>>VNIC_RXC_UNUSED4_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED4 +# define GET_NTOH_VNIC_RXC_UNUSED4(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED4_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED4_SHIFTED +# define GET_NTOH_VNIC_RXC_UNUSED4_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED4_MASK))>>VNIC_RXC_UNUSED4_SHIFT) +#endif +#ifndef SET_VNIC_RXC_UNUSED4 +# define SET_VNIC_RXC_UNUSED4(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_UNUSED4_MASK)) +#endif +#ifndef SET_VNIC_RXC_UNUSED4_SHIFTED +# define SET_VNIC_RXC_UNUSED4_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_UNUSED4_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED4 +# define SET_HTON_VNIC_RXC_UNUSED4(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_UNUSED4_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED4_SHIFTED +# define SET_HTON_VNIC_RXC_UNUSED4_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_UNUSED4_MASK)) +#endif + + /* RESERVED */ +# define VNIC_RXC_UNUSED5_WORD 3 +# define VNIC_RXC_UNUSED5_MASK 0x00f00000 +# define VNIC_RXC_UNUSED5_SHIFT 20 +#ifndef GET_VNIC_RXC_UNUSED5 +# define GET_VNIC_RXC_UNUSED5(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED5_MASK)) +#endif +#ifndef GET_VNIC_RXC_UNUSED5_SHIFTED +# define GET_VNIC_RXC_UNUSED5_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED5_MASK))>>VNIC_RXC_UNUSED5_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED5 +# define GET_NTOH_VNIC_RXC_UNUSED5(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED5_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_UNUSED5_SHIFTED +# define GET_NTOH_VNIC_RXC_UNUSED5_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_UNUSED5_MASK))>>VNIC_RXC_UNUSED5_SHIFT) +#endif +#ifndef SET_VNIC_RXC_UNUSED5 +# define SET_VNIC_RXC_UNUSED5(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_UNUSED5_MASK)) +#endif +#ifndef SET_VNIC_RXC_UNUSED5_SHIFTED +# define SET_VNIC_RXC_UNUSED5_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_UNUSED5_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED5 +# define SET_HTON_VNIC_RXC_UNUSED5(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_UNUSED5_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_UNUSED5_SHIFTED +# define SET_HTON_VNIC_RXC_UNUSED5_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_UNUSED5_MASK)) +#endif + + /* RxD queue ID for this packet buffer */ +# define VNIC_RXC_RXQ_ID_WORD 3 +# define VNIC_RXC_RXQ_ID_MASK 0x000f0000 +# define VNIC_RXC_RXQ_ID_SHIFT 16 +#ifndef GET_VNIC_RXC_RXQ_ID +# define GET_VNIC_RXC_RXQ_ID(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_RXQ_ID_MASK)) +#endif +#ifndef GET_VNIC_RXC_RXQ_ID_SHIFTED +# define GET_VNIC_RXC_RXQ_ID_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_RXQ_ID_MASK))>>VNIC_RXC_RXQ_ID_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_RXQ_ID +# define GET_NTOH_VNIC_RXC_RXQ_ID(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_RXQ_ID_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_RXQ_ID_SHIFTED +# define GET_NTOH_VNIC_RXC_RXQ_ID_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_RXQ_ID_MASK))>>VNIC_RXC_RXQ_ID_SHIFT) +#endif +#ifndef SET_VNIC_RXC_RXQ_ID +# define SET_VNIC_RXC_RXQ_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_RXQ_ID_MASK)) +#endif +#ifndef SET_VNIC_RXC_RXQ_ID_SHIFTED +# define SET_VNIC_RXC_RXQ_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_RXQ_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_RXQ_ID +# define SET_HTON_VNIC_RXC_RXQ_ID(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_RXQ_ID_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_RXQ_ID_SHIFTED +# define SET_HTON_VNIC_RXC_RXQ_ID_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_RXQ_ID_MASK)) +#endif + + /* Type of the packet fragment in the buffer */ +# define VNIC_RXC_FRAG_TYPE_WORD 3 +# define VNIC_RXC_FRAG_TYPE_MASK 0x0000c000 +# define VNIC_RXC_FRAG_TYPE_SHIFT 14 +#ifndef GET_VNIC_RXC_FRAG_TYPE +# define GET_VNIC_RXC_FRAG_TYPE(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FRAG_TYPE_MASK)) +#endif +#ifndef GET_VNIC_RXC_FRAG_TYPE_SHIFTED +# define GET_VNIC_RXC_FRAG_TYPE_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FRAG_TYPE_MASK))>>VNIC_RXC_FRAG_TYPE_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_FRAG_TYPE +# define GET_NTOH_VNIC_RXC_FRAG_TYPE(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FRAG_TYPE_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_FRAG_TYPE_SHIFTED +# define GET_NTOH_VNIC_RXC_FRAG_TYPE_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_FRAG_TYPE_MASK))>>VNIC_RXC_FRAG_TYPE_SHIFT) +#endif +#ifndef SET_VNIC_RXC_FRAG_TYPE +# define SET_VNIC_RXC_FRAG_TYPE(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_FRAG_TYPE_MASK)) +#endif +#ifndef SET_VNIC_RXC_FRAG_TYPE_SHIFTED +# define SET_VNIC_RXC_FRAG_TYPE_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_FRAG_TYPE_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_FRAG_TYPE +# define SET_HTON_VNIC_RXC_FRAG_TYPE(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_FRAG_TYPE_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_FRAG_TYPE_SHIFTED +# define SET_HTON_VNIC_RXC_FRAG_TYPE_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_FRAG_TYPE_MASK)) +#endif + /* Desc contains pkt body only (0x0<<14) */ +# define VNIC_RXC_FRAG_BODY_W 0x00000000 + /* Desc contains pkt tail (0x1<<14) */ +# define VNIC_RXC_FRAG_TAIL_W 0x00004000 + /* Desc contains pkt head (0x2<<14) */ +# define VNIC_RXC_FRAG_HEAD_W 0x00008000 + /* Desc contains pkt head, body & tail (0x3<<14) */ +# define VNIC_RXC_FRAG_ALL_W 0x0000c000 + + /* 14-Bit Count of bytes written into associated buffer */ +# define VNIC_RXC_LENGTH_WORD 3 +# define VNIC_RXC_LENGTH_MASK 0x00003fff +# define VNIC_RXC_LENGTH_SHIFT 0 +#ifndef GET_VNIC_RXC_LENGTH +# define GET_VNIC_RXC_LENGTH(p) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_LENGTH_MASK)) +#endif +#ifndef GET_VNIC_RXC_LENGTH_SHIFTED +# define GET_VNIC_RXC_LENGTH_SHIFTED(p) \ + (((((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_LENGTH_MASK))>>VNIC_RXC_LENGTH_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXC_LENGTH +# define GET_NTOH_VNIC_RXC_LENGTH(p) \ + (ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_LENGTH_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXC_LENGTH_SHIFTED +# define GET_NTOH_VNIC_RXC_LENGTH_SHIFTED(p) \ + ((ntohl(((struct rxc_pktDesc_Phys_w *)p)->word_3)&(VNIC_RXC_LENGTH_MASK))>>VNIC_RXC_LENGTH_SHIFT) +#endif +#ifndef SET_VNIC_RXC_LENGTH +# define SET_VNIC_RXC_LENGTH(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= (val & VNIC_RXC_LENGTH_MASK)) +#endif +#ifndef SET_VNIC_RXC_LENGTH_SHIFTED +# define SET_VNIC_RXC_LENGTH_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= ((val<word_3) &= (~VNIC_RXC_LENGTH_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_LENGTH +# define SET_HTON_VNIC_RXC_LENGTH(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl(val & VNIC_RXC_LENGTH_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXC_LENGTH_SHIFTED +# define SET_HTON_VNIC_RXC_LENGTH_SHIFTED(p,val) \ + ((((struct rxc_pktDesc_Phys_w *)p)->word_3) |= htonl((val<word_3) &= htonl(~VNIC_RXC_LENGTH_MASK)) +#endif + +}; + +struct rxc_pktStatusBlock_w { + u32 word_0; + + /* Current index in associated rxc */ +# define VNIC_RXS_IDX_WORD 0 +# define VNIC_RXS_IDX_MASK 0xffff0000 +# define VNIC_RXS_IDX_SHIFT 16 +#ifndef GET_VNIC_RXS_IDX +# define GET_VNIC_RXS_IDX(p) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_IDX_MASK)) +#endif +#ifndef GET_VNIC_RXS_IDX_SHIFTED +# define GET_VNIC_RXS_IDX_SHIFTED(p) \ + (((((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_IDX_MASK))>>VNIC_RXS_IDX_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXS_IDX +# define GET_NTOH_VNIC_RXS_IDX(p) \ + (ntohl(((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_IDX_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXS_IDX_SHIFTED +# define GET_NTOH_VNIC_RXS_IDX_SHIFTED(p) \ + ((ntohl(((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_IDX_MASK))>>VNIC_RXS_IDX_SHIFT) +#endif +#ifndef SET_VNIC_RXS_IDX +# define SET_VNIC_RXS_IDX(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= (val & VNIC_RXS_IDX_MASK)) +#endif +#ifndef SET_VNIC_RXS_IDX_SHIFTED +# define SET_VNIC_RXS_IDX_SHIFTED(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_RXS_IDX_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXS_IDX +# define SET_HTON_VNIC_RXS_IDX(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= htonl(val & VNIC_RXS_IDX_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXS_IDX_SHIFTED +# define SET_HTON_VNIC_RXS_IDX_SHIFTED(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_RXS_IDX_MASK)) +#endif + + /* RESERVED */ +# define VNIC_RXS_UNUSED0_WORD 0 +# define VNIC_RXS_UNUSED0_MASK 0x0000ffff +# define VNIC_RXS_UNUSED0_SHIFT 0 +#ifndef GET_VNIC_RXS_UNUSED0 +# define GET_VNIC_RXS_UNUSED0(p) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_UNUSED0_MASK)) +#endif +#ifndef GET_VNIC_RXS_UNUSED0_SHIFTED +# define GET_VNIC_RXS_UNUSED0_SHIFTED(p) \ + (((((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_UNUSED0_MASK))>>VNIC_RXS_UNUSED0_SHIFT) +#endif +#ifndef GET_NTOH_VNIC_RXS_UNUSED0 +# define GET_NTOH_VNIC_RXS_UNUSED0(p) \ + (ntohl(((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_UNUSED0_MASK)) +#endif +#ifndef GET_NTOH_VNIC_RXS_UNUSED0_SHIFTED +# define GET_NTOH_VNIC_RXS_UNUSED0_SHIFTED(p) \ + ((ntohl(((struct rxc_pktStatusBlock_w *)p)->word_0)&(VNIC_RXS_UNUSED0_MASK))>>VNIC_RXS_UNUSED0_SHIFT) +#endif +#ifndef SET_VNIC_RXS_UNUSED0 +# define SET_VNIC_RXS_UNUSED0(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= (val & VNIC_RXS_UNUSED0_MASK)) +#endif +#ifndef SET_VNIC_RXS_UNUSED0_SHIFTED +# define SET_VNIC_RXS_UNUSED0_SHIFTED(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= ((val<word_0) &= (~VNIC_RXS_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXS_UNUSED0 +# define SET_HTON_VNIC_RXS_UNUSED0(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= htonl(val & VNIC_RXS_UNUSED0_MASK)) +#endif +#ifndef SET_HTON_VNIC_RXS_UNUSED0_SHIFTED +# define SET_HTON_VNIC_RXS_UNUSED0_SHIFTED(p,val) \ + ((((struct rxc_pktStatusBlock_w *)p)->word_0) |= htonl((val<word_0) &= htonl(~VNIC_RXS_UNUSED0_MASK)) +#endif + +}; + +/* + * Rx Descriptor macros + */ +#define VNIC_RX_BUFADDR_MASK ((u64) \ + ((u64) VNIC_RX_BUFADDR_HI_MASK << 32) | \ + (u64) VNIC_RX_BUFADDR_LO_MASK) + +#define VNIC_RX_DESC_HW_FLAG ((u64) VNIC_RX_OWNED_HW_W << 32) + +#define SET_VNIC_RX_BUFADDR(d, bufaddr) do { \ + *((dma_addr_t *) d) = \ + ((dma_addr_t) bufaddr & VIOC_RX_BUFADDR_MASK); \ +}while (0) + +#define SET_VNIC_RX_BUFADDR_HW(d, bufaddr) do { \ + *((dma_addr_t *) d) = \ + (((dma_addr_t) bufaddr & VNIC_RX_BUFADDR_MASK) | \ + VNIC_RX_DESC_HW_FLAG) ; \ +} while (0) + +#endif /* _VNIC_H_ */ + diff --git a/drivers/net/vioc/khash.h b/drivers/net/vioc/khash.h new file mode 100644 index 0000000..ae4e986 --- /dev/null +++ b/drivers/net/vioc/khash.h @@ -0,0 +1,65 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * + * Copyright (C) 2002, 2003, 2004 David Gmez + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef __HASHIT__ +#define __HASHIT__ + +#define CHAIN_H 0U +#define OADDRESS_H 1U +#define OVERFLOW_H 2U + +#include +#include +#include +#include + +struct shash_t; + +/* Elem is used both for chain and overflow hash */ +struct hash_elem_t { + struct hash_elem_t *next; + void *key; + void *data; + void (*cb_fn)(u32, void *, int, u32); + u32 command; + u32 timestamp; + spinlock_t lock; +}; + + +struct shash_t *hashT_create(u32, size_t, size_t, u32(*)(unsigned char *, unsigned long), int(*)(void *, void *), unsigned int); +int hashT_delete(struct shash_t * , void *); +struct hash_elem_t *hashT_lookup(struct shash_t * , void *); +struct hash_elem_t *hashT_add(struct shash_t *, void *); +void hashT_destroy(struct shash_t *); +/* Accesors */ +void **hashT_getkeys(struct shash_t *); +size_t hashT_tablesize(struct shash_t *); +size_t hashT_size(struct shash_t *); + +#endif diff --git a/drivers/net/vioc/spp.c b/drivers/net/vioc/spp.c new file mode 100644 index 0000000..27ccc82 --- /dev/null +++ b/drivers/net/vioc/spp.c @@ -0,0 +1,626 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * + * Copyright (C) 2002, 2003, 2004 David Gmez + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include "f7/vioc_hw_registers.h" +#include "f7/spp.h" +#include "f7/sppapi.h" + +#include "vioc_vnic.h" +#include "vioc_api.h" +#include "khash.h" + +#define FACILITY_CNT 16 + +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c >> 13); \ + b -= c; b -= a; b ^= (a << 8); \ + c -= a; c -= b; c ^= (b >> 13); \ + a -= b; a -= c; a ^= (c >> 12); \ + b -= c; b -= a; b ^= (a << 16); \ + c -= a; c -= b; c ^= (b >> 5); \ + a -= b; a -= c; a ^= (c >> 3); \ + b -= c; b -= a; b ^= (a << 10); \ + c -= a; c -= b; c ^= (b >> 15); \ +} + + +struct shash_t { + /* Common fields for all hash tables types */ + size_t tsize; /* Table size */ + size_t ksize; /* Key size is fixed at creation time */ + size_t dsize; /* Data size is fixed at creation time */ + size_t nelems; /* Number of elements in the hash table */ + struct hash_ops *h_ops; + u32(*hash_fn) (unsigned char *, unsigned long); + void (*copy_fn) (void *, int, void *); + int (*compare_fn) (void *, void *); + struct hash_elem_t **chtable; /* Data for the collision */ +}; + +struct hash_ops { + int (*delete) (struct shash_t *, void *); + struct hash_elem_t *(*lookup) (struct shash_t *, void *); + void (*destroy) (struct shash_t *); + struct hash_elem_t *(*add) (struct shash_t *, void *); + void **(*getkeys) (struct shash_t *); +}; + +struct facility { + struct shash_t *hashT; + spinlock_t lock; +}; + +static u32 hash_func(unsigned char *k, unsigned long length) +{ + unsigned long a, b, c, len; + + /* Set up the internal state */ + len = length; + a = b = c = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + + /* Handle most of the key */ + while (len >= 12) { + a += (k[0] + ((unsigned long)k[1] << 8) + + ((unsigned long)k[2] << 16) + + ((unsigned long)k[3] << 24)); + b += (k[4] + ((unsigned long)k[5] << 8) + + ((unsigned long)k[6] << 16) + + ((unsigned long)k[7] << 24)); + c += (k[8] + ((unsigned long)k[9] << 8) + + ((unsigned long)k[10] << 16) + + ((unsigned long)k[11] << 24)); + mix(a, b, c); + k += 12; + len -= 12; + } + + /* Handle the last 11 bytes */ + c += length; + switch (len) { /* all the case statements fall through */ + case 11: + c += ((unsigned long)k[10] << 24); + case 10: + c += ((unsigned long)k[9] << 16); + case 9: + c += ((unsigned long)k[8] << 8); + /* the first byte of c is reserved for the length */ + case 8: + b += ((unsigned long)k[7] << 24); + case 7: + b += ((unsigned long)k[6] << 16); + case 6: + b += ((unsigned long)k[5] << 8); + case 5: + b += k[4]; + case 4: + a += ((unsigned long)k[3] << 24); + case 3: + a += ((unsigned long)k[2] << 16); + case 2: + a += ((unsigned long)k[1] << 8); + case 1: + a += k[0]; + } + mix(a, b, c); + + return c; +} + +static u32 gethash(struct shash_t *htable, void *key) +{ + size_t len; + + len = htable->ksize; + + /* Hash the key and get the meaningful bits for our table */ + return ((htable->hash_fn(key, len)) & (htable->tsize - 1)); +} + +/* Data associated to this key MUST be freed by the caller */ +static int ch_delete(struct shash_t *htable, void *key) +{ + u32 idx; + struct hash_elem_t *cursor; /* Cursor for the linked list */ + struct hash_elem_t *tmp; /* Pointer to the element to be deleted */ + + idx = gethash(htable, key); + + if (!htable->chtable[idx]) + return -1; + + /* Delete asked element */ + /* Element to delete is the first in the chain */ + if (htable->compare_fn(htable->chtable[idx]->key, key) == 0) { + tmp = htable->chtable[idx]; + htable->chtable[idx] = tmp->next; + vfree(tmp); + htable->nelems--; + return 0; + } + /* Search thru the chain for the element */ + else { + cursor = htable->chtable[idx]; + while (cursor->next != NULL) { + if (htable->compare_fn(cursor->next->key, key) == 0) { + tmp = cursor->next; + cursor->next = tmp->next; + vfree(tmp); + htable->nelems--; + return 0; + } + cursor = cursor->next; + } + } + + return -1; +} + +static void ch_destroy(struct shash_t *htable) +{ + u32 idx; + struct hash_elem_t *cursor; + + for (idx = 0; idx < htable->tsize; idx++) { + cursor = htable->chtable[idx]; + + while (cursor != NULL) { + struct hash_elem_t *tmp_cursor = cursor; + + cursor = cursor->next; + vfree(tmp_cursor); + } + } + vfree(htable->chtable); +} + +/* Return a NULL terminated string of pointers to all hash table keys */ +static void **ch_getkeys(struct shash_t *htable) +{ + u32 idx; + struct hash_elem_t *cursor; + void **keys; + u32 kidx; + + keys = vmalloc((htable->nelems + 1) * sizeof(void *)); + if (!keys) { + return NULL; + } + keys[htable->nelems] = NULL; + kidx = 0; + + for (idx = 0; idx < htable->tsize; idx++) { + + cursor = htable->chtable[idx]; + while (cursor != NULL) { + printk(KERN_INFO "Element %d in bucket %d, key %p value %px\n", + kidx, idx, cursor->key, cursor->data); + keys[kidx] = cursor->key; + kidx++; + + cursor = cursor->next; + } + } + + return keys; +} + +/* Accesors ******************************************************************/ +inline size_t hashT_tablesize(struct shash_t * htable) +{ + return htable->tsize; +} + +inline size_t hashT_size(struct shash_t * htable) +{ + return htable->nelems; +} + +static struct hash_elem_t *ch_lookup(struct shash_t *htable, void *key) +{ + u32 idx; + struct hash_elem_t *cursor; + + idx = gethash(htable, key); + + cursor = htable->chtable[idx]; + + /* Search thru the chain for the asked key */ + while (cursor != NULL) { + if (htable->compare_fn(cursor->key, key) == 0) + return cursor; + cursor = cursor->next; + } + + return NULL; +} + +static struct hash_elem_t *ch_add(struct shash_t *htable, void *key) +{ + u32 idx; + struct hash_elem_t *cursor; + struct hash_elem_t *oneelem; + + idx = gethash(htable, key); + + cursor = htable->chtable[idx]; + + /* Search thru the chain for the asked key */ + while (cursor != NULL) { + if (htable->compare_fn(cursor->key, key) == 0) + break; + cursor = cursor->next; + } + + if (!cursor) { + /* cursor == NULL, means, that no element with this key was found, + * need to insert one + */ + oneelem = + (struct hash_elem_t *)vmalloc(sizeof(struct hash_elem_t) + + htable->ksize + + htable->dsize); + if (!oneelem) + return (struct hash_elem_t *)NULL; + memset((void *)oneelem, 0, + sizeof(struct hash_elem_t) + htable->ksize + + htable->dsize); + + oneelem->command = 0; + oneelem->key = (void *)((char *)oneelem + sizeof(struct hash_elem_t)); + oneelem->data = (void *)((char *)oneelem->key + htable->ksize); + memcpy((void *)oneelem->key, (void *)key, htable->ksize); + + oneelem->next = NULL; + + if (htable->chtable[idx] == NULL) + /* No collision ;), first element in this bucket */ + htable->chtable[idx] = oneelem; + else { + /* Collision, insert at the end of the chain */ + cursor = htable->chtable[idx]; + while (cursor->next != NULL) + cursor = cursor->next; + + /* Insert element at the end of the chain */ + cursor->next = oneelem; + } + + htable->nelems++; + spin_lock_init(&oneelem->lock); + } else { + /* Found element with the key */ + oneelem = cursor; + } + + return oneelem; +} + +static int key_compare(void *key_in, void *key_out) +{ + if ((u16) * ((u16 *) key_in) == (u16) * ((u16 *) key_out)) + return 0; + else + return 1; +} + +struct hash_ops ch_ops = { + .delete = ch_delete, + .lookup = ch_lookup, + .destroy = ch_destroy, + .getkeys = ch_getkeys, + .add = ch_add +}; + +struct facility fTable[FACILITY_CNT]; + +int spp_init(void) +{ + int i; + + for (i = 0; i < FACILITY_CNT; i++) { + fTable[i].hashT = NULL; + spin_lock_init(&fTable[i].lock); + } + + spp_vnic_init(); + + return 0; +} + +void spp_terminate(void) +{ + int i; + + spp_vnic_exit(); + + for (i = 0; i < FACILITY_CNT; i++) { + if (fTable[i].hashT) { + spin_lock(&fTable[i].lock); + hashT_destroy(fTable[i].hashT); + fTable[i].hashT = NULL; + spin_unlock(&fTable[i].lock); + } + } +} + +void spp_msg_from_sim(int vioc_idx) +{ + struct vioc_device *viocdev = vioc_viocdev(vioc_idx); + u32 command_reg, pmm_reply; + u32 key, facility, uniqid; + u32 *data_p; + struct hash_elem_t *elem; + int i; + + vioc_reg_rd(viocdev->ba.virt, SPP_SIM_PMM_CMDREG, &command_reg); + + if (spp_mbox_empty(command_reg)) { + return; + } + + /* Validate checksum */ + if (spp_validate_u32_chksum(command_reg) != 0) { + return; + } + + /* Build reply message to SIM */ + pmm_reply = spp_mbox_build_reply(command_reg, SPP_CMD_OK); + + key = SPP_GET_KEY(command_reg); + facility = SPP_GET_FACILITY(command_reg); + uniqid = SPP_GET_UNIQID(command_reg); + + /* Check-and-create hash table */ + spin_lock(&fTable[facility].lock); + + if (fTable[facility].hashT == NULL) { + fTable[facility].hashT = + hashT_create(1024, 2, 128, NULL, key_compare, 0); + if (fTable[facility].hashT == NULL) { + goto error_exit; + } + } + + /* Add the hash table element */ + elem = hashT_add(fTable[facility].hashT, (void *)&key); + if (!elem) { + goto error_exit; + } + spin_unlock(&fTable[facility].lock); + + /* Copy data from SPP Registers to the key buffer */ + spin_lock(&elem->lock); + + /* Copy data from SPP Register Bank */ + for (i = 0, data_p = (u32 *) elem->data; i < SPP_BANK_REGS; + i++, (u32 *) data_p++) { + vioc_reg_rd(viocdev->ba.virt, SPP_SIM_PMM_DATA + (i << 2), (u32 *) data_p); + } + + elem->command = command_reg; + elem->timestamp++; + elem->timestamp = (elem->timestamp & 0x0fffffff) | (vioc_idx << 28); + + spin_unlock(&elem->lock); + + vioc_reg_wr(pmm_reply, viocdev->ba.virt, SPP_SIM_PMM_CMDREG); + viocdev->last_msg_to_sim = pmm_reply; + + /* If there was registered callback, execute it */ + if (elem->cb_fn) { + spin_lock(&elem->lock); + if (spp_validate_u32_chksum(elem->command) == 0) { + /* If there is a valid message waiting, call callback */ + elem->cb_fn(elem->command, + elem->data, 128, elem->timestamp); + elem->command = 0; + } + spin_unlock(&elem->lock); + } + return; + + error_exit: + spin_unlock(&fTable[facility].lock); + pmm_reply = spp_mbox_build_reply(command_reg, SPP_CMD_FAIL); + vioc_reg_wr(pmm_reply, viocdev->ba.virt, SPP_SIM_PMM_CMDREG); + return; + +} + +int spp_msg_register(u32 key_facility, void (*cb_fn) (u32, void *, int, u32)) +{ + u32 facility = SPP_GET_FACILITY(key_facility); + u32 key = SPP_GET_KEY(key_facility); + struct hash_elem_t *elem; + + /* Check-and-create hash table */ + spin_lock(&fTable[facility].lock); + + if (fTable[facility].hashT == NULL) { + fTable[facility].hashT = + hashT_create(1024, 2, 128, NULL, key_compare, 0); + if (fTable[facility].hashT == NULL) { + goto error_exit; + } + } + + /* Add the hash table element */ + elem = hashT_add(fTable[facility].hashT, (void *)&key); + if (!elem) { + goto error_exit; + } + spin_unlock(&fTable[facility].lock); + + spin_lock(&elem->lock); + elem->cb_fn = cb_fn; + if (spp_validate_u32_chksum(elem->command) == 0) { + /* If there is a valid message waiting, call callback */ + elem->cb_fn(elem->command, elem->data, 128, elem->timestamp); + elem->command = 0; + } + spin_unlock(&elem->lock); + return SPP_CMD_OK; + + error_exit: + spin_unlock(&fTable[facility].lock); + return SPP_CMD_FAIL; +} + +void spp_msg_unregister(u32 key_facility) +{ + u32 key = SPP_GET_KEY(key_facility); + u32 facility = SPP_GET_FACILITY(key_facility); + struct hash_elem_t *elem; + + if (fTable[facility].hashT == NULL) + return; + + elem = hashT_lookup(fTable[facility].hashT, (void *)&key); + if (!elem) + return; + + spin_lock(&elem->lock); + elem->cb_fn = NULL; + spin_unlock(&elem->lock); +} + + +int read_spp_regbank32(int vioc_idx, int bank, char *buffer) +{ + struct vioc_device *viocdev = vioc_viocdev(vioc_idx); + int i; + u32 *data_p; + u32 reg; + + if (!viocdev) + return 0; + + /* Copy data from SPP Register Bank */ + for (i = 0, data_p = (u32 *) buffer; i < SPP_BANK_REGS; + i++, (u32 *) data_p++) { + reg = SPP_BANK_ADDR(bank) + (i << 2); + vioc_reg_rd(viocdev->ba.virt, reg, (u32 *) data_p); + } + + return i; +} + +struct shash_t *hashT_create(u32 sizehint, + size_t keybuf_size, + size_t databuf_size, + u32(*hfunc) (unsigned char *, + unsigned long), + int (*cfunc) (void *, void *), + unsigned int flags) +{ + struct shash_t *htable; + u32 size = 0; /* Table size */ + int i = 1; + + /* Take the size hint and round it to the next higher power of two */ + while (size < sizehint) { + size = 1 << i++; + if (size == 0) { + size = 1 << (i - 2); + break; + } + } + + if (cfunc == NULL) + return NULL; + + /* Create hash table */ + htable = vmalloc(sizeof(struct shash_t) + keybuf_size + databuf_size); + if (!htable) + return NULL; + + /* And create structs for hash table */ + + htable->h_ops = &ch_ops; + htable->chtable = vmalloc(size * (sizeof(struct hash_elem_t) + + keybuf_size + + databuf_size)); + if (!htable->chtable) { + vfree(htable); + return NULL; + } + + memset(htable->chtable, '\0', + size * (sizeof(struct hash_elem_t) + keybuf_size + databuf_size)); + + /* Initialize hash table common fields */ + htable->tsize = size; + htable->ksize = keybuf_size; + htable->dsize = databuf_size; + htable->nelems = 0; + + if (hfunc) + htable->hash_fn = hfunc; + else + htable->hash_fn = hash_func; + + htable->compare_fn = cfunc; + + return htable; +} + +int hashT_delete(struct shash_t *htable, void *key) +{ + return htable->h_ops->delete(htable, key); +} + +struct hash_elem_t *hashT_add(struct shash_t *htable, void *key) +{ + return htable->h_ops->add(htable, key); +} + +struct hash_elem_t *hashT_lookup(struct shash_t *htable, void *key) +{ + return htable->h_ops->lookup(htable, key); +} + +void hashT_destroy(struct shash_t *htable) +{ + + htable->h_ops->destroy(htable); + + vfree(htable); +} + +void **hashT_getkeys(struct shash_t *htable) +{ + return htable->h_ops->getkeys(htable); +} + +#ifdef EXPORT_SYMTAB +EXPORT_SYMBOL(spp_msg_register); +EXPORT_SYMBOL(spp_msg_unregister); +EXPORT_SYMBOL(read_spp_regbank32); +#endif diff --git a/drivers/net/vioc/spp_vnic.c b/drivers/net/vioc/spp_vnic.c new file mode 100644 index 0000000..ec426f1 --- /dev/null +++ b/drivers/net/vioc/spp_vnic.c @@ -0,0 +1,131 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include "vioc_vnic.h" +#include "vioc_api.h" +#include "f7/sppapi.h" +#include "f7/spp_msgdata.h" +#include "f7/vioc_hw_registers.h" + + +#define VIOC_ID_FROM_STAMP(stamp) ((stamp >> 28) & 0xf) + +static u32 relative_time; + +static void spp_vnic_cb(u32 cmd, void *msg_buf, int buf_size, u32 viocstamp) +{ + u32 param, param2; + int viocdev_idx; + u32 timestamp = viocstamp & 0x0fffffff; + int vioc_id = VIOC_ID_FROM_STAMP(viocstamp); + + relative_time = timestamp; + + viocdev_idx = ((int *)msg_buf)[SPP_VIOC_ID_IDX]; + if (viocdev_idx != vioc_id) { + printk(KERN_ERR "%s: MSG to VIOC=%d, but param VIOC=%d\n", + __FUNCTION__, vioc_id, viocdev_idx); + } + param = vioc_rrd(viocdev_idx, VIOC_BMC, 0, VREG_BMC_VNIC_EN); + param2 = vioc_rrd(viocdev_idx, VIOC_BMC, 0, VREG_BMC_PORT_EN); +#ifdef VNIC_UNREGISTER_PATCH + vioc_vnic_prov(viocdev_idx, param, param2, 1); +#else + vioc_vnic_prov(viocdev_idx, param, param2, 0); +#endif +} + +static void spp_sys_cb(u32 cmd, void *msg_buf, int buf_size, u32 viocstamp) +{ + u32 reset_type; + u32 timestamp = viocstamp & 0x0fffffff; + + relative_time = timestamp; + + reset_type = ((u32 *) msg_buf)[SPP_UOS_RESET_TYPE_IDX]; + if (vioc_handle_reset_request(reset_type) < 0) { + /* Invalid reset type ..ignore the message */ + printk(KERN_ERR "Invalid reset request %d\n", reset_type); + } +} +static void spp_prov_cb(u32 cmd, void *msg_buf, int buf_size, u32 viocstamp) +{ + u32 timestamp = viocstamp & 0x0fffffff; + + relative_time = timestamp; +} + +struct kf_handler { + u32 key; + u32 facility; + void (*cb) (u32, void *, int, u32); +}; + +static +struct kf_handler local_cb[] = { + {SPP_KEY_VNIC_CTL, SPP_FACILITY_VNIC, spp_vnic_cb}, + {SPP_KEY_REQUEST_SIGNAL, SPP_FACILITY_SYS, spp_sys_cb}, + {SPP_KEY_SET_PROV, SPP_FACILITY_VNIC, spp_prov_cb}, + {0, 0, NULL} +}; + +int spp_vnic_init(void) +{ + u32 key_facility = 0; + int i; + + for (i = 0; local_cb[i].cb; i++) { + + SPP_SET_KEY(key_facility, local_cb[i].key); + SPP_SET_FACILITY(key_facility, local_cb[i].facility); + + spp_msg_register(key_facility, local_cb[i].cb); + } + return 0; +} + +void spp_vnic_exit(void) +{ + u32 key_facility = 0; + int i; + + for (i = 0; local_cb[i].cb; i++) { + + SPP_SET_KEY(key_facility, local_cb[i].key); + SPP_SET_FACILITY(key_facility, local_cb[i].facility); + + spp_msg_unregister(key_facility); + } + return; +} + diff --git a/drivers/net/vioc/vioc_api.c b/drivers/net/vioc/vioc_api.c new file mode 100644 index 0000000..5c3405d --- /dev/null +++ b/drivers/net/vioc/vioc_api.c @@ -0,0 +1,384 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" + +#include "vioc_vnic.h" +#include "vioc_api.h" + +int vioc_set_rx_intr_param(int viocdev_idx, int rx_intr_id, u32 timeout, u32 cntout) +{ + int ret = 0; + struct vioc_device *viocdev; + u64 regaddr; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(VIOC_IHCU, 0, (VREG_IHCU_RXCINTTIMER + + (rx_intr_id << 2))); + vioc_reg_wr(timeout, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_IHCU, 0, (VREG_IHCU_RXCINTPKTCNT + + (rx_intr_id << 2))); + vioc_reg_wr(cntout, viocdev->ba.virt, regaddr); + + return ret; +} + + +int vioc_get_vnic_mac(int viocdev_idx, u32 vnic_id, u8 * p) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + u64 regaddr; + u32 value; + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_MACADDRLO); + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + *((u32 *) & p[2]) = htonl(value); + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_MACADDRHI); + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + *((u16 *) & p[0]) = htons(value); + + return 0; +} + +int vioc_set_vnic_mac(int viocdev_idx, u32 vnic_id, u8 * p) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + u64 regaddr; + u32 value; + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_MACADDRLO); + value = ntohl(*((u32 *) & p[2])); + + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_MACADDRHI); + value = (ntohl(*((u32 *) & p[0])) >> 16) & 0xffff; + + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return 0; +} + +int vioc_set_txq(int viocdev_idx, u32 vnic_id, u32 txq_id, dma_addr_t base, + u32 num_elements) +{ + int ret = 0; + u32 value; + struct vioc_device *viocdev; + u64 regaddr; + + viocdev = vioc_viocdev(viocdev_idx); + if (vnic_id >= VIOC_MAX_VNICS) + goto parm_err_ret; + + if (txq_id >= VIOC_MAX_TXQ) + goto parm_err_ret; + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, (VREG_VENG_TXD_W0 + (txq_id << 5))); + + value = base; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, (VREG_VENG_TXD_W1 + (txq_id << 5))); + value = (((base >> 16) >> 16) & 0x000000ff) | + ((num_elements << 8) & 0x00ffff00); + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + /* + * Enable Interrupt-on-Empty + */ + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_TXINTCTL); + vioc_reg_wr(VREG_VENG_TXINTCTL_INTONEMPTY_MASK, viocdev->ba.virt, + regaddr); + + return ret; + + parm_err_ret: + return -EINVAL; +} + +int vioc_set_rxc(int viocdev_idx, struct rxc *rxc) +{ + u32 value; + struct vioc_device *viocdev; + u64 regaddr; + int ret = 0; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(VIOC_IHCU, 0, (VREG_IHCU_RXC_LO + (rxc->rxc_id << 4))); + value = rxc->dma; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_IHCU, 0, (VREG_IHCU_RXC_HI + (rxc->rxc_id << 4))); + value = (((rxc->dma >> 16) >> 16) & 0x000000ff) | + ((rxc->count << 8) & 0x00ffff00); + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + /* + * Set-up mapping between this RxC queue and Rx interrupt + */ + regaddr = GETRELADDR(VIOC_IHCU, 0, (VREG_IHCU_RXC_INT + (rxc->rxc_id << 4))); + vioc_reg_wr((rxc->interrupt_id & 0xF), viocdev->ba.virt, regaddr); + + ret = vioc_set_rx_intr_param(viocdev_idx, + rxc->interrupt_id, + viocdev->prov.run_param.rx_intr_timeout, + viocdev->prov.run_param.rx_intr_cntout); + return ret; +} + +int vioc_set_rxs(int viocdev_idx, dma_addr_t base) +{ + int ret = 0; + u32 value; + u64 regaddr; + struct vioc_device *viocdev; + + viocdev = vioc_viocdev(viocdev_idx); + regaddr = GETRELADDR(VIOC_IHCU, 0, VREG_IHCU_INTRSTATADDRLO); + value = base; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + regaddr = GETRELADDR(VIOC_IHCU, 0, VREG_IHCU_INTRSTATADDRHI); + value = ((base >> 16) >> 16) & 0x000000ff; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return ret; +} + +int vioc_set_rxdq(int viocdev_idx, u32 vnic_id, u32 rxdq_id, u32 rx_bufsize, + dma_addr_t base, u32 num_elements) +{ + int ret = 0; + u32 value; + struct vioc_device *viocdev; + u64 regaddr; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, (VREG_IHCU_RXD_W0_R0 + + (rxdq_id << 4))); + value = base; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, (VREG_IHCU_RXD_W1_R0 + + (rxdq_id << 4))); + value = (((base >> 16) >> 16) & 0x000000ff) | + ((num_elements << 8) & 0x00ffff00); + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, (VREG_IHCU_RXD_W2_R0 + + (rxdq_id << 4))); + value = rx_bufsize; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return ret; +} + +u32 vioc_rrd(int viocdev_idx, int module_id, int vnic_id, int reg_addr) +{ + u32 value; + u64 regaddr; + struct vioc_device *viocdev; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(module_id, vnic_id, reg_addr); + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + + return value; +} + +int vioc_rwr(int viocdev_idx, int module_id, int vnic_id, int reg_addr, + u32 value) +{ + int ret = 0; + struct vioc_device *viocdev; + u64 regaddr; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(module_id, vnic_id, reg_addr); + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return ret; +} + +int vioc_ena_dis_tx_on_empty(int viocdev_idx, u32 vnic_id, u32 txq_id, + int ena_dis) +{ + u32 value = 0; + u64 regaddr; + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + + if (ena_dis) + value |= VREG_VENG_TXINTCTL_INTONEMPTY_MASK; + else + value &= ~VREG_VENG_TXINTCTL_INTONEMPTY_MASK; + + regaddr = GETRELADDR(VIOC_VENG, vnic_id, VREG_VENG_TXINTCTL); + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return 0; +} + +int vioc_set_vnic_cfg(int viocdev_idx, u32 vnic_id, u32 cfg) +{ + int ret = 0; + u64 regaddr; + struct vioc_device *viocdev; + + viocdev = vioc_viocdev(viocdev_idx); + regaddr = GETRELADDR(VIOC_BMC, vnic_id, VREG_BMC_VNIC_CFG); + + vioc_reg_wr(cfg, viocdev->ba.virt, regaddr); + + return ret; +} + +int vioc_ena_dis_rxd_q(int viocdev_idx, u32 q_id, int ena_dis) +{ + int ret = 0; + u32 value; + u64 regaddr; + struct vioc_device *viocdev; + + viocdev = vioc_viocdev(viocdev_idx); + regaddr = GETRELADDR(VIOC_IHCU, 0, VREG_IHCU_RXDQEN); + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + + if (ena_dis) + value |= 1 << q_id; + else + value &= ~(1 << q_id); + + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + return ret; +} + +void vioc_sw_reset(int viocdev_idx) +{ + u32 value; + u64 regaddr; + struct vioc_device *viocdev; + + viocdev = vioc_viocdev(viocdev_idx); + + regaddr = GETRELADDR(VIOC_BMC, 0, VREG_BMC_GLOBAL); + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + value |= VREG_BMC_GLOBAL_SOFTRESET_MASK; + vioc_reg_wr(value, viocdev->ba.virt, regaddr); + + do { + vioc_reg_rd(viocdev->ba.virt, regaddr, &value); + mdelay(1); + } while (value & VREG_BMC_GLOBAL_SOFTRESET_MASK); + + /* + * Clear BMC INTERRUPT register + */ + regaddr = GETRELADDR(VIOC_BMC, 0, VREG_BMC_INTRSTATUS); + vioc_reg_wr(0xffff, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VING, 0, VREG_VING_BUFTH1); + vioc_reg_wr(128, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VING, 0, VREG_VING_BUFTH2); + vioc_reg_wr(150, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VING, 0, VREG_VING_BUFTH3); + vioc_reg_wr(200, viocdev->ba.virt, regaddr); + + regaddr = GETRELADDR(VIOC_VING, 0, VREG_VING_BUFTH4); + vioc_reg_wr(256, viocdev->ba.virt, regaddr); + + /* + * Initialize Context Scrub Control Register + */ + regaddr = GETRELADDR(VIOC_VING, 0, VREG_VING_CONTEXTSCRUB); + /* Enable Context Scrub, Timeout ~ 5 sec */ + vioc_reg_wr(0x8000000f, viocdev->ba.virt, regaddr); + /* + * Initialize Sleep Time Register + */ + regaddr = GETRELADDR(VIOC_IHCU, 0, VREG_IHCU_SLEEPTIME); + /* at 50ns ticks, 20 = 20x50 = 1usec */ + vioc_reg_wr(20, viocdev->ba.virt, regaddr); + /* + * VIOC bits version + */ + regaddr = GETRELADDR(VIOC_HT, 0, VREG_HT_CLASSREV); + vioc_reg_rd(viocdev->ba.virt, regaddr, &viocdev->vioc_bits_version); + /* + * VIOC bits sub-version + */ + regaddr = GETRELADDR(VIOC_HT, 0, VREG_HT_EXPREV); + vioc_reg_rd(viocdev->ba.virt, regaddr, &viocdev->vioc_bits_subversion); + +} + +int vioc_vnic_resources_set(int viocdev_idx, u32 vnic_id) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + struct vnic_device *vnicdev = viocdev->vnic_netdev[vnic_id]->priv; + u64 regaddr; + + /* Map VNIC-2-RXD */ + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, VREG_IHCU_VNICRXDMAP); + vioc_reg_wr(vnicdev->qmap, viocdev->ba.virt, regaddr); + + /* Map VNIC-2-RXC */ + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, VREG_IHCU_VNICRXCMAP); + vioc_reg_wr(vnicdev->rxc_id, viocdev->ba.virt, regaddr); + + /* Map Interrupt-2-RXC */ + regaddr = GETRELADDR(VIOC_IHCU, vnic_id, (VREG_IHCU_RXC_INT + + (vnicdev->rxc_id << 4))); + vioc_reg_wr(vnicdev->rxc_intr_id, viocdev->ba.virt, regaddr); + + return 0; +} diff --git a/drivers/net/vioc/vioc_api.h b/drivers/net/vioc/vioc_api.h new file mode 100644 index 0000000..8c2adff --- /dev/null +++ b/drivers/net/vioc/vioc_api.h @@ -0,0 +1,64 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _VIOC_API_H_ +#define _VIOC_API_H_ + +#include +#include "vioc_vnic.h" + +extern int vioc_vnic_resources_set(int vioc_id, u32 vnic_id); +extern void vioc_sw_reset(int vioc_id); +extern u32 vioc_rrd(int vioc_id, int module_id, int vnic_id, int reg_addr); +extern int vioc_rwr(int vioc_id, int module_id, int vnic_id, int reg_addr, u32 value); +extern int vioc_set_vnic_mac(int vioc_id, u32 vnic_id, u8 * p); +extern int vioc_get_vnic_mac(int vioc_id, u32 vnic_id, u8 * p); +extern int vioc_set_txq(int vioc_id, u32 vnic_id, u32 txq_id, dma_addr_t base, + u32 num_elements); + +extern int vioc_set_rxc(int viocdev_idx, struct rxc *rxc); + + +extern int vioc_set_rxdq(int vioc_id, u32 vnic_id, u32 rxq_id, u32 rx_bufsize, + dma_addr_t base, u32 num_elements); +extern int vioc_set_rxs(int vioc_id, dma_addr_t base); +extern int vioc_set_vnic_cfg(int viocdev_idx, u32 vnic_id, u32 vnic_q_map); +extern int vioc_ena_dis_rxd_q(int vioc_id, u32 q_id, int ena_dis); +extern int vioc_ena_dis_tx_on_empty(int viocdev_idx, u32 vnic_id, u32 txq_id, + int ena_dis); +static inline void +vioc_reg_wr(u32 value, void __iomem *vaddr, u32 offset) +{ + writel(value, vaddr + offset); +} + +static inline void +vioc_reg_rd(void __iomem *vaddr, u32 offset, u32 * value_p) +{ + *value_p = readl(vaddr + offset); +} + +#endif /* _VIOC_API_H_ */ diff --git a/drivers/net/vioc/vioc_driver.c b/drivers/net/vioc/vioc_driver.c new file mode 100644 index 0000000..43f8a43 --- /dev/null +++ b/drivers/net/vioc/vioc_driver.c @@ -0,0 +1,873 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#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 "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" + +#include +#include "vioc_vnic.h" +#include "vioc_api.h" + +#include "driver_version.h" + + +MODULE_AUTHOR("support@fabric7.com"); +MODULE_DESCRIPTION("VIOC interface driver"); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(VIOC_DISPLAY_VERSION); + +/* + * Standard parameters for ring provisioning. Single TxQ per VNIC. + * Two RX sets per VIOC, with 3 RxDs, 1 RxC, 1 Rx interrupt per set. + */ + +#define TXQ_SIZE 1024 +#define TX_INTR_ON_EMPTY 0 + +#define VNIC_RXQ_MAP 0xf /* Bits 0-3 for 4 VNIC queues */ +#define RXDQ_PERSET_COUNT 3 +#define RXDQ_COUNT (RXSET_COUNT * RXDQ_PERSET_COUNT) +/* RXDQ sizes (entry counts) must be multiples of this */ +#define RXDQ_ALIGN VIOC_RXD_BATCH_BITS +#define RXDQ_SIZE 2048 +#define RXDQ_JUMBO_SIZE ALIGN(RXDQ_SIZE, RXDQ_ALIGN) +#define RXDQ_STD_SIZE ALIGN(RXDQ_SIZE, RXDQ_ALIGN) +#define RXDQ_SMALL_SIZE ALIGN(RXDQ_SIZE, RXDQ_ALIGN) +#define RXDQ_EXTRA_SIZE ALIGN(RXDQ_SIZE, RXDQ_ALIGN) + +#define RXC_COUNT RXSET_COUNT +#define RXC_SIZE (RXDQ_JUMBO_SIZE+RXDQ_STD_SIZE+RXDQ_SMALL_SIZE+RXDQ_EXTRA_SIZE) + +/* VIOC devices */ +static struct pci_device_id vioc_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_FABRIC7, PCI_DEVICE_ID_VIOC_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_FABRIC7, PCI_DEVICE_ID_VIOC_8)}, + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, vioc_pci_tbl); + +static spinlock_t vioc_idx_lock = SPIN_LOCK_UNLOCKED; +static unsigned vioc_idx = 0; +static struct vioc_device *vioc_devices[VIOC_MAX_VIOCS]; + +static struct vioc_device *viocdev_new(int viocdev_idx, struct pci_dev *pdev) +{ + int k; + struct vioc_device *viocdev; + + if (viocdev_idx >= VIOC_MAX_VIOCS) + return NULL; + + viocdev = kmalloc(sizeof(struct vioc_device), GFP_KERNEL); + if (!viocdev) + return viocdev; + + memset(viocdev, 0, sizeof(struct vioc_device)); + + viocdev->pdev = pdev; + viocdev->vioc_state = VIOC_STATE_INIT; + viocdev->viocdev_idx = viocdev_idx; + + viocdev->prov.run_param.tx_pkts_per_bell = TX_PKTS_PER_BELL; + viocdev->prov.run_param.tx_pkts_per_irq = TX_PKTS_PER_IRQ; + viocdev->prov.run_param.tx_intr_on_empty = TX_INTR_ON_EMPTY; + viocdev->prov.run_param.rx_intr_timeout = RX_INTR_TIMEOUT; + viocdev->prov.run_param.rx_intr_cntout = RX_INTR_PKT_CNT; + viocdev->prov.run_param.rx_wdog_timeout = HZ / 4; + + for (k = 0; k < VIOC_MAX_VNICS; k++) { + viocdev->vnic_netdev[k] = NULL; /* spp */ + } + + vioc_devices[viocdev_idx] = viocdev; + + return viocdev; +} + +/* + * Remove all Rx descriptors from the queue. + */ +static void vioc_clear_rxq(struct vioc_device *viocdev, struct rxdq *rxdq) +{ + int j; + + /* Disable this queue */ + vioc_ena_dis_rxd_q(viocdev->viocdev_idx, rxdq->rxdq_id, 0); + + if (rxdq->vbuf == NULL) + return; + + for (j = 0; j < rxdq->count; j++) { + struct rx_pktBufDesc_Phys_w *rxd; + if (rxdq->vbuf[j].skb) { + pci_unmap_single(rxdq->viocdev->pdev, + rxdq->vbuf[j].dma, + rxdq->rx_buf_size, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any((struct sk_buff *)rxdq->vbuf[j].skb); + rxdq->vbuf[j].skb = NULL; + rxdq->vbuf[j].dma = (dma_addr_t) NULL; + } + rxd = RXD_PTR(rxdq, j); + wmb(); + CLR_VNIC_RX_OWNED(rxd); + } +} + +/* + * Refill an empty Rx queue with Rx with Rx buffers + */ +static int vioc_refill_rxq(struct vioc_device *viocdev, struct rxdq *rxdq) +{ + int ret = 0; + + memset(rxdq->vbuf, 0, rxdq->count * sizeof(struct vbuf)); + memset(rxdq->dmap, 0, rxdq->dmap_count * (VIOC_RXD_BATCH_BITS / 8)); + + rxdq->fence = 0; + rxdq->to_hw = VIOC_NONE_TO_HW; + rxdq->starvations = 0; + rxdq->run_to_end = 0; + rxdq->skip_fence_run = rxdq->dmap_count / 4; + + ret = vioc_next_fence_run(rxdq); + BUG_ON(ret != 0); + return ret; +} + +struct vioc_device *vioc_viocdev(u32 viocdev_idx) +{ + if (viocdev_idx >= vioc_idx) { + BUG_ON(viocdev_idx >= vioc_idx); + return NULL; + } + + BUG_ON(vioc_devices[viocdev_idx] == NULL); + return vioc_devices[viocdev_idx]; +} + +static void vioc_bmc_wdog(unsigned long data) +{ + + struct vioc_device *viocdev = (struct vioc_device *)data; + + if (!viocdev->bmc_wd_timer_active) + return; + + /* + * Send Heartbeat message to BMC + */ + vioc_hb_to_bmc(viocdev->viocdev_idx); + + /* + * Reset the timer + */ + mod_timer(&viocdev->bmc_wd_timer, jiffies + HZ); + + return; +} + +static int extract_vnic_prov(struct vioc_device *viocdev, + struct vnic_device *vnicdev) +{ + struct vnic_prov_def *vr; + int j; + + vr = viocdev->prov.vnic_prov_p[vnicdev->vnic_id]; + if (vr == NULL) { + dev_err(&viocdev->pdev->dev, "vioc %d: vnic %d No provisioning set\n", + viocdev->viocdev_idx, vnicdev->vnic_id); + return E_VIOCPARMERR; + } + + if (vr->tx_entries == 0) { + dev_err(&viocdev->pdev->dev, "vioc %d: vnic %d Tx ring not provisioned\n", + viocdev->viocdev_idx, vnicdev->vnic_id); + return E_VIOCPARMERR; + } + + if (viocdev->rxc_p[vr->rxc_id] == NULL) { + dev_err(&viocdev->pdev->dev, + "vioc %d: vnic %d RxC ring %d not provisioned\n", + viocdev->viocdev_idx, vnicdev->vnic_id, vr->rxc_id); + return E_VIOCPARMERR; + } + + if (vr->rxc_intr_id >= viocdev->num_rx_irqs) { + dev_err(&viocdev->pdev->dev, "vioc %d: vnic %d IRQ %d INVALID (max %d)\n", + viocdev->viocdev_idx, vnicdev->vnic_id, + vr->rxc_intr_id, (viocdev->num_rx_irqs - 1)); + return E_VIOCPARMERR; + } + + vnicdev->txq.count = vr->tx_entries; + vnicdev->rxc_id = vr->rxc_id; + vnicdev->rxc_intr_id = vr->rxc_intr_id; + + for (j = 0; j < 4; j++) { + struct rxd_q_prov *ring = &vr->rxd_ring[j]; + + if (ring->state == 0) + continue; + + if (viocdev->rxd_p[ring->id] == NULL) { + dev_err(&viocdev->pdev->dev, + "vioc %d: vnic %d RxD ring %d not provisioned\n", + viocdev->viocdev_idx, vnicdev->vnic_id, + ring->id); + return E_VIOCPARMERR; + } + + /* Set Rx queue ENABLE bit for BMC_VNIC_CFG register */ + vnicdev->vnic_q_en |= (1 << j); + + } + vnicdev->qmap = + ((vr->rxd_ring[0].id & 0xf) << (0 + 8 * 0)) | + ((vr->rxd_ring[0].state & 0x1) << (7 + 8 * 0)) | + ((vr->rxd_ring[1].id & 0xf) << (0 + 8 * 1)) | + ((vr->rxd_ring[1].state & 0x1) << (7 + 8 * 1)) | + ((vr->rxd_ring[2].id & 0xf) << (0 + 8 * 2)) | + ((vr->rxd_ring[2].state & 0x1) << (7 + 8 * 2)) | + ((vr->rxd_ring[3].id & 0xf) << (0 + 8 * 3)) | + ((vr->rxd_ring[3].state & 0x1) << (7 + 8 * 3)); + return E_VIOCOK; +} + +struct net_device *vioc_alloc_vnicdev(struct vioc_device *viocdev, int vnic_id) +{ + struct net_device *netdev; + struct vnic_device *vnicdev; + + netdev = alloc_etherdev(sizeof(struct vnic_device)); + if (!netdev) { + return NULL; + } + + viocdev->vnic_netdev[vnic_id] = netdev; + vnicdev = netdev_priv(netdev); + vnicdev->viocdev = viocdev; + vnicdev->netdev = netdev; + vnicdev->vnic_id = vnic_id; + sprintf(&netdev->name[0], "ve%d.%02d", viocdev->viocdev_idx, vnic_id); + netdev->init = &vioc_vnic_init; /* called when it is registered */ + vnicdev->txq.vnic_id = vnic_id; + + if (extract_vnic_prov(viocdev, vnicdev) != E_VIOCOK) { + free_netdev(netdev); + return NULL; + } + + return netdev; +} + +static void vioc_free_resources(struct vioc_device *viocdev, u32 viocidx) +{ + int i; + struct napi_poll *napi_p; + int start_j = jiffies; + int delta_j = 0; + + for (i = 0; i < VIOC_MAX_RXCQ; i++) { + struct rxc *rxc = viocdev->rxc_p[i]; + if (rxc == NULL) + continue; + + napi_p = &rxc->napi; + /* Tell NAPI poll to stop */ + napi_p->enabled = 0; + + /* Make sure that NAPI poll gets the message */ + netif_rx_schedule(&napi_p->poll_dev); + + /* Wait for an ack from NAPI that it stopped, + * so we can release resources + */ + while (!napi_p->stopped) { + schedule(); + delta_j = jiffies - start_j; + if (delta_j > 10 * HZ) { + /* Looks like NAPI didn;t get to run. + * Bail out hoping, we are not stuck + * in NAPI poll. + */ + break; + } + } + if (rxc->dma) { + pci_free_consistent(viocdev->pdev, + rxc->count * RXC_DESC_SIZE, + rxc->desc, rxc->dma); + rxc->desc = NULL; + rxc->dma = (dma_addr_t) NULL; + } + } + + for (i = 0; i < VIOC_MAX_RXDQ; i++) { + struct rxdq *rxdq = viocdev->rxd_p[i]; + if (rxdq == NULL) + continue; + + vioc_ena_dis_rxd_q(viocidx, rxdq->rxdq_id, 0); + if (rxdq->vbuf) { + vioc_clear_rxq(viocdev, rxdq); + vfree(rxdq->vbuf); + rxdq->vbuf = NULL; + } + if (rxdq->dmap) { + vfree(rxdq->dmap); + rxdq->dmap = NULL; + } + if (rxdq->dma) { + pci_free_consistent(viocdev->pdev, + rxdq->count * RX_DESC_SIZE, + rxdq->desc, rxdq->dma); + rxdq->desc = NULL; + rxdq->dma = (dma_addr_t) NULL; + } + viocdev->rxd_p[rxdq->rxdq_id] = NULL; + } + + /* Free RxC status block */ + if (viocdev->rxcstat.dma) { + pci_free_consistent(viocdev->pdev, RXS_DESC_SIZE, + viocdev->rxcstat.block, + viocdev->rxcstat.dma); + viocdev->rxcstat.block = NULL; + viocdev->rxcstat.dma = (dma_addr_t) NULL; + } + +} + +/* + * Initialize rxsets - RxS, RxCs and RxDs and push to VIOC. + * Return negative errno on failure. + */ +static int vioc_alloc_resources(struct vioc_device *viocdev, u32 viocidx) +{ + int j, i; + int ret; + struct vnic_prov_def *vr; + struct napi_poll *napi_p; + struct rxc *rxc; + + dev_err(&viocdev->pdev->dev, "vioc%d: ENTER %s\n", viocidx, __FUNCTION__); + + /* Allocate Rx Completion Status block */ + viocdev->rxcstat.block = (struct rxc_pktStatusBlock_w *) + pci_alloc_consistent(viocdev->pdev, + RXS_DESC_SIZE * VIOC_MAX_RXCQ, + &viocdev->rxcstat.dma); + if (!viocdev->rxcstat.block) { + dev_err(&viocdev->pdev->dev, "vioc%d: Could not allocate RxS\n", viocidx); + ret = -ENOMEM; + goto error; + } + /* Tell VIOC about this RxC Status block */ + ret = vioc_set_rxs(viocidx, viocdev->rxcstat.dma); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: Could not set RxS\n", viocidx); + goto error; + } + + /* Based on provisioning request, setup RxCs and RxDs */ + for (i = 0; i < VIOC_MAX_VNICS; i++) { + vr = viocdev->prov.vnic_prov_p[i]; + if (vr == NULL) { + dev_err(&viocdev->pdev->dev, + "vioc %d: vnic %d No provisioning set\n", + viocdev->viocdev_idx, i); + goto error; + } + + if (vr->rxc_id >= VIOC_MAX_RXCQ) { + dev_err(&viocdev->pdev->dev, "vioc%d: INVALID RxC %d provisioned\n", + viocidx, vr->rxc_id); + goto error; + } + rxc = viocdev->rxc_p[vr->rxc_id]; + if (rxc == NULL) { + rxc = &viocdev->rxc_buf[vr->rxc_id]; + viocdev->rxc_p[vr->rxc_id] = rxc; + rxc->rxc_id = vr->rxc_id; + rxc->viocdev = viocdev; + rxc->quota = POLL_WEIGHT; + rxc->budget = POLL_WEIGHT; + rxc->count = vr->rxc_entries; + + /* Allocate RxC ring memory */ + rxc->desc = (struct rxc_pktDesc_Phys_w *) + pci_alloc_consistent(viocdev->pdev, + rxc->count * RXC_DESC_SIZE, + &rxc->dma); + if (!rxc->desc) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Can't allocate RxC ring %d for %d entries\n", + viocidx, rxc->rxc_id, rxc->count); + ret = -ENOMEM; + goto error; + } + rxc->interrupt_id = vr->rxc_intr_id; + + rxc->va_of_vreg_ihcu_rxcinttimer = + (&viocdev->ba)->virt + GETRELADDR(VIOC_IHCU, 0, + (VREG_IHCU_RXCINTTIMER + + + (rxc-> + interrupt_id << + 2))); + + rxc->va_of_vreg_ihcu_rxcintpktcnt = + (&viocdev->ba)->virt + GETRELADDR(VIOC_IHCU, 0, + (VREG_IHCU_RXCINTPKTCNT + + + (rxc-> + interrupt_id << + 2))); + rxc->va_of_vreg_ihcu_rxcintctl = + (&viocdev->ba)->virt + GETRELADDR(VIOC_IHCU, 0, + (VREG_IHCU_RXCINTCTL + + + (rxc-> + interrupt_id << + 2))); + /* Set parameter (rxc->rxc_id), that will be passed to interrupt code */ + ret = vioc_set_intr_func_param(viocdev->viocdev_idx, + rxc->interrupt_id, + rxc->rxc_id); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not set PARAM for INTR ID %d\n", + viocidx, rxc->interrupt_id); + goto error; + } + + /* Register RxC ring and interrupt */ + ret = vioc_set_rxc(viocidx, rxc); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not set RxC %d\n", + viocidx, vr->rxc_id); + goto error; + } + + /* Initialize NAPI poll structure and device */ + napi_p = &rxc->napi; + napi_p->enabled = 1; /* ready for Rx poll */ + napi_p->stopped = 0; /* NOT stopped */ + napi_p->rxc = rxc; + napi_p->poll_dev.weight = POLL_WEIGHT; + napi_p->poll_dev.priv = &rxc->napi; /* Note */ + napi_p->poll_dev.poll = &vioc_rx_poll; + + dev_hold(&napi_p->poll_dev); + /* Enable the poll device */ + set_bit(__LINK_STATE_START, &napi_p->poll_dev.state); + netif_start_queue(&napi_p->poll_dev); + }; + + /* Allocate Rx rings */ + for (j = 0; j < 4; j++) { + struct rxd_q_prov *ring = &vr->rxd_ring[j]; + struct rxdq *rxdq; + + if (ring->id >= VIOC_MAX_RXDQ) { + dev_err(&viocdev->pdev->dev, + "vioc%d: BAD Provisioning request for RXD %d\n", + viocidx, ring->id); + goto error; + } + + rxdq = viocdev->rxd_p[ring->id]; + if (rxdq != NULL) + continue; + + if (ring->state == 0) + continue; + + rxdq = &viocdev->rxd_buf[ring->id]; + viocdev->rxd_p[ring->id] = rxdq; + + rxdq->rxdq_id = ring->id; + rxdq->viocdev = viocdev; + rxdq->count = ring->entries; + rxdq->rx_buf_size = ring->buf_size; + + /* skb array */ + rxdq->vbuf = vmalloc(rxdq->count * sizeof(struct vbuf)); + if (!rxdq->vbuf) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Can't allocate RxD vbuf (%d entries)\n", + viocidx, rxdq->count); + ret = -ENOMEM; + goto error; + } + + /* Ring memory */ + rxdq->desc = (struct rx_pktBufDesc_Phys_w *) + pci_alloc_consistent(viocdev->pdev, + rxdq->count * RX_DESC_SIZE, + &rxdq->dma); + if (!rxdq->desc) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Can't allocate RxD ring (%d entries)\n", + viocidx, rxdq->count); + ret = -ENOMEM; + goto error; + } + rxdq->dmap_count = rxdq->count / VIOC_RXD_BATCH_BITS; + /* Descriptor ownership bit map */ + rxdq->dmap = (u32 *) + vmalloc(rxdq->dmap_count * + (VIOC_RXD_BATCH_BITS / 8)); + if (!rxdq->dmap) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not allocate dmap\n", + viocidx); + ret = -ENOMEM; + goto error; + } + /* Refill ring */ + ret = vioc_refill_rxq(viocdev, rxdq); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not fill rxdq%d\n", + viocidx, rxdq->rxdq_id); + goto error; + } + /* Tell VIOC about this queue */ + ret = vioc_set_rxdq(viocidx, VIOC_ANY_VNIC, + rxdq->rxdq_id, rxdq->rx_buf_size, + rxdq->dma, rxdq->count); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not set rxdq%d\n", + viocidx, rxdq->rxdq_id); + goto error; + } + /* Enable this queue */ + ret = vioc_ena_dis_rxd_q(viocidx, rxdq->rxdq_id, 1); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: Could not enable rxdq%d\n", + viocidx, rxdq->rxdq_id); + goto error; + } + } /* for 4 rings */ + } + + return 0; + + error: + /* Caller is responsible for calling vioc_free_rxsets() */ + return ret; +} + +static void vioc_remove(struct pci_dev *pdev) +{ + struct vioc_device *viocdev = pci_get_drvdata(pdev); + + if (!viocdev) + return; + + /* Disable interrupts */ + vioc_free_irqs(viocdev->viocdev_idx); + + viocdev->vioc_state = VIOC_STATE_INIT; + + if (viocdev->bmc_wd_timer.function) { + viocdev->bmc_wd_timer_active = 0; + del_timer_sync(&viocdev->bmc_wd_timer); + } + + if (viocdev->tx_timer.function) { + viocdev->tx_timer_active = 0; + del_timer_sync(&viocdev->tx_timer); + } + + vioc_vnic_prov(viocdev->viocdev_idx, 0, 0, 1); + + vioc_free_resources(viocdev, viocdev->viocdev_idx); + + /* Reset VIOC chip */ + vioc_sw_reset(viocdev->viocdev_idx); + +#if defined(CONFIG_MSIX_MOD) + if (viocdev->num_irqs > 4) { + pci_disable_msix(viocdev->pdev); + } else { + pci_release_regions(viocdev->pdev); + } +#else + pci_release_regions(viocdev->pdev); +#endif + + iounmap(viocdev->ba.virt); + + if (viocdev->viocdev_idx < VIOC_MAX_VIOCS) + vioc_devices[viocdev->viocdev_idx] = NULL; + + kfree(viocdev); + pci_set_drvdata(pdev, NULL); + + pci_disable_device(pdev); +} + +/* + * vioc_probe - Device Initialization Routine + * @pdev: PCI device information struct (VIOC PCI device) + * @ent: entry in vioc_pci_tbl + * + * Returns 0 on success, negative on failure + * + */ +static int __devinit vioc_probe(struct pci_dev *pdev, const + struct pci_device_id *ent) +{ + int cur_vioc_idx; + struct vioc_device *viocdev; + unsigned long long mmio_start = 0, mmio_len; + u32 param1, param2; + int ret; + + viocdev = pci_get_drvdata(pdev); + if (viocdev) { + cur_vioc_idx = viocdev->viocdev_idx; + BUG_ON(viocdev != NULL); /* should not happen */ + } else { + spin_lock(&vioc_idx_lock); + cur_vioc_idx = vioc_idx++; + spin_unlock(&vioc_idx_lock); + if (cur_vioc_idx < VIOC_MAX_VIOCS) { + viocdev = viocdev_new(cur_vioc_idx, pdev); + BUG_ON(viocdev == NULL); + pci_set_drvdata(pdev, viocdev); + } else { + dev_err(&pdev->dev, + "vioc_id %d > maximum supported, aborting.\n", + cur_vioc_idx); + return -ENODEV; + } + } + + sprintf(viocdev->name, "vioc%d", cur_vioc_idx); + + if ((ret = pci_enable_device(pdev))) { + dev_err(&pdev->dev, "vioc%d: Cannot enable PCI device\n", + cur_vioc_idx); + goto vioc_probe_err; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "vioc%d: Cannot find PCI device base address\n", + cur_vioc_idx); + ret = -ENODEV; + goto vioc_probe_err; + } + + /* Initialize interrupts: get number if Rx IRQs, 2 or 16 are valid returns */ + viocdev->num_rx_irqs = vioc_request_irqs(cur_vioc_idx); + + if (viocdev->num_rx_irqs == 0) { + dev_err(&pdev->dev, "vioc%d: Request IRQ failed\n", cur_vioc_idx); + goto vioc_probe_err; + } + + pci_set_master(pdev); + + /* Configure DMA attributes. */ + if ((ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if ((ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + dev_err(&pdev->dev, "vioc%d: No usable DMA configuration\n", + cur_vioc_idx); + goto vioc_probe_err; + } + } else { + viocdev->highdma = 1; + } + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + viocdev->ba.virt = ioremap(mmio_start, mmio_len); + viocdev->ba.phy = mmio_start; + viocdev->ba.len = mmio_len; + + /* Soft reset the chip; pick up versions */ + vioc_sw_reset(cur_vioc_idx); + + viocdev->vioc_bits_version &= 0xff; + + if (viocdev->vioc_bits_version < 0x74) { + dev_err(&pdev->dev, "VIOC version %x not supported, aborting\n", + viocdev->vioc_bits_version); + ret = -EINVAL; + goto vioc_probe_err; + } + + dev_info(&pdev->dev, "vioc%d: Detected VIOC version %x.%x\n", + cur_vioc_idx, + viocdev->vioc_bits_version, viocdev->vioc_bits_subversion); + + viocdev->prov.vnic_prov_p = vioc_prov_get(viocdev->num_rx_irqs); + + /* Allocate and provision resources */ + if ((ret = vioc_alloc_resources(viocdev, cur_vioc_idx))) { + dev_err(&pdev->dev, "vioc%d: Could not allocate resources\n", + cur_vioc_idx); + goto vioc_probe_err; + } + + /* + * Initialize heartbeat (watchdog) timer: + */ + if (viocdev->viocdev_idx == 0) { + /* Heartbeat is delivered ONLY by "master" VIOC in a + * partition */ + init_timer(&viocdev->bmc_wd_timer); + viocdev->bmc_wd_timer.function = &vioc_bmc_wdog; + viocdev->bmc_wd_timer.expires = jiffies + HZ; + viocdev->bmc_wd_timer.data = (unsigned long)viocdev; + add_timer(&viocdev->bmc_wd_timer); + viocdev->bmc_wd_timer_active = 1; + } + + /* Disable all watchdogs by default */ + viocdev->bmc_wd_timer_active = 0; + + /* + * Initialize tx_timer (tx watchdog) timer: + */ + init_timer(&viocdev->tx_timer); + viocdev->tx_timer.function = &vioc_tx_timer; + viocdev->tx_timer.expires = jiffies + HZ / 4; + viocdev->tx_timer.data = (unsigned long)viocdev; + add_timer(&viocdev->tx_timer); + /* !!! TESTING ONLY !!! */ + viocdev->tx_timer_active = 1; + + viocdev->vnics_map = 0; + + param1 = vioc_rrd(viocdev->viocdev_idx, VIOC_BMC, 0, VREG_BMC_VNIC_EN); + param2 = vioc_rrd(viocdev->viocdev_idx, VIOC_BMC, 0, VREG_BMC_PORT_EN); + vioc_vnic_prov(viocdev->viocdev_idx, param1, param2, 1); + + viocdev->vioc_state = VIOC_STATE_UP; + + return ret; + + vioc_probe_err: + vioc_remove(pdev); + return ret; +} + +/* + * Set up "version" as a driver attribute. + */ +static ssize_t show_version(struct device_driver *drv, char *buf) +{ + sprintf(buf, "%s\n", VIOC_DISPLAY_VERSION); + return strlen(buf) + 1; +} + +static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); + +static struct pci_driver vioc_driver = { + .name = VIOC_DRV_MODULE_NAME, + .id_table = vioc_pci_tbl, + .probe = vioc_probe, + .remove = __devexit_p(vioc_remove), +}; + +static int __init vioc_module_init(void) +{ + int ret = 0; + + memset(&vioc_devices, 0, sizeof(vioc_devices)); + vioc_idx = 0; + spin_lock_init(&vioc_idx_lock); + + vioc_irq_init(); + spp_init(); + + ret = pci_register_driver(&vioc_driver); + if (ret) { + printk(KERN_ERR "%s: pci_register_driver() -> %d\n", __FUNCTION__, + ret); + vioc_irq_exit(); + return ret; + } else + driver_create_file(&vioc_driver.driver, &driver_attr_version); + + vioc_os_reset_notifier_init(); + + return ret; +} + +static void __exit vioc_module_exit(void) +{ + vioc_irq_exit(); + spp_terminate(); + flush_scheduled_work(); + vioc_os_reset_notifier_exit(); + driver_remove_file(&vioc_driver.driver, &driver_attr_version); + pci_unregister_driver(&vioc_driver); +} + +module_init(vioc_module_init); +module_exit(vioc_module_exit); + +#ifdef EXPORT_SYMTAB +EXPORT_SYMBOL(vioc_viocdev); +#endif /* EXPORT_SYMTAB */ diff --git a/drivers/net/vioc/vioc_ethtool.c b/drivers/net/vioc/vioc_ethtool.c new file mode 100644 index 0000000..fb65b72 --- /dev/null +++ b/drivers/net/vioc/vioc_ethtool.c @@ -0,0 +1,303 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" + +#include +#include "vioc_vnic.h" +#include "vioc_api.h" +#include "driver_version.h" + +/* ethtool support for vnic */ + +#ifdef SIOCETHTOOL +#include + +#ifndef ETH_GSTRING_LEN +#define ETH_GSTRING_LEN 32 +#endif + +#ifdef ETHTOOL_OPS_COMPAT +#include "kcompat_ethtool.c" +#endif + +#define VIOC_READ_REG(R, M, V, viocdev) (\ + readl((viocdev->ba.virt + GETRELADDR(M, V, R)))) + +#define VIOC_WRITE_REG(R, M, V, viocdev, value) (\ + (writel(value, viocdev->ba.virt + GETRELADDR(M, V, R)))) + +#ifdef ETHTOOL_GSTATS +struct vnic_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define VNIC_STAT(m) sizeof(((struct vnic_device *)0)->m), \ + offsetof(struct vnic_device, m) + +static const struct vnic_stats vnic_gstrings_stats[] = { + {"rx_packets", VNIC_STAT(net_stats.rx_packets)}, + {"tx_packets", VNIC_STAT(net_stats.tx_packets)}, + {"rx_bytes", VNIC_STAT(net_stats.rx_bytes)}, + {"tx_bytes", VNIC_STAT(net_stats.tx_bytes)}, + {"rx_errors", VNIC_STAT(net_stats.rx_errors)}, + {"tx_errors", VNIC_STAT(net_stats.tx_errors)}, + {"rx_dropped", VNIC_STAT(net_stats.rx_dropped)}, + {"tx_dropped", VNIC_STAT(net_stats.tx_dropped)}, + {"multicast", VNIC_STAT(net_stats.multicast)}, + {"collisions", VNIC_STAT(net_stats.collisions)}, + {"rx_length_errors", VNIC_STAT(net_stats.rx_length_errors)}, + {"rx_over_errors", VNIC_STAT(net_stats.rx_over_errors)}, + {"rx_crc_errors", VNIC_STAT(net_stats.rx_crc_errors)}, + {"rx_frame_errors", VNIC_STAT(net_stats.rx_frame_errors)}, + {"rx_fifo_errors", VNIC_STAT(net_stats.rx_fifo_errors)}, + {"rx_missed_errors", VNIC_STAT(net_stats.rx_missed_errors)}, + {"tx_aborted_errors", VNIC_STAT(net_stats.tx_aborted_errors)}, + {"tx_carrier_errors", VNIC_STAT(net_stats.tx_carrier_errors)}, + {"tx_fifo_errors", VNIC_STAT(net_stats.tx_fifo_errors)}, + {"tx_heartbeat_errors", VNIC_STAT(net_stats.tx_heartbeat_errors)}, + {"tx_window_errors", VNIC_STAT(net_stats.tx_window_errors)}, + {"rx_fragment_errors", VNIC_STAT(vnic_stats.rx_fragment_errors)}, + {"rx_dropped", VNIC_STAT(vnic_stats.rx_dropped)}, + {"tx_skb_equeued", VNIC_STAT(vnic_stats.skb_enqueued)}, + {"tx_skb_freed", VNIC_STAT(vnic_stats.skb_freed)}, + {"netif_stops", VNIC_STAT(vnic_stats.netif_stops)}, + {"tx_on_empty_intr", VNIC_STAT(vnic_stats.tx_on_empty_interrupts)}, + {"tx_headroom_misses", VNIC_STAT(vnic_stats.headroom_misses)}, + {"tx_headroom_miss_drops", VNIC_STAT(vnic_stats.headroom_miss_drops)}, + {"tx_ring_size", VNIC_STAT(txq.count)}, + {"tx_ring_capacity", VNIC_STAT(txq.empty)}, + {"pkts_till_intr", VNIC_STAT(txq.tx_pkts_til_irq)}, + {"pkts_till_bell", VNIC_STAT(txq.tx_pkts_til_bell)}, + {"bells", VNIC_STAT(txq.bells)}, + {"next_to_use", VNIC_STAT(txq.next_to_use)}, + {"next_to_clean", VNIC_STAT(txq.next_to_clean)}, + {"tx_frags", VNIC_STAT(txq.frags)}, + {"tx_ring_wraps", VNIC_STAT(txq.wraps)}, + {"tx_ring_fulls", VNIC_STAT(txq.full)} +}; + +#define VNIC_STATS_LEN \ + sizeof(vnic_gstrings_stats) / sizeof(struct vnic_stats) +#endif /* ETHTOOL_GSTATS */ +#ifdef ETHTOOL_TEST +static const char vnic_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; + +#define VNIC_TEST_LEN sizeof(vnic_gstrings_test) / ETH_GSTRING_LEN +#endif /* ETHTOOL_TEST */ + +static int vnic_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + ecmd->supported = SUPPORTED_1000baseT_Full; + ecmd->advertising = ADVERTISED_TP; + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + ecmd->duplex = DUPLEX_FULL; + ecmd->speed = 3; + ecmd->autoneg = 0; + return 0; +} + +int vioc_trace; + +static u32 vnic_get_msglevel(struct net_device *netdev) +{ + return vioc_trace; +} + +static void vnic_set_msglevel(struct net_device *netdev, u32 data) +{ + vioc_trace = (int)data; +} + +struct regs_line { + u32 addr; + u32 data; +}; + +#define VNIC_REGS_CNT 12 +#define VNIC_REGS_LINE_LEN sizeof(struct regs_line) + +static int vnic_get_regs_len(struct net_device *netdev) +{ + return (VNIC_REGS_CNT * VNIC_REGS_LINE_LEN); +} + + +static void vnic_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct vnic_device *vnicdev = netdev->priv; + struct vioc_device *viocdev = vnicdev->viocdev; + struct regs_line *regs_info = p; + int i = 0; + + memset((void *) regs_info, 0, VNIC_REGS_CNT * VNIC_REGS_LINE_LEN); + + regs->version = 1; + + regs_info[i].addr = GETRELADDR(VREG_BMC_GLOBAL, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_GLOBAL, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_DEBUG, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_DEBUG, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_DEBUGPRIV, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_DEBUGPRIV, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_FABRIC, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_FABRIC, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_VNIC_EN, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_VNIC_EN, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_PORT_EN, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_PORT_EN, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_BMC_VNIC_CFG, VIOC_BMC, 0); + regs_info[i].data = VIOC_READ_REG(VREG_BMC_VNIC_CFG, VIOC_BMC, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_IHCU_RXDQEN, VIOC_IHCU, 0); + regs_info[i].data = VIOC_READ_REG(VREG_IHCU_RXDQEN, VIOC_IHCU, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_VENG_VLANTAG, VIOC_VENG, 0); + regs_info[i].data = VIOC_READ_REG(VREG_VENG_VLANTAG, VIOC_VENG, 0, viocdev); + i++; + + regs_info[i].addr = GETRELADDR(VREG_VENG_TXD_CTL, VIOC_VENG, 0); + regs_info[i].data = VIOC_READ_REG(VREG_VENG_TXD_CTL, VIOC_VENG, 0, viocdev); +} + +static void vnic_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct vnic_device *vnicdev = netdev->priv; + struct vioc_device *viocdev = vnicdev->viocdev; + + sprintf(drvinfo->driver, VIOC_DRV_MODULE_NAME); + strncpy(drvinfo->version, VIOC_DISPLAY_VERSION, 32); + sprintf(drvinfo->fw_version, "%02X-%02X", viocdev->vioc_bits_version, + viocdev->vioc_bits_subversion); + strncpy(drvinfo->bus_info, pci_name(viocdev->pdev), 32); + drvinfo->n_stats = VNIC_STATS_LEN; + drvinfo->testinfo_len = VNIC_TEST_LEN; + drvinfo->regdump_len = vnic_get_regs_len(netdev); + drvinfo->eedump_len = 0; +} + +static int vnic_get_stats_count(struct net_device *netdev) +{ + return VNIC_STATS_LEN; +} + +static void vnic_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 * data) +{ + struct vnic_device *vnicdev = netdev->priv; + int i; + + for (i = 0; i < VNIC_STATS_LEN; i++) { + char *p = (char *)vnicdev + vnic_gstrings_stats[i].stat_offset; + data[i] = (vnic_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *) p : *(u32 *) p; + } +} + +static void vnic_get_strings(struct net_device *netdev, u32 stringset, + u8 * data) +{ + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *vnic_gstrings_test, + VNIC_TEST_LEN * ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < VNIC_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + vnic_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +struct ethtool_ops vioc_ethtool_ops = { + .get_settings = vnic_get_settings, + .get_drvinfo = vnic_get_drvinfo, + .get_regs_len = vnic_get_regs_len, + .get_regs = vnic_get_regs, + .get_msglevel = vnic_get_msglevel, + .set_msglevel = vnic_set_msglevel, + .get_strings = vnic_get_strings, + .get_stats_count = vnic_get_stats_count, + .get_ethtool_stats = vnic_get_ethtool_stats, +}; + +#endif /* SIOCETHTOOL */ diff --git a/drivers/net/vioc/vioc_irq.c b/drivers/net/vioc/vioc_irq.c new file mode 100644 index 0000000..b0fb998 --- /dev/null +++ b/drivers/net/vioc/vioc_irq.c @@ -0,0 +1,514 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" +#include "vioc_vnic.h" + +#define VIOC_INTERRUPTS_CNT 19 /* 16 Rx + 1 Tx + 1 BMC + 1 Error */ +#define VIOC_INTERRUPTS_CNT_PIN_IRQ 4 /* 2 Rx + 1 Tx + 1 BMC */ + +#define VIOC_SLVAR(x) x spinlock_t vioc_driver_lock = SPIN_LOCK_UNLOCKED +#define VIOC_CLI spin_lock_irq(&vioc_driver_lock) +#define VIOC_STI spin_unlock_irq(&vioc_driver_lock) +#define IRQRETURN return IRQ_HANDLED +#define TX_IRQ_IDX 16 +#define BMC_IRQ_IDX 17 +#define ERR_IRQ_IDX 18 +#define HANDLER_TASKLET 1 +#define HANDLER_DIRECT 2 +#define HANDLER_TASKQ 3 +#define VIOC_RX0_PCI_FUNC 0 +#define VIOC_TX_PCI_FUNC 1 +#define VIOC_BMC_PCI_FUNC 2 +#define VIOC_RX1_PCI_FUNC 3 +#define VIOC_IRQ_NONE (u16) -1 +#define VIOC_ID_NONE -1 +#define VIOC_IVEC_NONE -1 +#define VIOC_INTR_NONE -1 + + +struct vioc_msix_entry { + u16 vector; + u16 entry; +}; + +struct viocdev_intreq { + int vioc_id; + struct pci_dev *pci_dev; + void *vioc_virt; + unsigned long long vioc_phy; + void *ioapic_virt; + unsigned long long ioapic_phy; + struct vioc_intreq intreq[VIOC_INTERRUPTS_CNT]; + struct vioc_msix_entry irqs[VIOC_INTERRUPTS_CNT]; +}; + +/* GLOBAL VIOC Interrupt table/structure */ +struct viocdev_intreq vioc_interrupts[VIOC_MAX_VIOCS]; + +VIOC_SLVAR(); + +static irqreturn_t taskq_handler(int i, void *p) +{ + int intr_id = VIOC_IRQ_PARAM_INTR_ID(p); + int vioc_id = VIOC_IRQ_PARAM_VIOC_ID(p); + + schedule_work(&vioc_interrupts[vioc_id].intreq[intr_id].taskq); + IRQRETURN; +} + +static irqreturn_t tasklet_handler(int i, void *p) +{ + int intr_id = VIOC_IRQ_PARAM_INTR_ID(p); + int vioc_id = VIOC_IRQ_PARAM_VIOC_ID(p); + + tasklet_schedule(&vioc_interrupts[vioc_id].intreq[intr_id].tasklet); + IRQRETURN; +} + +static irqreturn_t direct_handler(int i, void *p) +{ + int intr_id = VIOC_IRQ_PARAM_INTR_ID(p); + int vioc_id = VIOC_IRQ_PARAM_VIOC_ID(p); + + vioc_interrupts[vioc_id].intreq[intr_id]. + intrFuncp((void *)&vioc_interrupts[vioc_id].intreq[intr_id].taskq); + IRQRETURN; +} + +static int vioc_enable_msix(u32 viocdev_idx) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + int ret; + +#if defined(CONFIG_MSIX_MOD) + ret = pci_enable_msix(viocdev->pdev, + (struct msix_entry *) + &vioc_interrupts[viocdev_idx].irqs, + VIOC_INTERRUPTS_CNT); + if (ret == 0) { + dev_err(&viocdev->pdev->dev, "MSI-X OK\n"); + return VIOC_INTERRUPTS_CNT; + } else { + dev_err(&viocdev->pdev->dev, + "Enabling MSIX failed (%d) VIOC %d, use PIN-IRQ\n", ret, + viocdev_idx); + pci_disable_msix(viocdev->pdev); + ret = pci_request_regions(viocdev->pdev, VIOC_DRV_MODULE_NAME); + if (ret != 0) { + dev_err(&viocdev->pdev->dev, "vioc%d: Cannot obtain PCI resources\n", + viocdev_idx); + return 0; + } + return VIOC_INTERRUPTS_CNT_PIN_IRQ; + } +#else + ret = pci_request_regions(viocdev->pdev, VIOC_DRV_MODULE_NAME); + if (ret != 0) { + dev_err(&viocdev->pdev->dev, "vioc%d: Cannot obtain PCI resources\n", + viocdev_idx); + return 0; + } + return VIOC_INTERRUPTS_CNT_PIN_IRQ; +#endif +} + +static void vioc_irq_remove(int viocdev_idx, int irq) +{ + int intr_id; + + if (viocdev_idx >= VIOC_MAX_VIOCS) + return; + + for (intr_id = 0; intr_id < VIOC_INTERRUPTS_CNT; intr_id++) { + if (vioc_interrupts[viocdev_idx].intreq[intr_id].irq == irq) { + if (vioc_interrupts[viocdev_idx].intreq[intr_id].irq != + VIOC_IRQ_NONE) { + free_irq(vioc_interrupts[viocdev_idx]. + intreq[intr_id].irq, + vioc_interrupts[viocdev_idx]. + intreq[intr_id].intrFuncparm); + } + vioc_interrupts[viocdev_idx].intreq[intr_id].irq = + VIOC_IRQ_NONE; + vioc_interrupts[viocdev_idx].irqs[intr_id].vector = + VIOC_IRQ_NONE; + } + } +} + +void vioc_free_irqs(u32 viocdev_idx) +{ + u32 i; + + for (i = 0; i < VIOC_INTERRUPTS_CNT; i++) { + if (vioc_interrupts[viocdev_idx].irqs[i].vector != + VIOC_IRQ_NONE) { + vioc_irq_remove(viocdev_idx, + vioc_interrupts[viocdev_idx].irqs[i]. + vector); + } + } +} + +void vioc_irq_exit(void) +{ + int vioc_id; + + for (vioc_id = 0; vioc_id < VIOC_MAX_VIOCS; vioc_id++) + vioc_free_irqs(vioc_id); +} + +int vioc_irq_init(void) +{ + int intr_id, vioc_id; + + /* Zero out whole vioc_interrupts array */ + memset(&vioc_interrupts, 0, sizeof(vioc_interrupts)); + + for (vioc_id = 0; vioc_id < VIOC_MAX_VIOCS; vioc_id++) { + vioc_interrupts[vioc_id].vioc_id = VIOC_ID_NONE; + for (intr_id = 0; intr_id < VIOC_INTERRUPTS_CNT; intr_id++) { + vioc_interrupts[vioc_id].intreq[intr_id].irq = + VIOC_IRQ_NONE; + vioc_interrupts[vioc_id].irqs[intr_id].vector = + VIOC_IRQ_NONE; + vioc_interrupts[vioc_id].irqs[intr_id].entry = intr_id; + } + } + return 0; +} + +int get_pci_pin_irq(struct pci_dev *dev_in, int func) +{ + struct pci_dev *dev = NULL; + unsigned int slot, fn, devfn; + + slot = PCI_SLOT(dev_in->devfn); + fn = PCI_FUNC(dev_in->devfn); + devfn = dev_in->devfn; + + devfn = PCI_DEVFN(slot, func); + /* Find pci_dev structure of the requested function */ + dev = pci_find_slot(dev_in->bus->number, devfn); + if (dev) { + return dev->irq; + } else { + return VIOC_IRQ_NONE; + } +} + +static int vioc_irq_install(struct pci_dev *vioc_pci_dev, + void (*routine) (struct work_struct *work), + int vioc_id, + int intr_id, + int irq, + int intr_handler_type, + int intr_param, char *intr_name) +{ + int ret; + + /* + * Find IRQ of requested interrupt: For now, search the + * vioc_interrupts[] table that was initialized with proper + * IRQs during viocdev_htirq_init() In the final product, the + * IRQ will be obtained from the pci_dev structure of the VIOC + * device. + */ + + if (vioc_id >= VIOC_MAX_VIOCS) + return -ENODEV; + + if (intr_id >= VIOC_INTERRUPTS_CNT) { + dev_err(&vioc_pci_dev->dev, + "%s: INTR ID (%d) out of range for Interrupt IRQ %d, name %s\n", + __FUNCTION__, intr_id, irq, intr_name); + return -EINVAL; + } + vioc_interrupts[vioc_id].vioc_id = vioc_id; + + if (vioc_interrupts[vioc_id].intreq[intr_id].irq != VIOC_IRQ_NONE) { + free_irq(vioc_interrupts[vioc_id]. + intreq[intr_id].irq, + vioc_interrupts[vioc_id].intreq[intr_id].intrFuncparm); + vioc_interrupts[vioc_id].intreq[intr_id].irq = VIOC_IRQ_NONE; + } + + vioc_set_intr_func_param(vioc_id, intr_id, intr_param); + INIT_WORK(&vioc_interrupts[vioc_id].intreq[intr_id].taskq, routine); + + vioc_interrupts[vioc_id].intreq[intr_id].irq = irq; + vioc_interrupts[vioc_id].intreq[intr_id].name[VIOC_NAME_LEN - 1] = '\0'; + + vioc_interrupts[vioc_id].intreq[intr_id].timeout_value = 100; + vioc_interrupts[vioc_id].intreq[intr_id].pkt_counter = 1; + vioc_interrupts[vioc_id].intreq[intr_id].vec = VIOC_IVEC_NONE; + vioc_interrupts[vioc_id].intreq[intr_id].intrFuncp = routine; + + /* Init work_struct used to schedule task from INTR handler code */ + + /* Init tasklet_struct used to run "tasklet" from INTR handler code */ + vioc_interrupts[vioc_id].intreq[intr_id].tasklet.next = NULL; + vioc_interrupts[vioc_id].intreq[intr_id].tasklet.state = 0; + atomic_set(&vioc_interrupts[vioc_id].intreq[intr_id].tasklet.count, 0); + vioc_interrupts[vioc_id].intreq[intr_id].tasklet.func = + (void (*)(unsigned long))routine; + + snprintf(&vioc_interrupts[vioc_id].intreq[intr_id].name[0], + VIOC_NAME_LEN, "%s_%02x", intr_name, vioc_id); + vioc_interrupts[vioc_id].intreq[intr_id].name[VIOC_NAME_LEN - 1] = '\0'; + + if (intr_handler_type == HANDLER_TASKLET) + vioc_interrupts[vioc_id].intreq[intr_id].hthandler = + tasklet_handler; + else if (intr_handler_type == HANDLER_TASKQ) + vioc_interrupts[vioc_id].intreq[intr_id].hthandler = + taskq_handler; + else if (intr_handler_type == HANDLER_DIRECT) + vioc_interrupts[vioc_id].intreq[intr_id].hthandler = + direct_handler; + else { + dev_err(&vioc_pci_dev->dev, + "%s: Interrupt handler type for name %s unknown\n", + __FUNCTION__, intr_name); + return -EINVAL; + } + + ret = request_irq(vioc_interrupts[vioc_id].intreq[intr_id].irq, + vioc_interrupts[vioc_id].intreq[intr_id].hthandler, + SA_INTERRUPT, + vioc_interrupts[vioc_id].intreq[intr_id].name, + vioc_interrupts[vioc_id].intreq[intr_id]. + intrFuncparm); + if (ret) { + dev_err(&vioc_pci_dev->dev, "%s: request_irq() -> %d\n", __FUNCTION__, ret); + return ret; + } + + return 0; +} + +int vioc_set_intr_func_param(int viocdev_idx, int intr_idx, int intr_param) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + + void *intr_func_param = (void *) + VIOC_IRQ_PARAM_SET(viocdev_idx, intr_idx, intr_param); + + if (viocdev_idx >= VIOC_MAX_VIOCS) { + dev_err(&viocdev->pdev->dev, "%s: VIOC ID (%d) is out of range\n", + __FUNCTION__, viocdev_idx); + return -ENODEV; + } + + if (intr_idx >= VIOC_INTERRUPTS_CNT) { + dev_err(&viocdev->pdev->dev, "%s: INTR ID (%d) is out of range\n", + __FUNCTION__, intr_idx); + return -EINVAL; + } + + vioc_interrupts[viocdev_idx].intreq[intr_idx].intrFuncparm = + intr_func_param; + return 0; +} + +/* + * Function returns number of Rx IRQs. + * When PIN IRQ is used, 2 Rx IRQs are supported. + * With MSI-X 16 Rx IRQs. + */ + +int vioc_request_irqs(u32 viocdev_idx) +{ + struct vioc_device *viocdev = vioc_viocdev(viocdev_idx); + int ret; + int total_num_irqs; + int intr_idx; + char name_buf[64]; + + /* Check for MSI-X, install either 2 or 16 Rx IRQs */ + total_num_irqs = vioc_enable_msix(viocdev_idx); + viocdev->num_irqs = total_num_irqs; + + switch (total_num_irqs) { + + case VIOC_INTERRUPTS_CNT_PIN_IRQ: + vioc_interrupts[viocdev_idx].irqs[2].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_TX_PCI_FUNC); + vioc_interrupts[viocdev_idx].irqs[3].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_BMC_PCI_FUNC); + + intr_idx = 0; + vioc_interrupts[viocdev_idx].irqs[intr_idx].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_RX0_PCI_FUNC); + sprintf(name_buf, "rx%02d_intr", intr_idx); + ret = vioc_irq_install(viocdev->pdev, + vioc_rxc_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_DIRECT, + intr_idx, name_buf); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: RX IRQ %02d not installed\n", + viocdev_idx, intr_idx); + return 0; + } + + intr_idx = 1; + vioc_interrupts[viocdev_idx].irqs[intr_idx].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_RX1_PCI_FUNC); + sprintf(name_buf, "rx%02d_intr", intr_idx); + ret = vioc_irq_install(viocdev->pdev, + vioc_rxc_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_DIRECT, + intr_idx, name_buf); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: RX IRQ %02d not installed\n", + viocdev_idx, intr_idx); + return 0; + } + + intr_idx = TX_IRQ_IDX; + vioc_interrupts[viocdev_idx].irqs[intr_idx].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_TX_PCI_FUNC); + ret = vioc_irq_install(viocdev->pdev, + vioc_tx_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_TASKLET, + intr_idx, "tx_intr"); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: TX IRQ not installed\n", + viocdev_idx); + return 0; + } + + intr_idx = BMC_IRQ_IDX; + vioc_interrupts[viocdev_idx].irqs[intr_idx].vector = + get_pci_pin_irq(viocdev->pdev, VIOC_BMC_PCI_FUNC); + ret = vioc_irq_install(viocdev->pdev, + vioc_bmc_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_TASKQ, + intr_idx, "bmc_intr"); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: BMC IRQ not installed\n", + viocdev_idx); + return 0; + } + + return 2; + + case VIOC_INTERRUPTS_CNT: + + for (intr_idx = 0; intr_idx < 16; intr_idx++) { + sprintf(name_buf, "rx%02d_intr", intr_idx); + ret = vioc_irq_install(viocdev->pdev, + vioc_rxc_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, + HANDLER_DIRECT, intr_idx, + name_buf); + if (ret) { + dev_err(&viocdev->pdev->dev, + "vioc%d: RX IRQ %02d not installed\n", + viocdev_idx, intr_idx); + return 0; + } + } + + intr_idx = TX_IRQ_IDX; + ret = vioc_irq_install(viocdev->pdev, + vioc_tx_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_TASKLET, + intr_idx, "tx_intr"); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: TX IRQ not installed\n", + viocdev_idx); + return 0; + } + + intr_idx = BMC_IRQ_IDX; + ret = vioc_irq_install(viocdev->pdev, + vioc_bmc_interrupt, + viocdev_idx, + intr_idx, + vioc_interrupts[viocdev_idx]. + irqs[intr_idx].vector, HANDLER_TASKQ, + intr_idx, "bmc_intr"); + if (ret) { + dev_err(&viocdev->pdev->dev, "vioc%d: BMC IRQ not installed\n", + viocdev_idx); + return 0; + } + + return 16; + + default: + + return 0; + } + + return 0; +} + diff --git a/drivers/net/vioc/vioc_provision.c b/drivers/net/vioc/vioc_provision.c new file mode 100644 index 0000000..571d308 --- /dev/null +++ b/drivers/net/vioc/vioc_provision.c @@ -0,0 +1,226 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include "f7/vioc_hw_registers.h" +#include "vioc_vnic.h" + +/* + * Standard parameters for ring provisioning. Single TxQ per VNIC. + * Two RX sets per VIOC, with 3 RxDs, 1 RxC, 1 Rx interrupt per set. + */ + +#define TXQ_ENTRIES 1024 +#define TX_INTR_ON_EMPTY false + +/* RXDQ sizes (entry counts) must be multiples of this */ +#define RXDQ_ALIGN VIOC_RXD_BATCH_BITS +#define RXDQ_ENTRIES 1024 + +#define RXDQ_JUMBO_ENTRIES ALIGN(RXDQ_ENTRIES, RXDQ_ALIGN) +#define RXDQ_STD_ENTRIES ALIGN(RXDQ_ENTRIES, RXDQ_ALIGN) +#define RXDQ_SMALL_ENTRIES ALIGN(RXDQ_ENTRIES, RXDQ_ALIGN) +#define RXDQ_EXTRA_ENTRIES ALIGN(RXDQ_ENTRIES, RXDQ_ALIGN) + +#define RXC_ENTRIES (RXDQ_JUMBO_ENTRIES+RXDQ_STD_ENTRIES+RXDQ_SMALL_ENTRIES+RXDQ_EXTRA_ENTRIES) + +#define RXDQ_JUMBO_BUFSIZE (VNIC_MAX_MTU+ETH_HLEN+F7PF_HLEN_STD) +#define RXDQ_STD_BUFSIZE (VNIC_STD_MTU+ETH_HLEN+F7PF_HLEN_STD) +#define RXDQ_SMALL_BUFSIZE (256+ETH_HLEN+F7PF_HLEN_STD) + +#define RXDQ_JUMBO_ALLOC_BUFSIZE ALIGN(RXDQ_JUMBO_BUFSIZE,64) +#define RXDQ_STD_ALLOC_BUFSIZE ALIGN(RXDQ_STD_BUFSIZE,64) +#define RXDQ_SMALL_ALLOC_BUFSIZE ALIGN(RXDQ_SMALL_BUFSIZE,64) + +/* + Every entry in this structure is defined as follows: + +struct vnic_prov_def { + struct rxd_q_prov rxd_ring[4]; + u32 tx_entries; Size of Tx Ring + u32 rxc_entries; Size of Rx Completion Ring + u8 rxc_id; Rx Completion queue ID + u8 rxc_intr_id; INTR servicing the above Rx Completion queue +}; + +The 4 rxd_q_prov structures of rxd_ring[] array define Rx queues per VNIC. +struct rxd_q_prov { + u32 buf_size; Buffer size + u32 entries; Size of the queue + u8 id; Queue id/ + u8 state; Provisioning state 1-ena, 0-dis +}; + +*/ + +struct vnic_prov_def vnic_set_0 = { + .rxd_ring[0].buf_size = RXDQ_SMALL_ALLOC_BUFSIZE, + .rxd_ring[0].entries = RXDQ_SMALL_ENTRIES, + .rxd_ring[0].id = 0, + .rxd_ring[0].state = 1, + .rxd_ring[1].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[1].entries = RXDQ_STD_ENTRIES, + .rxd_ring[1].id = 1, + .rxd_ring[1].state = 1, + .rxd_ring[2].buf_size = RXDQ_JUMBO_ALLOC_BUFSIZE, + .rxd_ring[2].entries = RXDQ_JUMBO_ENTRIES, + .rxd_ring[2].id = 2, + .rxd_ring[2].state = 1, + .tx_entries = TXQ_ENTRIES,.rxc_entries = RXC_ENTRIES,.rxc_id = + 0,.rxc_intr_id = 0 +}; + +struct vnic_prov_def vnic_set_1 = { + .rxd_ring[0].buf_size = RXDQ_SMALL_ALLOC_BUFSIZE, + .rxd_ring[0].entries = RXDQ_SMALL_ENTRIES, + .rxd_ring[0].id = 4, + .rxd_ring[0].state = 1, + .rxd_ring[1].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[1].entries = RXDQ_STD_ENTRIES, + .rxd_ring[1].id = 5, + .rxd_ring[1].state = 1, + .rxd_ring[2].buf_size = RXDQ_JUMBO_ALLOC_BUFSIZE, + .rxd_ring[2].entries = RXDQ_JUMBO_ENTRIES, + .rxd_ring[2].id = 6, + .rxd_ring[2].state = 1, + .tx_entries = TXQ_ENTRIES,.rxc_entries = RXC_ENTRIES,.rxc_id = + 1,.rxc_intr_id = 1 +}; + +struct vnic_prov_def vnic_set_2 = { + .rxd_ring[0].buf_size = RXDQ_SMALL_ALLOC_BUFSIZE, + .rxd_ring[0].entries = RXDQ_SMALL_ENTRIES, + .rxd_ring[0].id = 8, + .rxd_ring[0].state = 1, + .rxd_ring[1].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[1].entries = RXDQ_STD_ENTRIES, + .rxd_ring[1].id = 9, + .rxd_ring[1].state = 1, + .rxd_ring[2].buf_size = RXDQ_JUMBO_ALLOC_BUFSIZE, + .rxd_ring[2].entries = RXDQ_JUMBO_ENTRIES, + .rxd_ring[2].id = 10, + .rxd_ring[2].state = 1, + .tx_entries = TXQ_ENTRIES,.rxc_entries = RXC_ENTRIES,.rxc_id = + 2,.rxc_intr_id = 2 +}; + +struct vnic_prov_def vnic_set_3 = { + .rxd_ring[0].buf_size = RXDQ_SMALL_ALLOC_BUFSIZE, + .rxd_ring[0].entries = RXDQ_SMALL_ENTRIES, + .rxd_ring[0].id = 12, + .rxd_ring[0].state = 1, + .rxd_ring[1].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[1].entries = RXDQ_STD_ENTRIES, + .rxd_ring[1].id = 13, + .rxd_ring[1].state = 1, + .rxd_ring[2].buf_size = RXDQ_JUMBO_ALLOC_BUFSIZE, + .rxd_ring[2].entries = RXDQ_JUMBO_ENTRIES, + .rxd_ring[2].id = 15, + .rxd_ring[2].state = 1, + .tx_entries = TXQ_ENTRIES,.rxc_entries = RXC_ENTRIES,.rxc_id = + 3,.rxc_intr_id = 3 +}; + +struct vnic_prov_def vnic_set_sim = { + .rxd_ring[0].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[0].entries = 256, + .rxd_ring[0].id = 0, + .rxd_ring[0].state = 1, + .rxd_ring[1].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[1].entries = 256, + .rxd_ring[1].id = 1, + .rxd_ring[1].state = 1, + .rxd_ring[2].buf_size = RXDQ_STD_ALLOC_BUFSIZE, + .rxd_ring[2].entries = 256, + .rxd_ring[2].id = 2, + .rxd_ring[2].state = 1, + .tx_entries = 256,.rxc_entries = 256 * 3,.rxc_id = 0,.rxc_intr_id = 0 +}; + +struct vnic_prov_def *vnic_prov_pmm_pin_irq[VIOC_MAX_VNICS] = { + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1, + &vnic_set_0, + &vnic_set_1 +}; + +struct vnic_prov_def *vnic_prov_pmm_msi_x[VIOC_MAX_VNICS] = { + &vnic_set_0, + &vnic_set_1, + &vnic_set_2, + &vnic_set_3, + &vnic_set_0, + &vnic_set_1, + &vnic_set_2, + &vnic_set_3, + &vnic_set_0, + &vnic_set_1, + &vnic_set_2, + &vnic_set_3, + &vnic_set_0, + &vnic_set_1, + &vnic_set_2, + &vnic_set_3 +}; + +struct vnic_prov_def *vnic_prov_sim[VIOC_MAX_VNICS] = { + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim, + &vnic_set_sim +}; + +struct vnic_prov_def **vioc_prov_get(int num_rx_irq) +{ + if (num_rx_irq == 16) + return (struct vnic_prov_def **)&vnic_prov_pmm_msi_x; + else + return (struct vnic_prov_def **)&vnic_prov_pmm_pin_irq; + +} diff --git a/drivers/net/vioc/vioc_receive.c b/drivers/net/vioc/vioc_receive.c new file mode 100644 index 0000000..6c53455 --- /dev/null +++ b/drivers/net/vioc/vioc_receive.c @@ -0,0 +1,367 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" + +#include "vioc_vnic.h" +#include "vioc_api.h" + +/* + * Receive one packet. The VIOC is read-locked. Since RxDQs are + * partitioned into independent RxSets and VNICs assigned to exactly + * one RxSet, no locking is needed on RxDQs or RxCQs. + * Return true if we got a packet, false if the queue is empty. + */ +int vioc_rx_pkt(struct vioc_device *viocdev, struct rxc *rxc, u32 sw_idx) +{ + u32 rx_status; + u32 vnic_id; + u32 rxdq_id; + u32 rxd_id; + u32 pkt_len; + u32 dmap_idx; + struct sk_buff *in_skb, *out_skb; + struct vnic_device *vnicdev; + struct rxdq *rxdq; + struct rxc_pktDesc_Phys_w *rxcd; + struct rx_pktBufDesc_Phys_w *rxd; + + rxcd = &rxc->desc[sw_idx]; + if (GET_VNIC_RXC_FLAGGED(rxcd) != VNIC_RXC_FLAGGED_HW_W) + return 0; /* ring empty */ + + vnic_id = GET_VNIC_RXC_VNIC_ID_SHIFTED(rxcd); + rxdq_id = GET_VNIC_RXC_RXQ_ID_SHIFTED(rxcd); + rxd_id = GET_VNIC_RXC_IDX_SHIFTED(rxcd); + rxdq = viocdev->rxd_p[rxdq_id]; + rxd = &rxdq->desc[rxd_id]; + + in_skb = (struct sk_buff *)rxdq->vbuf[rxd_id].skb; + BUG_ON(in_skb == NULL); + out_skb = in_skb; /* default it here */ + + /* + * Reset HW FLAG in this RxC Descriptor, marking it as "SW + * acknowledged HW completion". + */ + CLR_VNIC_RXC_FLAGGED(rxcd); + + if (!(viocdev->vnics_map & (1 << vnic_id))) + /* VNIC is not enabled - silently drop packet */ + goto out; + + in_skb->dev = viocdev->vnic_netdev[vnic_id]; + vnicdev = in_skb->dev->priv; + BUG_ON(vnicdev == NULL); + + rx_status = GET_VNIC_RXC_STATUS(rxcd); + + if (likely(rx_status == VNIC_RXC_STATUS_OK_W)) { + + pkt_len = GET_NTOH_VIOC_F7PF_PKTLEN_SHIFTED(in_skb->data); + + /* Copy out mice packets in ALL rings, even small */ + if (pkt_len <= VIOC_COPYOUT_THRESHOLD) { + out_skb = dev_alloc_skb(pkt_len); + if (!out_skb) + goto drop; + out_skb->dev = in_skb->dev; + memcpy(out_skb->data, in_skb->data, pkt_len); + } + + vnicdev->net_stats.rx_bytes += pkt_len; + vnicdev->net_stats.rx_packets++; + /* Set ->len and ->tail to reflect packet size */ + skb_put(out_skb, pkt_len); + + skb_pull(out_skb, F7PF_HLEN_STD); + out_skb->protocol = eth_type_trans(out_skb, out_skb->dev); + + /* Checksum offload */ + if (GET_VNIC_RXC_ENTAG_SHIFTED(rxcd) == + VIOC_F7PF_ET_ETH_IPV4_CKS) + out_skb->ip_summed = CHECKSUM_UNNECESSARY; + else { + out_skb->ip_summed = VIOC_CSUM_OFFLOAD; + out_skb->csum = + ntohs(~GET_VNIC_RXC_CKSUM_SHIFTED(rxcd) & 0xffff); + } + + netif_receive_skb(out_skb); + } else { + vnicdev->net_stats.rx_errors++; + if (rx_status & VNIC_RXC_ISBADLENGTH_W) + vnicdev->net_stats.rx_length_errors++; + if (rx_status & VNIC_RXC_ISBADCRC_W) + vnicdev->net_stats.rx_crc_errors++; + vnicdev->net_stats.rx_missed_errors++; + drop: + vnicdev->net_stats.rx_dropped++; + } + + out: + CLR_VNIC_RX_OWNED(rxd); + + /* Deallocate only if we did not copy skb above */ + if (in_skb == out_skb) { + pci_unmap_single(viocdev->pdev, + rxdq->vbuf[rxd_id].dma, + rxdq->rx_buf_size, PCI_DMA_FROMDEVICE); + rxdq->vbuf[rxd_id].skb = NULL; + rxdq->vbuf[rxd_id].dma = (dma_addr_t) NULL; + } + + dmap_idx = rxd_id / VIOC_RXD_BATCH_BITS; + rxdq->dmap[dmap_idx] &= ~(1 << (rxd_id % VIOC_RXD_BATCH_BITS)); + + if (!rxdq->skip_fence_run) + vioc_next_fence_run(rxdq); + else + rxdq->skip_fence_run--; + + return 1; /* got a packet */ +} + +/* + * Refill one batch of VIOC_RXD_BATCH_BITS descriptors with skb's as + * needed. Transfer this batch to HW. Return -1 on success, the + * batch id otherwise (which means this batch must be retried.) + */ +static u32 _vioc_fill_n_xfer(struct rxdq *rxdq, unsigned batch_idx) +{ + unsigned first_idx, idx; + int i; + struct rx_pktBufDesc_Phys_w *rxd; + struct sk_buff *skb; + u64 x; + unsigned size; + + first_idx = batch_idx * VIOC_RXD_BATCH_BITS; + size = rxdq->rx_buf_size; + i = VIOC_RXD_BATCH_BITS; + + while (--i >= 0) { + idx = first_idx + i; + /* Check if that slot is unallocated */ + if (rxdq->vbuf[idx].skb == NULL) { + skb = dev_alloc_skb(size + 64); + if (skb == NULL) { + goto undo_refill; + } + /* Cache align */ + x = (u64) skb->data; + skb->data = (unsigned char *)ALIGN(x, 64); + rxdq->vbuf[idx].skb = skb; + rxdq->vbuf[idx].dma = + pci_map_single(rxdq->viocdev->pdev, + skb->data, size, PCI_DMA_FROMDEVICE); + } + + rxd = RXD_PTR(rxdq, idx); + + if (idx == first_idx) + /* + * Making sure that all writes to the Rx + * Descriptor Queue where completed before + * turning over up the last (i.e the first) + * descriptor to HW. + */ + wmb(); + + /* Set the address of the Rx buffer and HW FLAG */ + SET_VNIC_RX_BUFADDR_HW(rxd, rxdq->vbuf[idx].dma); + } + + rxdq->dmap[batch_idx] = ALL_BATCH_HW_OWNED; + return VIOC_NONE_TO_HW; /* XXX success */ + + undo_refill: + /* + * Just turn descriptors over to SW. Leave skb's allocated, + * they will be used when we retry. Uses idx! + */ + for (; idx < (first_idx + VIOC_RXD_BATCH_BITS); idx++) { + rxd = RXD_PTR(rxdq, idx); + CLR_VNIC_RX_OWNED(rxd); + } + + rxdq->starvations++; + return batch_idx; /* failure - retry this batch */ +} + +#define IDX_PLUS_DELTA(idx, count, delta) \ + (((idx) + (delta)) % (count)) +#define IDX_MINUS_DELTA(idx, count, delta) \ + (((idx) == 0) ? ((count) - (delta)): ((idx) - (delta))) + +/* + * Returns 0 on success, or a negative errno on failure + */ +int vioc_next_fence_run(struct rxdq *rxdq) +{ + unsigned dmap_idx, dmap_start, dmap_end, dmap_count; + unsigned to_hw = rxdq->to_hw; + + if (to_hw != VIOC_NONE_TO_HW) + to_hw = _vioc_fill_n_xfer(rxdq, to_hw); + if (to_hw != VIOC_NONE_TO_HW) { + /* Problem! Can't refill the Rx queue. */ + rxdq->to_hw = to_hw; + return -ENOMEM; + } + + dmap_count = rxdq->dmap_count; + dmap_start = rxdq->fence; + dmap_end = IDX_MINUS_DELTA(dmap_start, dmap_count, 1); + dmap_idx = dmap_start; + + while (rxdq->dmap[dmap_idx] == ALL_BATCH_SW_OWNED) { + dmap_idx = IDX_PLUS_DELTA(dmap_idx, dmap_count, 1); + if (dmap_idx == dmap_end) { + rxdq->run_to_end++; + break; + } + } + + dmap_idx = IDX_MINUS_DELTA(dmap_idx, dmap_count, 1); + + /* If are back at the fence - nothing to do */ + if (dmap_idx == dmap_start) + return 0; + /* + * Now dmap_idx points to the "last" batch, that is + * 100% owned by SW, this will become a new fence. + */ + rxdq->fence = dmap_idx; + rxdq->skip_fence_run = dmap_count / 4; + + /* + * Go back up tp dmap_start (old fence) and refill and + * turn over to HW Rx Descriptors + */ + while (dmap_idx != dmap_start) { + dmap_idx = IDX_MINUS_DELTA(dmap_idx, dmap_count, 1); + to_hw = _vioc_fill_n_xfer(rxdq, dmap_idx); + if (to_hw != VIOC_NONE_TO_HW) { + rxdq->to_hw = to_hw; + return -ENOMEM; + } + } + + return 0; +} + +/* + * NAPI poll method. RxC interrupt for this queue is disabled. + * The only lock we need is a read-lock on the VIOC. + */ +int vioc_rx_poll(struct net_device *dev, int *budget) +{ + struct napi_poll *napi = dev->priv; + struct rxc *rxc = napi->rxc; + struct vioc_device *viocdev = rxc->viocdev; /* safe */ + u32 sw_idx, count; + int rxflag = 0; + int quota, work_done = 0; + + if (!napi->enabled) { + /* If NOT enabled - do nothing. + * ACK by setting stopped. + */ + napi->stopped = 1; + netif_rx_complete(dev); + return 0; + } + + quota = min(*budget, dev->quota); + + sw_idx = rxc->sw_idx; + count = rxc->count; + while (work_done <= quota) { + rxflag = vioc_rx_pkt(viocdev, rxc, sw_idx); + if (unlikely(!rxflag)) + break; /* no work left */ + sw_idx++; + if (unlikely(sw_idx == count)) + sw_idx = 0; + work_done++; + } + rxc->sw_idx = sw_idx; + dev->quota -= work_done; + *budget -= work_done; + if (rxflag) + return 1; /* keep going */ + + netif_rx_complete(dev); + dev->weight = POLL_WEIGHT; + + vioc_rxc_interrupt_enable(rxc); + + return 0; /* poll done */ +} + +void vioc_rxc_interrupt(struct work_struct *work) +{ + struct vioc_intreq *input_param= container_of(work, struct vioc_intreq, + taskq); + unsigned vioc_idx = VIOC_IRQ_PARAM_VIOC_ID(input_param->intrFuncparm); + struct vioc_device *viocdev = vioc_viocdev(vioc_idx); + unsigned rxc_id = VIOC_IRQ_PARAM_PARAM_ID(input_param->intrFuncparm); + struct rxc *rxc = viocdev->rxc_p[rxc_id]; + struct napi_poll *napi = &rxc->napi; + + napi->rx_interrupts++; + /* Schedule NAPI poll */ + if (netif_rx_schedule_prep(&napi->poll_dev)) { + vioc_rxc_interrupt_disable(rxc); + __netif_rx_schedule(&napi->poll_dev); + } else { + vioc_rxc_interrupt_clear_pend(rxc); + } +} diff --git a/drivers/net/vioc/vioc_spp.c b/drivers/net/vioc/vioc_spp.c new file mode 100644 index 0000000..c5418ff --- /dev/null +++ b/drivers/net/vioc/vioc_spp.c @@ -0,0 +1,390 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#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 "f7/vioc_hw_registers.h" +#include "f7/vnic_defs.h" +#include "f7/spp_msgdata.h" +#include "vioc_vnic.h" +#include "vioc_api.h" + +/* Register definitions for communication between VIOC and BMC */ + +#define SPP_VIOC_MODULE VIOC_BMC + +#define SPP_BMC_VNIC 14 +#define SPP_SIM_VNIC 15 + +/* PMM-BMC communications messages */ +#define SPP_BMC_RST_RQ 0x01 +#define SPP_BMC_TUN_MSG 0x02 +#define SPP_BMC_HB 0x01 + +/* PMM-BMC Sensor register bits */ +#define SPP_HB_SENSOR_REG GETRELADDR(SPP_VIOC_MODULE, 0, VREG_BMC_SENSOR0) +#define SPP_SHUTDWN_SENSOR_REG GETRELADDR(SPP_VIOC_MODULE, 0, VREG_BMC_SENSOR1) +#define SPP_PANIC_SENSOR_REG GETRELADDR(SPP_VIOC_MODULE, 0, VREG_BMC_SENSOR2) +#define SPP_RST_SENSOR_REG GETRELADDR(SPP_VIOC_MODULE, 0, VREG_BMC_SENSOR3) + +/* PMM-BMC communications registers */ +#define SPP_BMC_HB_REG GETRELADDR(SPP_VIOC_MODULE, SPP_BMC_VNIC, VREG_BMC_REG_R31) +#define SPP_BMC_CMD_REG GETRELADDR(SPP_VIOC_MODULE, SPP_BMC_VNIC, VREG_BMC_REG_R30) + +static DECLARE_MUTEX(vnic_prov_sem); + +static inline void vnic_prov_get_sema(void) +{ + down(&vnic_prov_sem); +} + +static inline void vnic_prov_put_sema(void) +{ + up(&vnic_prov_sem); +} + +/* VIOC must be write-locked */ +static int vioc_vnic_enable(int vioc_id, int vnic_id) +{ + struct vioc_device *viocdev = vioc_viocdev(vioc_id); + struct net_device *netdev; + int rc = E_VIOCOK; + + netdev = viocdev->vnic_netdev[vnic_id]; + if (netdev == NULL) { + netdev = vioc_alloc_vnicdev(viocdev, vnic_id); + if (netdev == NULL) { + rc = -ENOMEM; + goto vioc_vnic_enable_exit; + } else { + viocdev->vnic_netdev[vnic_id] = netdev; + + if ((rc = register_netdev(netdev))) { + free_netdev(netdev); + viocdev->vnic_netdev[vnic_id] = NULL; + goto vioc_vnic_enable_exit; + } + } + } + + viocdev->vnics_map |= (1 << vnic_id); + + rc = vioc_vnic_resources_set(vioc_id, vnic_id); + + vioc_vnic_enable_exit: + + return rc; +} + +/* VIOC must be write-locked */ +static int vioc_vnic_disable(int vioc_id, int vnic_id, int unreg_flag) +{ + struct vioc_device *viocdev = vioc_viocdev(vioc_id); + + /* Remove VNIC from the map BEFORE releasing resources */ + viocdev->vnics_map &= ~(1 << vnic_id); + + if (unreg_flag) { + /* Unregister netdev */ + if (viocdev->vnic_netdev[vnic_id]) { + unregister_netdev(viocdev->vnic_netdev[vnic_id]); + dev_err(&viocdev->pdev->dev, "%s: %s\n", __FUNCTION__, + (viocdev->vnic_netdev[vnic_id])->name); + free_netdev(viocdev->vnic_netdev[vnic_id]); + viocdev->vnic_netdev[vnic_id] = NULL; + } else + BUG_ON(viocdev->vnic_netdev[vnic_id] == NULL); + } + + return E_VIOCOK; +} + +void vioc_vnic_prov(int vioc_id, u32 vnic_en, u32 port_en, int free_flag) +{ + u32 change_map; + u32 up_map; + u32 down_map; + int vnic_id; + int rc = E_VIOCOK; + struct vioc_device *viocdev = vioc_viocdev(vioc_id); + + change_map = vnic_en ^ viocdev->vnics_map; + up_map = vnic_en & change_map; + down_map = viocdev->vnics_map & change_map; + + /* Enable from 0 to max */ + for (vnic_id = 0; vnic_id < VIOC_MAX_VNICS; vnic_id++) { + if (up_map & (1 << vnic_id)) { + rc = vioc_vnic_enable(vioc_id, vnic_id); + if (rc) { + dev_err(&viocdev->pdev->dev, "%s: Enable VNIC %d FAILED\n", + __FUNCTION__, vnic_id); + } + } + } + + /* Disable from max to 0 */ + for (vnic_id = VIOC_MAX_VNICS - 1; vnic_id >= 0; vnic_id--) { + if (down_map & (1 << vnic_id)) { + rc = vioc_vnic_disable(vioc_id, vnic_id, free_flag); + if (rc) { + dev_err(&viocdev->pdev->dev, "%s: Disable VNIC %d FAILED\n", + __FUNCTION__, vnic_id); + } + } + } + + /* + * Now, after all VNIC enable-disable changes are in place, + * viocdev->vnics_map contains the current state of VNIC map. + * Use only ENABLED VNICs to process PORT_EN register, aka + * LINK state register. + */ + for (vnic_id = VIOC_MAX_VNICS - 1; vnic_id >= 0; vnic_id--) { + if (viocdev->vnics_map & (1 << vnic_id)) { + struct net_device *netdev = + viocdev->vnic_netdev[vnic_id]; + if (port_en & (1 << vnic_id)) { + /* PORT ENABLED - LINK UP */ + if (!netif_carrier_ok(netdev)) { + netif_carrier_on(netdev); + netif_wake_queue(netdev); + dev_err(&viocdev->pdev->dev, "idx %d, %s: Link UP\n", + vioc_id, netdev->name); + } + } else { + /* PORT DISABLED - LINK DOWN */ + if (netif_carrier_ok(netdev)) { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + dev_err(&viocdev->pdev->dev, + "idx %d, %s: Link DOWN\n", + vioc_id, netdev->name); + } + } + } + } +} + +/* + * Called from interrupt or task context + */ +void vioc_bmc_interrupt(struct work_struct *work) +{ + struct vioc_intreq *input_param= container_of(work, struct vioc_intreq, + taskq); + int vioc_id = VIOC_IRQ_PARAM_VIOC_ID(input_param->intrFuncparm); + int rc = 0; + u32 intr_source_map, intr_source; + struct vioc_device *viocdev = vioc_viocdev(vioc_id); + + if (viocdev->vioc_state != VIOC_STATE_UP) { + dev_err(&viocdev->pdev->dev, "VIOC %d is not UP yet\n", + viocdev->viocdev_idx); + return; + } + + /* Get the Interrupt Source Register */ + intr_source_map = vioc_rrd(viocdev->viocdev_idx, VIOC_BMC, 0, + VREG_BMC_INTRSTATUS); + + vnic_prov_get_sema(); + + /* + * Clear all pending interrupt bits, we will service all interrupts + * based on the copy of 0x144 register in intr_source. + */ + rc = vioc_rwr(viocdev->viocdev_idx, VIOC_BMC, 0, + VREG_BMC_INTRSTATUS, intr_source_map); + if (rc) { + dev_err(&viocdev->pdev->dev, "%s: vioc_rwr() -> %d\n", __FUNCTION__, rc); + goto vioc_bmc_interrupt_exit; + } + + for (intr_source = VIOC_BMC_INTR0; intr_source_map; intr_source <<= 1) { + switch (intr_source_map & intr_source) { + case VIOC_BMC_INTR0: + dev_err(&viocdev->pdev->dev, + "*** OLD SPP commands (BMC intr %08x) are no longer supported\n", + intr_source_map); + break; + case VIOC_BMC_INTR1: + spp_msg_from_sim(viocdev->viocdev_idx); + break; + + default: + break; + } + intr_source_map &= ~intr_source; + } + + vioc_bmc_interrupt_exit: + + vnic_prov_put_sema(); + + return; + +} + +/* SPP Messages originated by VIOC driver */ +void vioc_hb_to_bmc(int vioc_id) +{ + struct vioc_device *viocdev = vioc_viocdev(0); + + if (!viocdev) + return; + + /* Signal BMC that command was written by setting bit 0 of + * SENSOR Register */ + vioc_reg_wr(1, viocdev->ba.virt, SPP_HB_SENSOR_REG); +} + +void vioc_reset_rq_to_bmc(int vioc_id, u32 command) +{ + struct vioc_device *viocdev = vioc_viocdev(0); + + if (!viocdev) + return; + + switch (command) { + case SYS_RESTART: + vioc_reg_wr(1, viocdev->ba.virt, SPP_RST_SENSOR_REG); + break; + case SYS_HALT: + case SYS_POWER_OFF: + vioc_reg_wr(1, viocdev->ba.virt, SPP_SHUTDWN_SENSOR_REG); + break; + default: + dev_err(&viocdev->pdev->dev, "%s: Received invalid command %d\n", + __FUNCTION__, command); + } +} + +/*-------------------------------------------------------------------*/ + +/* Shutdown/Reboot handler definitions */ +static int vioc_shutdown_notify(struct notifier_block *thisblock, + unsigned long code, void *unused); + +static struct notifier_block vioc_shutdown_notifier = { + .notifier_call = vioc_shutdown_notify +}; + +void vioc_os_reset_notifier_init(void) +{ + /* We want to know get a callback when the system is going down */ + if (register_reboot_notifier(&vioc_shutdown_notifier)) { + printk(KERN_ERR "%s: register_reboot_notifier() returned error\n", + __FUNCTION__); + } +} + +void vioc_os_reset_notifier_exit(void) +{ + if (unregister_reboot_notifier(&vioc_shutdown_notifier)) { + printk (KERN_ERR "%s: unregister_reboot_notifier() returned error\n", + __FUNCTION__); + } +} + + /* + * vioc_shutdown_notify - Called when the OS is going down. + */ +static int vioc_shutdown_notify(struct notifier_block *thisblock, + unsigned long code, void *unused) +{ + vioc_reset_rq_to_bmc(0, code); + printk(KERN_ERR "%s: sent %s UOS state to BMC\n", + __FUNCTION__, + ((code == SYS_RESTART) ? "REBOOT" : + ((code == SYS_HALT) ? "HALT" : + ((code == SYS_POWER_OFF) ? "POWER_OFF" : "Unknown")))); + + return 0; +} + +/* + * FUNCTION: vioc_handle_reset_request + * INPUT: Reset type : Shutdown, Reboot, Poweroff + * OUTPUT: Returns 0 on Success -EINVAL on failure + * + */ +int vioc_handle_reset_request(int reset_type) +{ + struct sk_buff *msg = NULL; + void *hdr; + + printk(KERN_ERR "%s: received reset request %d via SPP\n", + __FUNCTION__, reset_type); + + /* Disable VIOC interrupts */ + // vioc_irq_exit(); + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + if (msg == NULL) { + printk(KERN_ERR "%s: nlmsg_new() FAILS\n", __FUNCTION__); + return (-ENOBUFS); + } + + hdr = nlmsg_put(msg, 0, 0, 0, 0, 0); + + if (reset_type == SPP_RESET_TYPE_REBOOT) + nla_put_string(msg, reset_type, "Reboot"); + else + nla_put_string(msg, reset_type, "Shutdown"); + + nlmsg_end(msg, hdr); + + return nlmsg_multicast(genl_sock, msg, 0, VIOC_LISTEN_GROUP, GFP_ATOMIC); +} diff --git a/drivers/net/vioc/vioc_transmit.c b/drivers/net/vioc/vioc_transmit.c new file mode 100644 index 0000000..8538e5e --- /dev/null +++ b/drivers/net/vioc/vioc_transmit.c @@ -0,0 +1,1034 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#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 +#include +#include + +#include "f7/vnic_defs.h" +#include "f7/vioc_pkts_defs.h" + +#include "vioc_vnic.h" +#include "vioc_api.h" + +#define VNIC_MIN_MTU 64 +#define TXQ0 0 +#define NOT_SET -1 + +static inline u32 vnic_rd_txd_ctl(struct txq *txq) +{ + return readl(txq->va_of_vreg_veng_txd_ctl); +} + +static inline void vnic_ring_tx_bell(struct txq *txq) +{ + writel(txq->shadow_VREG_VENG_TXD_CTL | VREG_VENG_TXD_CTL_QRING_MASK, + txq->va_of_vreg_veng_txd_ctl); + txq->bells++; +} + +static inline void vnic_reset_tx_ring_err(struct txq *txq) +{ + writel(txq->shadow_VREG_VENG_TXD_CTL | + (VREG_VENG_TXD_CTL_QENABLE_MASK | VREG_VENG_TXD_CTL_CLEARMASK), + txq->va_of_vreg_veng_txd_ctl); +} + +static inline void vnic_enable_tx_ring(struct txq *txq) +{ + txq->shadow_VREG_VENG_TXD_CTL = VREG_VENG_TXD_CTL_QENABLE_MASK; + writel(txq->shadow_VREG_VENG_TXD_CTL, txq->va_of_vreg_veng_txd_ctl); +} + +static inline void vnic_disable_tx_ring(struct txq *txq) +{ + txq->shadow_VREG_VENG_TXD_CTL = 0; + writel(0, txq->va_of_vreg_veng_txd_ctl); +} + +static inline void vnic_pause_tx_ring(struct txq *txq) +{ + txq->shadow_VREG_VENG_TXD_CTL |= VREG_VENG_TXD_CTL_QPAUSE_MASK; + writel(txq->shadow_VREG_VENG_TXD_CTL, txq->va_of_vreg_veng_txd_ctl); +} + +static inline void vnic_resume_tx_ring(struct txq *txq) +{ + txq->shadow_VREG_VENG_TXD_CTL &= ~VREG_VENG_TXD_CTL_QPAUSE_MASK; + writel(txq->shadow_VREG_VENG_TXD_CTL, txq->va_of_vreg_veng_txd_ctl); +} + + +/* TxQ must be locked */ +static void vnic_reset_txq(struct vnic_device *vnicdev, struct txq *txq) +{ + + struct tx_pktBufDesc_Phys_w *txd; + int i; + + vnic_reset_tx_ring_err(txq); + + /* The reset of the code is not executing + * because so far we can't reset individual VNICs. + * Need to (SW) Reset the whole VIOC. + */ + + vnic_disable_tx_ring(txq); + wmb(); + /* + * Clean-up all Tx Descriptors, take ownership of all + * descriptors + */ + for (i = 0; i < txq->count; i++) { + if (txq->desc) { + txd = TXD_PTR(txq, i); + txd->word_1 = 0; + txd->word_0 = 0; + } + if (txq->vbuf) { + if (txq->vbuf[i].dma) { + pci_unmap_page(vnicdev->viocdev->pdev, + txq->vbuf[i].dma, + txq->vbuf[i].length, + PCI_DMA_TODEVICE); + txq->vbuf[i].dma = 0; + } + + /* Free skb , should be for SOP (in case of frags) only */ + if (txq->vbuf[i].skb) { + dev_kfree_skb_any((struct sk_buff *)txq-> + vbuf[i].skb); + txq->vbuf[i].skb = NULL; + } + } + } + txq->next_to_clean = 0; + txq->next_to_use = 0; + txq->empty = txq->count; + wmb(); + vnic_enable_tx_ring(txq); +} + +/* TxQ must be locked */ +static int vnic_clean_txq(struct vnic_device *vnicdev, struct txq *txq) +{ + struct tx_pktBufDesc_Phys_w *txd; + int clean_idx, pkt_len; + int sop_idx = NOT_SET; + int eop_idx = NOT_SET; + int reset_flag = 0; + + if (unlikely(!txq->desc)) + return reset_flag; + + /* + * Clean-up all Tx Descriptors, whose buffers where + * transmitted by VIOC: + * bit 30 (Valid) indicates if bits 27-29 (Status) have been set + * by the VIOC HW, stating that descrptor was processed by HW. + */ + for (clean_idx = txq->next_to_clean;; + clean_idx = VNIC_NEXT_IDX(clean_idx, txq->count)) { + + txd = TXD_PTR(txq, clean_idx); + + if (GET_VNIC_TX_HANDED(txd) != VNIC_TX_HANDED_HW_W) + /* This descriptor has NOT been handed to HW, done! */ + break; + + if (GET_VNIC_TX_SOP(txd) == VNIC_TX_SOP_W) { + if (sop_idx != NOT_SET) { + /* Problem - SOP back-to-back without EOP */ + dev_err(&vnicdev->viocdev->pdev->dev, + "vioc%d-vnic%d-txd%d ERROR (back-to-back SOP) (txd->word_1=%08x).\n", + vnicdev->viocdev->viocdev_idx, + vnicdev->vnic_id, clean_idx, + txd->word_1); + + vnicdev->net_stats.tx_errors++; + reset_flag = 1; + break; + } + sop_idx = clean_idx; + } + + if (GET_VNIC_TX_EOP(txd) == VNIC_TX_EOP_W) { + eop_idx = clean_idx; + if (sop_idx == NOT_SET) { + /* Problem - EOP without SOP */ + dev_err(&vnicdev->viocdev->pdev->dev, + "vioc%d-vnic%d-txd%d ERROR (EOP without SOP) (txd->word_1=%08x).\n", + vnicdev->viocdev->viocdev_idx, + vnicdev->vnic_id, clean_idx, + txd->word_1); + + vnicdev->net_stats.tx_errors++; + reset_flag = 1; + break; + } + if (GET_VNIC_TX_VALID(txd) != VNIC_TX_VALID_W) + /* VIOC is still working on this descriptor */ + break; + } + + /* + * Check for errors: regardless of whether an error detected + * on SOP, MOP or EOP descritptor, reset the ring. + */ + if (GET_VNIC_TX_STS(txd) != VNIC_TX_TX_OK_W) { + dev_err(&vnicdev->viocdev->pdev->dev, + "vioc%d-vnic%d TxD ERROR (txd->word_1=%08x).\n", + vnicdev->viocdev->viocdev_idx, vnicdev->vnic_id, + txd->word_1); + + vnicdev->net_stats.tx_errors++; + reset_flag = 1; + break; + } + + if (eop_idx != NOT_SET) { + /* Found EOP fragment: start CLEANING */ + pkt_len = 0; + for (clean_idx = sop_idx;; + clean_idx = VNIC_NEXT_IDX(clean_idx, txq->count)) { + + txd = TXD_PTR(txq, clean_idx); + + /* Clear TxD's Handed bit, indicating that SW owns it now */ + CLR_VNIC_TX_HANDED(txd); + + /* One more empty descriptor */ + txq->empty++; + + if (txq->vbuf[clean_idx].dma) { + pci_unmap_page(vnicdev->viocdev->pdev, + txq->vbuf[clean_idx].dma, + txq->vbuf[clean_idx]. + length, + PCI_DMA_TODEVICE); + txq->vbuf[clean_idx].dma = 0; + } + + /* Free skb , should be for SOP (in case of frags) only */ + if (txq->vbuf[clean_idx].skb) { + dev_kfree_skb_any((struct sk_buff *) + txq->vbuf[clean_idx]. + skb); + txq->vbuf[clean_idx].skb = NULL; + } + + pkt_len += txq->vbuf[clean_idx].length; + + if (clean_idx == eop_idx) + goto set_pkt_stats; + } + + set_pkt_stats: + /* + * Since this Tx Descriptor was already + * transmitted, account for it - update stats. + */ + vnicdev->net_stats.tx_bytes += pkt_len; + vnicdev->net_stats.tx_packets++; + /* + * This is the ONLY place, where txq->next_to_clean is + * advanced. + * It will point past EOP descriptor of the just cleaned pkt. + */ + txq->next_to_clean = VNIC_NEXT_IDX(eop_idx, txq->count); + /* + * Reset sop_idx and eop_idx: start looking for next pkt + */ + sop_idx = eop_idx = NOT_SET; + /* + * At this point clean_idx == eop_idx, it will be advanced + * to the next descriptor at the top of the loop + */ + } + } + + if (reset_flag) { + /* For DEBUGGING */ + } + + /* + * If the queue was stopped, and if we have now enough room - + * wake it up + */ + if ((netif_queue_stopped(vnicdev->netdev)) && + !txq->vbuf[txq->next_to_use].skb) { + netif_wake_queue(vnicdev->netdev); + } + + return reset_flag; +} + +/* + * Only called from interrupt context. + */ +static void vnic_tx_interrupt(struct vioc_device *viocdev, int vnic_id, + int clean) +{ + struct vnic_device *vnicdev = viocdev->vnic_netdev[vnic_id]->priv; + u32 txd_ctl; + int txq_was_reset; + struct txq *txq; + char *txdesc_s = ""; + char *txring_s = ""; + + txq = &vnicdev->txq; + + if (!spin_trylock(&txq->lock)) { + /* Retry later */ + return; + } + + /* Get the TxD Control Register */ + txd_ctl = vnic_rd_txd_ctl(txq); + + if (txd_ctl & VREG_VENG_TXD_CTL_ERROR_MASK) + txring_s = "Tx Ring"; + + if (txd_ctl & VREG_VENG_TXD_CTL_INVDESC_MASK) + txdesc_s = "Tx Descriptor"; + + if (txd_ctl & + (VREG_VENG_TXD_CTL_INVDESC_MASK | VREG_VENG_TXD_CTL_ERROR_MASK)) { + dev_err(&viocdev->pdev->dev, + "vioc%d-vnic%d TxD Ctl=%08x, ERROR %s %s. Reset Tx Ring!\n", + viocdev->viocdev_idx, vnic_id, txd_ctl, txdesc_s, + txring_s); + + vnic_reset_txq(vnicdev, txq); + netif_wake_queue(vnicdev->netdev); + } else { + /* No problem with HW, just clean-up the Tx Ring */ + if (clean) + txq_was_reset = vnic_clean_txq(vnicdev, txq); + } + + if ((txd_ctl & VREG_VENG_TXD_CTL_TXSTATE_MASK) == + VVAL_VENG_TXD_CTL_TXSTATE_EMPTY) + vnicdev->vnic_stats.tx_on_empty_interrupts++; + + spin_unlock(&txq->lock); +} + +/* + * Must only be called from interrupt context. + */ +void vioc_tx_interrupt(struct work_struct *work) +{ + struct vioc_intreq *input_param= container_of(work, struct vioc_intreq, + taskq); + struct vioc_device *viocdev; + u32 vioc_idx; + u32 vnic_idx; + u32 vnic_map; + + vioc_idx = VIOC_IRQ_PARAM_VIOC_ID(input_param->intrFuncparm); + viocdev = vioc_viocdev(vioc_idx); + // read_lock(&viocdev->lock); /* protect against vnic changes */ + vnic_map = viocdev->vnics_map; + for (vnic_idx = 0; vnic_idx < VIOC_MAX_VNICS; vnic_idx++) { + if (vnic_map & (1 << vnic_idx)) + vnic_tx_interrupt(viocdev, vnic_idx, 1); + } + viocdev->vioc_stats.tx_tasklets++; + // read_unlock(&viocdev->lock); +} +void vnic_enqueue_tx_pkt(struct vnic_device *vnicdev, struct txq *txq, + struct sk_buff *skb, struct vioc_prov *prov) +{ + int idx, sop_idx, eop_idx, f; + struct tx_pktBufDesc_Phys_w *txd; + + /* + * Map Tx buffers vbuf queue. + */ + idx = txq->next_to_use; + sop_idx = idx; + + txq->vbuf[idx].skb = skb; + txq->vbuf[idx].dma = pci_map_single(vnicdev->viocdev->pdev, + skb->data, + skb->len, PCI_DMA_TODEVICE); + txq->vbuf[idx].length = skb_headlen(skb); + + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + + idx = VNIC_NEXT_IDX(idx, txq->count); + + txq->vbuf[idx].skb = NULL; + + txq->vbuf[idx].dma = pci_map_page(vnicdev->viocdev->pdev, + frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + txq->vbuf[idx].length = frag->size; + txq->frags++; + } + + eop_idx = idx; + + txq->next_to_use = VNIC_NEXT_IDX(eop_idx, txq->count); + + if (txq->next_to_use < sop_idx) + txq->empty -= ((txq->count + txq->next_to_use) - sop_idx); + else + txq->empty -= (txq->next_to_use - sop_idx); + + /* + * We are going backwards (from EOP to SOP) in setting up Tx Descriptors. + * (idx == eop_ied, when we enter the loop) + * So, by the time we will transfer the SOP Tx Descriptor + * fragment over to VIOC HW, ALL following fragments would have + * been already transferred, and VIOC HW should not have trouble + * picking all of them. + */ + + for (;;) { + u32 word_1 = 0; + + txd = TXD_PTR(txq, idx); + + /* Set Tx buffer address */ + *((dma_addr_t *) txd) = txq->vbuf[idx].dma; + + /* + * Force memory writes to complete (FENCE), before letting VIOC know, + * that there are new descriptor(s). Do it ONLY for the + * SOP descriptor: no point "fencing" on every other descriptori + * if, there were frags... + */ + /* Set SOP */ + if (idx == sop_idx) { + word_1 |= VNIC_TX_SOP_W; + wmb(); + } + /* Set EOP */ + if (idx == eop_idx) + word_1 |= VNIC_TX_EOP_W; + + /* Set Interrupt request (VNIC_TX_INTR_W), when needed */ + if (prov->run_param.tx_pkts_per_irq > 0) { + if (txq->tx_pkts_til_irq == 0) { + txq->tx_pkts_til_irq = + prov->run_param.tx_pkts_per_irq; + word_1 |= VNIC_TX_INTR_W; + } else { + txq->tx_pkts_til_irq--; + } + } + + /* Now the rest of it */ + txd->word_1 |= word_1 | + VNIC_TX_HANDED_HW_W | + ((txq->vbuf[idx].length << VNIC_TX_BUFLEN_SHIFT) & + VNIC_TX_BUFLEN_MASK); + + if (idx == sop_idx) + /* All done, if SOP descriptor was just set */ + break; + else + /* Go back one more fragment */ + idx = VNIC_PREV_IDX(idx, txq->count); + } + + /* + * Ring bell here, before checking, if vnic_clean_txq() needs to + * be called. + */ + vnic_ring_tx_bell(txq); + + if (txq->next_to_use == txq->next_to_clean) { + txq->wraps++; + vnic_clean_txq(vnicdev, txq); + if (txq->next_to_use == txq->next_to_clean) { + txq->full++; + } + } + +} + +void vnic_enqueue_tx_buffers(struct vnic_device *vnicdev, struct txq *txq, + struct sk_buff *skb, struct vioc_prov *prov) +{ + int len; + int idx; + struct tx_pktBufDesc_Phys_w *txd; + + idx = txq->next_to_use; + len = skb->len; + + txq->vbuf[idx].skb = skb; + txq->vbuf[idx].dma = pci_map_single(vnicdev->viocdev->pdev, + skb->data, len, PCI_DMA_TODEVICE); + txq->vbuf[idx].length = skb->len; + + /* + * We are going backwards in setting up Tx Descriptors. So, + * by the time we will trun the Tx Descriptor with the first + * fragment over to VIOC, the following fragments would have + * been already turned over. + */ + txd = TXD_PTR(txq, idx); + + /* + * Force memory writes to complete, before letting VIOC know, + * that there are new descriptor(s), but do it ONLY for the + * very first descriptor (in case there were frags). No point + * "fencing" on every descriptor in this request. + */ + wmb(); + + *((dma_addr_t *) txd) = txq->vbuf[idx].dma; + + if (prov->run_param.tx_pkts_per_irq > 0) { + if (txq->tx_pkts_til_irq == 0) { + txq->tx_pkts_til_irq = prov->run_param.tx_pkts_per_irq; + /* Set Interrupt request: VNIC_TX_INTR_W */ + txd->word_1 |= + (VNIC_TX_HANDED_HW_W | VNIC_TX_SOP_W | VNIC_TX_EOP_W + | VNIC_TX_INTR_W | ((len << VNIC_TX_BUFLEN_SHIFT) & + VNIC_TX_BUFLEN_MASK)); + } else { + /* Set NO Interrupt request... */ + txd->word_1 |= + (VNIC_TX_HANDED_HW_W | VNIC_TX_SOP_W | VNIC_TX_EOP_W + | ((len << VNIC_TX_BUFLEN_SHIFT) & + VNIC_TX_BUFLEN_MASK)); + txq->tx_pkts_til_irq--; + } + } else { + /* Set NO Interrupt request... */ + txd->word_1 |= + (VNIC_TX_HANDED_HW_W | VNIC_TX_SOP_W | VNIC_TX_EOP_W | + ((len << VNIC_TX_BUFLEN_SHIFT) & VNIC_TX_BUFLEN_MASK)); + } + + /* + * Ring bell here, before checking, if vnic_clean_txq() needs to + * be called. + */ + vnic_ring_tx_bell(txq); + + idx = VNIC_NEXT_IDX(idx, txq->count); + if (idx == txq->next_to_clean) { + txq->wraps++; + vnic_clean_txq(vnicdev, txq); + if (idx == txq->next_to_clean) { + txq->full++; + } + } + + txq->next_to_use = idx; +} + +static inline void init_f7_header(struct sk_buff *skb) +{ + struct vioc_f7pf_w *f7p; + unsigned char tag; + + /* + * Initialize F7 Header AFTER processing the skb + frags, because we + * need the TOTAL pkt length in the F7 Header. + */ + + /* Determine packet tag */ + if (((struct ethhdr *)skb->mac.raw)->h_proto == ntohs(ETH_P_IP)) { + if (skb->ip_summed == VIOC_CSUM_OFFLOAD) { + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + tag = VIOC_F7PF_ET_ETH_IPV4_CKS; + skb->h.th->check = 0; + break; + case IPPROTO_UDP: + tag = VIOC_F7PF_ET_ETH_IPV4_CKS; + skb->h.uh->check = 0; + break; + default: + tag = VIOC_F7PF_ET_ETH_IPV4; + break; + } + } else { + tag = VIOC_F7PF_ET_ETH_IPV4; + } + } else { + tag = VIOC_F7PF_ET_ETH; + } + + f7p = (struct vioc_f7pf_w *)skb->data; + memset((void *)skb->data, 0, F7PF_HLEN_STD); + + /* Encapsulation Version */ + SET_HTON_VIOC_F7PF_ENVER_SHIFTED(f7p, VIOC_F7PF_VERSION1); + /* Reserved */ + SET_HTON_VIOC_F7PF_MC_SHIFTED(f7p, 0); + /* No Touch Flag */ + SET_HTON_VIOC_F7PF_NOTOUCH_SHIFTED(f7p, 0); + /* Drop Precedence */ + SET_HTON_VIOC_F7PF_F7DP_SHIFTED(f7p, 0); + /* Class of Service */ + SET_HTON_VIOC_F7PF_F7COS_SHIFTED(f7p, 2); + /* Encapsulation Tag */ + SET_HTON_VIOC_F7PF_ENTAG_SHIFTED(f7p, tag); + /* Key Length */ + SET_HTON_VIOC_F7PF_EKLEN_SHIFTED(f7p, 1); + /* Packet Length */ + SET_HTON_VIOC_F7PF_PKTLEN_SHIFTED(f7p, skb->len); + + /* lifID */ + SET_HTON_VIOC_F7PF_LIFID_SHIFTED(f7p, 0); +} + +/** + * vioc_tx_timer - Tx Timer + * @data: pointer to viocdev cast into an unsigned long + **/ +void vioc_tx_timer(unsigned long data) +{ + struct vioc_device *viocdev = (struct vioc_device *)data; + u32 vnic_idx; + + if (!viocdev->tx_timer_active) + return; + + viocdev->vioc_stats.tx_timers++; + + for (vnic_idx = 0; vnic_idx < VIOC_MAX_VNICS; vnic_idx++) { + if (viocdev->vnics_map & (1 << vnic_idx)) { + vnic_tx_interrupt(viocdev, vnic_idx, 1); + } /* Process VNIC's TX interrupt */ + } + /* Reset the timer */ + mod_timer(&viocdev->tx_timer, jiffies + HZ / 4); +} + + +/* + * hard_start_xmit() routine. + * NOTE WELL: We don't take a read lock on the VIOC, but rely on the + * networking subsystem to guarantee we will not be asked to Tx if + * the interface is unregistered. Revisit if this assumption does + * not hold - add a tx_enabled flag to the vnic struct protected + * by txq->lock. Or just read-lock the VIOC. + */ +int vnic_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + struct txq *txq = &vnicdev->txq; + unsigned long flags; + int ret; + + local_irq_save(flags); + if (!spin_trylock(&txq->lock)) { + /* Retry later */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + if (unlikely(skb_headroom(skb) < F7PF_HLEN_STD)) { + vnicdev->vnic_stats.headroom_misses++; + if (unlikely(skb_cow(skb, F7PF_HLEN_STD))) { + dev_kfree_skb_any(skb); + vnicdev->vnic_stats.headroom_miss_drops++; + ret = NETDEV_TX_OK; /* since we freed it */ + goto end_start_xmit; + } + } + + /* Don't rely on the skb pointers being set */ + skb->mac.raw = skb->data; + skb->nh.raw = skb->data + ETH_HLEN; + skb_push(skb, F7PF_HLEN_STD); + + init_f7_header(skb); + + if (skb_shinfo(skb)->nr_frags) + vnic_enqueue_tx_pkt(vnicdev, txq, skb, &vnicdev->viocdev->prov); + else + vnic_enqueue_tx_buffers(vnicdev, txq, skb, + &vnicdev->viocdev->prov); + + /* + * Check if there is room on the queue. + */ + if (txq->empty < MAX_SKB_FRAGS) { + netif_stop_queue(netdev); + vnicdev->vnic_stats.netif_stops++; + ret = NETDEV_TX_BUSY; + } else { + ret = NETDEV_TX_OK; + } + + end_start_xmit: + spin_unlock_irqrestore(&txq->lock, flags); + return ret; +} + +/* + * Create Ethernet header + * + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp) + */ +int vnic_eth_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); + + skb->mac.raw = skb->data; + + /* + * Set the protocol type. For a packet of type + * ETH_P_802_3 we put the length in here instead. It is + * up to the 802.2 layer to carry protocol information. + */ + + if (type != ETH_P_802_3) + eth->h_proto = htons(type); + else + eth->h_proto = htons(len); + + if (saddr) + memcpy(eth->h_source, saddr, ETH_ALEN); + else + memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); + + if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { + memset(eth->h_dest, 0, ETH_ALEN); + return ETH_HLEN + F7PF_HLEN_STD; + } + + if (daddr) { + memcpy(eth->h_dest, daddr, ETH_ALEN); + return ETH_HLEN + F7PF_HLEN_STD; + } + + return -(ETH_HLEN + F7PF_HLEN_STD); /* XXX */ +} + + + +/** + * vnic_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ + +static int vnic_open(struct net_device *netdev) +{ + int ret = 0; + struct vnic_device *vnicdev = netdev->priv; + + ret = vioc_set_vnic_cfg(vnicdev->viocdev->viocdev_idx, + vnicdev->vnic_id, + (VREG_BMC_VNIC_CFG_ENABLE_MASK | + VREG_BMC_VNIC_CFG_PROMISCUOUS_MASK)); + + vnic_enable_tx_ring(&vnicdev->txq); + + netif_start_queue(netdev); + netif_carrier_on(netdev); + + return ret; +} + +static int vnic_close(struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + struct txq *txq = &vnicdev->txq; + unsigned long flags; + + vioc_set_vnic_cfg(vnicdev->viocdev->viocdev_idx, vnicdev->vnic_id, 0); + + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + spin_lock_irqsave(&txq->lock, flags); + + vnic_reset_txq(vnicdev, txq); + vnic_disable_tx_ring(&vnicdev->txq); + + spin_unlock_irqrestore(&txq->lock, flags); + + return 0; +} + +/* + * Set netdev->dev_addr to this interface's MAC Address + */ +static int vnic_set_mac_addr(struct net_device *netdev, void *p) +{ + struct vnic_device *vnicdev = netdev->priv; + + /* + * Get HW MAC address form VIOC egisters + */ + vioc_get_vnic_mac(vnicdev->viocdev->viocdev_idx, vnicdev->vnic_id, + &vnicdev->hw_mac[0]); + + if (!is_valid_ether_addr(vnicdev->hw_mac)) { + dev_err(&vnicdev->viocdev->pdev->dev, "Invalid MAC Address\n"); + return -EINVAL; + } + + /* + * ...and install it in nedev structure + */ + memcpy(netdev->dev_addr, vnicdev->hw_mac, netdev->addr_len); + netdev->addr_len = ETH_ALEN; + + return 0; +} + +/* + * Set netdev->mtu to this interface's MTU + */ +static int vnic_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct vnic_device *vnicdev = netdev->priv; + int max_frame = new_mtu + ETH_HLEN + F7PF_HLEN_STD; + + if ((max_frame < VNIC_MIN_MTU) || (max_frame > VNIC_MAX_MTU)) { + dev_err(&vnicdev->viocdev->pdev->dev, "Invalid MTU setting\n"); + return -EINVAL; + } + + netdev->mtu = new_mtu; + return 0; +} + +/** + * vnic_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ + +static struct net_device_stats *vnic_get_stats(struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + return &vnicdev->net_stats; +} + +static int vnic_alloc_tx_resources(struct vnic_device *vnicdev) +{ + struct vioc_device *viocdev = vnicdev->viocdev; + struct net_device *netdev = viocdev->vnic_netdev[vnicdev->vnic_id]; + struct txq *txq; + size_t size; + + vnicdev->vnic_stats.tx_on_empty_interrupts = 0; + + txq = &vnicdev->txq; + + txq->txq_id = TXQ0; + txq->vnic_id = vnicdev->vnic_id; + txq->next_to_use = 0; + txq->next_to_clean = 0; + txq->empty = txq->count; + txq->tx_pkts_til_irq = viocdev->prov.run_param.tx_pkts_per_irq; + txq->tx_pkts_til_bell = viocdev->prov.run_param.tx_pkts_per_bell; + txq->do_ring_bell = 0; + txq->bells = 0; + txq->frags = 0; + txq->wraps = 0; + txq->full = 0; + + size = TX_DESC_SIZE * txq->count; + txq->desc = pci_alloc_consistent(viocdev->pdev, size, &txq->dma); + if (!txq->desc) { + dev_err(&viocdev->pdev->dev, "%sError allocating Tx ring (size %d)\n", + netdev->name, txq->count); + return -ENOMEM; + } + + txq->vbuf = vmalloc(sizeof(struct vbuf) * txq->count); + if (!txq->vbuf) { + dev_err(&viocdev->pdev->dev, "%sError allocating Tx resource (size %d)\n", + netdev->name, txq->count); + return -ENOMEM; + } + memset(txq->vbuf, 0, sizeof(struct vbuf) * txq->count); + + txq->va_of_vreg_veng_txd_ctl = + (&viocdev->ba)->virt + + GETRELADDR(VIOC_VENG, vnicdev->vnic_id, + (VREG_VENG_TXD_CTL + (TXQ0 * 0x14))); + spin_lock_init(&txq->lock); + + /* + * Tell VIOC where TxQ things are + */ + vioc_set_txq(viocdev->viocdev_idx, vnicdev->vnic_id, TXQ0, + txq->dma, txq->count); + vnic_enable_tx_ring(txq); + vioc_ena_dis_tx_on_empty(viocdev->viocdev_idx, + vnicdev->vnic_id, + TXQ0, + viocdev->prov.run_param.tx_intr_on_empty); + return 0; +} + +static void vnic_free_tx_resources(struct vnic_device *vnicdev) +{ + pci_free_consistent(vnicdev->viocdev->pdev, + vnicdev->txq.count * TX_DESC_SIZE, + vnicdev->txq.desc, vnicdev->txq.dma); + vnicdev->txq.desc = NULL; + vnicdev->txq.dma = (dma_addr_t) NULL; + vfree(vnicdev->txq.vbuf); + vnicdev->txq.vbuf = NULL; +} + +void vioc_reset_if_tx(struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + struct txq *txq = &vnicdev->txq; + + vnic_reset_txq(vnicdev, txq); +} + +extern struct ethtool_ops vioc_ethtool_ops; + +/** + * vnic_uninit - Device Termination Routine + * + * Returns 0 on success, negative on failure + * + **/ +static void vnic_uninit(struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + vnic_free_tx_resources(vnicdev); +} + +/** + * vnic_init - Device Initialization Routine + * + * Returns 0 on success, negative on failure + * + **/ +int vioc_vnic_init(struct net_device *netdev) +{ + struct vnic_device *vnicdev = netdev->priv; + struct vioc_device *viocdev = vnicdev->viocdev; + int ret; + + SET_ETHTOOL_OPS(netdev, &vioc_ethtool_ops); + /* + * we're going to reset, so assume we have no link for now + */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + ether_setup(netdev); + + netdev->hard_header_len = ETH_HLEN + F7PF_HLEN_STD; /* XXX */ + netdev->hard_header = &vnic_eth_header; + netdev->rebuild_header = NULL; /* XXX */ + + vnic_change_mtu(netdev, 1500); /* default */ + vnic_set_mac_addr(netdev, NULL); + + netdev->open = &vnic_open; + netdev->stop = &vnic_close; + netdev->get_stats = &vnic_get_stats; + netdev->uninit = &vnic_uninit; + netdev->set_mac_address = &vnic_set_mac_addr; + netdev->change_mtu = &vnic_change_mtu; + netdev->watchdog_timeo = HZ; + if (viocdev->highdma) { + netdev->features |= NETIF_F_HIGHDMA; + } + netdev->features |= NETIF_F_VLAN_CHALLENGED; /* VLAN locked */ + netdev->features |= NETIF_F_LLTX; /* lockless Tx */ + + netdev->features |= NETIF_F_IP_CSUM; /* Tx checksum */ + dev_err(&viocdev->pdev->dev, "%s: HW IP checksum offload ENABLED\n", netdev->name); + + /* allocate Tx descriptors, tell VIOC where */ + if ((ret = vnic_alloc_tx_resources(vnicdev))) + goto vnic_init_err; + + netdev->hard_start_xmit = &vnic_start_xmit; + /* Set standard Rx callback */ + + return 0; + + vnic_init_err: + dev_err(&viocdev->pdev->dev, "%s: Error initializing vnic resources\n", + netdev->name); + return ret; +} diff --git a/drivers/net/vioc/vioc_vnic.h b/drivers/net/vioc/vioc_vnic.h new file mode 100644 index 0000000..c62e57c --- /dev/null +++ b/drivers/net/vioc/vioc_vnic.h @@ -0,0 +1,515 @@ +/* + * Fabric7 Systems Virtual IO Controller Driver + * Copyright (C) 2003-2006 Fabric7 Systems. 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 + * + * http://www.fabric7.com/ + * + * Maintainers: + * driver-support@fabric7.com + * + * + */ +#ifndef _VIOC_VNIC_H +#define _VIOC_VNIC_H + +#include +#include +#include + +#include "f7/vnic_defs.h" +#include "f7/vioc_hw_registers.h" +#include "f7/vioc_pkts_defs.h" + +/* + * VIOC PCI constants + */ +#define PCI_VENDOR_ID_FABRIC7 0xfab7 +#define PCI_DEVICE_ID_VIOC_1 0x0001 +#define PCI_DEVICE_ID_VIOC_8 0x0008 +#define PCI_DEVICE_ID_IOAPIC 0x7459 + +#define VIOC_DRV_MODULE_NAME "vioc" + +#define F7PF_HLEN_MIN 8 /* Minimal (kl=0) header */ +#define F7PF_HLEN_STD 10 /* Standard (kl=1) header */ + +#define VNIC_MAX_MTU 9180 +#define VNIC_STD_MTU 1500 + +/* VIOC device constants */ +#define VIOC_MAX_RXDQ 16 +#define VIOC_MAX_RXCQ 16 +#define VIOC_MAX_RXQ 4 +#define VIOC_MAX_TXQ 4 +#define VIOC_NAME_LEN 16 + +/* + * VIOC device state + */ + +#define VIOC_STATE_INIT 0 +#define VIOC_STATE_UP (VIOC_STATE_INIT + 1) + +#define RX_DESC_SIZE sizeof (struct rx_pktBufDesc_Phys_w) +#define RX_DESC_QUANT (4096/RX_DESC_SIZE) + +#define RXC_DESC_SIZE sizeof (struct rxc_pktDesc_Phys_w) +#define RXC_DESC_QUANT (4096/RXC_DESC_SIZE) + +#define TX_DESC_SIZE sizeof (struct tx_pktBufDesc_Phys_w) +#define TX_DESC_QUANT (4096/TX_DESC_SIZE) + +#define RXS_DESC_SIZE sizeof (struct rxc_pktStatusBlock_w) + +#define VIOC_COPYOUT_THRESHOLD 128 +#define VIOC_RXD_BATCH_BITS 32 +#define ALL_BATCH_SW_OWNED 0 +#define ALL_BATCH_HW_OWNED 0xffffffff + +#define VIOC_ANY_VNIC 0 +#define VIOC_NONE_TO_HW (u32) -1 + +/* + * Status of the Rx operation as reflected in Rx Completion Descriptor + */ +#define GET_VNIC_RXC_STATUS(rxcd) (\ + GET_VNIC_RXC_BADCRC(rxcd) |\ + GET_VNIC_RXC_BADLENGTH(rxcd) |\ + GET_VNIC_RXC_BADSMPARITY(rxcd) |\ + GET_VNIC_RXC_PKTABORT(rxcd)\ + ) +#define VNIC_RXC_STATUS_OK_W 0 + +#define VNIC_RXC_STATUS_MASK (\ + VNIC_RXC_ISBADLENGTH_W | \ + VNIC_RXC_ISBADCRC_W | \ + VNIC_RXC_ISBADSMPARITY_W | \ + VNIC_RXC_ISPKTABORT_W \ + ) + +#define VIOC_IRQ_PARAM_VIOC_ID(param) \ + (int) (((u64) param >> 28) & 0xf) +#define VIOC_IRQ_PARAM_INTR_ID(param) \ + (int) ((u64) param & 0xffff) +#define VIOC_IRQ_PARAM_PARAM_ID(param) \ + (int) (((u64) param >> 16) & 0xff) + +#define VIOC_IRQ_PARAM_SET(vioc, intr, param) \ + ((((u64) vioc & 0xf) << 28) | \ + (((u64) param & 0xff) << 16) | \ + ((u64) intr & 0xffff)) +/* + * Return status codes + */ +#define E_VIOCOK 0 +#define E_VIOCMAX 1 +#define E_VIOCINTERNAL 2 +#define E_VIOCNETREGERR 3 +#define E_VIOCPARMERR 4 +#define E_VIOCNOOP 5 +#define E_VIOCTXFULL 6 +#define E_VIOCIFNOTFOUND 7 +#define E_VIOCMALLOCERR 8 +#define E_VIOCORDERR 9 +#define E_VIOCHWACCESS 10 +#define E_VIOCHWNOTREADY 11 +#define E_ALLOCERR 12 +#define E_VIOCRXHW 13 +#define E_VIOCRXCEMPTY 14 + +/* + * From the HW statnd point, every VNIC has 4 RxQ - receive queues. + * Every RxQ is mapped to RxDQ (a ring with buffers for Rx Packets) + * and RxC queue (a ring with descriptors that reflect the status of the receive. + * I.e. when VIOC receives the packet on any of the 4 RxQ, it would use the mapping to determine where + * to get buffer for the packet (RxDQ) and where to post the result of the operation (RxC). + */ + +struct rxd_q_prov { + u32 buf_size; + u32 entries; + u8 id; + u8 state; +}; + +struct vnic_prov_def { + struct rxd_q_prov rxd_ring[4]; + u32 tx_entries; + u32 rxc_entries; + u8 rxc_id; + u8 rxc_intr_id; +}; + +struct vioc_run_param { + u32 rx_intr_timeout; + u32 rx_intr_cntout; + u32 rx_wdog_timeout; + u32 tx_pkts_per_bell; + u32 tx_pkts_per_irq; + int tx_intr_on_empty; +}; + +struct vioc_prov { + struct vnic_prov_def **vnic_prov_p; + struct vioc_run_param run_param; +}; + +struct vioc_irq { + int irq; + void *dev_id; +}; + +/* + * Wrapper around a pointer to a socket buffer + */ +struct vbuf { + volatile struct sk_buff *skb; + volatile dma_addr_t dma; + volatile u32 length; + volatile u32 special; + volatile unsigned long time_stamp; +}; + +struct rxc; + +/* Receive Completion set - RxC + NAPI device */ +struct napi_poll { + volatile u8 enabled; /* if 0, Rx resource are not available */ + volatile u8 stopped; /* if 1, NAPI has stopped servicing set */ + struct net_device poll_dev; /* for NAPI */ + u64 rx_interrupts; /* Number of Rx Interrupts for VIOC stats */ + struct rxc *rxc; +}; + +/* Rx Completion Queue */ +struct rxc { + u8 rxc_id; + u8 interrupt_id; + spinlock_t lock; + struct rxc_pktDesc_Phys_w *desc; + dma_addr_t dma; + u32 count; + u32 sw_idx; + u32 quota; + u32 budget; + void __iomem *va_of_vreg_ihcu_rxcintpktcnt; + void __iomem *va_of_vreg_ihcu_rxcinttimer; + void __iomem *va_of_vreg_ihcu_rxcintctl; + struct vioc_device *viocdev; + struct napi_poll napi; +}; + +/* Rx Descriptor Queue */ +struct rxdq { + u8 rxdq_id; + /* pointer to the Rx Buffer descriptor queue memory */ + struct rx_pktBufDesc_Phys_w *desc; + dma_addr_t dma; + struct vbuf *vbuf; + u32 count; + u16 rx_buf_size; + /* A bit map of descriptors: 0 - owned by SW, 1 - owned by HW */ + u32 *dmap; + u32 dmap_count; + /* dmap_idx is needed for proc fs */ + u32 dmap_idx; + /* Descriptor desginated as a "fence", i.e. owned by SW. */ + volatile u32 fence; + /* A counter that, when expires, forces a call to vioc_next_fence_run() */ + volatile u32 skip_fence_run; + volatile u32 run_to_end; + volatile u32 to_hw; + volatile u32 starvations; + u32 prev_rxd_id; + u32 err_cnt; + u32 reset_cnt; + struct vioc_device *viocdev; +}; + +/* Tx Buffer Descriptor queue */ +struct txq { + u8 txq_id; /* always TXQ0 for now */ + u8 vnic_id; + + spinlock_t lock; /* interrupt-safe */ + /* + * Shadow of the TxD Control Register, keep it here, so we do + * not have to read from HW + */ + u32 shadow_VREG_VENG_TXD_CTL; + /* + * Address of the TxD Control Register when we ring the + * bell. Keep this always ready, for expediency. + */ + void __iomem *va_of_vreg_veng_txd_ctl; + /* + * pointer to the Tx Buffer Descriptor queue memory + */ + struct tx_pktBufDesc_Phys_w *desc; + dma_addr_t dma; + struct vbuf *vbuf; + u32 count; + u32 tx_pkts_til_irq; + u32 tx_pkts_til_bell; + u32 bells; + int do_ring_bell; + /* next descriptor to use for Tx */ + volatile u32 next_to_use; + /* next descriptor to check completion of Tx */ + volatile u32 next_to_clean; + /* Frags count */ + volatile u32 frags; + /* Empty Tx descriptor slots */ + volatile u32 empty; + u32 wraps; + u32 full; +}; + +/* Rx Completion Status Block */ +struct rxs { + struct rxc_pktStatusBlock_w *block; + dma_addr_t dma; +}; + +typedef enum { RX_WDOG_DISABLED, RX_WDOG_EXPECT_PKT, + RX_WDOG_EXPECT_WDOGPKT +} wdog_state_t; + +struct vioc_device_stats { + u64 tx_tasklets; /* Number of Tx Interrupts */ + u64 tx_timers; /* Number of Tx watchdog timers */ +}; + +#define NETIF_STOP_Q 0xdead +#define NETIF_START_Q 0xfeed + +struct vnic_device_stats { + u64 rx_fragment_errors; + u64 rx_dropped; + u64 skb_enqueued; /* Total number of skb's enqueued */ + u64 skb_freed; /* Total number of skb's freed */ + u32 netif_stops; /* Number of times Tx was stopped */ + u32 netif_last; /* Last netif_ command */ + u64 tx_on_empty_interrupts; /* Number of Tx Empty Interrupts */ + u32 headroom_misses; /* Number of headroom misses */ + u32 headroom_miss_drops; /* Number of headroom misses */ +}; + +struct vioc_ba { + void __iomem *virt; + unsigned long long phy; + unsigned long len; +}; + +struct vioc_device { + char name[VIOC_NAME_LEN]; + u32 vioc_bits_version; + u32 vioc_bits_subversion; + + u8 viocdev_idx; + u8 vioc_state; /* Initialization state */ + u8 mgmt_state; /* Management state */ + u8 highdma; + + u32 vnics_map; + u32 vnics_admin_map; + u32 vnics_link_map; + + struct vioc_ba ba; /* VIOC PCI Dev Base Address: virtual and phy */ + struct vioc_ba ioapic_ba; /* VIOC's IOAPIC Base Address: virtual and phy */ + struct pci_dev *pdev; + + /* + * An array of pointers to net_device structures for + * every subordinate VNIC + */ + struct net_device *vnic_netdev[VIOC_MAX_VNICS]; + /* + * An array describing all Rx Completion Descriptor Queues in VIOC + */ + struct rxc *rxc_p[VIOC_MAX_RXCQ]; + struct rxc rxc_buf[VIOC_MAX_RXCQ]; + /* + * An array describing all Rx Descriptor Queues in VIOC + */ + struct rxdq *rxd_p[VIOC_MAX_RXDQ]; + struct rxdq rxd_buf[VIOC_MAX_RXDQ]; + + /* Rx Completion Status Block */ + struct rxs rxcstat; + + /* ----- SIM SPECIFIC ------ */ + /* * Round-robbin over Rx Completion queues */ + u32 next_rxc_to_use; + /* Round-robbin over RxDQs, when checking them out */ + u32 next_rxdq_to_use; + + struct vioc_prov prov; /* VIOC provisioning info */ + struct vioc_device_stats vioc_stats; + + struct timer_list bmc_wd_timer; + int bmc_wd_timer_active; + + struct timer_list tx_timer; + int tx_timer_active; + + u32 num_rx_irqs; + u32 num_irqs; + u32 last_msg_to_sim; +}; + +#define VIOC_BMC_INTR0 (1 << 0) +#define VIOC_BMC_INTR1 (1 << 1) +#define VIOC_BMC_INTR2 (1 << 2) +#define VIOC_BMC_INTR3 (1 << 3) +#define VIOC_BMC_INTR4 (1 << 4) +#define VIOC_BMC_INTR5 (1 << 5) +#define VIOC_BMC_INTR6 (1 << 6) +#define VIOC_BMC_INTR7 (1 << 7) +#define VIOC_BMC_INTR8 (1 << 8) +#define VIOC_BMC_INTR9 (1 << 9) +#define VIOC_BMC_INTR10 (1 << 10) +#define VIOC_BMC_INTR11 (1 << 11) +#define VIOC_BMC_INTR12 (1 << 12) +#define VIOC_BMC_INTR13 (1 << 13) +#define VIOC_BMC_INTR14 (1 << 14) +#define VIOC_BMC_INTR15 (1 << 15) +#define VIOC_BMC_INTR16 (1 << 16) +#define VIOC_BMC_INTR17 (1 << 17) + +#define VNIC_NEXT_IDX(i, count) ((count == 0) ? 0: (((i) + 1) % (count))) +#define VNIC_PREV_IDX(i, count) ((count == 0) ? 0: ((((i) == 0) ? ((count) - 1): ((i) - 1)))) + +#define VNIC_RING_BELL(vnic, q_idx) vnic_ring_bell(vnic, q_idx) + +#define TXDS_REQUIRED(skb) 1 + +#define TXD_WATER_MARK 8 + +#define GET_DESC_PTR(R, i, type) (&(((struct type *)((R)->desc))[i])) +#define RXD_PTR(R, i) GET_DESC_PTR(R, i, rx_pktBufDesc_Phys_w) +#define TXD_PTR(R, i) GET_DESC_PTR(R, i, tx_pktBufDesc_Phys_w) +#define RXC_PTR(R, i) GET_DESC_PTR(R, i, rxc_pktBufDesc_Phys_w) + +/* Receive packet fragments */ + +/* VNIC DEVICE */ +struct vnic_device { + u8 vnic_id; + u8 rxc_id; + u8 rxc_intr_id; + + u32 qmap; /* VNIC rx queues mappings */ + u32 vnic_q_en; /* VNIC queues enables */ + + struct txq txq; + struct vioc_device *viocdev; + struct net_device *netdev; + struct net_device_stats net_stats; + struct vnic_device_stats vnic_stats; + + u8 hw_mac[ETH_ALEN]; +}; + +struct vioc_intreq { + char name[VIOC_NAME_LEN]; + void (*intrFuncp) (struct work_struct *work); + void *intrFuncparm; + irqreturn_t(*hthandler) (int, void *); + unsigned int irq; + unsigned int vec; + unsigned int intr_base; + unsigned int intr_offset; + unsigned int timeout_value; + unsigned int pkt_counter; + unsigned int rxc_mask; + struct work_struct taskq; + struct tasklet_struct tasklet; +}; + + +/* vioc_transmit.c */ +extern int vioc_vnic_init(struct net_device *); +extern void vioc_tx_timer(unsigned long data); + +/* vioc_driver.c */ +extern struct vioc_device *vioc_viocdev(u32 vioc_id); +extern struct net_device *vioc_alloc_vnicdev(struct vioc_device *, int); + +/* vioc_irq.c */ +extern int vioc_irq_init(void); +extern void vioc_irq_exit(void); +extern void vioc_free_irqs(u32 viocdev_idx); +extern int vioc_request_irqs(u32 viocdev_idx); + +extern int vioc_set_intr_func_param(int viocdev_idx, int intr_idx, + int intr_param); + +extern void vioc_rxc_interrupt(struct work_struct *work); +extern void vioc_tx_interrupt(struct work_struct *work); +extern void vioc_bmc_interrupt(struct work_struct *work); + +/* vioc_receive.c */ +extern int vioc_rx_poll(struct net_device *dev, int *budget); +extern int vioc_next_fence_run(struct rxdq *); + +/* spp.c */ +extern int spp_init(void); +extern void spp_terminate(void); +extern void spp_msg_from_sim(int); + +/* spp_vnic.c */ +extern int spp_vnic_init(void); +extern void spp_vnic_exit(void); + +/* vioc_spp.c */ +extern void vioc_vnic_prov(int, u32, u32, int); +extern struct vnic_prov_def **vioc_prov_get(int); +extern void vioc_hb_to_bmc(int vioc_id); +extern int vioc_handle_reset_request(int); +extern void vioc_os_reset_notifier_exit(void); +extern void vioc_os_reset_notifier_init(void); + + + +static inline void vioc_rxc_interrupt_disable(struct rxc *rxc) +{ + writel(3, rxc->va_of_vreg_ihcu_rxcintctl); +} + +static inline void vioc_rxc_interrupt_enable(struct rxc *rxc) +{ + writel(0, rxc->va_of_vreg_ihcu_rxcintctl); +} + +static inline void vioc_rxc_interrupt_clear_pend(struct rxc *rxc) +{ + writel(2, rxc->va_of_vreg_ihcu_rxcintctl); +} + +#define POLL_WEIGHT 32 +#define RX_INTR_TIMEOUT 2 +#define RX_INTR_PKT_CNT 8 +#define TX_PKTS_PER_IRQ 64 +#define TX_PKTS_PER_BELL 1 +#define VIOC_CSUM_OFFLOAD CHECKSUM_COMPLETE +#define VIOC_TRACE 0 + +#define VIOC_LISTEN_GROUP 1 + +#endif /* _VIOC_VNIC_H */ diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index ece3d9c..11519de 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -280,6 +280,19 @@ config IPW2200_DEBUG If you are not sure, say N here. +config LIBERTAS_USB + tristate "Marvell Libertas 8388 802.11a/b/g cards" + depends on NET_RADIO && USB + select FW_LOADER + ---help--- + A driver for Marvell Libertas 8388 USB devices. + +config LIBERTAS_USB_DEBUG + bool "Enable full debugging output in the Libertas USB module." + depends on LIBERTAS_USB + ---help--- + Debugging support. + config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index c613af1..d212460 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_ZD1201) += zd1201.o +obj-$(CONFIG_LIBERTAS_USB) += libertas/ diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README deleted file mode 100644 index 0c274bf..0000000 --- a/drivers/net/wireless/README +++ /dev/null @@ -1,25 +0,0 @@ - README - ------ - - This directory is mostly for Wireless LAN drivers, in their -various incarnations (ISA, PCI, Pcmcia...). - This separate directory is needed because a lot of driver work -on different bus (typically PCI + Pcmcia) and share 95% of the -code. This allow the code and the config options to be in one single -place instead of scattered all over the driver tree, which is never -100% satisfactory. - - Note : if you want more info on the topic of Wireless LANs, -you are kindly invited to have a look at the Wireless Howto : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ - Some Wireless LAN drivers, like orinoco_cs, require the use of -Wireless Tools to be configured : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html - - Special notes for distribution maintainers : - 1) wvlan_cs will be discontinued soon in favor of orinoco_cs - 2) Please add Wireless Tools support in your scripts - - Have fun... - - Jean diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2ada76a..254f285 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1145,6 +1145,7 @@ static void airo_networks_free(struct ai struct airo_info { struct net_device_stats stats; struct net_device *dev; + struct list_head dev_list; /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we use the high bit to mark whether it is in use. */ #define MAX_FIDS 6 @@ -2360,6 +2361,21 @@ static int airo_change_mtu(struct net_de return 0; } +static LIST_HEAD(airo_devices); + +static void add_airo_dev(struct airo_info *ai) +{ + /* Upper layers already keep track of PCI devices, + * so we only need to remember our non-PCI cards. */ + if (!ai->pci) + list_add_tail(&ai->dev_list, &airo_devices); +} + +static void del_airo_dev(struct airo_info *ai) +{ + if (!ai->pci) + list_del(&ai->dev_list); +} static int airo_close(struct net_device *dev) { struct airo_info *ai = dev->priv; @@ -2381,8 +2397,6 @@ #endif return 0; } -static void del_airo_dev( struct net_device *dev ); - void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = dev->priv; @@ -2434,14 +2448,12 @@ void stop_airo_card( struct net_device * } } crypto_free_cipher(ai->tfm); - del_airo_dev( dev ); + del_airo_dev(ai); free_netdev( dev ); } EXPORT_SYMBOL(stop_airo_card); -static int add_airo_dev( struct net_device *dev ); - static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); @@ -2740,8 +2752,6 @@ static int airo_networks_allocate(struct static void airo_networks_free(struct airo_info *ai) { - if (!ai->networks) - return; kfree(ai->networks); ai->networks = NULL; } @@ -2816,12 +2826,10 @@ static struct net_device *_init_airo_car if (IS_ERR(ai->airo_thread_task)) goto err_out_free; ai->tfm = NULL; - rc = add_airo_dev( dev ); - if (rc) - goto err_out_thr; + add_airo_dev(ai); if (airo_networks_allocate (ai)) - goto err_out_unlink; + goto err_out_thr; airo_networks_initialize (ai); /* The Airo-specific entries in the device structure. */ @@ -2937,9 +2945,8 @@ err_out_irq: free_irq(dev->irq, dev); err_out_nets: airo_networks_free(ai); -err_out_unlink: - del_airo_dev(dev); err_out_thr: + del_airo_dev(ai); set_bit(JOB_DIE, &ai->jobs); kthread_stop(ai->airo_thread_task); err_out_free: @@ -5538,11 +5545,6 @@ static int proc_close( struct inode *ino return 0; } -static struct net_device_list { - struct net_device *dev; - struct net_device_list *next; -} *airo_devices; - /* Since the card doesn't automatically switch to the right WEP mode, we will make it do it. If the card isn't associated, every secs we will switch WEP modes to see if that will help. If the card is @@ -5585,26 +5587,6 @@ static void timer_func( struct net_devic apriv->expires = RUN_AT(HZ*3); } -static int add_airo_dev( struct net_device *dev ) { - struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL ); - if ( !node ) - return -ENOMEM; - - node->dev = dev; - node->next = airo_devices; - airo_devices = node; - - return 0; -} - -static void del_airo_dev( struct net_device *dev ) { - struct net_device_list **p = &airo_devices; - while( *p && ( (*p)->dev != dev ) ) - p = &(*p)->next; - if ( *p && (*p)->dev == dev ) - *p = (*p)->next; -} - #ifdef CONFIG_PCI static int __devinit airo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) @@ -5628,6 +5610,10 @@ static int __devinit airo_pci_probe(stru static void __devexit airo_pci_remove(struct pci_dev *pdev) { + struct net_device *dev = pci_get_drvdata(pdev); + + airo_print_info(dev->name, "Unregistering..."); + stop_airo_card(dev, 1); } static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) @@ -5753,9 +5739,11 @@ #endif static void __exit airo_cleanup_module( void ) { - while( airo_devices ) { - airo_print_info(airo_devices->dev->name, "Unregistering...\n"); - stop_airo_card( airo_devices->dev, 1 ); + struct airo_info *ai; + while(!list_empty(&airo_devices)) { + ai = list_entry(airo_devices.next, struct airo_info, dev_list); + airo_print_info(ai->dev->name, "Unregistering..."); + stop_airo_card(ai->dev, 1); } #ifdef CONFIG_PCI pci_unregister_driver(&airo_driver); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 95ff175..f8483c1 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -277,11 +277,14 @@ #define BCM43xx_SBTMSTATELOW_RESET 0x01 #define BCM43xx_SBTMSTATELOW_REJECT 0x02 #define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 +#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000 /* sbtmstatehigh state flags */ #define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001 #define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004 #define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020 +#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 +#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000 #define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 #define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000 #define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c index c947025..d2df6a0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c @@ -32,7 +32,7 @@ #include "bcm43xx_ethtool.h" #include #include #include -#include +#include static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct n struct bcm43xx_private *bcm = bcm43xx_priv(dev); strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strncpy(info->version, UTS_RELEASE, sizeof(info->version)); + strncpy(info->version, utsname()->release, sizeof(info->version)); strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 80cb88e..282f98f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1389,7 +1389,7 @@ #endif & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); } else { if (connect_phy) - flags |= 0x20000000; + flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; bcm43xx_phy_connect(bcm, connect_phy); bcm43xx_core_enable(bcm, flags); bcm43xx_write16(bcm, 0x03E6, 0x0000); @@ -3586,7 +3586,7 @@ int bcm43xx_select_wireless_core(struct u32 sbtmstatelow; sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow |= 0x20000000; + sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); } err = wireless_core_up(bcm, 1); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index cae8925..8a99790 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_p flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (connect) { - if (!(flags & 0x00010000)) + if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL)) return -ENODEV; flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags |= (0x800 << 18); + flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); } else { - if (!(flags & 0x00020000)) + if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL)) return -ENODEV; flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - flags &= ~(0x800 << 18); + flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); } out: diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index 0162400..b31e6a0 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -368,9 +368,9 @@ enum { #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 #define PRISM2_HOSTAPD_RID_HDR_LEN \ -((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) +offsetof(struct prism2_hostapd_param, u.rid.data) #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) +offsetof(struct prism2_hostapd_param, u.generic_elem.data) /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() */ diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 8d8f4b9..534da85 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -848,6 +848,11 @@ static struct pcmcia_device_id hostap_cs "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", "Eval-RevA", 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), + /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ + PCMCIA_DEVICE_PROD_ID1234( + "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", + "A3", + 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52), PCMCIA_DEVICE_PROD_ID123( "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 0xe6ec52ce, 0x08649af2, 0x4b74baa0), diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c878a2f..4372438 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct de static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, store_net_stats); +static ssize_t show_channels(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int len = 0, i; + + len = sprintf(&buf[len], + "Displaying %d channels in 2.4Ghz band " + "(802.11bg):\n", geo->bg_channels); + + for (i = 0; i < geo->bg_channels; i++) { + len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", + geo->bg[i].channel, + geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? + " (radar spectrum)" : "", + ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || + (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) + ? "" : ", IBSS", + geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + "passive only" : "active/passive", + geo->bg[i].flags & IEEE80211_CH_B_ONLY ? + "B" : "B/G"); + } + + len += sprintf(&buf[len], + "Displaying %d channels in 5.2Ghz band " + "(802.11a):\n", geo->a_channels); + for (i = 0; i < geo->a_channels; i++) { + len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", + geo->a[i].channel, + geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? + " (radar spectrum)" : "", + ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || + (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) + ? "" : ", IBSS", + geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? + "passive only" : "active/passive"); + } + + return len; +} + +static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); + static void notify_wx_assoc_event(struct ipw_priv *priv) { union iwreq_data wrqu; @@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entri &dev_attr_led.attr, &dev_attr_speed_scan.attr, &dev_attr_net_stats.attr, + &dev_attr_channels.attr, #ifdef CONFIG_IPW2200_PROMISCUOUS &dev_attr_rtap_iface.attr, &dev_attr_rtap_filter.attr, diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c new file mode 100644 index 0000000..e0ecc4d --- /dev/null +++ b/drivers/net/wireless/libertas/11d.c @@ -0,0 +1,754 @@ +/** + * This file contains functions for 802.11D. + */ +#include +#include +#include + +#include "host.h" +#include "decl.h" +#include "11d.h" +#include "dev.h" +#include "wext.h" + +#define TX_PWR_DEFAULT 10 + +static struct region_code_mapping region_code_mapping[] = { + {"US ", 0x10}, /* US FCC */ + {"CA ", 0x10}, /* IC Canada */ + {"SG ", 0x10}, /* Singapore */ + {"EU ", 0x30}, /* ETSI */ + {"AU ", 0x30}, /* Australia */ + {"KR ", 0x30}, /* Republic Of Korea */ + {"ES ", 0x31}, /* Spain */ + {"FR ", 0x32}, /* France */ + {"JP ", 0x40}, /* Japan */ +}; + +/* Following 2 structure defines the supported channels */ +static struct chan_freq_power channel_freq_power_UN_BG[] = { + {1, 2412, TX_PWR_DEFAULT}, + {2, 2417, TX_PWR_DEFAULT}, + {3, 2422, TX_PWR_DEFAULT}, + {4, 2427, TX_PWR_DEFAULT}, + {5, 2432, TX_PWR_DEFAULT}, + {6, 2437, TX_PWR_DEFAULT}, + {7, 2442, TX_PWR_DEFAULT}, + {8, 2447, TX_PWR_DEFAULT}, + {9, 2452, TX_PWR_DEFAULT}, + {10, 2457, TX_PWR_DEFAULT}, + {11, 2462, TX_PWR_DEFAULT}, + {12, 2467, TX_PWR_DEFAULT}, + {13, 2472, TX_PWR_DEFAULT}, + {14, 2484, TX_PWR_DEFAULT} +}; + +static u8 wlan_region_2_code(u8 * region) +{ + u8 i; + u8 size = sizeof(region_code_mapping)/ + sizeof(struct region_code_mapping); + + for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) + region[i] = toupper(region[i]); + + for (i = 0; i < size; i++) { + if (!memcmp(region, region_code_mapping[i].region, + COUNTRY_CODE_LEN)) + return (region_code_mapping[i].code); + } + + /* default is US */ + return (region_code_mapping[0].code); +} + +static u8 *wlan_code_2_region(u8 code) +{ + u8 i; + u8 size = sizeof(region_code_mapping) + / sizeof(struct region_code_mapping); + for (i = 0; i < size; i++) { + if (region_code_mapping[i].code == code) + return (region_code_mapping[i].region); + } + /* default is US */ + return (region_code_mapping[0].region); +} + +/** + * @brief This function finds the nrchan-th chan after the firstchan + * @param band band + * @param firstchan first channel number + * @param nrchan number of channels + * @return the nrchan-th chan number +*/ +static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) +/*find the nrchan-th chan after the firstchan*/ +{ + u8 i; + struct chan_freq_power *cfp; + u8 cfp_no; + + cfp = channel_freq_power_UN_BG; + cfp_no = sizeof(channel_freq_power_UN_BG) / + sizeof(struct chan_freq_power); + + for (i = 0; i < cfp_no; i++) { + if ((cfp + i)->channel == firstchan) { + lbs_pr_debug(1, "firstchan found\n"); + break; + } + } + + if (i < cfp_no) { + /*if beyond the boundary */ + if (i + nrchan < cfp_no) { + *chan = (cfp + i + nrchan)->channel; + return 1; + } + } + + return 0; +} + +/** + * @brief This function Checks if chan txpwr is learned from AP/IBSS + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return TRUE; FALSE +*/ +static u8 wlan_channel_known_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) +{ + struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; + u8 nr_chan = parsed_region_chan->nr_chan; + u8 i = 0; + + lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, + sizeof(struct chan_power_11d) * nr_chan); + + for (i = 0; i < nr_chan; i++) { + if (chan == chanpwr[i].chan) { + lbs_pr_debug(1, "11D: Found Chan:%d\n", chan); + return 1; + } + } + + lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan); + return 0; +} + +u32 libertas_chan_2_freq(u8 chan, u8 band) +{ + struct chan_freq_power *cf; + u16 cnt; + u16 i; + u32 freq = 0; + + cf = channel_freq_power_UN_BG; + cnt = + sizeof(channel_freq_power_UN_BG) / + sizeof(struct chan_freq_power); + + for (i = 0; i < cnt; i++) { + if (chan == cf[i].channel) + freq = cf[i].freq; + } + + return freq; +} + +static int generate_domain_info_11d(struct parsed_region_chan_11d + *parsed_region_chan, + struct wlan_802_11d_domain_reg * domaininfo) +{ + u8 nr_subband = 0; + + u8 nr_chan = parsed_region_chan->nr_chan; + u8 nr_parsedchan = 0; + + u8 firstchan = 0, nextchan = 0, maxpwr = 0; + + u8 i, flag = 0; + + memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, + COUNTRY_CODE_LEN); + + lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan); + lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, + sizeof(struct parsed_region_chan_11d)); + + for (i = 0; i < nr_chan; i++) { + if (!flag) { + flag = 1; + nextchan = firstchan = + parsed_region_chan->chanpwr[i].chan; + maxpwr = parsed_region_chan->chanpwr[i].pwr; + nr_parsedchan = 1; + continue; + } + + if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 && + parsed_region_chan->chanpwr[i].pwr == maxpwr) { + nextchan++; + nr_parsedchan++; + } else { + domaininfo->subband[nr_subband].firstchan = firstchan; + domaininfo->subband[nr_subband].nrchan = + nr_parsedchan; + domaininfo->subband[nr_subband].maxtxpwr = maxpwr; + nr_subband++; + nextchan = firstchan = + parsed_region_chan->chanpwr[i].chan; + maxpwr = parsed_region_chan->chanpwr[i].pwr; + } + } + + if (flag) { + domaininfo->subband[nr_subband].firstchan = firstchan; + domaininfo->subband[nr_subband].nrchan = nr_parsedchan; + domaininfo->subband[nr_subband].maxtxpwr = maxpwr; + nr_subband++; + } + domaininfo->nr_subband = nr_subband; + + lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband); + lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, + COUNTRY_CODE_LEN + 1 + + sizeof(struct ieeetypes_subbandset) * nr_subband); + return 0; +} + +/** + * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS + * @param region_chan pointer to struct region_channel + * @param *parsed_region_chan pointer to parsed_region_chan_11d + * @return N/A +*/ +static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, + struct parsed_region_chan_11d * + parsed_region_chan) +{ + u8 i; + struct chan_freq_power *cfp; + + if (region_chan == NULL) { + lbs_pr_debug(1, "11D: region_chan is NULL\n"); + return; + } + + cfp = region_chan->CFP; + if (cfp == NULL) { + lbs_pr_debug(1, "11D: cfp equal NULL \n"); + return; + } + + parsed_region_chan->band = region_chan->band; + parsed_region_chan->region = region_chan->region; + memcpy(parsed_region_chan->countrycode, + wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); + + lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region, + parsed_region_chan->band); + + for (i = 0; i < region_chan->nrcfp; i++, cfp++) { + parsed_region_chan->chanpwr[i].chan = cfp->channel; + parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; + lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n", + parsed_region_chan->chanpwr[i].chan, + parsed_region_chan->chanpwr[i].pwr); + } + parsed_region_chan->nr_chan = region_chan->nrcfp; + + lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan); + + return; +} + +/** + * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS + * @param region region ID + * @param band band + * @param chan chan + * @return TRUE;FALSE +*/ +static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) +{ + struct chan_freq_power *cfp; + int cfp_no; + u8 idx; + + ENTER(); + + cfp = libertas_get_region_cfp_table(region, band, &cfp_no); + if (cfp == NULL) + return 0; + + for (idx = 0; idx < cfp_no; idx++) { + if (chan == (cfp + idx)->channel) { + /* If Mrvl Chip Supported? */ + if ((cfp + idx)->unsupported) { + return 0; + } else { + return 1; + } + } + } + + /*chan is not in the region table */ + LEAVE(); + return 0; +} + +/** + * @brief This function checks if chan txpwr is learned from AP/IBSS + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return 0 +*/ +static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* + countryinfo, + u8 band, + struct parsed_region_chan_11d * + parsed_region_chan) +{ + u8 nr_subband, nrchan; + u8 lastchan, firstchan; + u8 region; + u8 curchan = 0; + + u8 idx = 0; /*chan index in parsed_region_chan */ + + u8 j, i; + + ENTER(); + + /*validation Rules: + 1. valid region Code + 2. First Chan increment + 3. channel range no overlap + 4. channel is valid? + 5. channel is supported by region? + 6. Others + */ + + lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); + + if ((*(countryinfo->countrycode)) == 0 + || (countryinfo->len <= COUNTRY_CODE_LEN)) { + /* No region Info or Wrong region info: treat as No 11D info */ + LEAVE(); + return 0; + } + + /*Step1: check region_code */ + parsed_region_chan->region = region = + wlan_region_2_code(countryinfo->countrycode); + + lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region); + lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, + COUNTRY_CODE_LEN); + + parsed_region_chan->band = band; + + memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, + COUNTRY_CODE_LEN); + + nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / + sizeof(struct ieeetypes_subbandset); + + for (j = 0, lastchan = 0; j < nr_subband; j++) { + + if (countryinfo->subband[j].firstchan <= lastchan) { + /*Step2&3. Check First Chan Num increment and no overlap */ + lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n", + countryinfo->subband[j].firstchan, lastchan); + continue; + } + + firstchan = countryinfo->subband[j].firstchan; + nrchan = countryinfo->subband[j].nrchan; + + for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { + /*step4: channel is supported? */ + + if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { + /* Chan is not found in UN table */ + lbs_pr_debug(1, "chan is not supported: %d \n", i); + break; + } + + lastchan = curchan; + + if (wlan_region_chan_supported_11d + (region, band, curchan)) { + /*step5: Check if curchan is supported by mrvl in region */ + parsed_region_chan->chanpwr[idx].chan = curchan; + parsed_region_chan->chanpwr[idx].pwr = + countryinfo->subband[j].maxtxpwr; + idx++; + } else { + /*not supported and ignore the chan */ + lbs_pr_debug(1, + "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", + i, curchan, region, band); + } + } + + /*Step6: Add other checking if any */ + + } + + parsed_region_chan->nr_chan = idx; + + lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan); + lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, + 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); + + LEAVE(); + return 0; +} + +/** + * @brief This function calculates the scan type for channels + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return PASSIVE if chan is unknown; ACTIVE if chan is known +*/ +u8 libertas_get_scan_type_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) +{ + u8 scan_type = cmd_scan_type_passive; + + ENTER(); + + if (wlan_channel_known_11d(chan, parsed_region_chan)) { + lbs_pr_debug(1, "11D: Found and do Active Scan\n"); + scan_type = cmd_scan_type_active; + } else { + lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n"); + } + + LEAVE(); + return scan_type; + +} + +void libertas_init_11d(wlan_private * priv) +{ + priv->adapter->enable11d = 0; + memset(&(priv->adapter->parsed_region_chan), 0, + sizeof(struct parsed_region_chan_11d)); + return; +} + +static int wlan_enable_11d(wlan_private * priv, u8 flag) +{ + int ret; + + priv->adapter->enable11d = flag; + + /* send cmd to FW to enable/disable 11D function in FW */ + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_snmp_mib, + cmd_act_set, + cmd_option_waitforrsp, + OID_802_11D_ENABLE, + &priv->adapter->enable11d); + if (ret) + lbs_pr_debug(1, "11D: Fail to enable 11D \n"); + + return 0; +} + +/** + * @brief This function sets DOMAIN INFO to FW + * @param priv pointer to wlan_private + * @return 0; -1 +*/ +static int set_domain_info_11d(wlan_private * priv) +{ + int ret; + + if (!priv->adapter->enable11d) { + lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n"); + return 0; + } + + ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + if (ret) + lbs_pr_debug(1, "11D: Fail to dnld domain Info\n"); + + return ret; +} + +/** + * @brief This function setups scan channels + * @param priv pointer to wlan_private + * @param band band + * @return 0 +*/ +int libertas_set_universaltable(wlan_private * priv, u8 band) +{ + wlan_adapter *adapter = priv->adapter; + u16 size = sizeof(struct chan_freq_power); + u16 i = 0; + + memset(adapter->universal_channel, 0, + sizeof(adapter->universal_channel)); + + adapter->universal_channel[i].nrcfp = + sizeof(channel_freq_power_UN_BG) / size; + lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n", + adapter->universal_channel[i].nrcfp); + + adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; + adapter->universal_channel[i].valid = 1; + adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE; + adapter->universal_channel[i].band = band; + i++; + + return 0; +} + +/** + * @brief This function implements command CMD_802_11D_DOMAIN_INFO + * @param priv pointer to wlan_private + * @param cmd pointer to cmd buffer + * @param cmdno cmd ID + * @param cmdOption cmd action + * @return 0 +*/ +int libertas_cmd_802_11d_domain_info(wlan_private * priv, + struct cmd_ds_command *cmd, u16 cmdno, + u16 cmdoption) +{ + struct cmd_ds_802_11d_domain_info *pdomaininfo = + &cmd->params.domaininfo; + struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; + wlan_adapter *adapter = priv->adapter; + u8 nr_subband = adapter->domainreg.nr_subband; + + ENTER(); + + lbs_pr_debug(1, "nr_subband=%x\n", nr_subband); + + cmd->command = cpu_to_le16(cmdno); + pdomaininfo->action = cpu_to_le16(cmdoption); + if (cmdoption == cmd_act_get) { + cmd->size = + cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); + lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, + (int)(cmd->size)); + LEAVE(); + return 0; + } + + domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); + memcpy(domain->countrycode, adapter->domainreg.countrycode, + sizeof(domain->countrycode)); + + domain->header.len = + cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + + sizeof(domain->countrycode)); + + if (nr_subband) { + memcpy(domain->subband, adapter->domainreg.subband, + nr_subband * sizeof(struct ieeetypes_subbandset)); + + cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + + domain->header.len + + sizeof(struct mrvlietypesheader) + + S_DS_GEN); + } else { + cmd->size = + cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); + } + + lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size)); + + LEAVE(); + + return 0; +} + +/** + * @brief This function implements private cmd: enable/disable 11D + * @param priv pointer to wlan_private + * @param wrq pointer to user data + * @return 0 or -1 + */ +int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) +{ + int data = 0; + int *val; + + ENTER(); + data = SUBCMD_DATA(wrq); + + lbs_pr_debug(1, "enable 11D: %s\n", + (data == 1) ? "enable" : "Disable"); + + wlan_enable_11d(priv, data); + val = (int *)wrq->u.name; + *val = priv->adapter->enable11d; + + LEAVE(); + return 0; +} + +/** + * @brief This function parses countryinfo from AP and download country info to FW + * @param priv pointer to wlan_private + * @param resp pointer to command response buffer + * @return 0; -1 + */ +int libertas_ret_802_11d_domain_info(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11d_domain_info + *domaininfo = &resp->params.domaininforesp; + struct mrvlietypes_domainparamset *domain = &domaininfo->domain; + u16 action = le16_to_cpu(domaininfo->action); + s16 ret = 0; + u8 nr_subband = 0; + + ENTER(); + + lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, + (int)le16_to_cpu(resp->size)); + + nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset); + /* countrycode 3 bytes */ + + lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband); + + if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { + lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n"); + return -1; + } + + switch (action) { + case cmd_act_set: /*Proc Set action */ + break; + + case cmd_act_get: + break; + default: + lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action); + ret = -1; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief This function parses countryinfo from AP and download country info to FW + * @param priv pointer to wlan_private + * @return 0; -1 + */ +int libertas_parse_dnld_countryinfo_11d(wlan_private * priv) +{ + int ret; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + if (priv->adapter->enable11d) { + memset(&adapter->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); + ret = parse_domain_info_11d(&adapter->pattemptedbssdesc-> + countryinfo, 0, + &adapter->parsed_region_chan); + + if (ret == -1) { + lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n"); + LEAVE(); + return ret; + } + + memset(&adapter->domainreg, 0, + sizeof(struct wlan_802_11d_domain_reg)); + generate_domain_info_11d(&adapter->parsed_region_chan, + &adapter->domainreg); + + ret = set_domain_info_11d(priv); + + if (ret) { + lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); + LEAVE(); + return ret; + } + } + LEAVE(); + return 0; +} + +/** + * @brief This function generates 11D info from user specified regioncode and download to FW + * @param priv pointer to wlan_private + * @return 0; -1 + */ +int libertas_create_dnld_countryinfo_11d(wlan_private * priv) +{ + int ret; + wlan_adapter *adapter = priv->adapter; + struct region_channel *region_chan; + u8 j; + + ENTER(); + lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band); + + if (priv->adapter->enable11d) { + /* update parsed_region_chan_11; dnld domaininf to FW */ + + for (j = 0; j < sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0]); j++) { + region_chan = &adapter->region_channel[j]; + + lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j, + region_chan->band); + + if (!region_chan || !region_chan->valid + || !region_chan->CFP) + continue; + if (region_chan->band != adapter->curbssparams.band) + continue; + break; + } + + if (j >= sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0])) { + lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n", + adapter->curbssparams.band); + LEAVE(); + return -1; + } + + memset(&adapter->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); + wlan_generate_parsed_region_chan_11d(region_chan, + &adapter-> + parsed_region_chan); + + memset(&adapter->domainreg, 0, + sizeof(struct wlan_802_11d_domain_reg)); + generate_domain_info_11d(&adapter->parsed_region_chan, + &adapter->domainreg); + + ret = set_domain_info_11d(priv); + + if (ret) { + lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); + LEAVE(); + return ret; + } + + } + + LEAVE(); + return 0; +} diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h new file mode 100644 index 0000000..db2ebea --- /dev/null +++ b/drivers/net/wireless/libertas/11d.h @@ -0,0 +1,105 @@ +/** + * This header file contains data structures and + * function declarations of 802.11d + */ +#ifndef _WLAN_11D_ +#define _WLAN_11D_ + +#include "types.h" +#include "defs.h" + +#define UNIVERSAL_REGION_CODE 0xff + +/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) + */ +#define MRVDRV_MAX_SUBBAND_802_11D 83 + +#define COUNTRY_CODE_LEN 3 +#define MAX_NO_OF_CHAN 40 + +struct cmd_ds_command; + +/** Data structure for Country IE*/ +struct ieeetypes_subbandset { + u8 firstchan; + u8 nrchan; + u8 maxtxpwr; +} __attribute__ ((packed)); + +struct ieeetypes_countryinfoset { + u8 element_id; + u8 len; + u8 countrycode[COUNTRY_CODE_LEN]; + struct ieeetypes_subbandset subband[1]; +}; + +struct ieeetypes_countryinfofullset { + u8 element_id; + u8 len; + u8 countrycode[COUNTRY_CODE_LEN]; + struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; +} __attribute__ ((packed)); + +struct mrvlietypes_domainparamset { + struct mrvlietypesheader header; + u8 countrycode[COUNTRY_CODE_LEN]; + struct ieeetypes_subbandset subband[1]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11d_domain_info { + u16 action; + struct mrvlietypes_domainparamset domain; +} __attribute__ ((packed)); + +/** domain regulatory information */ +struct wlan_802_11d_domain_reg { + /** country Code*/ + u8 countrycode[COUNTRY_CODE_LEN]; + /** No. of subband*/ + u8 nr_subband; + struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; +}; + +struct chan_power_11d { + u8 chan; + u8 pwr; +} __attribute__ ((packed)); + +struct parsed_region_chan_11d { + u8 band; + u8 region; + s8 countrycode[COUNTRY_CODE_LEN]; + struct chan_power_11d chanpwr[MAX_NO_OF_CHAN]; + u8 nr_chan; +} __attribute__ ((packed)); + +struct region_code_mapping { + u8 region[COUNTRY_CODE_LEN]; + u8 code; +}; + +u8 libertas_get_scan_type_11d(u8 chan, + struct parsed_region_chan_11d *parsed_region_chan); + +u32 libertas_chan_2_freq(u8 chan, u8 band); + +enum state_11d libertas_get_state_11d(wlan_private * priv); + +void libertas_init_11d(wlan_private * priv); + +int libertas_set_universaltable(wlan_private * priv, u8 band); + +int libertas_cmd_802_11d_domain_info(wlan_private * priv, + struct cmd_ds_command *cmd, u16 cmdno, + u16 cmdOption); + +int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); + +int libertas_ret_802_11d_domain_info(wlan_private * priv, + struct cmd_ds_command *resp); + +int libertas_parse_dnld_countryinfo_11d(wlan_private * priv); + +int libertas_create_dnld_countryinfo_11d(wlan_private * priv); + +#endif /* _WLAN_11D_ */ diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE new file mode 100644 index 0000000..8862742 --- /dev/null +++ b/drivers/net/wireless/libertas/LICENSE @@ -0,0 +1,16 @@ + Copyright (c) 2003-2006, Marvell International Ltd. + 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. + diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile new file mode 100644 index 0000000..19c9350 --- /dev/null +++ b/drivers/net/wireless/libertas/Makefile @@ -0,0 +1,21 @@ +# EXTRA_CFLAGS += -Wpacked + +usb8xxx-objs := main.o fw.o wext.o \ + rx.o tx.o cmd.o \ + cmdresp.o scan.o \ + join.o 11d.o \ + ioctl.o debugfs.o \ + ethtool.o assoc.o + +ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y) +EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG +endif + + +# This is needed to support the newer boot2 bootloader (v >= 3104) +EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND +usb8xxx-objs += if_bootcmd.o +usb8xxx-objs += if_usb.o + +obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o + diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README new file mode 100644 index 0000000..688da4c --- /dev/null +++ b/drivers/net/wireless/libertas/README @@ -0,0 +1,1044 @@ +================================================================================ + README for USB8388 + + (c) Copyright © 2003-2006, Marvell International Ltd. + All Rights Reserved + + This software file (the "File") is distributed by Marvell International + Ltd. under the terms of the GNU General Public License Version 2, June 1991 + (the "License"). You may use, redistribute and/or modify this File in + accordance with the terms and conditions of the License, a copy of which + is available along with the File in the license.txt file or by writing to + the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + + THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + ARE EXPRESSLY DISCLAIMED. The License provides additional details about + this warranty disclaimer. +================================================================================ + +===================== +DRIVER LOADING +===================== + + o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/ + + o. Load driver by using the following command: + + insmod usb8388.ko [fw_name=usb8388.bin] + +===================== +IWPRIV COMMAND +===================== + +NAME + This manual describes the usage of private commands used in Marvell WLAN + Linux Driver. All the commands available in Wlanconfig will not be available + in the iwpriv. + +SYNOPSIS + iwpriv [sub-command] ... + + iwpriv ethX version + iwpriv ethX scantype [sub-command] + iwpriv ethX getSNR + iwpriv ethX getNF + iwpriv ethX getRSSI + iwpriv ethX setrxant + iwpriv ethX getrxant + iwpriv ethX settxant + iwpriv ethX gettxant + iwpriv ethX authalgs + iwpriv ethX pre-TBTT + iwpriv ethX 8021xauthalgs + iwpriv ethX encryptionmode + iwpriv ethX setregioncode + iwpriv ethX getregioncode + iwpriv ethX setbcnavg + iwpriv ethX getbcnavg + iwpriv ethX setdataavg + iwpriv ethX setlisteninter + iwpriv ethX getlisteninter + iwpriv ethX setmultipledtim + iwpriv ethX getmultipledtim + iwpriv ethX atimwindow + iwpriv ethX deauth + iwpriv ethX adhocstop + iwpriv ethX radioon + iwpriv ethX radiooff + iwpriv ethX reasso-on + iwpriv ethX reasso-off + iwpriv ethX scanmode [sub-command] + iwpriv ethX setwpaie + iwpriv ethX wlanidle-off + iwpriv ethX wlanidle-on + iwpriv ethX getcis + iwpriv ethX getlog + iwpriv ethX getadhocstatus + iwpriv ethX adhocgrate + +Version 4 Command: + iwpriv ethX inactvityto + iwpriv ethX sleeppd + iwpriv ethX enable11d + iwpriv ethX tpccfg + iwpriv ethX powercfg + iwpriv ethX setafc + iwpriv ethX getafc + +Version 5 Command: + iwpriv ethX ledgpio + iwpriv ethX scanprobes + iwpriv ethX lolisteninter + iwpriv ethX rateadapt + iwpriv ethX txcontrol + iwpriv ethX psnullinterval + iwpriv ethX prescan + iwpriv ethX getrxinfo + iwpriv ethX gettxrate + iwpriv ethX beaconinterval + +BT Commands: + The blinding table (BT) contains a list of mac addresses that should be + ignored by the firmware. It is primarily used for debugging and + testing networks. It can be edited and inspected with the following + commands: + + iwpriv ethX bt_reset + iwpriv ethX bt_add + iwpriv ethX bt_del + iwpriv ethX bt_list + +FWT Commands: + The forwarding table (FWT) is a feature used to manage mesh network + routing in the firmware. The FWT is essentially a routing table that + associates a destination mac address (da) with a next hop receiver + address (ra). The FWT can be inspected and edited with the following + iwpriv commands, which are described in greater detail below. + Eventually, the table will be automatically maintained by a custom + routing protocol. + + NOTE: FWT commands replace the previous DFT commands. What were the DFT + commands?, you might ask. They were an earlier API to the firmware that + implemented a simple MAC-layer forwarding mechanism. In the unlikely + event that you were using these commands, you must migrate to the new + FWT commands which can be used to achieve the same functionality. + + iwpriv ethX fwt_add [parameters] + iwpriv ethX fwt_del [parameters] + iwpriv ethX fwt_lookup [parameters] + iwpriv ethX fwt_list [parameters] + iwpriv ethX fwt_list_route [parameters] + iwpriv ethX fwt_list_neigh [parameters] + iwpriv ethX fwt_reset [parameters] + iwpriv ethX fwt_cleanup + iwpriv ethX fwt_time + +MESH Commands: + + The MESH commands are used to configure various features of the mesh + routing protocol. The following commands are supported: + + iwpriv ethX mesh_get_ttl + iwpriv ethX mesh_set_ttl ttl + +DESCRIPTION + Those commands are used to send additional commands to the Marvell WLAN + card via the Linux device driver. + + The ethX parameter specifies the network device that is to be used to + perform this command on. it could be eth0, eth1 etc. + +version + This is used to get the current version of the driver and the firmware. + +scantype + This command is used to set the scan type to be used by the driver in + the scan command. This setting will not be used while performing a scan + for a specific SSID, as it is always done with scan type being active. + + where the sub-commands are: - + active -- to set the scan type to active + passive -- to set the scan type to passive + get -- to get the scan type set in the driver + +getSNR + This command gets the average and non average value of Signal to Noise + Ratio of Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + If no value is given, all four values are returned in the order mentioned + above. + + Note: This command is available only when STA is connected. + +getRSSI + This command gets the average and non average value os Receive Signal + Strength of Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + Note: This command is available only when STA is connected. + +getNF + This command gets the average and non average value of Noise Floor of + Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + Note: This command is available only when STA is connected. + +setrxant + This command is used to set the mode for Rx antenna. + + The options that can be sent are:- + 1 -- Antenna 1. + 2 -- Antenna 2. + 0xFFFF -- Diversity. + + Usage: + iwpriv ethX setrxant 0x01: select Antenna 1. + +getrxant + This command is used to get the mode for Rx antenna. + + +settxant + This command is used to set the mode for Tx antenna. + The options that can be sent are:- + 1 -- Antenna 1. + 2 -- Antenna 2. + 0xFFFF -- Diversity. + Usage: + iwpriv ethX settxant 0x01: select Antenna 1. + +gettxant + This command is used to get the mode for Tx antenna. + +authalgs + This command is used by the WPA supplicant to set the authentication + algorithms in the station. + +8021xauthalgs + This command is used by the WPA supplicant to set the 8021.x authentication algorithm type + station. + + where values can be:- + 1 -- None + 2 -- LEAP + 4 -- TLS + 8 -- TTLs + 16 -- MD5 + + +encryptionmode + This command is used by the WPA supplicant to set the encryption algorithm. + + where values can be:- + 0 -- NONE + 1 -- WEP40 + 2 -- TKIP + 3 -- CCMP + 4 -- WEP104 + +pre-TBTT + This command is used to set pre-TBTT time period where value is in microseconds. + +setregioncode + This command is used to set the region code in the station. + where value is 'region code' for various regions like + USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ... + + Usage: + iwpriv ethX setregioncode 0x10: set region code to USA (0x10). + +getregioncode + This command is used to get the region code information set in the + station. + +setbcnavg + Set the weighting factor for calculating RSSI. + +getbcnavg + Get weighting factor for calculating RSSI. + +setdataavg + Set the weighting factor for calculating SNR. + +setlisteninter + This command is used to set the listen interval in the + station. + + where the value ranges between 1 - 255 + +getlisteninter + This command is used to get the listen interval value set in the + station. + +setmultipledtim + This command is used to set the multiple dtim value in the + station. + where the value is 1,2,3,4,5,0xfffe + 0xfffe means the firmware will use listen interval in association + command for waking up + +getmultipledtim + This command is used to get the multiple dtim value set in the station. + +atimwindow + This command is used to set the atim value in the + station. + + where the value ranges between 0 - 50 + +deauth + This command is used to send the de-authentication to the AP with which + the station is associated. This command is valid only when + station is in Infrastructure mode. + + Note: This command is available only when STA is connected. + +adhocstop + This command is used to stop beacon transmission from the station and + go into idle state in ad-hoc mode. + + Note: This command is available only when STA is connected. + +radioon + This command is used to turn on the RF antenna. + +radiooff + This command is sued to turn off the RF antenna. + +scanmode + This command is used to set the station to scan for either IBSS + networks or BSS networks or both BSS and IBSS networks. This + command can be used with sub commands, + + where the value for + bss -- Scan All the BSS networks. + ibss -- Scan All the IBSS networks. + any -- Scan both BSS and IBSS networks. + + + +setwpaie + This command is used by WPA supplicant to send the WPA-IE to the driver. + +wlanidle-off + This command is used to get into idle state. + + Note: This command is available only when STA is connected. + +wlanidle-on + This command is used to get off the idle state. + + Note: This command is available only when STA is connected. + + +getlog + This command is used to get the 802.11 statistics available in the + station. + + Note: This command is available only when STA is connected. + +getadhocstatus + This command is used to get the ad-hoc Network Status. + + The various status codes are: + AdhocStarted + AdhocJoined + AdhocIdle + InfraMode + AutoUnknownMode + + Note: This command is available only when STA is connected. + +adhocgrate + This command is used to enable(1) g_rate, Disable(0) g_rate + and request(2) the status which g_rate is disabled/enabled, + for Ad-hoc creator. + + where value is:- + 0 -- Disabled + 1 -- Enabled + 2 -- Get + +ledgpio + This command is used to set/get LEDs. + + iwpriv ethX ledgpio + will set the corresponding LED for the GPIO Line. + + iwpriv ethX ledgpio + will give u which LEDs are Enabled. + + Usage: + iwpriv eth1 ledgpio 1 0 2 1 3 4 + will enable + LED 1 -> GPIO 0 + LED 2 -> GPIO 1 + LED 3 -> GPIO 4 + + iwpriv eth1 ledgpio + shows LED information in the format as mentioned above. + + Note: LED0 is invalid + Note: Maximum Number of LEDs are 16. + +inactivityto + This command is used by the host to set/get the inactivity timeout value, + which specifies when WLAN device is put to sleep. + + Usage: + iwpriv ethX inactivityto [] + + where the parameter are: + timeout: timeout value in milliseconds. + + Example: + iwpriv eth1 inactivityto + "get the timeout value" + + iwpriv eth1 inactivityto X + "set timeout value to X ms" + + +sleeppd + This command is used to configure the sleep period of the WLAN device. + + Usage: + iwpriv ethX sleeppd [] + + where the parameter are: + Period: sleep period in milliseconds. Range 10~60. + + Example: + iwpriv eth1 sleeppd 10 + "set period as 10 ms" + iwpriv eth1 sleeppd + "get the sleep period configuration" + +enable11d + This command is used to control 11d + where value is:- + 1 -- Enabled + 0 -- Disabled + 2 -- Get + + + + +tpccfg + Enables or disables automatic transmit power control. + + The first parameter turns this feature on (1) or off (0). When turning + on, the user must also supply four more parameters in the following + order: + -UseSNR (Use SNR (in addition to PER) for TPC algorithm), + -P0 (P0 power level for TPC), + -P1 (P1 power level for TPC), + -P2 (P2 power level for TPC). + + Usage: + iwpriv ethX tpccfg: Get current configuration + iwpriv ethX tpccfg 0: disable auto TPC + iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR; + P0=0x05; P1=0x0a; P2=0x0d; + iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR; + P0=0x05; P1=0x0a; P2=0x0d. + +powercfg + Enables or disables power adaptation. + + The first parameter turns this feature on (1) or off (0). When turning + on, the user must also supply three more parameters in the following + order: + -P0 (P0 power level for Power Adaptation), + -P1 (P1 power level for Power Adaptation), + -P2 (P2 power level for Power Adaptation). + + Usage: + iwpriv ethX powercfg: Get current configuration + iwpriv ethX powercfg 0: disable power adaptation + iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation; + P0=0x0d; P1=0x0f; P2=0x12. + +getafc + This command returns automatic frequency control parameters. It returns + three integers: + -P0: automatic is on (1), or off (0), + -P1: current timing offset in PPM (part per million), and + -P2: current frequency offset in PPM. + +setafc + Set automatic frequency control options. + + The first parameter turns automatic on (1) or off (0). + The user must supply two more parameters in either case, in the following + order: + + When auto is on: + + -P0 (automatic adjustment frequency threshold in PPM), + -P1 (automatic adjustment period in beacon period), + + When auto is off: + + -P0 (manual adjustment timing offset in PPM), and + -P1 (manual adjustment frequency offset in PPM). + + Usage: + iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy + offset are 10 PPM. + + iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment, + frequency threshold 10 PPM, for every 10 beacon periods. + + + +scanprobes + This command sets number of probe requests per channel. + + Usage: + iwpriv ethX scanprobes 3 (set scan probes to 3) + iwpriv ethX scanprobes (get scan probes) + +lolisteninter + This command sets the value of listen interval. + + Usage: + iwpriv ethX lolisteninter 234 (set the lolisteninter to 234) + iwpriv ethX lolisteninter (get the lolisteninter value) + +rateadapt + This command sets the data rates bitmap. + Where + 0: Disable auto rate adapt + 1: Enable auto rate adapt + + + data rate bitmap + Bit Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 12-15 Reserved + + Usage: + iwpriv ethX rateadapt + read the currect data rate setting + iwpriv ethX rateadapt 1 0x07 + enable auto data rate adapt and + data rates are 1Mbps, 2Mbsp and 5.5Mbps + + +txcontrol + This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis. + + Where value is: + if bit[4] == 1: + bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16 + Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv + + bit[12:8] + if bit[12] == 1, bit[11:8] specifies the Tx retry limit. + + bit[14:13] specifies per packet ack policy: + bit[14:13] + 1 0 use immediate ack policy for this packet + 1 1 use no ack policy for this packet + 0 x use the per-packet ack policy setting + + Usage: + iwpriv ethX txcontrol 0x7513 + Use no-ack policy, 5 retires for Tx, 11Mbps rate + + + +psnullinterval + This command is used to set/request NULL package interval for Power Save + under infrastructure mode. + + where value is:- + -1 -- Disabled + n>0 -- Set interval as n (seconds) + +prescan + This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap + + where value is:- + 0 -- Disabled + 1 -- Enabled + 2 -- Get + +getrxinfo + This command gets non average value of Signal to Noise Ratio of Data and rate index. + + The following table shows RateIndex and Rate + + RateIndex Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 13-15 Reserved + +gettxrate + This command gets current Tx rate index of the first packet associated with Rate Adaptation. + + The following table shows RateIndex and Rate + + RateIndex Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 13-15 Reserved + +bcninterval + This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc + beacon interval when no argument is given. The valid beacon interval is between 20 - 1000, + default beacon interval is 100. + + Usage: + iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100) + iwpriv ethX bcninterval (get adhoc beacon interval) + +fwt_add + This command is used to insert an entry into the FWT table. The list of + parameters must follow the following structure: + + iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr] + + The parameters between brackets are optional, but they must appear in + the order specified. For example, if you want to specify the metric, + you must also specify the dir, ssn, and dsn but you need not specify the + hopcount, expiration, sleepmode, or snr. Any unspecified parameters + will be assigned the defaults specified below. + + The different parameters are:- + da -- DA MAC address in the form 00:11:22:33:44:55 + ra -- RA MAC address in the form 00:11:22:33:44:55 + metric -- route metric (cost: smaller-metric routes are + preferred, default is 0) + dir -- direction (1 for direct, 0 for reverse, + default is 1) + ssn -- Source Sequence Number (time at the RA for + reverse routes. Default is 0) + dsn -- Destination Sequence Number (time at the DA + for direct routes. Default is 0) + hopcount -- hop count (currently unused, default is 0) + ttl -- TTL (Only used in reverse entries) + expiration -- entry expiration (in ticks, where a tick is + 1024us, or ~ 1ms. Use 0 for an indefinite + entry, default is 0) + sleepmode -- RA's sleep mode (currently unused, default is + 0) + snr -- SNR in the link to RA (currently unused, + default is 0) + + The command does not return anything. + +fwt_del + This command is used to remove an entry to the FWT table. The list of + parameters must follow the following structure: + + iwpriv ethX fwt_del da ra [dir] + + where the different parameters are:- + da -- DA MAC address (in the form "00:11:22:33:44:55") + ra -- RA MAC address (in the form "00:11:22:33:44:55") + dir -- direction (1 for direct, 0 for reverse, + default is 1) + + The command does not return anything. + +fwt_lookup + This command is used to get the best route in the FWT table to a given + host. The only parameter is the MAC address of the host that is being + looked for. + + iwpriv ethX fwt_lookup da + + where:- + da -- DA MAC address (in the form "00:11:22:33:44:55") + + The command returns an output string identical to the one returned by + fwt_list described below. + + +fwt_list + This command is used to list a route from the FWT table. The only + parameter is the index into the table. If you want to list all the + routes in a table, start with index=0, and keep listing until you get a + "(null)" string. Note that the indicies may change as the fwt is + updated. It is expected that most users will not use fwt_list directly, + but that a utility similar to the traditional route command will be used + to invoke fwt_list over and over. + + iwpriv ethX fwt_list index + + The output is a string of the following form: + + da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr + + where the different fields are:- + da -- DA MAC address (in the form "00:11:22:33:44:55") + ra -- RA MAC address (in the form "00:11:22:33:44:55") + metric -- route metric (cost: smaller-metric routes are preferred) + dir -- direction (1 for direct, 0 for reverse) + ssn -- Source Sequence Number (time at the RA for reverse routes) + dsn -- Destination Sequence Number (time at the DA for direct routes) + hopcount -- hop count (currently unused) + ttl -- TTL (only used in reverse entries) + expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) + sleepmode -- RA's sleep mode (currently unused) + snr -- SNR in the link to RA (currently unused) + +fwt_list_route + This command is used to list a route from the FWT table. The only + parameter is the route ID. If you want to list all the routes in a + table, start with rid=0, and keep incrementing rid until you get a + "(null)" string. This function is similar to fwt_list. The only + difference is the output format. Also note that this command is meant + for debugging. It is expected that users will use fwt_lookup and + fwt_list. One important reason for this is that the route id may change + as the route table is altered. + + iwpriv ethX fwt_list_route rid + + The output is a string of the following form: + + da metric dir nid ssn dsn hopcount ttl expiration + + where the different fields are:- + da -- DA MAC address (in the form "00:11:22:33:44:55") + metric -- route metric (cost: smaller-metric routes are preferred) + dir -- direction (1 for direct, 0 for reverse) + nid -- Next-hop (neighbor) host ID (nid) + ssn -- Source Sequence Number (time at the RA for reverse routes) + dsn -- Destination Sequence Number (time at the DA for direct routes) + hopcount -- hop count (currently unused) + ttl -- TTL count (only used in reverse entries) + expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) + +fwt_list_neigh + This command is used to list a neighbor from the FWT table. The only + parameter is the neighbor ID. If you want to list all the neighbors in a + table, start with nid=0, and keep incrementing nid until you get a + "(null)" string. Note that the nid from a fwt_list_route command can be + used as an input to this command. Also note that this command is meant + mostly for debugging. It is expected that users will use fwt_lookup. + One important reason for this is that the neighbor id may change as the + neighbor table is altered. + + iwpriv ethX fwt_list_neigh nid + + The output is a string of the following form: + + ra sleepmode snr references + + where the different fields are:- + ra -- RA MAC address (in the form "00:11:22:33:44:55") + sleepmode -- RA's sleep mode (currently unused) + snr -- SNR in the link to RA (currently unused) + references -- RA's reference counter + +fwt_reset + This command is used to reset the FWT table, getting rid of all the + entries. There are no input parameters. + + iwpriv ethX fwt_reset + + The command does not return anything. + +fwt_cleanup + This command is used to perform user-based garbage recollection. The + FWT table is checked, and all the entries that are expired or invalid + are cleaned. Note that this is exported to the driver for debugging + purposes, as garbage collection is also fired by the firmware when in + space problems. There are no input parameters. + + iwpriv ethX fwt_cleanup + + The command does returns the number of invalid/expired routes deleted. + +fwt_time + This command returns a card's internal time representation. It is this + time that is used to represent the expiration times of FWT entries. The + number is not consistent from card to card; it is simply a timer count. + The fwt_time command is used to inspect the timer so that expiration + times reported by fwt_list can be properly interpreted. + + iwpriv ethX fwt_time + +mesh_get_ttl + + The mesh ttl is the number of hops a mesh packet can traverse before it + is dropped. This parameter is used to prevent infinite loops in the + mesh network. The value returned by this function is the ttl assigned + to all mesh packets. Currently there is no way to control the ttl on a + per packet or per socket basis. + + iwpriv ethX mesh_get_ttl + +mesh_set_ttl ttl + + Set the ttl. The argument must be between 0 and 255. + + iwpriv ethX mesh_set_ttl + +========================= +ETHTOOL +========================= + + +Use the -i option to retrieve version information from the driver. + +# ethtool -i eth0 +driver: libertas +version: COMM-USB8388-318.p4 +firmware-version: 5.110.7 +bus-info: + +Use the -e option to read the EEPROM contents of the card. + + Usage: + ethtool -e ethX [raw on|off] [offset N] [length N] + + -e retrieves and prints an EEPROM dump for the specified ethernet + device. When raw is enabled, then it dumps the raw EEPROM data + to stdout. The length and offset parameters allow dumping cer- + tain portions of the EEPROM. Default is to dump the entire EEP- + ROM. + +# ethtool -e eth0 offset 0 length 16 +Offset Values +------ ------ +0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00 + +======================== +DEBUGFS COMMANDS +======================== + +those commands are used via debugfs interface + +=========== +rdmac +rdbbp +rdrf + These commands are used to read the MAC, BBP and RF registers from the + card. These commands take one parameter that specifies the offset + 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/ + + Usage: + echo "0xa123" > rdmac ; cat rdmac + echo "0xa123" > rdbbp ; cat rdbbp + echo "0xa123" > rdrf ; cat rdrf +wrmac +wrbbp +wrrf + These commands are used to write the MAC, BBP and RF registers in the + card. These commands take two parameters that specify the offset + location and the value that is to be written. This parameters must + be specified in hexadecimal (its possible to preceed the number + with a "0x"). + + Usage: + echo "0xa123 0xaa" > wrmac + echo "0xa123 0xaa" > wrbbp + echo "0xa123 0xaa" > wrrf + +sleepparams + This command is used to set the sleepclock configurations + + Path: /debugfs/libertas_wireless/ethX/ + + Usage: + cat sleepparams: reads the current sleepclock configuration + + echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration. + + where: + p1 is Sleep clock error in ppm (0-65535) + p2 is Wakeup offset in usec (0-65535) + p3 is Clock stabilization time in usec (0-65535) + p4 is Control periodic calibration (0-2) + p5 is Control the use of external sleep clock (0-2) + p6 is reserved for debug (0-65535) + +subscribed_events + + The subscribed_events directory contains the interface for the + subscribed events API. + + Path: /debugfs/libertas_wireless/ethX/subscribed_events/ + + Each event is represented by a filename. Each filename consists of the + following three fields: + Value Frequency Subscribed + + To read the current values for a given event, do: + cat event + To set the current values, do: + echo "60 2 1" > event + + Frequency field specifies the reporting frequency for this event. + If it is set to 0, then the event is reported only once, and then + automatically unsubscribed. If it is set to 1, then the event is + reported every time it occurs. If it is set to N, then the event is + reported every Nth time it occurs. + + beacon_missed + Value field specifies the number of consecutive missing beacons which + triggers the LINK_LOSS event. This event is generated only once after + which the firmware resets its state. At initialization, the LINK_LOSS + event is subscribed by default. The default value of MissedBeacons is + 60. + + failure_count + Value field specifies the consecutive failure count threshold which + triggers the generation of the MAX_FAIL event. Once this event is + generated, the consecutive failure count is reset to 0. + At initialization, the MAX_FAIL event is NOT subscribed by + default. + + high_rssi + This event is generated when the average received RSSI in beacons goes + above a threshold, specified by Value. + + low_rssi + This event is generated when the average received RSSI in beacons goes + below a threshold, specified by Value. + + high_snr + This event is generated when the average received SNR in beacons goes + above a threshold, specified by Value. + + low_snr + This event is generated when the average received SNR in beacons goes + below a threshold, specified by Value. + +extscan + This command is used to do a specific scan. + + Path: /debugfs/libertas_wireless/ethX/ + + Usage: echo "SSID" > extscan + + Example: + echo "LINKSYS-AP" > extscan + + To see the results of use getscantable command. + +getscantable + + Display the current contents of the driver scan table (ie. get the + scan results). + + Path: /debugfs/libertas_wireless/ethX/ + + Usage: + cat getscantable + +setuserscan + Initiate a customized scan and retrieve the results + + + Path: /debugfs/libertas_wireless/ethX/ + + Usage: + echo "[ARGS]" > setuserscan + + where [ARGS]: + + chan=[chan#][band][mode] where band is [a,b,g] and mode is + blank for active or 'p' for passive + bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan + ssid="[SSID]" specify a SSID filter for the scan + keep=[0 or 1] keep the previous scan results (1), discard (0) + dur=[scan time] time to scan for each channel in milliseconds + probes=[#] number of probe requests to send on each chan + type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) + + Any combination of the above arguments can be supplied on the command line. + If the chan token is absent, a full channel scan will be completed by + the driver. If the dur or probes tokens are absent, the driver default + setting will be used. The bssid and ssid fields, if blank, + will produce an unfiltered scan. The type field will default to 3 (Any) + and the keep field will default to 0 (Discard). + + Examples: + 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: + echo "chan=1g,6g,11g" > setuserscan + + 2) Perform a passive scan on channel 11 for 20 ms: + echo "chan=11gp dur=20" > setuserscan + + 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on + channel 36 in the 'a' band: + + echo "chan=1g,6g,11g,36ap" > setuserscan + + 4) Perform an active scan on channel 6 and 36 for a specific SSID: + echo "chan=6g,36a ssid="TestAP"" > setuserscan + + 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep + the current scan table intact, update existing or append new scan data: + echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan + + 6) Scan channel 6, for all infrastructure networks, sending two probe + requests. Keep the previous scan table intact. Update any duplicate + BSSID/SSID matches with the new scan data: + echo "chan=6g type=1 probes=2 keep=1" > setuserscan + + All entries in the scan table (not just the new scan data when keep=1) + will be displayed upon completion by use of the getscantable ioctl. + +============================================================================== diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c new file mode 100644 index 0000000..b55c7f5 --- /dev/null +++ b/drivers/net/wireless/libertas/assoc.c @@ -0,0 +1,588 @@ +/* Copyright (C) 2006, Red Hat, Inc. */ + +#include +#include + +#include "assoc.h" +#include "join.h" +#include "decl.h" +#include "hostcmd.h" +#include "host.h" + + +static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static int assoc_helper_essid(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + int i; + + ENTER(); + + lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid); + if (assoc_req->mode == wlan802_11infrastructure) { + if (adapter->prescan) { + libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1); + } + + i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, + NULL, wlan802_11infrastructure); + if (i >= 0) { + lbs_pr_debug(1, + "SSID found in scan list ... associating...\n"); + + ret = wlan_associate(priv, &adapter->scantable[i]); + if (ret == 0) { + memcpy(&assoc_req->bssid, + &adapter->scantable[i].macaddress, + ETH_ALEN); + } + } else { + lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n", + assoc_req->ssid.ssid); + } + } else if (assoc_req->mode == wlan802_11ibss) { + /* Scan for the network, do not save previous results. Stale + * scan data will cause us to join a non-existant adhoc network + */ + libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0); + + /* Search for the requested SSID in the scan table */ + i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL, + wlan802_11ibss); + if (i >= 0) { + lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret); + libertas_join_adhoc_network(priv, &adapter->scantable[i]); + } else { + /* else send START command */ + lbs_pr_debug(1, "SSID not found in list, so creating adhoc" + " with SSID '%s'\n", assoc_req->ssid.ssid); + libertas_start_adhoc_network(priv, &assoc_req->ssid); + } + memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN); + } + + LEAVE(); + return ret; +} + + +static int assoc_helper_bssid(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int i, ret = 0; + + ENTER(); + + lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n", + MAC_ARG(assoc_req->bssid)); + + /* Search for index position in list for requested MAC */ + i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid, + assoc_req->mode); + if (i < 0) { + lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, " + "cannot associate.\n", MAC_ARG(assoc_req->bssid)); + goto out; + } + + if (assoc_req->mode == wlan802_11infrastructure) { + ret = wlan_associate(priv, &adapter->scantable[i]); + lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret); + } else if (assoc_req->mode == wlan802_11ibss) { + libertas_join_adhoc_network(priv, &adapter->scantable[i]); + } + memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid, + sizeof(struct WLAN_802_11_SSID)); + +out: + LEAVE(); + return ret; +} + + +static int assoc_helper_associate(wlan_private *priv, + struct assoc_request * assoc_req) +{ + int ret = 0, done = 0; + + /* If we're given and 'any' BSSID, try associating based on SSID */ + + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { + if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN) + && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) { + ret = assoc_helper_bssid(priv, assoc_req); + done = 1; + if (ret) { + lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); + } + } + } + + if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + ret = assoc_helper_essid(priv, assoc_req); + if (ret) { + lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); + } + } + + return ret; +} + + +static int assoc_helper_mode(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + if (assoc_req->mode == adapter->inframode) { + LEAVE(); + return 0; + } + + if (assoc_req->mode == wlan802_11infrastructure) { + if (adapter->psstate != PS_STATE_FULL_POWER) + libertas_ps_wakeup(priv, cmd_option_waitforrsp); + adapter->psmode = wlan802_11powermodecam; + } + + adapter->inframode = assoc_req->mode; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_snmp_mib, + 0, cmd_option_waitforrsp, + OID_802_11_INFRASTRUCTURE_MODE, + (void *) assoc_req->mode); + + LEAVE(); + return ret; +} + + +static int assoc_helper_wep_keys(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int i; + int ret = 0; + + ENTER(); + + /* Set or remove WEP keys */ + if ( assoc_req->wep_keys[0].len + || assoc_req->wep_keys[1].len + || assoc_req->wep_keys[2].len + || assoc_req->wep_keys[3].len) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_set_wep, + cmd_act_add, + cmd_option_waitforrsp, + 0, assoc_req); + } else { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_set_wep, + cmd_act_remove, + cmd_option_waitforrsp, + 0, NULL); + } + + if (ret) + goto out; + + /* enable/disable the MAC's WEP packet filter */ + if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled) + adapter->currentpacketfilter |= cmd_act_mac_wep_enable; + else + adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; + ret = libertas_set_mac_packet_filter(priv); + if (ret) + goto out; + + mutex_lock(&adapter->lock); + + /* Copy WEP keys into adapter wep key fields */ + for (i = 0; i < 4; i++) { + memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], + sizeof(struct WLAN_802_11_KEY)); + } + adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; + + mutex_unlock(&adapter->lock); + +out: + LEAVE(); + return ret; +} + +static int assoc_helper_secinfo(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + memcpy(&adapter->secinfo, &assoc_req->secinfo, + sizeof(struct wlan_802_11_security)); + + ret = libertas_set_mac_packet_filter(priv); + + LEAVE(); + return ret; +} + + +static int assoc_helper_wpa_keys(wlan_private *priv, + struct assoc_request * assoc_req) +{ + int ret = 0; + + ENTER(); + + /* enable/Disable RSN */ + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_enable_rsn, + cmd_act_set, + cmd_option_waitforrsp, + 0, assoc_req); + if (ret) + goto out; + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_key_material, + cmd_act_set, + cmd_option_waitforrsp, + 0, assoc_req); + +out: + LEAVE(); + return ret; +} + + +static int assoc_helper_wpa_ie(wlan_private *priv, + struct assoc_request * assoc_req) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { + memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); + adapter->wpa_ie_len = assoc_req->wpa_ie_len; + } else { + memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN); + adapter->wpa_ie_len = 0; + } + + LEAVE(); + return ret; +} + + +static int should_deauth_infrastructure(wlan_adapter *adapter, + struct assoc_request * assoc_req) +{ + if (adapter->connect_status != libertas_connected) + return 0; + + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + lbs_pr_debug(1, "Deauthenticating due to new SSID in " + " configuration request.\n"); + return 1; + } + + if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { + if (adapter->secinfo.authmode != + assoc_req->secinfo.authmode) { + lbs_pr_debug(1, "Deauthenticating due to updated security " + "info in configuration request.\n"); + return 1; + } + } + + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { + lbs_pr_debug(1, "Deauthenticating due to new BSSID in " + " configuration request.\n"); + return 1; + } + + /* FIXME: deal with 'auto' mode somehow */ + if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { + if (assoc_req->mode != wlan802_11infrastructure) + return 1; + } + + return 0; +} + + +static int should_stop_adhoc(wlan_adapter *adapter, + struct assoc_request * assoc_req) +{ + if (adapter->connect_status != libertas_connected) + return 0; + + if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength) + return 1; + if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid, + sizeof(struct WLAN_802_11_SSID))) + return 1; + + /* FIXME: deal with 'auto' mode somehow */ + if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { + if (assoc_req->mode != wlan802_11ibss) + return 1; + } + + return 0; +} + + +void wlan_association_worker(struct work_struct *work) +{ + wlan_private *priv = container_of(work, wlan_private, assoc_work.work); + wlan_adapter *adapter = priv->adapter; + struct assoc_request * assoc_req = NULL; + int ret = 0; + int find_any_ssid = 0; + + ENTER(); + + mutex_lock(&adapter->lock); + assoc_req = adapter->assoc_req; + adapter->assoc_req = NULL; + mutex_unlock(&adapter->lock); + + if (!assoc_req) { + LEAVE(); + return; + } + + lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n", + assoc_req->flags); + + /* If 'any' SSID was specified, find an SSID to associate with */ + if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) + && !assoc_req->ssid.ssidlength) + find_any_ssid = 1; + + /* But don't use 'any' SSID if there's a valid locked BSSID to use */ + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { + if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN) + && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN)) + find_any_ssid = 0; + } + + if (find_any_ssid) { + enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; + + ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid, + assoc_req->mode, &new_mode); + if (ret) { + lbs_pr_debug(1, "Could not find best network\n"); + ret = -ENETUNREACH; + goto out; + } + + /* Ensure we switch to the mode of the AP */ + if (assoc_req->mode == wlan802_11autounknown) { + set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); + assoc_req->mode = new_mode; + } + } + + /* + * Check if the attributes being changing require deauthentication + * from the currently associated infrastructure access point. + */ + if (adapter->inframode == wlan802_11infrastructure) { + if (should_deauth_infrastructure(adapter, assoc_req)) { + ret = libertas_send_deauthentication(priv); + if (ret) { + lbs_pr_debug(1, "Deauthentication due to new " + "configuration request failed: %d\n", + ret); + } + } + } else if (adapter->inframode == wlan802_11ibss) { + if (should_stop_adhoc(adapter, assoc_req)) { + ret = libertas_stop_adhoc_network(priv); + if (ret) { + lbs_pr_debug(1, "Teardown of AdHoc network due to " + "new configuration request failed: %d\n", + ret); + } + + } + } + + /* Send the various configuration bits to the firmware */ + if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { + ret = assoc_helper_mode(priv, assoc_req); + if (ret) { +lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); + goto out; + } + } + + if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { + ret = assoc_helper_wep_keys(priv, assoc_req); + if (ret) { +lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); + goto out; + } + } + + if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { + ret = assoc_helper_secinfo(priv, assoc_req); + if (ret) { +lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); + goto out; + } + } + + if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { + ret = assoc_helper_wpa_ie(priv, assoc_req); + if (ret) { +lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); + goto out; + } + } + + if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) + || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + ret = assoc_helper_wpa_keys(priv, assoc_req); + if (ret) { +lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); + goto out; + } + } + + /* SSID/BSSID should be the _last_ config option set, because they + * trigger the association attempt. + */ + if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) + || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + int success = 1; + + ret = assoc_helper_associate(priv, assoc_req); + if (ret) { + lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n", + ret); + success = 0; + } + + if (adapter->connect_status != libertas_connected) { + lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, " + "not connected.\n"); + success = 0; + } + + if (success) { + lbs_pr_debug(1, "ASSOC: association attempt successful. " + "Associated to '%s' (" MAC_FMT ")\n", + assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid)); + libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, cmd_option_waitforrsp, 0, NULL); + + libertas_prepare_and_send_command(priv, + cmd_802_11_get_log, + 0, cmd_option_waitforrsp, 0, NULL); + } else { + + ret = -1; + } + } + +out: + if (ret) { + lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n", + ret); + } + kfree(assoc_req); + LEAVE(); +} + + +/* + * Caller MUST hold any necessary locks + */ +struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) +{ + struct assoc_request * assoc_req; + + if (!adapter->assoc_req) { + adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL); + if (!adapter->assoc_req) { + lbs_pr_info("Not enough memory to allocate association" + " request!\n"); + return NULL; + } + } + + /* Copy current configuration attributes to the association request, + * but don't overwrite any that are already set. + */ + assoc_req = adapter->assoc_req; + if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { + memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid, + adapter->curbssparams.ssid.ssidlength); + } + + if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) + assoc_req->channel = adapter->curbssparams.channel; + + if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) + assoc_req->mode = adapter->inframode; + + if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { + memcpy(&assoc_req->bssid, adapter->curbssparams.bssid, + ETH_ALEN); + } + + if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { + int i; + for (i = 0; i < 4; i++) { + memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], + sizeof(struct WLAN_802_11_KEY)); + } + } + + if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) + assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx; + + if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { + memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, + sizeof(struct WLAN_802_11_KEY)); + } + + if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { + memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, + sizeof(struct WLAN_802_11_KEY)); + } + + if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { + memcpy(&assoc_req->secinfo, &adapter->secinfo, + sizeof(struct wlan_802_11_security)); + } + + if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { + memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie, + MAX_WPA_IE_LEN); + assoc_req->wpa_ie_len = adapter->wpa_ie_len; + } + + return assoc_req; +} + + diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h new file mode 100644 index 0000000..2ffd82d --- /dev/null +++ b/drivers/net/wireless/libertas/assoc.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2006, Red Hat, Inc. */ + +#ifndef _WLAN_ASSOC_H_ +#define _WLAN_ASSOC_H_ + +#include "dev.h" + +void wlan_association_worker(struct work_struct *work); + +struct assoc_request * wlan_get_association_request(wlan_adapter *adapter); + +#define ASSOC_DELAY (HZ / 2) +static inline void wlan_postpone_association_work(wlan_private *priv) +{ + if (priv->adapter->surpriseremoved) + return; + cancel_delayed_work(&priv->assoc_work); + queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); +} + +static inline void wlan_cancel_association_work(wlan_private *priv) +{ + cancel_delayed_work(&priv->assoc_work); + if (priv->adapter->assoc_req) { + kfree(priv->adapter->assoc_req); + priv->adapter->assoc_req = NULL; + } +} + +#endif /* _WLAN_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c new file mode 100644 index 0000000..bfdac58 --- /dev/null +++ b/drivers/net/wireless/libertas/cmd.c @@ -0,0 +1,1958 @@ +/** + * This file contains the handling of command. + * It prepares command and sends it to firmware when it is ready. + */ + +#include +#include "host.h" +#include "hostcmd.h" +#include "sbi.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "wext.h" + +static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); + +static u16 commands_allowed_in_ps[] = { + cmd_802_11_rssi, +}; + +/** + * @brief This function checks if the commans is allowed + * in PS mode not. + * + * @param command the command ID + * @return TRUE or FALSE + */ +static u8 is_command_allowed_in_ps(u16 command) +{ + int count = sizeof(commands_allowed_in_ps) + / sizeof(commands_allowed_in_ps[0]); + int i; + + for (i = 0; i < count; i++) { + if (command == cpu_to_le16(commands_allowed_in_ps[i])) + return 1; + } + + return 0; +} + +static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) +{ + struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_get_hw_spec); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); + memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_ps_mode(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; + u16 action = cmd_action; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_802_11_ps_mode); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + + S_DS_GEN); + psm->action = cpu_to_le16(cmd_action); + psm->multipledtim = 0; + switch (action) { + case cmd_subcmd_enter_ps: + lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n"); + lbs_pr_debug(1, "locallisteninterval = %d\n", + adapter->locallisteninterval); + + psm->locallisteninterval = + cpu_to_le16(adapter->locallisteninterval); + psm->nullpktinterval = + cpu_to_le16(adapter->nullpktinterval); + psm->multipledtim = + cpu_to_le16(priv->adapter->multipledtim); + break; + + case cmd_subcmd_exit_ps: + lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n"); + break; + + case cmd_subcmd_sleep_confirmed: + lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n"); + break; + + default: + break; + } + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + u16 *timeout = pdata_buf; + + cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) + + S_DS_GEN); + + cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action); + + if (cmd_action) + cmd->params.inactivity_timeout.timeout = + cpu_to_le16(*timeout); + else + cmd->params.inactivity_timeout.timeout = 0; + + return 0; +} + +static int wlan_cmd_802_11_sleep_params(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params; + + ENTER(); + + cmd->size = + cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + + S_DS_GEN); + cmd->command = cpu_to_le16(cmd_802_11_sleep_params); + + if (cmd_action == cmd_act_get) { + memset(&adapter->sp, 0, sizeof(struct sleep_params)); + memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); + sp->action = cpu_to_le16(cmd_action); + } else if (cmd_action == cmd_act_set) { + sp->action = cpu_to_le16(cmd_action); + sp->error = cpu_to_le16(adapter->sp.sp_error); + sp->offset = cpu_to_le16(adapter->sp.sp_offset); + sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime); + sp->calcontrol = (u8) adapter->sp.sp_calcontrol; + sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk; + sp->reserved = cpu_to_le16(adapter->sp.sp_reserved); + } + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_set_wep(wlan_private * priv, + struct cmd_ds_command *cmd, + u32 cmd_act, + void * pdata_buf) +{ + struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct assoc_request * assoc_req = pdata_buf; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_802_11_set_wep); + cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep)) + + S_DS_GEN); + + if (cmd_act == cmd_act_add) { + int i; + + if (!assoc_req) { + lbs_pr_debug(1, "Invalid association request!"); + ret = -1; + goto done; + } + + wep->action = cpu_to_le16(cmd_act_add); + + /* default tx key index */ + wep->keyindex = cpu_to_le16((u16) + (assoc_req->wep_tx_keyidx & + (u32)cmd_WEP_KEY_INDEX_MASK)); + + lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex); + + /* Copy key types and material to host command structure */ + for (i = 0; i < 4; i++) { + struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i]; + + switch (pkey->len) { + case KEY_LEN_WEP_40: + wep->keytype[i] = cmd_type_wep_40_bit; + memmove(&wep->keymaterial[i], pkey->key, + pkey->len); + break; + case KEY_LEN_WEP_104: + wep->keytype[i] = cmd_type_wep_104_bit; + memmove(&wep->keymaterial[i], pkey->key, + pkey->len); + break; + case 0: + break; + default: + lbs_pr_debug(1, "Invalid WEP key %d length of %d\n", + i, pkey->len); + ret = -1; + goto done; + break; + } + } + } else if (cmd_act == cmd_act_remove) { + /* ACT_REMOVE clears _all_ WEP keys */ + wep->action = cpu_to_le16(cmd_act_remove); + + /* default tx key index */ + wep->keyindex = cpu_to_le16((u16) + (adapter->wep_tx_keyidx & + (u32)cmd_WEP_KEY_INDEX_MASK)); + } + + ret = 0; + +done: + LEAVE(); + return ret; +} + +static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn; + wlan_adapter *adapter = priv->adapter; + + cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) + + S_DS_GEN); + penableRSN->action = cpu_to_le16(cmd_action); + if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { + penableRSN->enable = cpu_to_le16(cmd_enable_rsn); + } else { + penableRSN->enable = cpu_to_le16(cmd_disable_rsn); + } + + return 0; +} + + +static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, + struct WLAN_802_11_KEY * pkey) +{ + pkeyparamset->keytypeid = cpu_to_le16(pkey->type); + + if (pkey->flags & KEY_INFO_WPA_ENABLED) { + pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED); + } else { + pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED); + } + + if (pkey->flags & KEY_INFO_WPA_UNICAST) { + pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); + } else if (pkey->flags & KEY_INFO_WPA_MCAST) { + pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); + } + + pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + pkeyparamset->keylen = cpu_to_le16(pkey->len); + memcpy(pkeyparamset->key, pkey->key, pkey->len); + pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) + + sizeof(pkeyparamset->keyinfo) + + sizeof(pkeyparamset->keylen) + + sizeof(pkeyparamset->key)); +} + +static int wlan_cmd_802_11_key_material(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, + u32 cmd_oid, void *pdata_buf) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_key_material *pkeymaterial = + &cmd->params.keymaterial; + int ret = 0; + int index = 0; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_802_11_key_material); + pkeymaterial->action = cpu_to_le16(cmd_action); + + if (cmd_action == cmd_act_get) { + cmd->size = cpu_to_le16( S_DS_GEN + + sizeof (pkeymaterial->action)); + ret = 0; + goto done; + } + + memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); + + if (adapter->wpa_unicast_key.len) { + set_one_wpa_key(&pkeymaterial->keyParamSet[index], + &adapter->wpa_unicast_key); + index++; + } + + if (adapter->wpa_mcast_key.len) { + set_one_wpa_key(&pkeymaterial->keyParamSet[index], + &adapter->wpa_mcast_key); + index++; + } + + cmd->size = cpu_to_le16( S_DS_GEN + + sizeof (pkeymaterial->action) + + index * sizeof(struct MrvlIEtype_keyParamSet)); + + ret = 0; + +done: + LEAVE(); + return ret; +} + +static int wlan_cmd_802_11_reset(wlan_private * priv, + struct cmd_ds_command *cmd, int cmd_action) +{ + struct cmd_ds_802_11_reset *reset = &cmd->params.reset; + + cmd->command = cpu_to_le16(cmd_802_11_reset); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); + reset->action = cpu_to_le16(cmd_action); + + return 0; +} + +static int wlan_cmd_802_11_get_log(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(cmd_802_11_get_log); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); + + return 0; +} + +static int wlan_cmd_802_11_get_stat(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(cmd_802_11_get_stat); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + + S_DS_GEN); + + return 0; +} + +static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, + struct cmd_ds_command *cmd, + int cmd_action, + int cmd_oid, void *pdata_buf) +{ + struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; + wlan_adapter *adapter = priv->adapter; + u8 ucTemp; + + ENTER(); + + lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); + + cmd->command = cpu_to_le16(cmd_802_11_snmp_mib); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) + + S_DS_GEN); + + switch (cmd_oid) { + case OID_802_11_INFRASTRUCTURE_MODE: + { + enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode = + (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf; + pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); + pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i); + pSNMPMIB->bufsize = sizeof(u8); + if (mode == wlan802_11infrastructure) + ucTemp = SNMP_MIB_VALUE_INFRA; + else + ucTemp = SNMP_MIB_VALUE_ADHOC; + + memmove(pSNMPMIB->value, &ucTemp, sizeof(u8)); + + break; + } + + case OID_802_11D_ENABLE: + { + u32 ulTemp; + + pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i); + + if (cmd_action == cmd_act_set) { + pSNMPMIB->querytype = cmd_act_set; + pSNMPMIB->bufsize = sizeof(u16); + ulTemp = *(u32 *)pdata_buf; + *((unsigned short *)(pSNMPMIB->value)) = + cpu_to_le16((u16) ulTemp); + } + break; + } + + case OID_802_11_FRAGMENTATION_THRESHOLD: + { + u32 ulTemp; + + pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i); + + if (cmd_action == cmd_act_get) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_get); + } else if (cmd_action == cmd_act_set) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_set); + pSNMPMIB->bufsize = + cpu_to_le16(sizeof(u16)); + ulTemp = *((u32 *) pdata_buf); + *((unsigned short *)(pSNMPMIB->value)) = + cpu_to_le16((u16) ulTemp); + + } + + break; + } + + case OID_802_11_RTS_THRESHOLD: + { + + u32 ulTemp; + pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i); + + if (cmd_action == cmd_act_get) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_get); + } else if (cmd_action == cmd_act_set) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_set); + pSNMPMIB->bufsize = + cpu_to_le16(sizeof(u16)); + ulTemp = *((u32 *) + pdata_buf); + *(unsigned short *)(pSNMPMIB->value) = + cpu_to_le16((u16) ulTemp); + + } + break; + } + case OID_802_11_TX_RETRYCOUNT: + pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i); + + if (cmd_action == cmd_act_get) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_get); + } else if (cmd_action == cmd_act_set) { + pSNMPMIB->querytype = + cpu_to_le16(cmd_act_set); + pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); + *((unsigned short *)(pSNMPMIB->value)) = + cpu_to_le16((u16) adapter->txretrycount); + } + + break; + default: + break; + } + + lbs_pr_debug(1, + "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n", + cmd->command, cmd->size, cmd->seqnum, cmd->result); + + lbs_pr_debug(1, + "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n", + pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize, + *(u16 *) pSNMPMIB->value); + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_radio_control(wlan_private * priv, + struct cmd_ds_command *cmd, + int cmd_action) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_radio_control *pradiocontrol = + &cmd->params.radio; + + ENTER(); + + cmd->size = + cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + + S_DS_GEN); + cmd->command = cpu_to_le16(cmd_802_11_radio_control); + + pradiocontrol->action = cpu_to_le16(cmd_action); + + switch (adapter->preamble) { + case cmd_type_short_preamble: + pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); + break; + + case cmd_type_long_preamble: + pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); + break; + + case cmd_type_auto_preamble: + default: + pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); + break; + } + + if (adapter->radioon) + pradiocontrol->control |= cpu_to_le16(TURN_ON_RF); + else + pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF); + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + + struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; + + ENTER(); + + cmd->size = + cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + + S_DS_GEN); + cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power); + prtp->action = cmd_action; + + lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size, + cmd->command, prtp->action); + + switch (cmd_action) { + case cmd_act_tx_power_opt_get: + prtp->action = cpu_to_le16(cmd_act_get); + prtp->currentlevel = 0; + break; + + case cmd_act_tx_power_opt_set_high: + prtp->action = cpu_to_le16(cmd_act_set); + prtp->currentlevel = + cpu_to_le16(cmd_act_tx_power_index_high); + break; + + case cmd_act_tx_power_opt_set_mid: + prtp->action = cpu_to_le16(cmd_act_set); + prtp->currentlevel = + cpu_to_le16(cmd_act_tx_power_index_mid); + break; + + case cmd_act_tx_power_opt_set_low: + prtp->action = cpu_to_le16(cmd_act_set); + prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); + break; + } + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; + + cmd->command = cpu_to_le16(cmd_802_11_rf_antenna); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + + S_DS_GEN); + + rant->action = cpu_to_le16(cmd_action); + if ((cmd_action == cmd_act_set_rx) || + (cmd_action == cmd_act_set_tx)) { + rant->antennamode = + cpu_to_le16((u16) (*(u32 *) pdata_buf)); + } + + return 0; +} + +static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_802_11_rate_adapt_rateset + *rateadapt = &cmd->params.rateset; + wlan_adapter *adapter = priv->adapter; + + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) + + S_DS_GEN); + cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset); + + ENTER(); + + rateadapt->action = cmd_action; + rateadapt->enablehwauto = adapter->enablehwauto; + rateadapt->bitmap = adapter->ratebitmap; + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_data_rate(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate; + wlan_adapter *adapter = priv->adapter; + u16 action = cmd_action; + + ENTER(); + + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + + S_DS_GEN); + + cmd->command = cpu_to_le16(cmd_802_11_data_rate); + + memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); + + pdatarate->action = cpu_to_le16(cmd_action); + + if (action == cmd_act_set_tx_fix_rate) { + pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); + lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n", + adapter->datarate); + } else if (action == cmd_act_set_tx_auto) { + lbs_pr_debug(1, "Setting FW for AUTO rate\n"); + } + + LEAVE(); + return 0; +} + +static int wlan_cmd_mac_multicast_adr(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; + wlan_adapter *adapter = priv->adapter; + + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + + S_DS_GEN); + cmd->command = cpu_to_le16(cmd_mac_multicast_adr); + + pMCastAdr->action = cpu_to_le16(cmd_action); + pMCastAdr->nr_of_adrs = + cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); + memcpy(pMCastAdr->maclist, adapter->multicastlist, + adapter->nr_of_multicastmacaddr * ETH_ALEN); + + return 0; +} + +static int wlan_cmd_802_11_rf_channel(wlan_private * priv, + struct cmd_ds_command *cmd, + int option, void *pdata_buf) +{ + struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; + + cmd->command = cpu_to_le16(cmd_802_11_rf_channel); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + + S_DS_GEN); + + if (option == cmd_opt_802_11_rf_channel_set) { + rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); + } + + rfchan->action = cpu_to_le16(option); + + return 0; +} + +static int wlan_cmd_802_11_rssi(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + wlan_adapter *adapter = priv->adapter; + + cmd->command = cpu_to_le16(cmd_802_11_rssi); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); + cmd->params.rssi.N = priv->adapter->bcn_avg_factor; + + /* reset Beacon SNR/NF/RSSI values */ + adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; + adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0; + adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0; + adapter->NF[TYPE_BEACON][TYPE_AVG] = 0; + adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; + adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + + return 0; +} + +static int wlan_cmd_reg_access(wlan_private * priv, + struct cmd_ds_command *cmdptr, + u8 cmd_action, void *pdata_buf) +{ + struct wlan_offset_value *offval; + + ENTER(); + + offval = (struct wlan_offset_value *)pdata_buf; + + switch (cmdptr->command) { + case cmd_mac_reg_access: + { + struct cmd_ds_mac_reg_access *macreg; + + cmdptr->size = + cpu_to_le16(sizeof + (struct cmd_ds_mac_reg_access) + + S_DS_GEN); + macreg = + (struct cmd_ds_mac_reg_access *)&cmdptr->params. + macreg; + + macreg->action = cpu_to_le16(cmd_action); + macreg->offset = cpu_to_le16((u16) offval->offset); + macreg->value = cpu_to_le32(offval->value); + + break; + } + + case cmd_bbp_reg_access: + { + struct cmd_ds_bbp_reg_access *bbpreg; + + cmdptr->size = + cpu_to_le16(sizeof + (struct cmd_ds_bbp_reg_access) + + S_DS_GEN); + bbpreg = + (struct cmd_ds_bbp_reg_access *)&cmdptr->params. + bbpreg; + + bbpreg->action = cpu_to_le16(cmd_action); + bbpreg->offset = cpu_to_le16((u16) offval->offset); + bbpreg->value = (u8) offval->value; + + break; + } + + case cmd_rf_reg_access: + { + struct cmd_ds_rf_reg_access *rfreg; + + cmdptr->size = + cpu_to_le16(sizeof + (struct cmd_ds_rf_reg_access) + + S_DS_GEN); + rfreg = + (struct cmd_ds_rf_reg_access *)&cmdptr->params. + rfreg; + + rfreg->action = cpu_to_le16(cmd_action); + rfreg->offset = cpu_to_le16((u16) offval->offset); + rfreg->value = (u8) offval->value; + + break; + } + + default: + break; + } + + LEAVE(); + return 0; +} + +static int wlan_cmd_802_11_mac_address(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action) +{ + wlan_adapter *adapter = priv->adapter; + + cmd->command = cpu_to_le16(cmd_802_11_mac_address); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.macadd.action = cpu_to_le16(cmd_action); + + if (cmd_action == cmd_act_set) { + memcpy(cmd->params.macadd.macadd, + adapter->current_addr, ETH_ALEN); + lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); + } + + return 0; +} + +static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, + struct cmd_ds_command *cmd, + int cmd_action, void *pdata_buf) +{ + struct wlan_ioctl_regrdwr *ea = pdata_buf; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_802_11_eeprom_access); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + + S_DS_GEN); + cmd->result = 0; + + cmd->params.rdeeprom.action = cpu_to_le16(ea->action); + cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset); + cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); + cmd->params.rdeeprom.value = 0; + + return 0; +} + +static int wlan_cmd_bt_access(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_bt_access *bt_access = &cmd->params.bt; + lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action); + + cmd->command = cpu_to_le16(cmd_bt_access); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + + S_DS_GEN); + cmd->result = 0; + bt_access->action = cpu_to_le16(cmd_action); + + switch (cmd_action) { + case cmd_act_bt_access_add: + memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); + lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); + break; + case cmd_act_bt_access_del: + memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); + lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); + break; + case cmd_act_bt_access_list: + bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); + break; + case cmd_act_bt_access_reset: + break; + default: + break; + } + return 0; +} + +static int wlan_cmd_fwt_access(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; + lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); + + cmd->command = cpu_to_le16(cmd_fwt_access); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + + S_DS_GEN); + cmd->result = 0; + + if (pdata_buf) + memcpy(fwt_access, pdata_buf, sizeof(*fwt_access)); + else + memset(fwt_access, 0, sizeof(*fwt_access)); + + fwt_access->action = cpu_to_le16(cmd_action); + + return 0; +} + +static int wlan_cmd_mesh_access(wlan_private * priv, + struct cmd_ds_command *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; + lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); + + cmd->command = cpu_to_le16(cmd_mesh_access); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + + S_DS_GEN); + cmd->result = 0; + + if (pdata_buf) + memcpy(mesh_access, pdata_buf, sizeof(*mesh_access)); + else + memset(mesh_access, 0, sizeof(*mesh_access)); + + mesh_access->action = cpu_to_le16(cmd_action); + + return 0; +} + +void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) +{ + unsigned long flags; + struct cmd_ds_command *cmdptr; + + ENTER(); + + if (!cmdnode) { + lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n"); + goto done; + } + + cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + if (!cmdptr) { + lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n"); + goto done; + } + + /* Exit_PS command needs to be queued in the header always. */ + if (cmdptr->command == cmd_802_11_ps_mode) { + struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; + if (psm->action == cmd_subcmd_exit_ps) { + if (adapter->psstate != PS_STATE_FULL_POWER) + addtail = 0; + } + } + + spin_lock_irqsave(&adapter->driver_lock, flags); + + if (addtail) + list_add_tail((struct list_head *)cmdnode, + &adapter->cmdpendingq); + else + list_add((struct list_head *)cmdnode, &adapter->cmdpendingq); + + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n", + (u32) cmdnode, + ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command); + +done: + LEAVE(); + return; +} + +/* + * TODO: Fix the issue when DownloadcommandToStation is being called the + * second time when the command timesout. All the cmdptr->xxx are in little + * endian and therefore all the comparissions will fail. + * For now - we are not performing the endian conversion the second time - but + * for PS and DEEP_SLEEP we need to worry + */ +static int DownloadcommandToStation(wlan_private * priv, + struct cmd_ctrl_node *cmdnode) +{ + unsigned long flags; + struct cmd_ds_command *cmdptr; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + u16 cmdsize; + u16 command; + + ENTER(); + + if (!adapter || !cmdnode) { + lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n", + (int)adapter, (int)cmdnode); + if (cmdnode) { + spin_lock_irqsave(&adapter->driver_lock, flags); + __libertas_cleanup_and_insert_cmd(priv, cmdnode); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + } + ret = -1; + goto done; + } + + cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (!cmdptr || !cmdptr->size) { + lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, " + "Not sending\n"); + __libertas_cleanup_and_insert_cmd(priv, cmdnode); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + ret = -1; + goto done; + } + + adapter->cur_cmd = cmdnode; + adapter->cur_cmd_retcode = 0; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n", + cmdptr->size); + + cmdsize = cmdptr->size; + + command = cpu_to_le16(cmdptr->command); + + cmdnode->cmdwaitqwoken = 0; + cmdsize = cpu_to_le16(cmdsize); + + ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); + + if (ret != 0) { + lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n"); + spin_lock_irqsave(&adapter->driver_lock, flags); + __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + ret = -1; + goto done; + } + + lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies); + lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); + + /* Setup the timer after transmit command */ + if (command == cmd_802_11_scan + || command == cmd_802_11_authenticate + || command == cmd_802_11_associate) + mod_timer(&adapter->command_timer, jiffies + (10*HZ)); + else + mod_timer(&adapter->command_timer, jiffies + (5*HZ)); + + ret = 0; + + done: + LEAVE(); + return ret; +} + +static int wlan_cmd_mac_control(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + struct cmd_ds_mac_control *mac = &cmd->params.macctrl; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_mac_control); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); + mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); + + lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n", + mac->action, cmd->size); + + LEAVE(); + return 0; +} + +/** + * This function inserts command node to cmdfreeq + * after cleans it. Requires adapter->driver_lock held. + */ +void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +{ + wlan_adapter *adapter = priv->adapter; + + if (!ptempcmd) + goto done; + + cleanup_cmdnode(ptempcmd); + list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); +done: + return; +} + +void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->adapter->driver_lock, flags); + __libertas_cleanup_and_insert_cmd(priv, ptempcmd); + spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); +} + +int libertas_set_radio_control(wlan_private * priv) +{ + int ret = 0; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_radio_control, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + + lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", + priv->adapter->radioon, priv->adapter->preamble); + + LEAVE(); + return ret; +} + +int libertas_set_mac_packet_filter(wlan_private * priv) +{ + int ret = 0; + + ENTER(); + + lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n", + priv->adapter->currentpacketfilter); + + /* Send MAC control command to station */ + ret = libertas_prepare_and_send_command(priv, + cmd_mac_control, 0, 0, 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief This function prepare the command before send to firmware. + * + * @param priv A pointer to wlan_private structure + * @param cmd_no command number + * @param cmd_action command action: GET or SET + * @param wait_option wait option: wait response or not + * @param cmd_oid cmd oid: treated as sub command + * @param pdata_buf A pointer to informaion buffer + * @return 0 or -1 + */ +int libertas_prepare_and_send_command(wlan_private * priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmdnode; + struct cmd_ds_command *cmdptr; + unsigned long flags; + + ENTER(); + + if (!adapter) { + lbs_pr_debug(1, "PREP_CMD: adapter is Null\n"); + ret = -1; + goto done; + } + + if (adapter->surpriseremoved) { + lbs_pr_debug(1, "PREP_CMD: Card is Removed\n"); + ret = -1; + goto done; + } + + cmdnode = libertas_get_free_cmd_ctrl_node(priv); + + if (cmdnode == NULL) { + lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n"); + + /* Wake up main thread to execute next command */ + wake_up_interruptible(&priv->mainthread.waitq); + ret = -1; + goto done; + } + + libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf); + + cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + + lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n", + (u32) cmdptr, cmd_no); + + if (!cmdptr) { + lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n"); + libertas_cleanup_and_insert_cmd(priv, cmdnode); + ret = -1; + goto done; + } + + /* Set sequence number, command and INT option */ + adapter->seqnum++; + cmdptr->seqnum = cpu_to_le16(adapter->seqnum); + + cmdptr->command = cmd_no; + cmdptr->result = 0; + + switch (cmd_no) { + case cmd_get_hw_spec: + ret = wlan_cmd_hw_spec(priv, cmdptr); + break; + case cmd_802_11_ps_mode: + ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_scan: + ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); + break; + + case cmd_mac_control: + ret = wlan_cmd_mac_control(priv, cmdptr); + break; + + case cmd_802_11_associate: + case cmd_802_11_reassociate: + ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); + break; + + case cmd_802_11_deauthenticate: + ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); + break; + + case cmd_802_11_set_wep: + ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); + break; + + case cmd_802_11_ad_hoc_start: + ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); + break; + case cmd_code_dnld: + break; + + case cmd_802_11_reset: + ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_get_log: + ret = wlan_cmd_802_11_get_log(priv, cmdptr); + break; + + case cmd_802_11_authenticate: + ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); + break; + + case cmd_802_11_get_stat: + ret = wlan_cmd_802_11_get_stat(priv, cmdptr); + break; + + case cmd_802_11_snmp_mib: + ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, + cmd_action, cmd_oid, pdata_buf); + break; + + case cmd_mac_reg_access: + case cmd_bbp_reg_access: + case cmd_rf_reg_access: + ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); + break; + + case cmd_802_11_rf_channel: + ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, + cmd_action, pdata_buf); + break; + + case cmd_802_11_rf_tx_power: + ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, + cmd_action, pdata_buf); + break; + + case cmd_802_11_radio_control: + ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_rf_antenna: + ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, + cmd_action, pdata_buf); + break; + + case cmd_802_11_data_rate: + ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); + break; + case cmd_802_11_rate_adapt_rateset: + ret = wlan_cmd_802_11_rate_adapt_rateset(priv, + cmdptr, cmd_action); + break; + + case cmd_mac_multicast_adr: + ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_ad_hoc_join: + ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); + break; + + case cmd_802_11_rssi: + ret = wlan_cmd_802_11_rssi(priv, cmdptr); + break; + + case cmd_802_11_ad_hoc_stop: + ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); + break; + + case cmd_802_11_enable_rsn: + ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_key_material: + ret = wlan_cmd_802_11_key_material(priv, cmdptr, + cmd_action, cmd_oid, + pdata_buf); + break; + + case cmd_802_11_pairwise_tsc: + break; + case cmd_802_11_group_tsc: + break; + + case cmd_802_11_mac_address: + ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); + break; + + case cmd_802_11_eeprom_access: + ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, + cmd_action, pdata_buf); + break; + + case cmd_802_11_set_afc: + case cmd_802_11_get_afc: + + cmdptr->command = cpu_to_le16(cmd_no); + cmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + + S_DS_GEN); + + memmove(&cmdptr->params.afc, + pdata_buf, sizeof(struct cmd_ds_802_11_afc)); + + ret = 0; + goto done; + + case cmd_802_11d_domain_info: + ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, + cmd_no, cmd_action); + break; + + case cmd_802_11_sleep_params: + ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); + break; + case cmd_802_11_inactivity_timeout: + ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, + cmd_action, pdata_buf); + libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); + break; + + case cmd_802_11_tpc_cfg: + cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg); + cmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + + S_DS_GEN); + + memmove(&cmdptr->params.tpccfg, + pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); + + ret = 0; + break; + case cmd_802_11_led_gpio_ctrl: + { + struct mrvlietypes_ledgpio *gpio = + (struct mrvlietypes_ledgpio*) + cmdptr->params.ledgpio.data; + + memmove(&cmdptr->params.ledgpio, + pdata_buf, + sizeof(struct cmd_ds_802_11_led_ctrl)); + + cmdptr->command = + cpu_to_le16(cmd_802_11_led_gpio_ctrl); + +#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 + cmdptr->size = + cpu_to_le16(gpio->header.len + S_DS_GEN + + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); + gpio->header.len = cpu_to_le16(gpio->header.len); + + ret = 0; + break; + } + case cmd_802_11_pwr_cfg: + cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg); + cmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + + S_DS_GEN); + memmove(&cmdptr->params.pwrcfg, pdata_buf, + sizeof(struct cmd_ds_802_11_pwr_cfg)); + + ret = 0; + break; + case cmd_bt_access: + ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); + break; + + case cmd_fwt_access: + ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); + break; + + case cmd_mesh_access: + ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); + break; + + case cmd_get_tsf: + cmdptr->command = cpu_to_le16(cmd_get_tsf); + cmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_get_tsf) + + S_DS_GEN); + ret = 0; + break; + case cmd_802_11_tx_rate_query: + cmdptr->command = + cpu_to_le16(cmd_802_11_tx_rate_query); + cmdptr->size = + cpu_to_le16(sizeof(struct cmd_tx_rate_query) + + S_DS_GEN); + adapter->txrate = 0; + ret = 0; + break; + default: + lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no); + ret = -1; + break; + } + + /* return error, since the command preparation failed */ + if (ret != 0) { + lbs_pr_debug(1, "PREP_CMD: command preparation failed\n"); + libertas_cleanup_and_insert_cmd(priv, cmdnode); + ret = -1; + goto done; + } + + cmdnode->cmdwaitqwoken = 0; + + libertas_queue_cmd(adapter, cmdnode, 1); + adapter->nr_cmd_pending++; + wake_up_interruptible(&priv->mainthread.waitq); + + if (wait_option & cmd_option_waitforrsp) { + lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n"); + might_sleep(); + wait_event_interruptible(cmdnode->cmdwait_q, + cmdnode->cmdwaitqwoken); + } + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd_retcode) { + lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n", + adapter->cur_cmd_retcode); + adapter->cur_cmd_retcode = 0; + ret = -1; + } + spin_unlock_irqrestore(&adapter->driver_lock, flags); + +done: + LEAVE(); + return ret; +} + +/** + * @brief This function allocates the command buffer and link + * it to command free queue. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +int libertas_allocate_cmd_buffer(wlan_private * priv) +{ + int ret = 0; + u32 ulbufsize; + u32 i; + struct cmd_ctrl_node *tempcmd_array; + u8 *ptempvirtualaddr; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* Allocate and initialize cmdCtrlNode */ + ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; + + if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) { + lbs_pr_debug(1, + "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n"); + ret = -1; + goto done; + } + + adapter->cmd_array = tempcmd_array; + memset(adapter->cmd_array, 0, ulbufsize); + + /* Allocate and initialize command buffers */ + ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) { + lbs_pr_debug(1, + "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n"); + ret = -1; + goto done; + } + + memset(ptempvirtualaddr, 0, ulbufsize); + + /* Update command buffer virtual */ + tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr; + } + + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + init_waitqueue_head(&tempcmd_array[i].cmdwait_q); + libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]); + } + + ret = 0; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function frees the command buffer. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +int libertas_free_cmd_buffer(wlan_private * priv) +{ + u32 ulbufsize; + unsigned int i; + struct cmd_ctrl_node *tempcmd_array; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* need to check if cmd array is allocated or not */ + if (adapter->cmd_array == NULL) { + lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n"); + goto done; + } + + tempcmd_array = adapter->cmd_array; + + /* Release shared memory buffers */ + ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + if (tempcmd_array[i].bufvirtualaddr) { + lbs_pr_debug(1, "Free all the array\n"); + kfree(tempcmd_array[i].bufvirtualaddr); + tempcmd_array[i].bufvirtualaddr = NULL; + } + } + + /* Release cmd_ctrl_node */ + if (adapter->cmd_array) { + lbs_pr_debug(1, "Free cmd_array\n"); + kfree(adapter->cmd_array); + adapter->cmd_array = NULL; + } + +done: + LEAVE(); + return 0; +} + +/** + * @brief This function gets a free command node if available in + * command free queue. + * + * @param priv A pointer to wlan_private structure + * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL + */ +struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) +{ + struct cmd_ctrl_node *tempnode; + wlan_adapter *adapter = priv->adapter; + unsigned long flags; + + if (!adapter) + return NULL; + + spin_lock_irqsave(&adapter->driver_lock, flags); + + if (!list_empty(&adapter->cmdfreeq)) { + tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; + list_del((struct list_head *)tempnode); + } else { + lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n"); + tempnode = NULL; + } + + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + if (tempnode) { + lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n"); + lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n", + tempnode); + cleanup_cmdnode(tempnode); + } + + return tempnode; +} + +/** + * @brief This function cleans command node. + * + * @param ptempnode A pointer to cmdCtrlNode structure + * @return n/a + */ +static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) +{ + if (!ptempnode) + return; + ptempnode->cmdwaitqwoken = 1; + wake_up_interruptible(&ptempnode->cmdwait_q); + ptempnode->status = 0; + ptempnode->cmd_oid = (u32) 0; + ptempnode->wait_option = 0; + ptempnode->pdata_buf = NULL; + + if (ptempnode->bufvirtualaddr != NULL) + memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + return; +} + +/** + * @brief This function initializes the command node. + * + * @param priv A pointer to wlan_private structure + * @param ptempnode A pointer to cmd_ctrl_node structure + * @param cmd_oid cmd oid: treated as sub command + * @param wait_option wait option: wait response or not + * @param pdata_buf A pointer to informaion buffer + * @return 0 or -1 + */ +void libertas_set_cmd_ctrl_node(wlan_private * priv, + struct cmd_ctrl_node *ptempnode, + u32 cmd_oid, u16 wait_option, void *pdata_buf) +{ + ENTER(); + + if (!ptempnode) + return; + + ptempnode->cmd_oid = cmd_oid; + ptempnode->wait_option = wait_option; + ptempnode->pdata_buf = pdata_buf; + + LEAVE(); +} + +/** + * @brief This function executes next command in command + * pending queue. It will put fimware back to PS mode + * if applicable. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +int libertas_execute_next_command(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmdnode = NULL; + struct cmd_ds_command *cmdptr; + unsigned long flags; + int ret = 0; + + lbs_pr_debug(1, "libertas_execute_next_command\n"); + + spin_lock_irqsave(&adapter->driver_lock, flags); + + if (adapter->cur_cmd) { + lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n"); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + ret = -1; + goto done; + } + + if (!list_empty(&adapter->cmdpendingq)) { + cmdnode = (struct cmd_ctrl_node *) + adapter->cmdpendingq.next; + } + + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + if (cmdnode) { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: Got next command from cmdpendingq\n"); + cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + + if (is_command_allowed_in_ps(cmdptr->command)) { + if ((adapter->psstate == PS_STATE_SLEEP) + || (adapter->psstate == PS_STATE_PRE_SLEEP) + ) { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n", + cmdptr->command, adapter->psstate); + ret = -1; + goto done; + } + lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command " + "0x%x in psstate %d\n", + cmdptr->command, adapter->psstate); + } else if (adapter->psstate != PS_STATE_FULL_POWER) { + /* + * 1. Non-PS command: + * Queue it. set needtowakeup to TRUE if current state + * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. + * 2. PS command but not Exit_PS: + * Ignore it. + * 3. PS command Exit_PS: + * Set needtowakeup to TRUE if current state is SLEEP, + * otherwise send this command down to firmware + * immediately. + */ + if (cmdptr->command != + cpu_to_le16(cmd_802_11_ps_mode)) { + /* Prepare to send Exit PS, + * this non PS command will be sent later */ + if ((adapter->psstate == PS_STATE_SLEEP) + || (adapter->psstate == PS_STATE_PRE_SLEEP) + ) { + /* w/ new scheme, it will not reach here. + since it is blocked in main_thread. */ + adapter->needtowakeup = 1; + } else + libertas_ps_wakeup(priv, 0); + + ret = 0; + goto done; + } else { + /* + * PS command. Ignore it if it is not Exit_PS. + * otherwise send it down immediately. + */ + struct cmd_ds_802_11_ps_mode *psm = + &cmdptr->params.psmode; + + lbs_pr_debug(1, + "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", + psm->action); + if (psm->action != + cpu_to_le16(cmd_subcmd_exit_ps)) { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); + list_del((struct list_head *)cmdnode); + libertas_cleanup_and_insert_cmd(priv, cmdnode); + + ret = 0; + goto done; + } + + if ((adapter->psstate == PS_STATE_SLEEP) + || (adapter->psstate == PS_STATE_PRE_SLEEP) + ) { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); + list_del((struct list_head *)cmdnode); + libertas_cleanup_and_insert_cmd(priv, cmdnode); + adapter->needtowakeup = 1; + + ret = 0; + goto done; + } + + lbs_pr_debug(1, + "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); + } + } + list_del((struct list_head *)cmdnode); + lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n", + cmdptr->command); + DownloadcommandToStation(priv, cmdnode); + } else { + /* + * check if in power save mode, if yes, put the device back + * to PS mode + */ + if ((adapter->psmode != wlan802_11powermodecam) && + (adapter->psstate == PS_STATE_FULL_POWER) && + (adapter->connect_status == libertas_connected)) { + if (adapter->secinfo.WPAenabled + || adapter->secinfo.WPA2enabled) { + /* check for valid WPA group keys */ + if (adapter->wpa_mcast_key.len + || adapter->wpa_unicast_key.len) { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: WPA enabled and GTK_SET" + " go back to PS_SLEEP"); + libertas_ps_sleep(priv, 0); + } + } else { + lbs_pr_debug(1, + "EXEC_NEXT_CMD: command PendQ is empty," + " go back to PS_SLEEP"); + libertas_ps_sleep(priv, 0); + } + } + } + + ret = 0; +done: + return ret; +} + +void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) +{ + union iwreq_data iwrq; + u8 buf[50]; + + ENTER(); + + memset(&iwrq, 0, sizeof(union iwreq_data)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, sizeof(buf) - 1, "%s", str); + + iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; + + /* Send Event to upper layer */ + lbs_pr_debug(1, "Event Indication string = %s\n", + (char *)buf); + lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length); + + lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str); + wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf); + + LEAVE(); + return; +} + +static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) +{ + unsigned long flags; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", + size); + + lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size); + + ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size); + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->intcounter || adapter->currenttxskb) + lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n", + adapter->intcounter, adapter->currenttxskb); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + if (ret) { + lbs_pr_alert( + "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); + } else { + spin_lock_irqsave(&adapter->driver_lock, flags); + if (!adapter->intcounter) { + adapter->psstate = PS_STATE_SLEEP; + } else { + lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n", + adapter->intcounter); + } + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); + lbs_pr_debug(1, "+"); + } + + LEAVE(); + return ret; +} + +void libertas_ps_sleep(wlan_private * priv, int wait_option) +{ + + ENTER(); + + /* + * PS is currently supported only in Infrastructure mode + * Remove this check if it is to be supported in IBSS mode also + */ + + libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, + cmd_subcmd_enter_ps, wait_option, 0, NULL); + + LEAVE(); + return; +} + +/** + * @brief This function sends Eixt_PS command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param wait_option wait response or not + * @return n/a + */ +void libertas_ps_wakeup(wlan_private * priv, int wait_option) +{ + enum WLAN_802_11_POWER_MODE Localpsmode; + + ENTER(); + + Localpsmode = wlan802_11powermodecam; + + lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode); + + libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, + cmd_subcmd_exit_ps, + wait_option, 0, &Localpsmode); + + LEAVE(); + return; +} + +/** + * @brief This function checks condition and prepares to + * send sleep confirm command to firmware if ok. + * + * @param priv A pointer to wlan_private structure + * @param psmode Power Saving mode + * @return n/a + */ +void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) +{ + unsigned long flags =0; + wlan_adapter *adapter = priv->adapter; + u8 allowed = 1; + + ENTER(); + + if (priv->wlan_dev.dnld_sent) { + allowed = 0; + lbs_pr_debug(1, "D"); + } + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd) { + allowed = 0; + lbs_pr_debug(1, "C"); + } + if (adapter->intcounter > 0) { + allowed = 0; + lbs_pr_debug(1, "I%d", adapter->intcounter); + } + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + if (allowed) { + lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n"); + sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, + sizeof(struct PS_CMD_ConfirmSleep)); + } else { + lbs_pr_debug(1, "Sleep Confirm has been delayed\n"); + } + + LEAVE(); +} diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c new file mode 100644 index 0000000..cdb012c --- /dev/null +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -0,0 +1,1031 @@ +/** + * This file contains the handling of command + * responses as well as events generated by firmware. + */ +#include +#include +#include + +#include + +#include "host.h" +#include "sbi.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "wext.h" + +/** + * @brief This function handles disconnect event. it + * reports disconnect to upper layer, clean tx/rx packets, + * reset link state etc. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +void libertas_mac_event_disconnected(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + union iwreq_data wrqu; + + if (adapter->connect_status != libertas_connected) + return; + + lbs_pr_debug(1, "Handles disconnect event.\n"); + + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + + /* + * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. + * It causes problem in the Supplicant + */ + + msleep_interruptible(1000); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + /* Free Tx and Rx packets */ + kfree_skb(priv->adapter->currenttxskb); + priv->adapter->currenttxskb = NULL; + + /* report disconnect to upper layer */ + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + + /* reset SNR/NF/RSSI values */ + memset(adapter->SNR, 0x00, sizeof(adapter->SNR)); + memset(adapter->NF, 0x00, sizeof(adapter->NF)); + memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI)); + memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); + memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); + adapter->nextSNRNF = 0; + adapter->numSNRNF = 0; + adapter->rxpd_rate = 0; + lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n", + adapter->curbssparams.ssid.ssid, + adapter->curbssparams.ssid.ssidlength); + lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n", + adapter->previousssid.ssid, adapter->previousssid.ssidlength); + + /* reset internal flags */ + adapter->secinfo.WPAenabled = 0; + adapter->secinfo.WPA2enabled = 0; + adapter->wpa_ie_len = 0; + adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; + adapter->secinfo.Encryptionmode = CIPHER_NONE; + + adapter->connect_status = libertas_disconnected; + + /* + * memorize the previous SSID and BSSID + * it could be used for re-assoc + */ + memcpy(&adapter->previousssid, + &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID)); + memcpy(adapter->previousbssid, + adapter->curbssparams.bssid, ETH_ALEN); + + /* need to erase the current SSID and BSSID info */ + adapter->pattemptedbssdesc = NULL; + memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); + + if (adapter->psstate != PS_STATE_FULL_POWER) { + /* make firmware to exit PS mode */ + lbs_pr_debug(1, "Disconnected, so exit PS mode.\n"); + libertas_ps_wakeup(priv, 0); + } +} + +/** + * @brief This function handles MIC failure event. + * + * @param priv A pointer to wlan_private structure + * @para event the event id + * @return n/a + */ +static void handle_mic_failureevent(wlan_private * priv, u32 event) +{ + char buf[50]; + + memset(buf, 0, sizeof(buf)); + + sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); + + if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { + strcat(buf, "unicast "); + } else { + strcat(buf, "multicast "); + } + + libertas_send_iwevcustom_event(priv, buf); +} + +static int wlan_ret_reg_access(wlan_private * priv, + u16 type, struct cmd_ds_command *resp) +{ + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + switch (type) { + case cmd_ret_mac_reg_access: + { + struct cmd_ds_mac_reg_access *reg; + + reg = + (struct cmd_ds_mac_reg_access *)&resp->params. + macreg; + + adapter->offsetvalue.offset = reg->offset; + adapter->offsetvalue.value = reg->value; + break; + } + + case cmd_ret_bbp_reg_access: + { + struct cmd_ds_bbp_reg_access *reg; + reg = + (struct cmd_ds_bbp_reg_access *)&resp->params. + bbpreg; + + adapter->offsetvalue.offset = reg->offset; + adapter->offsetvalue.value = reg->value; + break; + } + + case cmd_ret_rf_reg_access: + { + struct cmd_ds_rf_reg_access *reg; + reg = + (struct cmd_ds_rf_reg_access *)&resp->params. + rfreg; + + adapter->offsetvalue.offset = reg->offset; + adapter->offsetvalue.value = reg->value; + break; + } + + default: + LEAVE(); + return -1; + } + + LEAVE(); + return 0; +} + +static int wlan_ret_get_hw_spec(wlan_private * priv, + struct cmd_ds_command *resp) +{ + u32 i; + struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo); + + adapter->fwreleasenumber = hwspec->fwreleasenumber; + + lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n", + adapter->fwreleasenumber); + lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", + hwspec->permanentaddr[0], hwspec->permanentaddr[1], + hwspec->permanentaddr[2], hwspec->permanentaddr[3], + hwspec->permanentaddr[4], hwspec->permanentaddr[5]); + lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n", + hwspec->hwifversion, hwspec->version); + + adapter->regioncode = le16_to_cpu(hwspec->regioncode); + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + /* use the region code to search for the index */ + if (adapter->regioncode == libertas_region_code_to_index[i]) { + adapter->regiontableindex = (u16) i; + break; + } + } + + /* if it's unidentified region code, use the default (USA) */ + if (i >= MRVDRV_MAX_REGION_CODE) { + adapter->regioncode = 0x10; + adapter->regiontableindex = 0; + lbs_pr_info( + "unidentified region code, use the default (USA)\n"); + } + + if (adapter->current_addr[0] == 0xff) { + memmove(adapter->current_addr, hwspec->permanentaddr, + ETH_ALEN); + } + + memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN); + memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); + + if (libertas_set_regiontable(priv, adapter->regioncode, 0)) { + ret = -1; + goto done; + } + + if (libertas_set_universaltable(priv, 0)) { + ret = -1; + goto done; + } + + done: + LEAVE(); + return ret; +} + +static int wlan_ret_802_11_sleep_params(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n" + " extsleepclk=%x\n", sp->error, sp->offset, + sp->stabletime, sp->calcontrol, sp->externalsleepclk); + adapter->sp.sp_error = le16_to_cpu(sp->error); + adapter->sp.sp_offset = le16_to_cpu(sp->offset); + adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime); + adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol); + adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk); + adapter->sp.sp_reserved = le16_to_cpu(sp->reserved); + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_stat(wlan_private * priv, + struct cmd_ds_command *resp) +{ +/* currently adapter->wlan802_11Stat is unused + + struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; + wlan_adapter *adapter = priv->adapter; + + // TODO Convert it to Big endian befor copy + memcpy(&adapter->wlan802_11Stat, + p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); +*/ + return 0; +} + +static int wlan_ret_802_11_snmp_mib(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; + u16 oid = le16_to_cpu(smib->oid); + u16 querytype = le16_to_cpu(smib->querytype); + + ENTER(); + + lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid, + querytype); + lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n", + le16_to_cpu(smib->bufsize)); + + if (querytype == cmd_act_get) { + switch (oid) { + case fragthresh_i: + priv->adapter->fragthsd = + le16_to_cpu(* + ((unsigned short *)(smib->value))); + lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n", + priv->adapter->fragthsd); + break; + case rtsthresh_i: + priv->adapter->rtsthsd = + le16_to_cpu(* + ((unsigned short *)(smib->value))); + lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n", + priv->adapter->rtsthsd); + break; + case short_retrylim_i: + priv->adapter->txretrycount = + le16_to_cpu(* + ((unsigned short *)(smib->value))); + lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n", + priv->adapter->rtsthsd); + break; + default: + break; + } + } + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_key_material(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_key_material *pkeymaterial = + &resp->params.keymaterial; + wlan_adapter *adapter = priv->adapter; + u16 action = le16_to_cpu(pkeymaterial->action); + + ENTER(); + + /* Copy the returned key to driver private data */ + if (action == cmd_act_get) { + u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; + u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); + + while (buf_ptr < resp_end) { + struct MrvlIEtype_keyParamSet * pkeyparamset = + (struct MrvlIEtype_keyParamSet *) buf_ptr; + struct WLAN_802_11_KEY * pkey; + u16 key_info = le16_to_cpu(pkeyparamset->keyinfo); + u16 param_set_len = le16_to_cpu(pkeyparamset->length); + u8 * end; + u16 key_len = le16_to_cpu(pkeyparamset->keylen); + + end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) + + sizeof (pkeyparamset->length) + + param_set_len; + /* Make sure we don't access past the end of the IEs */ + if (end > resp_end) + break; + + if (key_info & KEY_INFO_WPA_UNICAST) + pkey = &adapter->wpa_unicast_key; + else if (key_info & KEY_INFO_WPA_MCAST) + pkey = &adapter->wpa_mcast_key; + else + break; + + /* Copy returned key into driver */ + memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + if (key_len > sizeof(pkey->key)) + break; + pkey->type = le16_to_cpu(pkeyparamset->keytypeid); + pkey->flags = le16_to_cpu(pkeyparamset->keyinfo); + pkey->len = le16_to_cpu(pkeyparamset->keylen); + memcpy(pkey->key, pkeyparamset->key, pkey->len); + + buf_ptr = end + 1; + } + } + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_mac_address(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN); + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); + + lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel); + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_rf_antenna(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant; + wlan_adapter *adapter = priv->adapter; + u16 action = le16_to_cpu(pAntenna->action); + + if (action == cmd_act_get_rx) + adapter->rxantennamode = + le16_to_cpu(pAntenna->antennamode); + + if (action == cmd_act_get_tx) + adapter->txantennamode = + le16_to_cpu(pAntenna->antennamode); + + lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", + action, le16_to_cpu(pAntenna->antennamode)); + + return 0; +} + +static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rate_adapt_rateset *rates = + &resp->params.rateset; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (rates->action == cmd_act_get) { + adapter->enablehwauto = rates->enablehwauto; + adapter->ratebitmap = rates->bitmap; + } + + LEAVE(); + + return 0; +} + +static int wlan_ret_802_11_data_rate(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; + wlan_adapter *adapter = priv->adapter; + u8 dot11datarate; + + ENTER(); + + lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", + (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); + + dot11datarate = pdatarate->datarate[0]; + if (pdatarate->action == cmd_act_get_tx_rate) { + memcpy(adapter->libertas_supported_rates, pdatarate->datarate, + sizeof(adapter->libertas_supported_rates)); + } + adapter->datarate = libertas_index_to_data_rate(dot11datarate); + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_rf_channel(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rf_channel *rfchannel = + &resp->params.rfchannel; + wlan_adapter *adapter = priv->adapter; + u16 action = le16_to_cpu(rfchannel->action); + u16 newchannel = le16_to_cpu(rfchannel->currentchannel); + + ENTER(); + + if (action == cmd_opt_802_11_rf_channel_get + && adapter->curbssparams.channel != newchannel) { + lbs_pr_debug(1, "channel Switch: %d to %d\n", + adapter->curbssparams.channel, newchannel); + + /* Update the channel again */ + adapter->curbssparams.channel = newchannel; + } + + LEAVE(); + return 0; +} + +static int wlan_ret_802_11_rssi(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; + wlan_adapter *adapter = priv->adapter; + + /* store the non average value */ + adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); + adapter->NF[TYPE_BEACON][TYPE_NOAVG] = + le16_to_cpu(rssirsp->noisefloor); + + adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); + adapter->NF[TYPE_BEACON][TYPE_AVG] = + le16_to_cpu(rssirsp->avgnoisefloor); + + adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = + CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + + adapter->RSSI[TYPE_BEACON][TYPE_AVG] = + CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); + + lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n", + adapter->RSSI[TYPE_BEACON][TYPE_AVG]); + + return 0; +} + +static int wlan_ret_802_11_eeprom_access(wlan_private * priv, + struct cmd_ds_command *resp) +{ + wlan_adapter *adapter = priv->adapter; + struct wlan_ioctl_regrdwr *pbuf; + pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; + + lbs_pr_debug(1, "eeprom read len=%x\n", + le16_to_cpu(resp->params.rdeeprom.bytecount)); + if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { + pbuf->NOB = 0; + lbs_pr_debug(1, "eeprom read return length is too big\n"); + return -1; + } + pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); + if (pbuf->NOB > 0) { + + memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, + le16_to_cpu(resp->params.rdeeprom.bytecount)); + lbs_dbg_hex("adapter", (char *)&pbuf->value, + le16_to_cpu(resp->params.rdeeprom.bytecount)); + } + return 0; +} + +static int wlan_ret_get_log(wlan_private * priv, + struct cmd_ds_command *resp) +{ + struct cmd_ds_802_11_get_log *logmessage = + (struct cmd_ds_802_11_get_log *)&resp->params.glog; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* TODO Convert it to Big Endian before copy */ + memcpy(&adapter->logmsg, logmessage, + sizeof(struct cmd_ds_802_11_get_log)); + + LEAVE(); + return 0; +} + +static inline int handle_cmd_response(u16 respcmd, + struct cmd_ds_command *resp, + wlan_private *priv) +{ + int ret = 0; + unsigned long flags; + wlan_adapter *adapter = priv->adapter; + + switch (respcmd) { + case cmd_ret_mac_reg_access: + case cmd_ret_bbp_reg_access: + case cmd_ret_rf_reg_access: + ret = wlan_ret_reg_access(priv, respcmd, resp); + break; + + case cmd_ret_hw_spec_info: + ret = wlan_ret_get_hw_spec(priv, resp); + break; + + case cmd_ret_802_11_scan: + ret = libertas_ret_80211_scan(priv, resp); + break; + + case cmd_ret_802_11_get_log: + ret = wlan_ret_get_log(priv, resp); + break; + + case cmd_ret_802_11_associate: + case cmd_ret_802_11_reassociate: + ret = libertas_ret_80211_associate(priv, resp); + break; + + case cmd_ret_802_11_disassociate: + case cmd_ret_802_11_deauthenticate: + ret = libertas_ret_80211_disassociate(priv, resp); + break; + + case cmd_ret_802_11_ad_hoc_start: + case cmd_ret_802_11_ad_hoc_join: + ret = libertas_ret_80211_ad_hoc_start(priv, resp); + break; + + case cmd_ret_802_11_stat: + ret = wlan_ret_802_11_stat(priv, resp); + break; + + case cmd_ret_802_11_snmp_mib: + ret = wlan_ret_802_11_snmp_mib(priv, resp); + break; + + case cmd_ret_802_11_rf_tx_power: + ret = wlan_ret_802_11_rf_tx_power(priv, resp); + break; + + case cmd_ret_802_11_set_afc: + case cmd_ret_802_11_get_afc: + spin_lock_irqsave(&adapter->driver_lock, flags); + memmove(adapter->cur_cmd->pdata_buf, + &resp->params.afc, + sizeof(struct cmd_ds_802_11_afc)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + break; + case cmd_ret_802_11_rf_antenna: + ret = wlan_ret_802_11_rf_antenna(priv, resp); + break; + + case cmd_ret_mac_multicast_adr: + case cmd_ret_mac_control: + case cmd_ret_802_11_set_wep: + case cmd_ret_802_11_reset: + case cmd_ret_802_11_authenticate: + case cmd_ret_802_11_radio_control: + case cmd_ret_802_11_beacon_stop: + case cmd_ret_802_11_enable_rsn: + break; + + case cmd_ret_802_11_data_rate: + ret = wlan_ret_802_11_data_rate(priv, resp); + break; + case cmd_ret_802_11_rate_adapt_rateset: + ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); + break; + case cmd_ret_802_11_rf_channel: + ret = wlan_ret_802_11_rf_channel(priv, resp); + break; + + case cmd_ret_802_11_rssi: + ret = wlan_ret_802_11_rssi(priv, resp); + break; + + case cmd_ret_802_11_mac_address: + ret = wlan_ret_802_11_mac_address(priv, resp); + break; + + case cmd_ret_802_11_ad_hoc_stop: + ret = libertas_ret_80211_ad_hoc_stop(priv, resp); + break; + + case cmd_ret_802_11_key_material: + lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n"); + ret = wlan_ret_802_11_key_material(priv, resp); + break; + + case cmd_ret_802_11_eeprom_access: + ret = wlan_ret_802_11_eeprom_access(priv, resp); + break; + + case cmd_ret_802_11d_domain_info: + ret = libertas_ret_802_11d_domain_info(priv, resp); + break; + + case cmd_ret_802_11_sleep_params: + ret = wlan_ret_802_11_sleep_params(priv, resp); + break; + case cmd_ret_802_11_inactivity_timeout: + spin_lock_irqsave(&adapter->driver_lock, flags); + *((u16 *) adapter->cur_cmd->pdata_buf) = + le16_to_cpu(resp->params.inactivity_timeout.timeout); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + + case cmd_ret_802_11_tpc_cfg: + spin_lock_irqsave(&adapter->driver_lock, flags); + memmove(adapter->cur_cmd->pdata_buf, + &resp->params.tpccfg, + sizeof(struct cmd_ds_802_11_tpc_cfg)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + case cmd_ret_802_11_led_gpio_ctrl: + spin_lock_irqsave(&adapter->driver_lock, flags); + memmove(adapter->cur_cmd->pdata_buf, + &resp->params.ledgpio, + sizeof(struct cmd_ds_802_11_led_ctrl)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + case cmd_ret_802_11_pwr_cfg: + spin_lock_irqsave(&adapter->driver_lock, flags); + memmove(adapter->cur_cmd->pdata_buf, + &resp->params.pwrcfg, + sizeof(struct cmd_ds_802_11_pwr_cfg)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + break; + + case cmd_ret_get_tsf: + spin_lock_irqsave(&adapter->driver_lock, flags); + memcpy(priv->adapter->cur_cmd->pdata_buf, + &resp->params.gettsf.tsfvalue, sizeof(u64)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + case cmd_ret_bt_access: + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd->pdata_buf) + memcpy(adapter->cur_cmd->pdata_buf, + &resp->params.bt.addr1, 2 * ETH_ALEN); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + case cmd_ret_fwt_access: + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd->pdata_buf) + memcpy(adapter->cur_cmd->pdata_buf, + &resp->params.fwt, + sizeof(resp->params.fwt)); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + break; + case cmd_ret_mesh_access: + if (adapter->cur_cmd->pdata_buf) + memcpy(adapter->cur_cmd->pdata_buf, + &resp->params.mesh, + sizeof(resp->params.mesh)); + break; + case cmd_rte_802_11_tx_rate_query: + priv->adapter->txrate = resp->params.txrate.txrate; + break; + default: + lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n", + resp->command); + break; + } + return ret; +} + +int libertas_process_rx_command(wlan_private * priv) +{ + u16 respcmd; + struct cmd_ds_command *resp; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + ulong flags; + u16 result; + + ENTER(); + + lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies); + + /* Now we got response from FW, cancel the command timer */ + del_timer(&adapter->command_timer); + + mutex_lock(&adapter->lock); + spin_lock_irqsave(&adapter->driver_lock, flags); + + if (!adapter->cur_cmd) { + lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd); + ret = -1; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + goto done; + } + resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); + + lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr, + priv->wlan_dev.upld_len); + + respcmd = le16_to_cpu(resp->command); + + result = le16_to_cpu(resp->result); + + lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd, + result, priv->wlan_dev.upld_len); + + if (!(respcmd & 0x8000)) { + lbs_pr_debug(1, "Invalid response to command!"); + adapter->cur_cmd_retcode = -1; + __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + ret = -1; + goto done; + } + + /* Store the response code to cur_cmd_retcode. */ + adapter->cur_cmd_retcode = le16_to_cpu(resp->result); + + if (respcmd == cmd_ret_802_11_ps_mode) { + struct cmd_ds_802_11_ps_mode *psmode; + + psmode = &resp->params.psmode; + lbs_pr_debug(1, + "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", + resp->result, psmode->action); + psmode->action = cpu_to_le16(psmode->action); + + if (result) { + lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n", + resp->result); + if (adapter->inframode == wlan802_11ibss) { + /* + * We should not re-try enter-ps command in + * ad-hoc mode. It takes place in + * libertas_execute_next_command(). + */ + if (psmode->action == cmd_subcmd_enter_ps) + adapter->psmode = + wlan802_11powermodecam; + } + } else if (psmode->action == cmd_subcmd_enter_ps) { + adapter->needtowakeup = 0; + adapter->psstate = PS_STATE_AWAKE; + + lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n"); + if (adapter->connect_status != libertas_connected) { + /* + * When Deauth Event received before Enter_PS command + * response, We need to wake up the firmware. + */ + lbs_pr_debug(1, + "Disconnected, Going to invoke libertas_ps_wakeup\n"); + + mutex_unlock(&adapter->lock); + spin_unlock_irqrestore(&adapter->driver_lock, flags); + libertas_ps_wakeup(priv, 0); + mutex_lock(&adapter->lock); + spin_lock_irqsave(&adapter->driver_lock, flags); + } + } else if (psmode->action == cmd_subcmd_exit_ps) { + adapter->needtowakeup = 0; + adapter->psstate = PS_STATE_FULL_POWER; + lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n"); + } else { + lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n", + psmode->action); + } + + __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + ret = 0; + goto done; + } + + if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { + /* Copy the response back to response buffer */ + memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size); + + adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; + } + + /* If the command is not successful, cleanup and return failure */ + if ((result != 0 || !(respcmd & 0x8000))) { + lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n", + resp->command, resp->result); + /* + * Handling errors here + */ + switch (respcmd) { + case cmd_ret_hw_spec_info: + case cmd_ret_802_11_reset: + lbs_pr_debug(1, "CMD_RESP: Reset command failed\n"); + break; + + } + + __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + ret = -1; + goto done; + } + + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + ret = handle_cmd_response(respcmd, resp, priv); + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd) { + /* Clean up and Put current command back to cmdfreeq */ + __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); + adapter->nr_cmd_pending--; + WARN_ON(adapter->nr_cmd_pending > 128); + adapter->cur_cmd = NULL; + } + spin_unlock_irqrestore(&adapter->driver_lock, flags); + +done: + mutex_unlock(&adapter->lock); + LEAVE(); + return ret; +} + +int libertas_process_event(wlan_private * priv) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + u32 eventcause; + + spin_lock_irq(&adapter->driver_lock); + eventcause = adapter->eventcause; + spin_unlock_irq(&adapter->driver_lock); + + ENTER(); + + lbs_pr_debug(1, "EVENT Cause %x\n", eventcause); + + switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { + case MACREG_INT_CODE_LINK_SENSED: + lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n"); + break; + + case MACREG_INT_CODE_DEAUTHENTICATED: + lbs_pr_debug(1, "EVENT: Deauthenticated\n"); + libertas_mac_event_disconnected(priv); + break; + + case MACREG_INT_CODE_DISASSOCIATED: + lbs_pr_debug(1, "EVENT: Disassociated\n"); + libertas_mac_event_disconnected(priv); + break; + + case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: + lbs_pr_debug(1, "EVENT: Link lost\n"); + libertas_mac_event_disconnected(priv); + break; + + case MACREG_INT_CODE_PS_SLEEP: + lbs_pr_debug(1, "EVENT: SLEEP\n"); + lbs_pr_debug(1, "_"); + + /* handle unexpected PS SLEEP event */ + if (adapter->psstate == PS_STATE_FULL_POWER) { + lbs_pr_debug(1, + "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); + break; + } + adapter->psstate = PS_STATE_PRE_SLEEP; + + libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); + + break; + + case MACREG_INT_CODE_PS_AWAKE: + lbs_pr_debug(1, "EVENT: AWAKE \n"); + lbs_pr_debug(1, "|"); + + /* handle unexpected PS AWAKE event */ + if (adapter->psstate == PS_STATE_FULL_POWER) { + lbs_pr_debug(1, + "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); + break; + } + + adapter->psstate = PS_STATE_AWAKE; + + if (adapter->needtowakeup) { + /* + * wait for the command processing to finish + * before resuming sending + * adapter->needtowakeup will be set to FALSE + * in libertas_ps_wakeup() + */ + lbs_pr_debug(1, "Waking up...\n"); + libertas_ps_wakeup(priv, 0); + } + break; + + case MACREG_INT_CODE_MIC_ERR_UNICAST: + lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n"); + handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); + break; + + case MACREG_INT_CODE_MIC_ERR_MULTICAST: + lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n"); + handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); + break; + case MACREG_INT_CODE_MIB_CHANGED: + case MACREG_INT_CODE_INIT_DONE: + break; + + case MACREG_INT_CODE_ADHOC_BCN_LOST: + lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n"); + break; + + case MACREG_INT_CODE_RSSI_LOW: + lbs_pr_alert( "EVENT: RSSI_LOW\n"); + break; + case MACREG_INT_CODE_SNR_LOW: + lbs_pr_alert( "EVENT: SNR_LOW\n"); + break; + case MACREG_INT_CODE_MAX_FAIL: + lbs_pr_alert( "EVENT: MAX_FAIL\n"); + break; + case MACREG_INT_CODE_RSSI_HIGH: + lbs_pr_alert( "EVENT: RSSI_HIGH\n"); + break; + case MACREG_INT_CODE_SNR_HIGH: + lbs_pr_alert( "EVENT: SNR_HIGH\n"); + break; + + default: + lbs_pr_alert( "EVENT: unknown event id: %#x\n", + eventcause >> SBI_EVENT_CAUSE_SHIFT); + break; + } + + spin_lock_irq(&adapter->driver_lock); + adapter->eventcause = 0; + spin_unlock_irq(&adapter->driver_lock); + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c new file mode 100644 index 0000000..3ad1e03 --- /dev/null +++ b/drivers/net/wireless/libertas/debugfs.c @@ -0,0 +1,1968 @@ +#include +#include +#include +#include +#include +#include +#include "dev.h" +#include "decl.h" +#include "host.h" + +static struct dentry *libertas_dir = NULL; +static char *szStates[] = { + "Connected", + "Disconnected" +}; + +void libertas_debug_init(wlan_private * priv, struct net_device *dev); + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t write_file_dummy(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static const size_t len = PAGE_SIZE; + +static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + size_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + ssize_t res; + + pos += snprintf(buf+pos, len-pos, "state = %s\n", + szStates[priv->adapter->connect_status]); + pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", + (u32) priv->adapter->regioncode); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + + +static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + size_t pos = 0; + int numscansdone = 0, res; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + pos += snprintf(buf+pos, len-pos, + "---------------------------------------"); + pos += snprintf(buf+pos, len-pos, + "---------------------------------------\n"); + pos += snprintf(buf+pos, len-pos, + "# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); + pos += snprintf(buf+pos, len-pos, + "---------------------------------------"); + pos += snprintf(buf+pos, len-pos, + "---------------------------------------\n"); + + while (numscansdone < priv->adapter->numinscantable) { + struct bss_descriptor *pbssinfo; + u16 cap; + + pbssinfo = &priv->adapter->scantable[numscansdone]; + memcpy(&cap, &pbssinfo->cap, sizeof(cap)); + pos += snprintf(buf+pos, len-pos, + "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |", + numscansdone, pbssinfo->channel, pbssinfo->rssi, + pbssinfo->macaddress[0], pbssinfo->macaddress[1], + pbssinfo->macaddress[2], pbssinfo->macaddress[3], + pbssinfo->macaddress[4], pbssinfo->macaddress[5]); + pos += snprintf(buf+pos, len-pos, " %04x-", cap); + pos += snprintf(buf+pos, len-pos, "%c%c%c |", + pbssinfo->cap.ibss ? 'A' : 'I', + pbssinfo->cap.privacy ? 'P' : ' ', + pbssinfo->cap.spectrummgmt ? 'S' : ' '); + pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf); + pos += snprintf(buf+pos, len-pos, " %d |", + SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi)); + + pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid); + + numscansdone++; + } + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + +static ssize_t libertas_sleepparams_write(struct file *file, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t buf_size, res; + int p1, p2, p3, p4, p5, p6; + struct sleep_params sp; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); + if (res != 6) { + res = -EFAULT; + goto out_unlock; + } + sp.sp_error = p1; + sp.sp_offset = p2; + sp.sp_stabletime = p3; + sp.sp_calcontrol = p4; + sp.sp_extsleepclk = p5; + sp.sp_reserved = p6; + + memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params)); + + res = libertas_prepare_and_send_command(priv, + cmd_802_11_sleep_params, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + + if (!res) + res = count; + else + res = -EINVAL; + +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res; + size_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_prepare_and_send_command(priv, + cmd_802_11_sleep_params, + cmd_act_get, + cmd_option_waitforrsp, 0, NULL); + if (res) { + res = -EFAULT; + goto out_unlock; + } + + pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error, + adapter->sp.sp_offset, adapter->sp.sp_stabletime, + adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk, + adapter->sp.sp_reserved); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + struct WLAN_802_11_SSID extscan_ssid; + union iwreq_data wrqu; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + + memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1); + extscan_ssid.ssidlength = strlen(buf)-1; + + libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1); + + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); + +out_unlock: + free_page(addr); + return count; +} + +static int libertas_parse_chan(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur) +{ + char *start, *end, *hold, *str; + int i = 0; + + start = strstr(buf, "chan="); + if (!start) + return -EINVAL; + start += 5; + end = strstr(start, " "); + if (!end) + end = buf + count; + hold = kzalloc((end - start)+1, GFP_KERNEL); + if (!hold) + return -ENOMEM; + strncpy(hold, start, end - start); + hold[(end-start)+1] = '\0'; + while(hold && (str = strsep(&hold, ","))) { + int chan; + char band, passive = 0; + sscanf(str, "%d%c%c", &chan, &band, &passive); + scan_cfg->chanlist[i].channumber = chan; + scan_cfg->chanlist[i].scantype = passive ? 1 : 0; + if (band == 'b' || band == 'g') + scan_cfg->chanlist[i].radiotype = 0; + else if (band == 'a') + scan_cfg->chanlist[i].radiotype = 1; + + scan_cfg->chanlist[i].scantime = dur; + i++; + } + + kfree(hold); + return i; +} + +static void libertas_parse_bssid(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold; + unsigned int mac[ETH_ALEN]; + int i; + + hold = strstr(buf, "bssid="); + if (!hold) + return; + hold += 6; + sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3, + mac+4, mac+5); + for(i=0;ispecificBSSID[i] = mac[i]; +} + +static void libertas_parse_ssid(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold, *end; + ssize_t size; + + hold = strstr(buf, "ssid="); + if (!hold) + return; + hold += 5; + end = strstr(hold, " "); + if (!end) + end = buf + count - 1; + + size = min(IW_ESSID_MAX_SIZE, end - hold); + strncpy(scan_cfg->specificSSID, hold, size); + + return; +} + +static void libertas_parse_keep(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold; + int val; + + hold = strstr(buf, "keep="); + if (!hold) + return; + hold += 5; + sscanf(hold, "%d", &val); + + if (val != 0) + val = 1; + + scan_cfg->keeppreviousscan = val; + return; +} + +static int libertas_parse_dur(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold; + int val; + + hold = strstr(buf, "dur="); + if (!hold) + return 0; + hold += 4; + sscanf(hold, "%d", &val); + + return val; +} + +static void libertas_parse_probes(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold; + int val; + + hold = strstr(buf, "probes="); + if (!hold) + return; + hold += 7; + sscanf(hold, "%d", &val); + + scan_cfg->numprobes = val; + + return; +} + +static void libertas_parse_type(char *buf, size_t count, + struct wlan_ioctl_user_scan_cfg *scan_cfg) +{ + char *hold; + int val; + + hold = strstr(buf, "type="); + if (!hold) + return; + hold += 5; + sscanf(hold, "%d", &val); + + /* type=1,2 or 3 */ + if (val < 1 || val > 3) + return; + + scan_cfg->bsstype = val; + + return; +} + +static ssize_t libertas_setuserscan(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + struct wlan_ioctl_user_scan_cfg *scan_cfg; + union iwreq_data wrqu; + int dur; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL); + if (!scan_cfg) + return -ENOMEM; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + + scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY; + + dur = libertas_parse_dur(buf, count, scan_cfg); + libertas_parse_chan(buf, count, scan_cfg, dur); + libertas_parse_bssid(buf, count, scan_cfg); + libertas_parse_ssid(buf, count, scan_cfg); + libertas_parse_keep(buf, count, scan_cfg); + libertas_parse_probes(buf, count, scan_cfg); + libertas_parse_type(buf, count, scan_cfg); + + wlan_scan_networks(priv, scan_cfg); + wait_event_interruptible(priv->adapter->cmd_pending, + !priv->adapter->nr_cmd_pending); + + memset(&wrqu, 0x00, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); + +out_unlock: + free_page(addr); + kfree(scan_cfg); + return count; +} + +static int libertas_event_initcmd(wlan_private *priv, void **response_buf, + struct cmd_ctrl_node **cmdnode, + struct cmd_ds_command **cmd) +{ + u16 wait_option = cmd_option_waitforrsp; + + if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { + lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n"); + return -ENOMEM; + } + if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) { + lbs_pr_debug(1, "failed to allocate response buffer!\n"); + return -ENOMEM; + } + libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL); + init_waitqueue_head(&(*cmdnode)->cmdwait_q); + (*cmdnode)->pdata_buf = *response_buf; + (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; + (*cmdnode)->cmdwaitqwoken = 0; + *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; + (*cmd)->command = cmd_802_11_subscribe_event; + (*cmd)->seqnum = ++priv->adapter->seqnum; + (*cmd)->result = 0; + return 0; +} + +static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_rssithreshold *Lowrssi; + case TLV_TYPE_RSSI_LOW: + Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d %d %d\n", + Lowrssi->rssivalue, + Lowrssi->rssifreq, + (event->events & 0x0001)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_snrthreshold); + break; + } + } + + kfree(response_buf); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static u16 libertas_get_events_bitmap(wlan_private *priv) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res; + u16 event_bitmap; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + return res; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + return 0; + } + + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + event_bitmap = event->events; + kfree(response_buf); + return event_bitmap; +} + +static ssize_t libertas_lowrssi_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_rssithreshold *rssi_threshold; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_rssithreshold)); + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); + rssi_threshold->header.type = cpu_to_le16(0x0104); + rssi_threshold->header.len = 2; + rssi_threshold->rssivalue = cpu_to_le16(value); + rssi_threshold->rssifreq = cpu_to_le16(freq); + event_bitmap |= subscribed ? 0x0001 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_snrthreshold *LowSnr; + case TLV_TYPE_SNR_LOW: + LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d %d %d\n", + LowSnr->snrvalue, + LowSnr->snrfreq, + (event->events & 0x0002)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_snrthreshold); + break; + } + } + + kfree(response_buf); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static ssize_t libertas_lowsnr_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_snrthreshold *snr_threshold; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_snrthreshold)); + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); + snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW); + snr_threshold->header.len = 2; + snr_threshold->snrvalue = cpu_to_le16(value); + snr_threshold->snrfreq = cpu_to_le16(freq); + event_bitmap |= subscribed ? 0x0002 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + res = count; + +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_failurecount *failcount; + case TLV_TYPE_FAILCOUNT: + failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d %d %d\n", + failcount->failvalue, + failcount->Failfreq, + (event->events & 0x0004)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_failurecount); + break; + } + } + + kfree(response_buf); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static ssize_t libertas_failcount_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_failurecount *failcount; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_failurecount)); + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + failcount = (struct mrvlietypes_failurecount *)(ptr); + failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); + failcount->header.len = 2; + failcount->failvalue = cpu_to_le16(value); + failcount->Failfreq = cpu_to_le16(freq); + event_bitmap |= subscribed ? 0x0004 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = (struct cmd_ds_command *)response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + free_page(addr); + kfree(response_buf); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + free_page(addr); + kfree(response_buf); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_beaconsmissed *bcnmiss; + case TLV_TYPE_BCNMISS: + bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d N/A %d\n", + bcnmiss->beaconmissed, + (event->events & 0x0008)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_beaconsmissed); + break; + } + } + + kfree(response_buf); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static ssize_t libertas_bcnmiss_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_beaconsmissed *bcnmiss; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_beaconsmissed)); + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr); + bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS); + bcnmiss->header.len = 2; + bcnmiss->beaconmissed = cpu_to_le16(value); + event_bitmap |= subscribed ? 0x0008 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + free_page(addr); + kfree(response_buf); + return 0; + } + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_rssithreshold *Highrssi; + case TLV_TYPE_RSSI_HIGH: + Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d %d %d\n", + Highrssi->rssivalue, + Highrssi->rssifreq, + (event->events & 0x0010)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_snrthreshold); + break; + } + } + + kfree(response_buf); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static ssize_t libertas_highrssi_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_rssithreshold *rssi_threshold; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_rssithreshold)); + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); + rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); + rssi_threshold->header.len = 2; + rssi_threshold->rssivalue = cpu_to_le16(value); + rssi_threshold->rssifreq = cpu_to_le16(freq); + event_bitmap |= subscribed ? 0x0010 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + return 0; + } + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + void *response_buf; + int res, cmd_len; + ssize_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) { + free_page(addr); + return res; + } + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_get; + pcmdptr->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); + while (cmd_len < pcmdptr->size) { + struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); + switch(header->type) { + struct mrvlietypes_snrthreshold *HighSnr; + case TLV_TYPE_SNR_HIGH: + HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); + pos += snprintf(buf+pos, len-pos, "%d %d %d\n", + HighSnr->snrvalue, + HighSnr->snrfreq, + (event->events & 0x0020)?1:0); + default: + cmd_len += sizeof(struct mrvlietypes_snrthreshold); + break; + } + } + + kfree(response_buf); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return res; +} + +static ssize_t libertas_highsnr_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + ssize_t res, buf_size; + int value, freq, subscribed, cmd_len; + struct cmd_ctrl_node *pcmdnode; + struct cmd_ds_command *pcmdptr; + struct cmd_ds_802_11_subscribe_event *event; + struct mrvlietypes_snrthreshold *snr_threshold; + void *response_buf; + u16 event_bitmap; + u8 *ptr; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); + if (res != 3) { + res = -EFAULT; + goto out_unlock; + } + + event_bitmap = libertas_get_events_bitmap(priv); + + res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); + if (res < 0) + goto out_unlock; + + event = &pcmdptr->params.subscribe_event; + event->action = cmd_act_set; + pcmdptr->size = cpu_to_le16(S_DS_GEN + + sizeof(struct cmd_ds_802_11_subscribe_event) + + sizeof(struct mrvlietypes_snrthreshold)); + cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); + ptr = (u8*) pcmdptr+cmd_len; + snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); + snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH); + snr_threshold->header.len = 2; + snr_threshold->snrvalue = cpu_to_le16(value); + snr_threshold->snrfreq = cpu_to_le16(freq); + event_bitmap |= subscribed ? 0x0020 : 0x0; + event->events = event_bitmap; + + libertas_queue_cmd(adapter, pcmdnode, 1); + wake_up_interruptible(&priv->mainthread.waitq); + + /* Sleep until response is generated by FW */ + wait_event_interruptible(pcmdnode->cmdwait_q, + pcmdnode->cmdwaitqwoken); + + pcmdptr = response_buf; + + if (pcmdptr->result) { + lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, + pcmdptr->result); + kfree(response_buf); + free_page(addr); + return 0; + } + + if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { + lbs_pr_err("command response incorrect!\n"); + kfree(response_buf); + free_page(addr); + return 0; + } + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct wlan_offset_value offval; + ssize_t pos = 0; + int ret; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + offval.offset = priv->mac_offset; + offval.value = 0; + + ret = libertas_prepare_and_send_command(priv, + cmd_mac_reg_access, 0, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", + priv->mac_offset, adapter->offsetvalue.value); + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + return ret; +} + +static ssize_t libertas_rdmac_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + priv->mac_offset = simple_strtoul((char *)buf, NULL, 16); + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_wrmac_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + u32 offset, value; + struct wlan_offset_value offval; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%x %x", &offset, &value); + if (res != 2) { + res = -EFAULT; + goto out_unlock; + } + + offval.offset = offset; + offval.value = value; + res = libertas_prepare_and_send_command(priv, + cmd_mac_reg_access, 1, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct wlan_offset_value offval; + ssize_t pos = 0; + int ret; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + offval.offset = priv->bbp_offset; + offval.value = 0; + + ret = libertas_prepare_and_send_command(priv, + cmd_bbp_reg_access, 0, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", + priv->bbp_offset, adapter->offsetvalue.value); + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + + return ret; +} + +static ssize_t libertas_rdbbp_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16); + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_wrbbp_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + u32 offset, value; + struct wlan_offset_value offval; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%x %x", &offset, &value); + if (res != 2) { + res = -EFAULT; + goto out_unlock; + } + + offval.offset = offset; + offval.value = value; + res = libertas_prepare_and_send_command(priv, + cmd_bbp_reg_access, 1, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + wlan_adapter *adapter = priv->adapter; + struct wlan_offset_value offval; + ssize_t pos = 0; + int ret; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + offval.offset = priv->rf_offset; + offval.value = 0; + + ret = libertas_prepare_and_send_command(priv, + cmd_rf_reg_access, 0, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", + priv->rf_offset, adapter->offsetvalue.value); + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + free_page(addr); + + return ret; +} + +static ssize_t libertas_rdrf_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + priv->rf_offset = simple_strtoul((char *)buf, NULL, 16); + res = count; +out_unlock: + free_page(addr); + return res; +} + +static ssize_t libertas_wrrf_write(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + + wlan_private *priv = file->private_data; + ssize_t res, buf_size; + u32 offset, value; + struct wlan_offset_value offval; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + buf_size = min(count, len - 1); + if (copy_from_user(buf, userbuf, buf_size)) { + res = -EFAULT; + goto out_unlock; + } + res = sscanf(buf, "%x %x", &offset, &value); + if (res != 2) { + res = -EFAULT; + goto out_unlock; + } + + offval.offset = offset; + offval.value = value; + res = libertas_prepare_and_send_command(priv, + cmd_rf_reg_access, 1, + cmd_option_waitforrsp, 0, &offval); + mdelay(10); + + res = count; +out_unlock: + free_page(addr); + return res; +} + +#define FOPS(fread, fwrite) { \ + .owner = THIS_MODULE, \ + .open = open_file_generic, \ + .read = (fread), \ + .write = (fwrite), \ +} + +struct libertas_debugfs_files { + char *name; + int perm; + struct file_operations fops; +}; + +struct libertas_debugfs_files debugfs_files[] = { + { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), }, + { "getscantable", 0444, FOPS(libertas_getscantable, + write_file_dummy), }, + { "sleepparams", 0644, FOPS(libertas_sleepparams_read, + libertas_sleepparams_write), }, + { "extscan", 0600, FOPS(NULL, libertas_extscan), }, + { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), }, +}; + +struct libertas_debugfs_files debugfs_events_files[] = { + {"low_rssi", 0644, FOPS(libertas_lowrssi_read, + libertas_lowrssi_write), }, + {"low_snr", 0644, FOPS(libertas_lowsnr_read, + libertas_lowsnr_write), }, + {"failure_count", 0644, FOPS(libertas_failcount_read, + libertas_failcount_write), }, + {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read, + libertas_bcnmiss_write), }, + {"high_rssi", 0644, FOPS(libertas_highrssi_read, + libertas_highrssi_write), }, + {"high_snr", 0644, FOPS(libertas_highsnr_read, + libertas_highsnr_write), }, +}; + +struct libertas_debugfs_files debugfs_regs_files[] = { + {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), }, + {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), }, + {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), }, + {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), }, + {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), }, + {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), }, +}; + +void libertas_debugfs_init(void) +{ + if (!libertas_dir) + libertas_dir = debugfs_create_dir("libertas_wireless", NULL); + + return; +} + +void libertas_debugfs_remove(void) +{ + if (libertas_dir) + debugfs_remove(libertas_dir); + return; +} + +void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) +{ + int i; + struct libertas_debugfs_files *files; + if (!libertas_dir) + goto exit; + + priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir); + if (!priv->debugfs_dir) + goto exit; + + for (i=0; idebugfs_files[i] = debugfs_create_file(files->name, + files->perm, + priv->debugfs_dir, + priv, + &files->fops); + } + + priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); + if (!priv->events_dir) + goto exit; + + for (i=0; idebugfs_events_files[i] = debugfs_create_file(files->name, + files->perm, + priv->events_dir, + priv, + &files->fops); + } + + priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); + if (!priv->regs_dir) + goto exit; + + for (i=0; idebugfs_regs_files[i] = debugfs_create_file(files->name, + files->perm, + priv->regs_dir, + priv, + &files->fops); + } + +#ifdef PROC_DEBUG + libertas_debug_init(priv, dev); +#endif +exit: + return; +} + +void libertas_debugfs_remove_one(wlan_private *priv) +{ + int i; + + for(i=0; idebugfs_regs_files[i]); + + debugfs_remove(priv->regs_dir); + + for(i=0; idebugfs_events_files[i]); + + debugfs_remove(priv->events_dir); +#ifdef PROC_DEBUG + debugfs_remove(priv->debugfs_debug); +#endif + for(i=0; idebugfs_files[i]); +} + +/* debug entry */ + +#define item_size(n) (sizeof ((wlan_adapter *)0)->n) +#define item_addr(n) ((u32) &((wlan_adapter *)0)->n) + +struct debug_data { + char name[32]; + u32 size; + u32 addr; +}; + +/* To debug any member of wlan_adapter, simply add one line here. + */ +static struct debug_data items[] = { + {"intcounter", item_size(intcounter), item_addr(intcounter)}, + {"psmode", item_size(psmode), item_addr(psmode)}, + {"psstate", item_size(psstate), item_addr(psstate)}, +}; + +static int num_of_items = sizeof(items) / sizeof(items[0]); + +/** + * @brief convert string to number + * + * @param s pointer to numbered string + * @return converted number from string s + */ +static int string_to_number(char *s) +{ + int r = 0; + int base = 0; + + if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0)) + base = 16; + else + base = 10; + + if (base == 16) + s += 2; + + for (s = s; *s != 0; s++) { + if ((*s >= 48) && (*s <= 57)) + r = (r * base) + (*s - 48); + else if ((*s >= 65) && (*s <= 70)) + r = (r * base) + (*s - 55); + else if ((*s >= 97) && (*s <= 102)) + r = (r * base) + (*s - 87); + else + break; + } + + return r; +} + +/** + * @brief proc read function + * + * @param page pointer to buffer + * @param s read data starting position + * @param off offset + * @param cnt counter + * @param eof end of file flag + * @param data data to output + * @return number of output data + */ +static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + int val = 0; + size_t pos = 0; + ssize_t res; + char *p; + int i; + struct debug_data *d; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + p = buf; + + d = (struct debug_data *)file->private_data; + + for (i = 0; i < num_of_items; i++) { + if (d[i].size == 1) + val = *((u8 *) d[i].addr); + else if (d[i].size == 2) + val = *((u16 *) d[i].addr); + else if (d[i].size == 4) + val = *((u32 *) d[i].addr); + + pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); + } + + res = simple_read_from_buffer(userbuf, count, ppos, p, pos); + + free_page(addr); + return res; +} + +/** + * @brief proc write function + * + * @param f file pointer + * @param buf pointer to data buffer + * @param cnt data number to write + * @param data data to write + * @return number of data + */ +static int wlan_debugfs_write(struct file *f, const char __user *buf, + size_t cnt, loff_t *ppos) +{ + int r, i; + char *pdata; + char *p; + char *p0; + char *p1; + char *p2; + struct debug_data *d = (struct debug_data *)f->private_data; + + pdata = (char *)kmalloc(cnt, GFP_KERNEL); + if (pdata == NULL) + return 0; + + if (copy_from_user(pdata, buf, cnt)) { + lbs_pr_debug(1, "Copy from user failed\n"); + kfree(pdata); + return 0; + } + + p0 = pdata; + for (i = 0; i < num_of_items; i++) { + do { + p = strstr(p0, d[i].name); + if (p == NULL) + break; + p1 = strchr(p, '\n'); + if (p1 == NULL) + break; + p0 = p1++; + p2 = strchr(p, '='); + if (!p2) + break; + p2++; + r = string_to_number(p2); + if (d[i].size == 1) + *((u8 *) d[i].addr) = (u8) r; + else if (d[i].size == 2) + *((u16 *) d[i].addr) = (u16) r; + else if (d[i].size == 4) + *((u32 *) d[i].addr) = (u32) r; + break; + } while (1); + } + kfree(pdata); + + return cnt; +} + +static struct file_operations libertas_debug_fops = { + .owner = THIS_MODULE, + .open = open_file_generic, + .write = wlan_debugfs_write, + .read = wlan_debugfs_read, +}; + +/** + * @brief create debug proc file + * + * @param priv pointer wlan_private + * @param dev pointer net_device + * @return N/A + */ +void libertas_debug_init(wlan_private * priv, struct net_device *dev) +{ + int i; + + if (!priv->debugfs_dir) + return; + + for (i = 0; i < num_of_items; i++) + items[i].addr += (u32) priv->adapter; + + priv->debugfs_debug = debugfs_create_file("debug", 0644, + priv->debugfs_dir, &items[0], + &libertas_debug_fops); +} + +/** + * @brief remove proc file + * + * @param priv pointer wlan_private + * @return N/A + */ +void libertas_debug_remove(wlan_private * priv) +{ + debugfs_remove(priv->debugfs_debug); +} diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h new file mode 100644 index 0000000..880a11b --- /dev/null +++ b/drivers/net/wireless/libertas/debugfs.h @@ -0,0 +1,6 @@ +void libertas_debugfs_init(void); +void libertas_debugfs_remove(void); + +void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev); +void libertas_debugfs_remove_one(wlan_private *priv); + diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h new file mode 100644 index 0000000..606bdd0 --- /dev/null +++ b/drivers/net/wireless/libertas/decl.h @@ -0,0 +1,83 @@ +/** + * This file contains declaration referring to + * functions defined in other source files + */ + +#ifndef _WLAN_DECL_H_ +#define _WLAN_DECL_H_ + +#include "defs.h" + +/** Function Prototype Declaration */ +struct wlan_private; +struct sk_buff; +struct net_device; + +extern char *libertas_fw_name; + +void libertas_free_adapter(wlan_private * priv); +int libertas_set_mac_packet_filter(wlan_private * priv); + +int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); +void libertas_send_tx_feedback(wlan_private * priv); +u8 libertas_check_last_packet_indication(wlan_private * priv); + +int libertas_free_cmd_buffer(wlan_private * priv); +struct cmd_ctrl_node; +struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv); + +void libertas_set_cmd_ctrl_node(wlan_private * priv, + struct cmd_ctrl_node *ptempnode, + u32 cmd_oid, u16 wait_option, void *pdata_buf); + +int libertas_prepare_and_send_command(wlan_private * priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf); + +void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail); + +int libertas_allocate_cmd_buffer(wlan_private * priv); +int libertas_execute_next_command(wlan_private * priv); +int libertas_process_event(wlan_private * priv); +void libertas_interrupt(struct net_device *); +int libertas_set_radio_control(wlan_private * priv); +u32 libertas_index_to_data_rate(u8 index); +u8 libertas_data_rate_to_index(u32 rate); +void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); + +int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); + +/** The proc fs interface */ +int libertas_process_rx_command(wlan_private * priv); +int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); +void libertas_cleanup_and_insert_cmd(wlan_private * priv, + struct cmd_ctrl_node *ptempcmd); +void __libertas_cleanup_and_insert_cmd(wlan_private * priv, + struct cmd_ctrl_node *ptempcmd); + +int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band); + +int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *); + +void libertas_ps_sleep(wlan_private * priv, int wait_option); +void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode); +void libertas_ps_wakeup(wlan_private * priv, int wait_option); + +void libertas_tx_runqueue(wlan_private *priv); + +extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel( + wlan_adapter * adapter, u8 band, u16 channel); + +extern void libertas_mac_event_disconnected(wlan_private * priv); + +void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); + +int reset_device(wlan_private *priv); +/* main.c */ +extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, + int *cfp_no); +wlan_private *wlan_add_card(void *card); +int wlan_remove_card(void *card); + +#endif /* _WLAN_DECL_H_ */ diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h new file mode 100644 index 0000000..fb1478c --- /dev/null +++ b/drivers/net/wireless/libertas/defs.h @@ -0,0 +1,369 @@ +/** + * This header file contains global constant/enum definitions, + * global variable declaration. + */ +#ifndef _WLAN_DEFS_H_ +#define _WLAN_DEFS_H_ + +#include + +extern unsigned int libertas_debug; + +#define DRV_NAME "usb8xxx" + +#define lbs_pr_info(format, args...) \ + printk(KERN_INFO DRV_NAME": " format, ## args) +#define lbs_pr_err(format, args...) \ + printk(KERN_ERR DRV_NAME": " format, ## args) +#define lbs_pr_alert(format, args...) \ + printk(KERN_ALERT DRV_NAME": " format, ## args) + +#ifdef DEBUG +#define lbs_pr_debug(level, format, args...) \ + do { if (libertas_debug >= level) \ + printk(KERN_INFO DRV_NAME": " format, ##args); } while (0) +#define lbs_dev_dbg(level, device, format, args...) \ + lbs_pr_debug(level, "%s: " format, \ + (device)->bus_id , ## args) + +static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) +{ + int i = 0; + + if (!libertas_debug) + return; + + printk(KERN_DEBUG "%s: ", prompt); + for (i = 1; i <= len; i++) { + printk(KERN_DEBUG "%02x ", (u8) * buf); + buf++; + } + printk("\n"); +} +#else +#define lbs_pr_debug(level, format, args...) do {} while (0) +#define lbs_dev_dbg(level, device, format, args...) do {} while (0) +#define lbs_dbg_hex(x,y,z) do {} while (0) +#endif + +#define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \ + __FUNCTION__, __FILE__, __LINE__) +#define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \ + __FUNCTION__, __FILE__, __LINE__) + +/** Buffer Constants */ + +/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical +* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas +* driver has more local TxPDs. Each TxPD on the host memory is associated +* with a Tx control node. The driver maintains 8 RxPD descriptors for +* station firmware to store Rx packet information. +* +* Current version of MAC has a 32x6 multicast address buffer. +* +* 802.11b can have up to 14 channels, the driver keeps the +* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. +*/ + +#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 +#define MRVDRV_NUM_OF_CMD_BUFFER 10 +#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) +#define MRVDRV_MAX_CHANNEL_SIZE 14 +#define MRVDRV_MAX_BSSID_LIST 64 +#define MRVDRV_ASSOCIATION_TIME_OUT 255 +#define MRVDRV_SNAP_HEADER_LEN 8 + +#define WLAN_UPLD_SIZE 2312 +#define DEV_NAME_LEN 32 + +/** Misc constants */ +/* This section defines 802.11 specific contants */ + +#define MRVDRV_MAX_BSS_DESCRIPTS 16 +#define MRVDRV_MAX_REGION_CODE 6 + +#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe +#define MRVDRV_MIN_MULTIPLE_DTIM 1 +#define MRVDRV_MAX_MULTIPLE_DTIM 5 +#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1 + +#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10 + +#define MRVDRV_CHANNELS_PER_SCAN 4 +#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 + +#define MRVDRV_DEBUG_RX_PATH 0x00000001 +#define MRVDRV_DEBUG_TX_PATH 0x00000002 + +#define MRVDRV_MIN_BEACON_INTERVAL 20 +#define MRVDRV_MAX_BEACON_INTERVAL 1000 +#define MRVDRV_BEACON_INTERVAL 100 + +/** TxPD status */ + +/* Station firmware use TxPD status field to report final Tx transmit +* result, Bit masks are used to present combined situations. +*/ + +#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +/** Tx mesh flag */ +/* Currently we are using normal WDS flag as mesh flag. + * TODO: change to proper mesh flag when MAC understands it. + */ +#define TxPD_CONTROL_WDS_FRAME (1<<17) +#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME + +/** RxPD status */ + +#define MRVDRV_RXPD_STATUS_OK 0x0001 + +/** RxPD status - Received packet types */ +/** Rx mesh flag */ +/* Currently we are using normal WDS flag as mesh flag. + * TODO: change to proper mesh flag when MAC understands it. + */ +#define RxPD_CONTROL_WDS_FRAME (0x40) +#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME + +/** RSSI-related defines */ +/* RSSI constants are used to implement 802.11 RSSI threshold +* indication. if the Rx packet signal got too weak for 5 consecutive +* times, miniport driver (driver) will report this event to wrapper +*/ + +#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) + +/** RTS/FRAG related defines */ +#define MRVDRV_RTS_MIN_VALUE 0 +#define MRVDRV_RTS_MAX_VALUE 2347 +#define MRVDRV_FRAG_MIN_VALUE 256 +#define MRVDRV_FRAG_MAX_VALUE 2346 + +/* This is for firmware specific length */ +#define EXTRA_LEN 36 + +#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) + +#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct rxpd) \ + + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) + +#define CMD_F_HOSTCMD (1 << 0) +#define FW_CAPINFO_WPA (1 << 0) + +/** WPA key LENGTH*/ +#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 + +#define KEY_LEN_WPA_AES 16 +#define KEY_LEN_WPA_TKIP 32 +#define KEY_LEN_WEP_104 13 +#define KEY_LEN_WEP_40 5 + +#define RF_ANTENNA_1 0x1 +#define RF_ANTENNA_2 0x2 +#define RF_ANTENNA_AUTO 0xFFFF + +#define BAND_B (0x01) +#define BAND_G (0x02) +#define ALL_802_11_BANDS (BAND_B | BAND_G) + +/** MACRO DEFINITIONS */ +#define CAL_NF(NF) ((s32)(-(s32)(NF))) +#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF))) +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 +#define AVG_SCALE 100 +#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \ + (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \ + ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ + AVG_SCALE)) / N)) + +#define B_SUPPORTED_RATES 8 +#define G_SUPPORTED_RATES 14 + +#define WLAN_SUPPORTED_RATES 14 + +#define MAX_LEDS 8 + +#define IS_MESH_FRAME(x) (x->cb[6]) +#define SET_MESH_FRAME(x) (x->cb[6]=1) +#define UNSET_MESH_FRAME(x) (x->cb[6]=0) + +/** Global Variable Declaration */ +typedef struct _wlan_private wlan_private; +typedef struct _wlan_adapter wlan_adapter; +extern const char libertas_driver_version[]; +extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; + +extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES]; + +extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; + +extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; + +extern u8 libertas_adhoc_rates_b[4]; + +/** ENUM definition*/ +/** SNRNF_TYPE */ +enum SNRNF_TYPE { + TYPE_BEACON = 0, + TYPE_RXPD, + MAX_TYPE_B +}; + +/** SNRNF_DATA*/ +enum SNRNF_DATA { + TYPE_NOAVG = 0, + TYPE_AVG, + MAX_TYPE_AVG +}; + +/** WLAN_802_11_AUTH_ALG*/ +enum WLAN_802_11_AUTH_ALG { + AUTH_ALG_OPEN_SYSTEM = 1, + AUTH_ALG_SHARED_KEY = 2, + AUTH_ALG_NETWORK_EAP = 8, +}; + +/** WLAN_802_1X_AUTH_ALG */ +enum WLAN_802_1X_AUTH_ALG { + WLAN_1X_AUTH_ALG_NONE = 1, + WLAN_1X_AUTH_ALG_LEAP = 2, + WLAN_1X_AUTH_ALG_TLS = 4, + WLAN_1X_AUTH_ALG_TTLS = 8, + WLAN_1X_AUTH_ALG_MD5 = 16, +}; + +/** WLAN_802_11_ENCRYPTION_MODE */ +enum WLAN_802_11_ENCRYPTION_MODE { + CIPHER_NONE, + CIPHER_WEP40, + CIPHER_TKIP, + CIPHER_CCMP, + CIPHER_WEP104, +}; + +/** WLAN_802_11_POWER_MODE */ +enum WLAN_802_11_POWER_MODE { + wlan802_11powermodecam, + wlan802_11powermodemax_psp, + wlan802_11Powermodefast_psp, + /*not a real mode, defined as an upper bound */ + wlan802_11powemodemax +}; + +/** PS_STATE */ +enum PS_STATE { + PS_STATE_FULL_POWER, + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP +}; + +/** DNLD_STATE */ +enum DNLD_STATE { + DNLD_RES_RECEIVED, + DNLD_DATA_SENT, + DNLD_CMD_SENT +}; + +/** WLAN_MEDIA_STATE */ +enum WLAN_MEDIA_STATE { + libertas_connected, + libertas_disconnected +}; + +/** WLAN_802_11_PRIVACY_FILTER */ +enum WLAN_802_11_PRIVACY_FILTER { + wlan802_11privfilteracceptall, + wlan802_11privfilter8021xWEP +}; + +/** mv_ms_type */ +enum mv_ms_type { + MVMS_DAT = 0, + MVMS_CMD = 1, + MVMS_TXDONE = 2, + MVMS_EVENT +}; + +/** WLAN_802_11_NETWORK_INFRASTRUCTURE */ +enum WLAN_802_11_NETWORK_INFRASTRUCTURE { + wlan802_11ibss, + wlan802_11infrastructure, + wlan802_11autounknown, + /*defined as upper bound */ + wlan802_11infrastructuremax +}; + +/** WLAN_802_11_AUTHENTICATION_MODE */ +enum WLAN_802_11_AUTHENTICATION_MODE { + wlan802_11authmodeopen = 0x00, + wlan802_11authmodeshared = 0x01, + wlan802_11authmodenetworkEAP = 0x80, +}; + +/** WLAN_802_11_WEP_STATUS */ +enum WLAN_802_11_WEP_STATUS { + wlan802_11WEPenabled, + wlan802_11WEPdisabled, +}; + +/** SNMP_MIB_INDEX_e */ +enum SNMP_MIB_INDEX_e { + desired_bsstype_i = 0, + op_rateset_i, + bcnperiod_i, + dtimperiod_i, + assocrsp_timeout_i, + rtsthresh_i, + short_retrylim_i, + long_retrylim_i, + fragthresh_i, + dot11d_i, + dot11h_i, + manufid_i, + prodID_i, + manuf_oui_i, + manuf_name_i, + manuf_prodname_i, + manuf_prodver_i, +}; + +/** KEY_TYPE_ID */ +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES +}; + +/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ +enum KEY_INFO_WPA { + KEY_INFO_WPA_MCAST = 0x01, + KEY_INFO_WPA_UNICAST = 0x02, + KEY_INFO_WPA_ENABLED = 0x04 +}; + +/** SNMP_MIB_VALUE_e */ +enum SNMP_MIB_VALUE_e { + SNMP_MIB_VALUE_INFRA = 1, + SNMP_MIB_VALUE_ADHOC +}; + +/* Default values for fwt commands. */ +#define FWT_DEFAULT_METRIC 0 +#define FWT_DEFAULT_DIR 1 +#define FWT_DEFAULT_SSN 0xffffffff +#define FWT_DEFAULT_DSN 0 +#define FWT_DEFAULT_HOPCOUNT 0 +#define FWT_DEFAULT_TTL 0 +#define FWT_DEFAULT_EXPIRATION 0 +#define FWT_DEFAULT_SLEEPMODE 0 +#define FWT_DEFAULT_SNR 0 + +#endif /* _WLAN_DEFS_H_ */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h new file mode 100644 index 0000000..b1f876f --- /dev/null +++ b/drivers/net/wireless/libertas/dev.h @@ -0,0 +1,403 @@ +/** + * This file contains definitions and data structures specific + * to Marvell 802.11 NIC. It contains the Device Information + * structure wlan_adapter. + */ +#ifndef _WLAN_DEV_H_ +#define _WLAN_DEV_H_ + +#include +#include +#include +#include + +#include "defs.h" +#include "scan.h" +#include "thread.h" + +extern struct ethtool_ops libertas_ethtool_ops; + +#define MAX_BSSID_PER_CHANNEL 16 + +#define NR_TX_QUEUE 3 + +/* For the extended Scan */ +#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \ + MRVDRV_MAX_CHANNEL_SIZE + 1 + +#define MAX_REGION_CHANNEL_NUM 2 + +/** Chan-freq-TxPower mapping table*/ +struct chan_freq_power { + /** channel Number */ + u16 channel; + /** frequency of this channel */ + u32 freq; + /** Max allowed Tx power level */ + u16 maxtxpower; + /** TRUE:channel unsupported; FLASE:supported*/ + u8 unsupported; +}; + +/** region-band mapping table*/ +struct region_channel { + /** TRUE if this entry is valid */ + u8 valid; + /** region code for US, Japan ... */ + u8 region; + /** band B/G/A, used for BAND_CONFIG cmd */ + u8 band; + /** Actual No. of elements in the array below */ + u8 nrcfp; + /** chan-freq-txpower mapping table*/ + struct chan_freq_power *CFP; +}; + +struct wlan_802_11_security { + u8 WPAenabled; + u8 WPA2enabled; + enum WLAN_802_11_WEP_STATUS WEPstatus; + enum WLAN_802_11_AUTHENTICATION_MODE authmode; + enum WLAN_802_1X_AUTH_ALG auth1xalg; + enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode; +}; + +/** Current Basic Service Set State Structure */ +struct current_bss_params { + struct bss_descriptor bssdescriptor; + /** bssid */ + u8 bssid[ETH_ALEN]; + /** ssid */ + struct WLAN_802_11_SSID ssid; + + /** band */ + u8 band; + /** channel */ + u8 channel; + /** number of rates supported */ + int numofrates; + /** supported rates*/ + u8 datarates[WLAN_SUPPORTED_RATES]; +}; + +/** sleep_params */ +struct sleep_params { + u16 sp_error; + u16 sp_offset; + u16 sp_stabletime; + u8 sp_calcontrol; + u8 sp_extsleepclk; + u16 sp_reserved; +}; + +/** Data structure for the Marvell WLAN device */ +typedef struct _wlan_dev { + /** device name */ + char name[DEV_NAME_LEN]; + /** card pointer */ + void *card; + /** IO port */ + u32 ioport; + /** Upload received */ + u32 upld_rcv; + /** Upload type */ + u32 upld_typ; + /** Upload length */ + u32 upld_len; + /** netdev pointer */ + struct net_device *netdev; + /* Upload buffer */ + u8 upld_buf[WLAN_UPLD_SIZE]; + /* Download sent: + bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ + u8 dnld_sent; +} wlan_dev_t, *pwlan_dev_t; + +/* Mesh statistics */ +struct wlan_mesh_stats { + u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ + u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ + u32 fwd_drop_ttl; /* Fwd: TTL zero */ + u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ + u32 fwd_drop_noroute; /* Fwd: No route to Destination */ + u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ + u32 drop_blind; /* Rx: Dropped by blinding table */ +}; + +/** Private structure for the MV device */ +struct _wlan_private { + int open; + int mesh_open; + int infra_open; + + wlan_adapter *adapter; + wlan_dev_t wlan_dev; + + struct net_device_stats stats; + struct net_device *mesh_dev ; /* Virtual device */ + + struct iw_statistics wstats; + struct wlan_mesh_stats mstats; + struct dentry *debugfs_dir; + struct dentry *debugfs_debug; + struct dentry *debugfs_files[6]; + + struct dentry *events_dir; + struct dentry *debugfs_events_files[6]; + + struct dentry *regs_dir; + struct dentry *debugfs_regs_files[6]; + + u32 mac_offset; + u32 bbp_offset; + u32 rf_offset; + + const struct firmware *firmware; + struct device *hotplug_device; + + /** thread to service interrupts */ + struct wlan_thread mainthread; + + struct delayed_work assoc_work; + struct workqueue_struct *assoc_thread; +}; + +/** Association request + * + * Encapsulates all the options that describe a specific assocation request + * or configuration of the wireless card's radio, mode, and security settings. + */ +struct assoc_request { +#define ASSOC_FLAG_SSID 1 +#define ASSOC_FLAG_CHANNEL 2 +#define ASSOC_FLAG_MODE 3 +#define ASSOC_FLAG_BSSID 4 +#define ASSOC_FLAG_WEP_KEYS 5 +#define ASSOC_FLAG_WEP_TX_KEYIDX 6 +#define ASSOC_FLAG_WPA_MCAST_KEY 7 +#define ASSOC_FLAG_WPA_UCAST_KEY 8 +#define ASSOC_FLAG_SECINFO 9 +#define ASSOC_FLAG_WPA_IE 10 + unsigned long flags; + + struct WLAN_802_11_SSID ssid; + u8 channel; + enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode; + u8 bssid[ETH_ALEN]; + + /** WEP keys */ + struct WLAN_802_11_KEY wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ + struct WLAN_802_11_KEY wpa_mcast_key; + struct WLAN_802_11_KEY wpa_unicast_key; + + struct wlan_802_11_security secinfo; + + /** WPA Information Elements*/ +#define MAX_WPA_IE_LEN 64 + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; +}; + +/** Wlan adapter data structure*/ +struct _wlan_adapter { + /** STATUS variables */ + u32 fwreleasenumber; + u32 fwcapinfo; + /* protected with big lock */ + + struct mutex lock; + + u8 tmptxbuf[WLAN_UPLD_SIZE]; + /* protected by hard_start_xmit serialization */ + + /** command-related variables */ + u16 seqnum; + /* protected by big lock */ + + struct cmd_ctrl_node *cmd_array; + /** Current command */ + struct cmd_ctrl_node *cur_cmd; + int cur_cmd_retcode; + /** command Queues */ + /** Free command buffers */ + struct list_head cmdfreeq; + /** Pending command buffers */ + struct list_head cmdpendingq; + + wait_queue_head_t cmd_pending; + u8 nr_cmd_pending; + /* command related variables protected by adapter->driver_lock */ + + /** Async and Sync Event variables */ + u32 intcounter; + u32 eventcause; + u8 nodename[16]; /* nickname */ + + /** spin locks */ + spinlock_t driver_lock; + + /** Timers */ + struct timer_list command_timer; + + /* TX queue used in PS mode */ + spinlock_t txqueue_lock; + struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; + unsigned int tx_queue_idx; + + u8 hisregcpy; + + /** current ssid/bssid related parameters*/ + struct current_bss_params curbssparams; + + enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; + + struct bss_descriptor *pattemptedbssdesc; + + struct WLAN_802_11_SSID previousssid; + u8 previousbssid[ETH_ALEN]; + + struct bss_descriptor *scantable; + u32 numinscantable; + + u8 scantype; + u32 scanmode; + + u16 beaconperiod; + u8 adhoccreate; + + /** capability Info used in Association, start, join */ + struct ieeetypes_capinfo capinfo; + + /** MAC address information */ + u8 current_addr[ETH_ALEN]; + u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; + u32 nr_of_multicastmacaddr; + + /** 802.11 statistics */ +// struct cmd_DS_802_11_GET_STAT wlan802_11Stat; + + u16 enablehwauto; + u16 ratebitmap; + /** control G rates */ + u8 adhoc_grate_enabled; + + u32 txantenna; + u32 rxantenna; + + u8 adhocchannel; + u32 fragthsd; + u32 rtsthsd; + + u32 datarate; + u8 is_datarate_auto; + + u16 listeninterval; + u16 prescan; + u8 txretrycount; + + /** Tx-related variables (for single packet tx) */ + struct sk_buff *currenttxskb; + u16 TxLockFlag; + + /** NIC Operation characteristics */ + u16 currentpacketfilter; + u32 connect_status; + u16 regioncode; + u16 regiontableindex; + u16 txpowerlevel; + + /** POWER MANAGEMENT AND PnP SUPPORT */ + u8 surpriseremoved; + u16 atimwindow; + + u16 psmode; /* Wlan802_11PowermodeCAM=disable + Wlan802_11PowermodeMAX_PSP=enable */ + u16 multipledtim; + u32 psstate; + u8 needtowakeup; + + struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; + u16 locallisteninterval; + u16 nullpktinterval; + + struct assoc_request * assoc_req; + + /** Encryption parameter */ + struct wlan_802_11_security secinfo; + + /** WEP keys */ + struct WLAN_802_11_KEY wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ + struct WLAN_802_11_KEY wpa_mcast_key; + struct WLAN_802_11_KEY wpa_unicast_key; + + /** WPA Information Elements*/ +#define MAX_WPA_IE_LEN 64 + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + + u16 rxantennamode; + u16 txantennamode; + + /** Requested Signal Strength*/ + u16 bcn_avg_factor; + u16 data_avg_factor; + u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; + u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; + u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; + u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; + u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; + u16 nextSNRNF; + u16 numSNRNF; + u16 rxpd_rate; + + u8 radioon; + u32 preamble; + + /** Multi bands Parameter*/ + u8 libertas_supported_rates[G_SUPPORTED_RATES]; + + /** Blue Tooth Co-existence Arbitration */ + + /** sleep_params */ + struct sleep_params sp; + + /** RF calibration data */ + +#define MAX_REGION_CHANNEL_NUM 2 + /** region channel data */ + struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; + + struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; + + /** 11D and Domain Regulatory Data */ + struct wlan_802_11d_domain_reg domainreg; + struct parsed_region_chan_11d parsed_region_chan; + + /** FSM variable for 11d support */ + u32 enable11d; + + /** MISCELLANEOUS */ + u8 *prdeeprom; + struct wlan_offset_value offsetvalue; + + struct cmd_ds_802_11_get_log logmsg; + u16 scanprobes; + + u32 pkttxctrl; + + u16 txrate; + u32 linkmode; + u32 radiomode; + u32 debugmode; + u8 fw_ready; +}; + +#endif /* _WLAN_DEV_H_ */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c new file mode 100644 index 0000000..0064de5 --- /dev/null +++ b/drivers/net/wireless/libertas/ethtool.c @@ -0,0 +1,184 @@ + +#include +#include +#include + +#include "host.h" +#include "sbi.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "wext.h" +static const char * mesh_stat_strings[]= { + "drop_duplicate_bcast", + "drop_ttl_zero", + "drop_no_fwd_route", + "drop_no_buffers", + "fwded_unicast_cnt", + "fwded_bcast_cnt", + "drop_blind_table" +}; + +static void libertas_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + wlan_private *priv = (wlan_private *) dev->priv; + char fwver[32]; + + libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); + + strcpy(info->driver, "libertas"); + strcpy(info->version, libertas_driver_version); + strcpy(info->fw_version, fwver); +} + +/* All 8388 parts have 16KiB EEPROM size at the time of writing. + * In case that changes this needs fixing. + */ +#define LIBERTAS_EEPROM_LEN 16384 + +static int libertas_ethtool_get_eeprom_len(struct net_device *dev) +{ + return LIBERTAS_EEPROM_LEN; +} + +static int libertas_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 * bytes) +{ + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *adapter = priv->adapter; + struct wlan_ioctl_regrdwr regctrl; + char *ptr; + int ret; + + regctrl.action = 0; + regctrl.offset = eeprom->offset; + regctrl.NOB = eeprom->len; + + if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) + return -EINVAL; + +// mutex_lock(&priv->mutex); + + adapter->prdeeprom = + (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); + if (!adapter->prdeeprom) + return -ENOMEM; + memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); + + /* +14 is for action, offset, and NOB in + * response */ + lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n", + regctrl.action, regctrl.offset, regctrl.NOB); + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_eeprom_access, + regctrl.action, + cmd_option_waitforrsp, 0, + ®ctrl); + + if (ret) { + if (adapter->prdeeprom) + kfree(adapter->prdeeprom); + LEAVE(); + return ret; + } + + mdelay(10); + + ptr = (char *)adapter->prdeeprom; + + /* skip the command header, but include the "value" u32 variable */ + ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; + + /* + * Return the result back to the user + */ + memcpy(bytes, ptr, eeprom->len); + + if (adapter->prdeeprom) + kfree(adapter->prdeeprom); +// mutex_unlock(&priv->mutex); + + return 0; +} + +static void libertas_ethtool_get_stats(struct net_device * dev, + struct ethtool_stats * stats, u64 * data) +{ + wlan_private *priv = dev->priv; + + ENTER(); + + stats->cmd = ETHTOOL_GSTATS; + BUG_ON(stats->n_stats != MESH_STATS_NUM); + + data[0] = priv->mstats.fwd_drop_rbt; + data[1] = priv->mstats.fwd_drop_ttl; + data[2] = priv->mstats.fwd_drop_noroute; + data[3] = priv->mstats.fwd_drop_nobuf; + data[4] = priv->mstats.fwd_unicast_cnt; + data[5] = priv->mstats.fwd_bcast_cnt; + data[6] = priv->mstats.drop_blind; + + LEAVE(); +} + +static int libertas_ethtool_get_stats_count(struct net_device * dev) +{ + int ret; + wlan_private *priv = dev->priv; + struct cmd_ds_mesh_access mesh_access; + + ENTER(); + /* Get Mesh Statistics */ + ret = libertas_prepare_and_send_command(priv, + cmd_mesh_access, cmd_act_mesh_get_stats, + cmd_option_waitforrsp, 0, &mesh_access); + + if (ret) { + LEAVE(); + return 0; + } + + priv->mstats.fwd_drop_rbt = mesh_access.data[0]; + priv->mstats.fwd_drop_ttl = mesh_access.data[1]; + priv->mstats.fwd_drop_noroute = mesh_access.data[2]; + priv->mstats.fwd_drop_nobuf = mesh_access.data[3]; + priv->mstats.fwd_unicast_cnt = mesh_access.data[4]; + priv->mstats.fwd_bcast_cnt = mesh_access.data[5]; + priv->mstats.drop_blind = mesh_access.data[6]; + + LEAVE(); + return MESH_STATS_NUM; +} + +static void libertas_ethtool_get_strings (struct net_device * dev, + u32 stringset, + u8 * s) +{ + int i; + + ENTER(); + switch (stringset) { + case ETH_SS_STATS: + for (i=0; i < MESH_STATS_NUM; i++) { + memcpy(s + i * ETH_GSTRING_LEN, + mesh_stat_strings[i], + ETH_GSTRING_LEN); + } + break; + } + LEAVE(); +} + +struct ethtool_ops libertas_ethtool_ops = { + .get_drvinfo = libertas_ethtool_get_drvinfo, + .get_eeprom = libertas_ethtool_get_eeprom, + .get_eeprom_len = libertas_ethtool_get_eeprom_len, + .get_stats_count = libertas_ethtool_get_stats_count, + .get_ethtool_stats = libertas_ethtool_get_stats, + .get_strings = libertas_ethtool_get_strings, +}; + diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c new file mode 100644 index 0000000..b194a45 --- /dev/null +++ b/drivers/net/wireless/libertas/fw.c @@ -0,0 +1,361 @@ +/** + * This file contains the initialization for FW and HW + */ +#include +#include + +#include +#include +#include + +#include "host.h" +#include "sbi.h" +#include "defs.h" +#include "decl.h" +#include "dev.h" +#include "fw.h" +#include "wext.h" +#include "if_usb.h" + +char *libertas_fw_name = NULL; +module_param_named(fw_name, libertas_fw_name, charp, 0644); + +unsigned int libertas_debug = 0; +module_param(libertas_debug, int, 0); + +/** + * @brief This function checks the validity of Boot2/FW image. + * + * @param data pointer to image + * len image length + * @return 0 or -1 + */ +static int check_fwfile_format(u8 *data, u32 totlen) +{ + u8 bincmd, exit; + u32 blksize, offset, len; + int ret; + + ret = 1; + exit = len = 0; + + do { + bincmd = *data; + blksize = *(u32*)(data + offsetof(struct fwheader, datalength)); + switch (bincmd) { + case FW_HAS_DATA_TO_RECV: + offset = sizeof(struct fwheader) + blksize; + data += offset; + len += offset; + if (len >= totlen) + exit = 1; + break; + case FW_HAS_LAST_BLOCK: + exit = 1; + ret = 0; + break; + default: + exit = 1; + break; + } + } while (!exit); + + if (ret) + lbs_pr_err("bin file format check FAIL...\n"); + else + lbs_pr_debug(1, "bin file format check PASS...\n"); + + return ret; +} + +/** + * @brief This function downloads firmware image, gets + * HW spec from firmware and set basic parameters to + * firmware. + * + * @param priv A pointer to wlan_private structure + * @return 0 or -1 + */ +static int wlan_setup_station_hw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if ((ret = request_firmware(&priv->firmware, libertas_fw_name, + priv->hotplug_device)) < 0) { + lbs_pr_err("request_firmware() failed, error code = %#x\n", + ret); + lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name); + goto done; + } + + if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) { + release_firmware(priv->firmware); + goto done; + } + + ret = libertas_sbi_prog_firmware(priv); + + release_firmware(priv->firmware); + + if (ret) { + lbs_pr_debug(1, "Bootloader in invalid state!\n"); + ret = -1; + goto done; + } + + /* + * Read MAC address from HW + */ + memset(adapter->current_addr, 0xff, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, + 0, cmd_option_waitforrsp, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + libertas_set_mac_packet_filter(priv); + + /* Get the supported Data rates */ + ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, + cmd_act_get_tx_rate, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + ret = -1; + goto done; + } + + ret = 0; +done: + LEAVE(); + + return (ret); +} + +static int wlan_allocate_adapter(wlan_private * priv) +{ + u32 ulbufsize; + wlan_adapter *adapter = priv->adapter; + + struct bss_descriptor *ptempscantable; + + /* Allocate buffer to store the BSSID list */ + ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; + if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) { + libertas_free_adapter(priv); + return -1; + } + + adapter->scantable = ptempscantable; + memset(adapter->scantable, 0, ulbufsize); + + /* Allocate the command buffers */ + libertas_allocate_cmd_buffer(priv); + + memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); + adapter->libertas_ps_confirm_sleep.command = + cpu_to_le16(cmd_802_11_ps_mode); + adapter->libertas_ps_confirm_sleep.size = + cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); + adapter->libertas_ps_confirm_sleep.result = 0; + adapter->libertas_ps_confirm_sleep.action = + cpu_to_le16(cmd_subcmd_sleep_confirmed); + + return 0; +} + +static void wlan_init_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int i; + + adapter->scanprobes = 0; + + adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + /* ATIM params */ + adapter->atimwindow = 0; + + adapter->connect_status = libertas_disconnected; + memset(adapter->current_addr, 0xff, ETH_ALEN); + + /* scan type */ + adapter->scantype = cmd_scan_type_active; + + /* scan mode */ + adapter->scanmode = cmd_bss_type_any; + + /* 802.11 specific */ + adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; + for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); + i++) + memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); + adapter->wep_tx_keyidx = 0; + adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; + adapter->secinfo.authmode = wlan802_11authmodeopen; + adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; + adapter->secinfo.Encryptionmode = CIPHER_NONE; + adapter->inframode = wlan802_11infrastructure; + + adapter->assoc_req = NULL; + + adapter->numinscantable = 0; + adapter->pattemptedbssdesc = NULL; + mutex_init(&adapter->lock); + + adapter->prescan = 1; + + memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); + + /* PnP and power profile */ + adapter->surpriseremoved = 0; + + adapter->currentpacketfilter = + cmd_act_mac_rx_on | cmd_act_mac_tx_on; + + adapter->radioon = RADIO_ON; + adapter->txantenna = RF_ANTENNA_2; + adapter->rxantenna = RF_ANTENNA_AUTO; + + adapter->is_datarate_auto = 1; + adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; + + // set default value of capinfo. +#define SHORT_PREAMBLE_ALLOWED 1 + memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); + adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; + + adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; + + adapter->psmode = wlan802_11powermodecam; + adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; + + adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; + + adapter->psstate = PS_STATE_FULL_POWER; + adapter->needtowakeup = 0; + adapter->locallisteninterval = 0; /* default value in firmware will be used */ + + adapter->datarate = 0; // Initially indicate the rate as auto + + adapter->adhoc_grate_enabled = 0; + + adapter->intcounter = 0; + + adapter->currenttxskb = NULL; + adapter->pkttxctrl = 0; + + memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); + adapter->tx_queue_idx = 0; + spin_lock_init(&adapter->txqueue_lock); + + return; +} + +static void command_timer_fn(unsigned long data); + +int libertas_init_fw(wlan_private * priv) +{ + int ret = -1; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* Allocate adapter structure */ + if ((ret = wlan_allocate_adapter(priv)) != 0) + goto done; + + /* init adapter structure */ + wlan_init_adapter(priv); + + /* init timer etc. */ + setup_timer(&adapter->command_timer, command_timer_fn, + (unsigned long)priv); + + /* download fimrware etc. */ + if ((ret = wlan_setup_station_hw(priv)) != 0) { + del_timer_sync(&adapter->command_timer); + goto done; + } + + /* init 802.11d */ + libertas_init_11d(priv); + + ret = 0; +done: + LEAVE(); + return ret; +} + +void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + + if (!adapter) { + lbs_pr_debug(1, "Why double free adapter?:)\n"); + return; + } + + lbs_pr_debug(1, "Free command buffer\n"); + libertas_free_cmd_buffer(priv); + + lbs_pr_debug(1, "Free commandTimer\n"); + del_timer(&adapter->command_timer); + + lbs_pr_debug(1, "Free scantable\n"); + if (adapter->scantable) { + kfree(adapter->scantable); + adapter->scantable = NULL; + } + + lbs_pr_debug(1, "Free adapter\n"); + + /* Free the adapter object itself */ + kfree(adapter); + priv->adapter = NULL; +} + +/** + * This function handles the timeout of command sending. + * It will re-send the same command again. + */ +static void command_timer_fn(unsigned long data) +{ + wlan_private *priv = (wlan_private *)data; + wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *ptempnode; + struct cmd_ds_command *cmd; + unsigned long flags; + + ptempnode = adapter->cur_cmd; + cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; + + lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command); + + if (!adapter->fw_ready) + return; + + if (ptempnode == NULL) { + lbs_pr_debug(1, "PTempnode Empty\n"); + return; + } + + spin_lock_irqsave(&adapter->driver_lock, flags); + adapter->cur_cmd = NULL; + spin_unlock_irqrestore(&adapter->driver_lock, flags); + + lbs_pr_debug(1, "Re-sending same command as it timeout...!\n"); + libertas_queue_cmd(adapter, ptempnode, 0); + + wake_up_interruptible(&priv->mainthread.waitq); + + return; +} diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h new file mode 100644 index 0000000..1f9ae26 --- /dev/null +++ b/drivers/net/wireless/libertas/fw.h @@ -0,0 +1,13 @@ +/** + * This header file contains FW interface related definitions. + */ +#ifndef _WLAN_FW_H_ +#define _WLAN_FW_H_ + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +int libertas_init_fw(wlan_private * priv); + +#endif /* _WLAN_FW_H_ */ diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h new file mode 100644 index 0000000..c0faaec --- /dev/null +++ b/drivers/net/wireless/libertas/host.h @@ -0,0 +1,338 @@ +/** + * This file contains definitions of WLAN commands. + */ + +#ifndef _HOST_H_ +#define _HOST_H_ + +/** PUBLIC DEFINITIONS */ +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 + +/** IEEE 802.11 oids */ +#define OID_802_11_SSID 0x00008002 +#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 +#define OID_802_11_RTS_THRESHOLD 0x0000800A +#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D +#define OID_802_11_SUPPORTED_RATES 0x0000800E +#define OID_802_11_STATISTICS 0x00008012 +#define OID_802_11_TX_RETRYCOUNT 0x0000801D +#define OID_802_11D_ENABLE 0x00008020 + +#define cmd_option_waitforrsp 0x0002 + +/** Host command ID */ +#define cmd_code_dnld 0x0002 +#define cmd_get_hw_spec 0x0003 +#define cmd_eeprom_update 0x0004 +#define cmd_802_11_reset 0x0005 +#define cmd_802_11_scan 0x0006 +#define cmd_802_11_get_log 0x000b +#define cmd_mac_multicast_adr 0x0010 +#define cmd_802_11_authenticate 0x0011 +#define cmd_802_11_eeprom_access 0x0059 +#define cmd_802_11_associate 0x0050 +#define cmd_802_11_set_wep 0x0013 +#define cmd_802_11_get_stat 0x0014 +#define cmd_802_3_get_stat 0x0015 +#define cmd_802_11_snmp_mib 0x0016 +#define cmd_mac_reg_map 0x0017 +#define cmd_bbp_reg_map 0x0018 +#define cmd_mac_reg_access 0x0019 +#define cmd_bbp_reg_access 0x001a +#define cmd_rf_reg_access 0x001b +#define cmd_802_11_radio_control 0x001c +#define cmd_802_11_rf_channel 0x001d +#define cmd_802_11_rf_tx_power 0x001e +#define cmd_802_11_rssi 0x001f +#define cmd_802_11_rf_antenna 0x0020 + +#define cmd_802_11_ps_mode 0x0021 + +#define cmd_802_11_data_rate 0x0022 +#define cmd_rf_reg_map 0x0023 +#define cmd_802_11_deauthenticate 0x0024 +#define cmd_802_11_reassociate 0x0025 +#define cmd_802_11_disassociate 0x0026 +#define cmd_mac_control 0x0028 +#define cmd_802_11_ad_hoc_start 0x002b +#define cmd_802_11_ad_hoc_join 0x002c + +#define cmd_802_11_query_tkip_reply_cntrs 0x002e +#define cmd_802_11_enable_rsn 0x002f +#define cmd_802_11_pairwise_tsc 0x0036 +#define cmd_802_11_group_tsc 0x0037 +#define cmd_802_11_key_material 0x005e + +#define cmd_802_11_set_afc 0x003c +#define cmd_802_11_get_afc 0x003d + +#define cmd_802_11_ad_hoc_stop 0x0040 + +#define cmd_802_11_beacon_stop 0x0049 + +#define cmd_802_11_mac_address 0x004D +#define cmd_802_11_eeprom_access 0x0059 + +#define cmd_802_11_band_config 0x0058 + +#define cmd_802_11d_domain_info 0x005b + +#define cmd_802_11_sleep_params 0x0066 + +#define cmd_802_11_inactivity_timeout 0x0067 + +#define cmd_802_11_tpc_cfg 0x0072 +#define cmd_802_11_pwr_cfg 0x0073 + +#define cmd_802_11_led_gpio_ctrl 0x004e + +#define cmd_802_11_subscribe_event 0x0075 + +#define cmd_802_11_rate_adapt_rateset 0x0076 + +#define cmd_802_11_tx_rate_query 0x007f + +#define cmd_get_tsf 0x0080 + +#define cmd_bt_access 0x0087 +#define cmd_ret_bt_access 0x8087 + +#define cmd_fwt_access 0x0088 +#define cmd_ret_fwt_access 0x8088 + +#define cmd_mesh_access 0x0090 +#define cmd_ret_mesh_access 0x8090 + +/* For the IEEE Power Save */ +#define cmd_subcmd_enter_ps 0x0030 +#define cmd_subcmd_exit_ps 0x0031 +#define cmd_subcmd_sleep_confirmed 0x0034 +#define cmd_subcmd_full_powerdown 0x0035 +#define cmd_subcmd_full_powerup 0x0036 + +/* command RET code, MSB is set to 1 */ +#define cmd_ret_hw_spec_info 0x8003 +#define cmd_ret_eeprom_update 0x8004 +#define cmd_ret_802_11_reset 0x8005 +#define cmd_ret_802_11_scan 0x8006 +#define cmd_ret_802_11_get_log 0x800b +#define cmd_ret_mac_control 0x8028 +#define cmd_ret_mac_multicast_adr 0x8010 +#define cmd_ret_802_11_authenticate 0x8011 +#define cmd_ret_802_11_deauthenticate 0x8024 +#define cmd_ret_802_11_associate 0x8012 +#define cmd_ret_802_11_reassociate 0x8025 +#define cmd_ret_802_11_disassociate 0x8026 +#define cmd_ret_802_11_set_wep 0x8013 +#define cmd_ret_802_11_stat 0x8014 +#define cmd_ret_802_3_stat 0x8015 +#define cmd_ret_802_11_snmp_mib 0x8016 +#define cmd_ret_mac_reg_map 0x8017 +#define cmd_ret_bbp_reg_map 0x8018 +#define cmd_ret_rf_reg_map 0x8023 +#define cmd_ret_mac_reg_access 0x8019 +#define cmd_ret_bbp_reg_access 0x801a +#define cmd_ret_rf_reg_access 0x801b +#define cmd_ret_802_11_radio_control 0x801c +#define cmd_ret_802_11_rf_channel 0x801d +#define cmd_ret_802_11_rssi 0x801f +#define cmd_ret_802_11_rf_tx_power 0x801e +#define cmd_ret_802_11_rf_antenna 0x8020 +#define cmd_ret_802_11_ps_mode 0x8021 +#define cmd_ret_802_11_data_rate 0x8022 + +#define cmd_ret_802_11_ad_hoc_start 0x802B +#define cmd_ret_802_11_ad_hoc_join 0x802C + +#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e +#define cmd_ret_802_11_enable_rsn 0x802f +#define cmd_ret_802_11_pairwise_tsc 0x8036 +#define cmd_ret_802_11_group_tsc 0x8037 +#define cmd_ret_802_11_key_material 0x805e + +#define cmd_enable_rsn 0x0001 +#define cmd_disable_rsn 0x0000 + +#define cmd_act_set 0x0001 +#define cmd_act_get 0x0000 + +#define cmd_act_get_AES (cmd_act_get + 2) +#define cmd_act_set_AES (cmd_act_set + 2) +#define cmd_act_remove_aes (cmd_act_set + 3) + +#define cmd_ret_802_11_set_afc 0x803c +#define cmd_ret_802_11_get_afc 0x803d + +#define cmd_ret_802_11_ad_hoc_stop 0x8040 + +#define cmd_ret_802_11_beacon_stop 0x8049 + +#define cmd_ret_802_11_mac_address 0x804D +#define cmd_ret_802_11_eeprom_access 0x8059 + +#define cmd_ret_802_11_band_config 0x8058 + +#define cmd_ret_802_11_sleep_params 0x8066 + +#define cmd_ret_802_11_inactivity_timeout 0x8067 + +#define cmd_ret_802_11d_domain_info (0x8000 | \ + cmd_802_11d_domain_info) + +#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000) +#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000) + +#define cmd_ret_802_11_led_gpio_ctrl 0x804e + +#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000) + +#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000) + +#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000) + +#define cmd_ret_get_tsf 0x8080 + +/* Define action or option for cmd_802_11_set_wep */ +#define cmd_act_add 0x0002 +#define cmd_act_remove 0x0004 +#define cmd_act_use_default 0x0008 + +#define cmd_type_wep_40_bit 0x0001 +#define cmd_type_wep_104_bit 0x0002 + +#define cmd_NUM_OF_WEP_KEYS 4 + +#define cmd_WEP_KEY_INDEX_MASK 0x3fff + +/* Define action or option for cmd_802_11_reset */ +#define cmd_act_halt 0x0003 + +/* Define action or option for cmd_802_11_scan */ +#define cmd_bss_type_bss 0x0001 +#define cmd_bss_type_ibss 0x0002 +#define cmd_bss_type_any 0x0003 + +/* Define action or option for cmd_802_11_scan */ +#define cmd_scan_type_active 0x0000 +#define cmd_scan_type_passive 0x0001 + +#define cmd_scan_radio_type_bg 0 + +#define cmd_scan_probe_delay_time 0 + +/* Define action or option for cmd_mac_control */ +#define cmd_act_mac_rx_on 0x0001 +#define cmd_act_mac_tx_on 0x0002 +#define cmd_act_mac_loopback_on 0x0004 +#define cmd_act_mac_wep_enable 0x0008 +#define cmd_act_mac_int_enable 0x0010 +#define cmd_act_mac_multicast_enable 0x0020 +#define cmd_act_mac_broadcast_enable 0x0040 +#define cmd_act_mac_promiscuous_enable 0x0080 +#define cmd_act_mac_all_multicast_enable 0x0100 +#define cmd_act_mac_strict_protection_enable 0x0400 + +/* Define action or option for cmd_802_11_radio_control */ +#define cmd_type_auto_preamble 0x0001 +#define cmd_type_short_preamble 0x0002 +#define cmd_type_long_preamble 0x0003 + +#define TURN_ON_RF 0x01 +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +#define SET_AUTO_PREAMBLE 0x05 +#define SET_SHORT_PREAMBLE 0x03 +#define SET_LONG_PREAMBLE 0x01 + +/* Define action or option for CMD_802_11_RF_CHANNEL */ +#define cmd_opt_802_11_rf_channel_get 0x00 +#define cmd_opt_802_11_rf_channel_set 0x01 + +/* Define action or option for cmd_802_11_rf_tx_power */ +#define cmd_act_tx_power_opt_get 0x0000 +#define cmd_act_tx_power_opt_set_high 0x8007 +#define cmd_act_tx_power_opt_set_mid 0x8004 +#define cmd_act_tx_power_opt_set_low 0x8000 + +#define cmd_act_tx_power_index_high 0x0007 +#define cmd_act_tx_power_index_mid 0x0004 +#define cmd_act_tx_power_index_low 0x0000 + +/* Define action or option for cmd_802_11_data_rate */ +#define cmd_act_set_tx_auto 0x0000 +#define cmd_act_set_tx_fix_rate 0x0001 +#define cmd_act_get_tx_rate 0x0002 + +#define cmd_act_set_rx 0x0001 +#define cmd_act_set_tx 0x0002 +#define cmd_act_set_both 0x0003 +#define cmd_act_get_rx 0x0004 +#define cmd_act_get_tx 0x0008 +#define cmd_act_get_both 0x000c + +/* Define action or option for cmd_802_11_ps_mode */ +#define cmd_type_cam 0x0000 +#define cmd_type_max_psp 0x0001 +#define cmd_type_fast_psp 0x0002 + +/* Define action or option for cmd_bt_access */ +enum cmd_bt_access_opts { + /* The bt commands start at 5 instead of 1 because the old dft commands + * are mapped to 1-4. These old commands are no longer maintained and + * should not be called. + */ + cmd_act_bt_access_add = 5, + cmd_act_bt_access_del, + cmd_act_bt_access_list, + cmd_act_bt_access_reset +}; + +/* Define action or option for cmd_fwt_access */ +enum cmd_fwt_access_opts { + cmd_act_fwt_access_add = 1, + cmd_act_fwt_access_del, + cmd_act_fwt_access_lookup, + cmd_act_fwt_access_list, + cmd_act_fwt_access_list_route, + cmd_act_fwt_access_list_neighbor, + cmd_act_fwt_access_reset, + cmd_act_fwt_access_cleanup, + cmd_act_fwt_access_time, +}; + +/* Define action or option for cmd_mesh_access */ +enum cmd_mesh_access_opts { + cmd_act_mesh_get_ttl = 1, + cmd_act_mesh_set_ttl, + cmd_act_mesh_get_stats, + cmd_act_mesh_get_mpp, + cmd_act_mesh_set_mpp, +}; + +/** Card Event definition */ +#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000 +#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001 +#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002 +#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003 +#define MACREG_INT_CODE_LINK_SENSED 0x00000004 +#define MACREG_INT_CODE_CMD_FINISHED 0x00000005 +#define MACREG_INT_CODE_MIB_CHANGED 0x00000006 +#define MACREG_INT_CODE_INIT_DONE 0x00000007 +#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008 +#define MACREG_INT_CODE_DISASSOCIATED 0x00000009 +#define MACREG_INT_CODE_PS_AWAKE 0x0000000a +#define MACREG_INT_CODE_PS_SLEEP 0x0000000b +#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d +#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e +#define MACREG_INT_CODE_WM_AWAKE 0x0000000f +#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011 +#define MACREG_INT_CODE_RSSI_LOW 0x00000019 +#define MACREG_INT_CODE_SNR_LOW 0x0000001a +#define MACREG_INT_CODE_MAX_FAIL 0x0000001b +#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c +#define MACREG_INT_CODE_SNR_HIGH 0x0000001d + +#endif /* _HOST_H_ */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h new file mode 100644 index 0000000..f239e5d --- /dev/null +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -0,0 +1,693 @@ +/* + * This file contains the function prototypes, data structure + * and defines for all the host/station commands + */ +#ifndef __HOSTCMD__H +#define __HOSTCMD__H + +#include +#include "11d.h" +#include "types.h" + +/* 802.11-related definitions */ + +/* TxPD descriptor */ +struct txpd { + /* Current Tx packet status */ + u32 tx_status; + /* Tx control */ + u32 tx_control; + u32 tx_packet_location; + /* Tx packet length */ + u16 tx_packet_length; + /* First 2 byte of destination MAC address */ + u8 tx_dest_addr_high[2]; + /* Last 4 byte of destination MAC address */ + u8 tx_dest_addr_low[4]; + /* Pkt Priority */ + u8 priority; + /* Pkt Trasnit Power control */ + u8 powermgmt; + /* Amount of time the packet has been queued in the driver (units = 2ms) */ + u8 pktdelay_2ms; + /* reserved */ + u8 reserved1; +}; + +/* RxPD Descriptor */ +struct rxpd { + /* Current Rx packet status */ + u16 status; + + /* SNR */ + u8 snr; + + /* Tx control */ + u8 rx_control; + + /* Pkt length */ + u16 pkt_len; + + /* Noise Floor */ + u8 nf; + + /* Rx Packet Rate */ + u8 rx_rate; + + /* Pkt addr */ + u32 pkt_ptr; + + /* Next Rx RxPD addr */ + u32 next_rxpd_ptr; + + /* Pkt Priority */ + u8 priority; + u8 reserved[3]; +}; + +struct cmd_ctrl_node { + /* CMD link list */ + struct list_head list; + u32 status; + /* CMD ID */ + u32 cmd_oid; + /*CMD wait option: wait for finish or no wait */ + u16 wait_option; + /* command parameter */ + void *pdata_buf; + /*command data */ + u8 *bufvirtualaddr; + u16 cmdflags; + /* wait queue */ + u16 cmdwaitqwoken; + wait_queue_head_t cmdwait_q; +}; + +/* WLAN_802_11_KEY + * + * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES) + * is determined from the keylength field. + */ +struct WLAN_802_11_KEY { + u32 len; + u32 flags; /* KEY_INFO_* from wlan_defs.h */ + u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH]; + u16 type; /* KEY_TYPE_* from wlan_defs.h */ +}; + +struct IE_WPA { + u8 elementid; + u8 len; + u8 oui[4]; + u16 version; +}; + +struct WLAN_802_11_SSID { + /* SSID length */ + u32 ssidlength; + + /* SSID information field */ + u8 ssid[IW_ESSID_MAX_SIZE]; +}; + +struct WPA_SUPPLICANT { + u8 wpa_ie[256]; + u8 wpa_ie_len; +}; + +/* wlan_offset_value */ +struct wlan_offset_value { + u32 offset; + u32 value; +}; + +struct WLAN_802_11_FIXED_IEs { + u8 timestamp[8]; + u16 beaconinterval; + u16 capabilities; +}; + +struct WLAN_802_11_VARIABLE_IEs { + u8 elementid; + u8 length; + u8 data[1]; +}; + +/* Define general data structure */ +/* cmd_DS_GEN */ +struct cmd_ds_gen { + u16 command; + u16 size; + u16 seqnum; + u16 result; +}; + +#define S_DS_GEN sizeof(struct cmd_ds_gen) +/* + * Define data structure for cmd_get_hw_spec + * This structure defines the response for the GET_HW_SPEC command + */ +struct cmd_ds_get_hw_spec { + /* HW Interface version number */ + u16 hwifversion; + /* HW version number */ + u16 version; + /* Max number of TxPD FW can handle */ + u16 nr_txpd; + /* Max no of Multicast address */ + u16 nr_mcast_adr; + /* MAC address */ + u8 permanentaddr[6]; + + /* region Code */ + u16 regioncode; + + /* Number of antenna used */ + u16 nr_antenna; + + /* FW release number, example 0x1234=1.2.3.4 */ + u32 fwreleasenumber; + + /* Base Address of TxPD queue */ + u32 wcb_base; + /* Read Pointer of RxPd queue */ + u32 rxpd_rdptr; + + /* Write Pointer of RxPd queue */ + u32 rxpd_wrptr; + + /*FW/HW capability */ + u32 fwcapinfo; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_reset { + u16 action; +}; + +struct cmd_ds_802_11_subscribe_event { + u16 action; + u16 events; +}; + +/* + * This scan handle Country Information IE(802.11d compliant) + * Define data structure for cmd_802_11_scan + */ +struct cmd_ds_802_11_scan { + u8 bsstype; + u8 BSSID[ETH_ALEN]; + u8 tlvbuffer[1]; +#if 0 + mrvlietypes_ssidparamset_t ssidParamSet; + mrvlietypes_chanlistparamset_t ChanListParamSet; + mrvlietypes_ratesparamset_t OpRateSet; +#endif +}; + +struct cmd_ds_802_11_scan_rsp { + u16 bssdescriptsize; + u8 nr_sets; + u8 bssdesc_and_tlvbuffer[1]; +}; + +struct cmd_ds_802_11_get_log { + u32 mcasttxframe; + u32 failed; + u32 retry; + u32 multiretry; + u32 framedup; + u32 rtssuccess; + u32 rtsfailure; + u32 ackfailure; + u32 rxfrag; + u32 mcastrxframe; + u32 fcserror; + u32 txframe; + u32 wepundecryptable; +}; + +struct cmd_ds_mac_control { + u16 action; + u16 reserved; +}; + +struct cmd_ds_mac_multicast_adr { + u16 action; + u16 nr_of_adrs; + u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; +}; + +struct cmd_ds_802_11_authenticate { + u8 macaddr[ETH_ALEN]; + u8 authtype; + u8 reserved[10]; +}; + +struct cmd_ds_802_11_deauthenticate { + u8 macaddr[6]; + u16 reasoncode; +}; + +struct cmd_ds_802_11_associate { + u8 peerstaaddr[6]; + struct ieeetypes_capinfo capinfo; + u16 listeninterval; + u16 bcnperiod; + u8 dtimperiod; + +#if 0 + mrvlietypes_ssidparamset_t ssidParamSet; + mrvlietypes_phyparamset_t phyparamset; + mrvlietypes_ssparamset_t ssparamset; + mrvlietypes_ratesparamset_t ratesParamSet; +#endif +} __attribute__ ((packed)); + +struct cmd_ds_802_11_disassociate { + u8 destmacaddr[6]; + u16 reasoncode; +}; + +struct cmd_ds_802_11_associate_rsp { + struct ieeetypes_assocrsp assocRsp; +}; + +struct cmd_ds_802_11_ad_hoc_result { + u8 PAD[3]; + u8 BSSID[ETH_ALEN]; +}; + +struct cmd_ds_802_11_set_wep { + /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ + u16 action; + + /* key Index selected for Tx */ + u16 keyindex; + + /* 40, 128bit or TXWEP */ + u8 keytype[4]; + u8 keymaterial[4][16]; +}; + +struct cmd_ds_802_3_get_stat { + u32 xmitok; + u32 rcvok; + u32 xmiterror; + u32 rcverror; + u32 rcvnobuffer; + u32 rcvcrcerror; +}; + +struct cmd_ds_802_11_get_stat { + u32 txfragmentcnt; + u32 mcasttxframecnt; + u32 failedcnt; + u32 retrycnt; + u32 Multipleretrycnt; + u32 rtssuccesscnt; + u32 rtsfailurecnt; + u32 ackfailurecnt; + u32 frameduplicatecnt; + u32 rxfragmentcnt; + u32 mcastrxframecnt; + u32 fcserrorcnt; + u32 bcasttxframecnt; + u32 bcastrxframecnt; + u32 txbeacon; + u32 rxbeacon; + u32 wepundecryptable; +}; + +struct cmd_ds_802_11_snmp_mib { + u16 querytype; + u16 oid; + u16 bufsize; + u8 value[128]; +}; + +struct cmd_ds_mac_reg_map { + u16 buffersize; + u8 regmap[128]; + u16 reserved; +}; + +struct cmd_ds_bbp_reg_map { + u16 buffersize; + u8 regmap[128]; + u16 reserved; +}; + +struct cmd_ds_rf_reg_map { + u16 buffersize; + u8 regmap[64]; + u16 reserved; +}; + +struct cmd_ds_mac_reg_access { + u16 action; + u16 offset; + u32 value; +}; + +struct cmd_ds_bbp_reg_access { + u16 action; + u16 offset; + u8 value; + u8 reserved[3]; +}; + +struct cmd_ds_rf_reg_access { + u16 action; + u16 offset; + u8 value; + u8 reserved[3]; +}; + +struct cmd_ds_802_11_radio_control { + u16 action; + u16 control; +}; + +struct cmd_ds_802_11_sleep_params { + /* ACT_GET/ACT_SET */ + u16 action; + + /* Sleep clock error in ppm */ + u16 error; + + /* Wakeup offset in usec */ + u16 offset; + + /* Clock stabilization time in usec */ + u16 stabletime; + + /* control periodic calibration */ + u8 calcontrol; + + /* control the use of external sleep clock */ + u8 externalsleepclk; + + /* reserved field, should be set to zero */ + u16 reserved; +}; + +struct cmd_ds_802_11_inactivity_timeout { + /* ACT_GET/ACT_SET */ + u16 action; + + /* Inactivity timeout in msec */ + u16 timeout; +}; + +struct cmd_ds_802_11_rf_channel { + u16 action; + u16 currentchannel; + u16 rftype; + u16 reserved; + u8 channellist[32]; +}; + +struct cmd_ds_802_11_rssi { + /* weighting factor */ + u16 N; + + u16 reserved_0; + u16 reserved_1; + u16 reserved_2; +}; + +struct cmd_ds_802_11_rssi_rsp { + u16 SNR; + u16 noisefloor; + u16 avgSNR; + u16 avgnoisefloor; +}; + +struct cmd_ds_802_11_mac_address { + u16 action; + u8 macadd[ETH_ALEN]; +}; + +struct cmd_ds_802_11_rf_tx_power { + u16 action; + u16 currentlevel; +}; + +struct cmd_ds_802_11_rf_antenna { + u16 action; + + /* Number of antennas or 0xffff(diversity) */ + u16 antennamode; + +}; + +struct cmd_ds_802_11_ps_mode { + u16 action; + u16 nullpktinterval; + u16 multipledtim; + u16 reserved; + u16 locallisteninterval; +}; + +struct PS_CMD_ConfirmSleep { + u16 command; + u16 size; + u16 seqnum; + u16 result; + + u16 action; + u16 reserved1; + u16 multipledtim; + u16 reserved; + u16 locallisteninterval; +}; + +struct cmd_ds_802_11_data_rate { + u16 action; + u16 reserverd; + u8 datarate[G_SUPPORTED_RATES]; +}; + +struct cmd_ds_802_11_rate_adapt_rateset { + u16 action; + u16 enablehwauto; + u16 bitmap; +}; + +struct cmd_ds_802_11_ad_hoc_start { + u8 SSID[IW_ESSID_MAX_SIZE]; + u8 bsstype; + u16 beaconperiod; + u8 dtimperiod; + union IEEEtypes_ssparamset ssparamset; + union ieeetypes_phyparamset phyparamset; + u16 probedelay; + struct ieeetypes_capinfo cap; + u8 datarate[G_SUPPORTED_RATES]; + u8 tlv_memory_size_pad[100]; +} __attribute__ ((packed)); + +struct adhoc_bssdesc { + u8 BSSID[6]; + u8 SSID[32]; + u8 bsstype; + u16 beaconperiod; + u8 dtimperiod; + u8 timestamp[8]; + u8 localtime[8]; + union ieeetypes_phyparamset phyparamset; + union IEEEtypes_ssparamset ssparamset; + struct ieeetypes_capinfo cap; + u8 datarates[G_SUPPORTED_RATES]; + + /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + * Adhoc join command and will cause a binary layout mismatch with + * the firmware + */ +} __attribute__ ((packed)); + +struct cmd_ds_802_11_ad_hoc_join { + struct adhoc_bssdesc bssdescriptor; + u16 failtimeout; + u16 probedelay; + +} __attribute__ ((packed)); + +struct cmd_ds_802_11_enable_rsn { + u16 action; + u16 enable; +}; + +struct MrvlIEtype_keyParamSet { + /* type ID */ + u16 type; + + /* length of Payload */ + u16 length; + + /* type of key: WEP=0, TKIP=1, AES=2 */ + u16 keytypeid; + + /* key control Info specific to a keytypeid */ + u16 keyinfo; + + /* length of key */ + u16 keylen; + + /* key material of size keylen */ + u8 key[32]; +}; + +struct cmd_ds_802_11_key_material { + u16 action; + struct MrvlIEtype_keyParamSet keyParamSet[2]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_eeprom_access { + u16 action; + + /* multiple 4 */ + u16 offset; + u16 bytecount; + u8 value; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_tpc_cfg { + u16 action; + u8 enable; + s8 P0; + s8 P1; + s8 P2; + u8 usesnr; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_led_ctrl { + u16 action; + u16 numled; + u8 data[256]; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_pwr_cfg { + u16 action; + u8 enable; + s8 PA_P0; + s8 PA_P1; + s8 PA_P2; +} __attribute__ ((packed)); + +struct cmd_ds_802_11_afc { + u16 afc_auto; + union { + struct { + u16 threshold; + u16 period; + }; + struct { + s16 timing_offset; + s16 carrier_offset; + }; + }; +} __attribute__ ((packed)); + +struct cmd_tx_rate_query { + u16 txrate; +} __attribute__ ((packed)); + +struct cmd_ds_get_tsf { + __le64 tsfvalue; +} __attribute__ ((packed)); + +struct cmd_ds_bt_access { + u16 action; + u32 id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; +} __attribute__ ((packed)); + +struct cmd_ds_fwt_access { + u16 action; + u32 id; + u8 da[ETH_ALEN]; + u8 dir; + u8 ra[ETH_ALEN]; + u32 ssn; + u32 dsn; + u32 metric; + u8 hopcount; + u8 ttl; + u32 expiration; + u8 sleepmode; + u32 snr; + u32 references; +} __attribute__ ((packed)); + +#define MESH_STATS_NUM 7 +struct cmd_ds_mesh_access { + u16 action; + u32 data[MESH_STATS_NUM + 1]; /* last position reserved */ +} __attribute__ ((packed)); + +struct cmd_ds_command { + /* command header */ + u16 command; + u16 size; + u16 seqnum; + u16 result; + + /* command Body */ + union { + struct cmd_ds_get_hw_spec hwspec; + struct cmd_ds_802_11_ps_mode psmode; + struct cmd_ds_802_11_scan scan; + struct cmd_ds_802_11_scan_rsp scanresp; + struct cmd_ds_mac_control macctrl; + struct cmd_ds_802_11_associate associate; + struct cmd_ds_802_11_deauthenticate deauth; + struct cmd_ds_802_11_set_wep wep; + struct cmd_ds_802_11_ad_hoc_start ads; + struct cmd_ds_802_11_reset reset; + struct cmd_ds_802_11_ad_hoc_result result; + struct cmd_ds_802_11_get_log glog; + struct cmd_ds_802_11_authenticate auth; + struct cmd_ds_802_11_get_stat gstat; + struct cmd_ds_802_3_get_stat gstat_8023; + struct cmd_ds_802_11_snmp_mib smib; + struct cmd_ds_802_11_rf_tx_power txp; + struct cmd_ds_802_11_rf_antenna rant; + struct cmd_ds_802_11_data_rate drate; + struct cmd_ds_802_11_rate_adapt_rateset rateset; + struct cmd_ds_mac_multicast_adr madr; + struct cmd_ds_802_11_ad_hoc_join adj; + struct cmd_ds_802_11_radio_control radio; + struct cmd_ds_802_11_rf_channel rfchannel; + struct cmd_ds_802_11_rssi rssi; + struct cmd_ds_802_11_rssi_rsp rssirsp; + struct cmd_ds_802_11_disassociate dassociate; + struct cmd_ds_802_11_mac_address macadd; + struct cmd_ds_802_11_enable_rsn enbrsn; + struct cmd_ds_802_11_key_material keymaterial; + struct cmd_ds_mac_reg_access macreg; + struct cmd_ds_bbp_reg_access bbpreg; + struct cmd_ds_rf_reg_access rfreg; + struct cmd_ds_802_11_eeprom_access rdeeprom; + + struct cmd_ds_802_11d_domain_info domaininfo; + struct cmd_ds_802_11d_domain_info domaininforesp; + + struct cmd_ds_802_11_sleep_params sleep_params; + struct cmd_ds_802_11_inactivity_timeout inactivity_timeout; + struct cmd_ds_802_11_tpc_cfg tpccfg; + struct cmd_ds_802_11_pwr_cfg pwrcfg; + struct cmd_ds_802_11_afc afc; + struct cmd_ds_802_11_led_ctrl ledgpio; + + struct cmd_tx_rate_query txrate; + struct cmd_ds_bt_access bt; + struct cmd_ds_fwt_access fwt; + struct cmd_ds_mesh_access mesh; + struct cmd_ds_get_tsf gettsf; + struct cmd_ds_802_11_subscribe_event subscribe_event; + } params; +} __attribute__ ((packed)); + +#endif diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c new file mode 100644 index 0000000..567000c --- /dev/null +++ b/drivers/net/wireless/libertas/if_bootcmd.c @@ -0,0 +1,38 @@ +/** + * This file contains functions used in USB Boot command + * and Boot2/FW update + */ + +#include +#include +#include +#include + +#include "defs.h" +#include "dev.h" +#include "if_usb.h" + +/** + * @brief This function issues Boot command to the Boot2 code + * @param ivalue 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * @return 0 + */ +int if_usb_issue_boot_command(wlan_private *priv, int ivalue) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + struct bootcmdstr sbootcmd; + int i; + + /* Prepare command */ + sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER; + sbootcmd.u8cmd_tag = ivalue; + for (i=0; i<11; i++) + sbootcmd.au8dumy[i]=0x00; + memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); + + /* Issue command */ + usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + + return 0; +} diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c new file mode 100644 index 0000000..695fb6a --- /dev/null +++ b/drivers/net/wireless/libertas/if_usb.c @@ -0,0 +1,952 @@ +/** + * This file contains functions used in USB interface module. + */ +#include +#include +#include +#include + +#include "host.h" +#include "sbi.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "if_usb.h" + +#define MESSAGE_HEADER_LEN 4 + +static const char usbdriver_name[] = "usb8xxx"; + +static struct usb_device_id if_usb_table[] = { + /* Enter the device signature inside */ + { + USB_DEVICE(USB8388_VID_1, USB8388_PID_1), + }, + { + USB_DEVICE(USB8388_VID_2, USB8388_PID_2), + }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, if_usb_table); + +static void if_usb_receive(struct urb *urb); +static void if_usb_receive_fwload(struct urb *urb); + +/** + * @brief call back function to handle the status of the URB + * @param urb pointer to urb structure + * @return N/A + */ +static void if_usb_write_bulk_callback(struct urb *urb) +{ + wlan_private *priv = (wlan_private *) (urb->context); + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->wlan_dev.netdev; + + /* handle the transmission complete validations */ + + if (urb->status != 0) { + /* print the failure status number for debug */ + lbs_pr_info("URB in failure status\n"); + } else { + lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n"); + lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n", + urb->actual_length); + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + /* Wake main thread if commands are pending */ + if (!adapter->cur_cmd) + wake_up_interruptible(&priv->mainthread.waitq); + if ((adapter->connect_status == libertas_connected)) + netif_wake_queue(dev); + } + + return; +} + +/** + * @brief free tx/rx urb, skb and rx buffer + * @param cardp pointer usb_card_rec + * @return N/A + */ +void if_usb_free(struct usb_card_rec *cardp) +{ + ENTER(); + + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; + + usb_free_urb(cardp->rx_urb); + cardp->rx_urb = NULL; + + kfree(cardp->bulk_out_buffer); + cardp->bulk_out_buffer = NULL; + + LEAVE(); + return; +} + +/** + * @brief sets the configuration values + * @param ifnum interface number + * @param id pointer to usb_device_id + * @return 0 on success, error code on failure + */ +static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + wlan_private *pwlanpriv; + struct usb_card_rec *usb_cardp; + int i; + + udev = interface_to_usbdev(intf); + + usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); + if (!usb_cardp) { + lbs_pr_err("Out of memory allocating private data.\n"); + goto error; + } + + usb_cardp->udev = udev; + iface_desc = intf->cur_altsetting; + + lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" + " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", + udev->descriptor.bcdUSB, + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + /* we found a bulk in endpoint */ + lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n", + endpoint->wMaxPacketSize); + if (! + (usb_cardp->rx_urb = + usb_alloc_urb(0, GFP_KERNEL))) { + lbs_dev_dbg(1, &udev->dev, + "Rx URB allocation failed\n"); + goto dealloc; + } + usb_cardp->rx_urb_recall = 0; + + usb_cardp->bulk_in_size = + endpoint->wMaxPacketSize; + usb_cardp->bulk_in_endpointAddr = + (endpoint-> + bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n", + endpoint->bEndpointAddress); + } + + 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 */ + if (! + (usb_cardp->tx_urb = + usb_alloc_urb(0, GFP_KERNEL))) { + lbs_dev_dbg(1,&udev->dev, + "Tx URB allocation failed\n"); + goto dealloc; + } + + usb_cardp->bulk_out_size = + endpoint->wMaxPacketSize; + lbs_dev_dbg(1, &udev->dev, + "Bulk out size is %d\n", + endpoint->wMaxPacketSize); + usb_cardp->bulk_out_endpointAddr = + endpoint->bEndpointAddress; + lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n", + endpoint->bEndpointAddress); + usb_cardp->bulk_out_buffer = + kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, + GFP_KERNEL); + + if (!usb_cardp->bulk_out_buffer) { + lbs_dev_dbg(1, &udev->dev, + "Could not allocate buffer\n"); + goto dealloc; + } + } + } + + + /* At this point wlan_add_card() will be called. Don't worry + * about keeping pwlanpriv around since it will be set on our + * usb device data in -> add() -> libertas_sbi_register_dev(). + */ + if (!(pwlanpriv = wlan_add_card(usb_cardp))) + goto dealloc; + + usb_get_dev(udev); + usb_set_intfdata(intf, usb_cardp); + + /* + * return card structure, which can be got back in the + * diconnect function as the ptr + * argument. + */ + return 0; + +dealloc: + if_usb_free(usb_cardp); + +error: + return -ENOMEM; +} + +/** + * @brief free resource and cleanup + * @param udev pointer to usb_device + * @param ptr pointer to usb_cardp + * @return N/A + */ +static void if_usb_disconnect(struct usb_interface *intf) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + wlan_private *priv = (wlan_private *) cardp->priv; + wlan_adapter *adapter = NULL; + + adapter = priv->adapter; + + /* + * Update Surprise removed to TRUE + */ + adapter->surpriseremoved = 1; + + /* card is removed and we can call wlan_remove_card */ + lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n"); + wlan_remove_card(cardp); + + /* Unlink and free urb */ + if_usb_free(cardp); + + usb_set_intfdata(intf, NULL); + usb_put_dev(interface_to_usbdev(intf)); + + return; +} + +/** + * @brief This function download FW + * @param priv pointer to wlan_private + * @return 0 + */ +static int if_prog_firmware(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + struct FWData *fwdata; + struct fwheader *fwheader; + u8 *firmware = priv->firmware->data; + + fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); + + if (!fwdata) + return -1; + + fwheader = &fwdata->fwheader; + + if (!cardp->CRC_OK) { + cardp->totalbytes = cardp->fwlastblksent; + cardp->fwseqnum = cardp->lastseqnum - 1; + } + + lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n", + cardp->totalbytes); + + memcpy(fwheader, &firmware[cardp->totalbytes], + sizeof(struct fwheader)); + + cardp->fwlastblksent = cardp->totalbytes; + cardp->totalbytes += sizeof(struct fwheader); + + lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n"); + memcpy(fwdata->data, &firmware[cardp->totalbytes], + fwdata->fwheader.datalength); + + lbs_dev_dbg(2, &cardp->udev->dev, + "Data length = %d\n", fwdata->fwheader.datalength); + + cardp->fwseqnum = cardp->fwseqnum + 1; + + fwdata->seqnum = cardp->fwseqnum; + cardp->lastseqnum = fwdata->seqnum; + cardp->totalbytes += fwdata->fwheader.datalength; + + if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) { + lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n"); + lbs_dev_dbg(2, &cardp->udev->dev, + "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, + cardp->totalbytes); + memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); + usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + + } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) { + lbs_dev_dbg(2, &cardp->udev->dev, + "Host has finished FW downloading\n"); + lbs_dev_dbg(2, &cardp->udev->dev, + "Donwloading FW JUMP BLOCK\n"); + memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); + usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + cardp->fwfinalblk = 1; + } + + lbs_dev_dbg(2, &cardp->udev->dev, + "The firmware download is done size is %d\n", + cardp->totalbytes); + + kfree(fwdata); + + return 0; +} + +static int libertas_do_reset(wlan_private *priv) +{ + int ret; + struct usb_card_rec *cardp = priv->wlan_dev.card; + + ret = usb_reset_device(cardp->udev); + if (!ret) { + msleep(10); + reset_device(priv); + msleep(10); + } + return ret; +} + +/** + * @brief This function transfer the data to the device. + * @param priv pointer to wlan_private + * @param payload pointer to payload data + * @param nb data length + * @return 0 or -1 + */ +int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +{ + /* pointer to card structure */ + struct usb_card_rec *cardp = priv->wlan_dev.card; + int ret = -1; + + /* check if device is removed */ + if (priv->adapter->surpriseremoved) { + lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n"); + goto tx_ret; + } + + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, + cardp->bulk_out_endpointAddr), + payload, nb, if_usb_write_bulk_callback, priv); + + cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; + + if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { + /* transfer failed */ + lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n"); + ret = -1; + } else { + lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n"); + ret = 0; + } + +tx_ret: + return ret; +} + +static int __if_usb_submit_rx_urb(wlan_private * priv, + void (*callbackfn) + (struct urb *urb)) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + struct sk_buff *skb; + struct read_cb_info *rinfo = &cardp->rinfo; + int ret = -1; + + if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { + lbs_pr_err("No free skb\n"); + goto rx_ret; + } + + rinfo->skb = skb; + + /* Fill the receive configuration URB and initialise the Rx call back */ + usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, + usb_rcvbulkpipe(cardp->udev, + cardp->bulk_in_endpointAddr), + skb->tail + IPFIELD_ALIGN_OFFSET, + MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, + rinfo); + + cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; + + lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); + if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { + /* handle failure conditions */ + lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n"); + ret = -1; + } else { + lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n"); + ret = 0; + } + +rx_ret: + return ret; +} + +static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) +{ + return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); +} + +static inline int if_usb_submit_rx_urb(wlan_private * priv) +{ + return __if_usb_submit_rx_urb(priv, &if_usb_receive); +} + +static void if_usb_receive_fwload(struct urb *urb) +{ + struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; + wlan_private *priv = rinfo->priv; + struct sk_buff *skb = rinfo->skb; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + struct fwsyncheader *syncfwheader; + struct bootcmdrespStr bootcmdresp; + + if (urb->status) { + lbs_dev_dbg(1, &cardp->udev->dev, + "URB status is failed during fw load\n"); + kfree_skb(skb); + return; + } + + if (cardp->bootcmdresp == 0) { + memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, + sizeof(bootcmdresp)); + if (cardp->udev->descriptor.bcdDevice < 0x3106) { + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(priv); + cardp->bootcmdresp = 1; + lbs_dev_dbg(1, &cardp->udev->dev, + "Received valid boot command response\n"); + return; + } + if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) { + lbs_pr_info( + "boot cmd response wrong magic number (0x%x)\n", + bootcmdresp.u32magicnumber); + } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { + lbs_pr_info( + "boot cmd response cmd_tag error (%d)\n", + bootcmdresp.u8cmd_tag); + } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { + lbs_pr_info( + "boot cmd response result error (%d)\n", + bootcmdresp.u8result); + } else { + cardp->bootcmdresp = 1; + lbs_dev_dbg(1, &cardp->udev->dev, + "Received valid boot command response\n"); + } + kfree_skb(skb); + if_usb_submit_rx_urb_fwload(priv); + return; + } + + syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); + if (!syncfwheader) { + lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n"); + kfree_skb(skb); + return; + } + + memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, + sizeof(struct fwsyncheader)); + + if (!syncfwheader->cmd) { + lbs_dev_dbg(2, &cardp->udev->dev, + "FW received Blk with correct CRC\n"); + lbs_dev_dbg(2, &cardp->udev->dev, + "FW received Blk seqnum = %d\n", + syncfwheader->seqnum); + cardp->CRC_OK = 1; + } else { + lbs_dev_dbg(1, &cardp->udev->dev, + "FW received Blk with CRC error\n"); + cardp->CRC_OK = 0; + } + + kfree_skb(skb); + + if (cardp->fwfinalblk) { + cardp->fwdnldover = 1; + goto exit; + } + + if_prog_firmware(priv); + + if_usb_submit_rx_urb_fwload(priv); +exit: + kfree(syncfwheader); + + return; + +} + +#define MRVDRV_MIN_PKT_LEN 30 + +static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, + struct usb_card_rec *cardp, + wlan_private *priv) +{ + if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + + MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { + lbs_dev_dbg(1, &cardp->udev->dev, + "Packet length is Invalid\n"); + kfree_skb(skb); + return; + } + + skb_reserve(skb, IPFIELD_ALIGN_OFFSET); + skb_put(skb, recvlength); + skb_pull(skb, MESSAGE_HEADER_LEN); + libertas_process_rxed_packet(priv, skb); + priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); +} + +static inline void process_cmdrequest(int recvlength, u8 *recvbuff, + struct sk_buff *skb, + struct usb_card_rec *cardp, + wlan_private *priv) +{ + u8 *cmdbuf; + if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { + lbs_dev_dbg(1, &cardp->udev->dev, + "The receive buffer is too large\n"); + kfree_skb(skb); + return; + } + + if (!in_interrupt()) + BUG(); + + spin_lock(&priv->adapter->driver_lock); + /* take care of cur_cmd = NULL case by reading the + * data to clear the interrupt */ + if (!priv->adapter->cur_cmd) { + cmdbuf = priv->wlan_dev.upld_buf; + priv->adapter->hisregcpy &= ~his_cmdupldrdy; + } else + cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; + + cardp->usb_int_cause |= his_cmdupldrdy; + priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); + memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, + priv->wlan_dev.upld_len); + + kfree_skb(skb); + libertas_interrupt(priv->wlan_dev.netdev); + spin_unlock(&priv->adapter->driver_lock); + + lbs_dev_dbg(1, &cardp->udev->dev, + "Wake up main thread to handle cmd response\n"); + + return; +} + +/** + * @brief This function reads of the packet into the upload buff, + * wake up the main thread and initialise the Rx callack. + * + * @param urb pointer to struct urb + * @return N/A + */ +static void if_usb_receive(struct urb *urb) +{ + struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; + wlan_private *priv = rinfo->priv; + struct sk_buff *skb = rinfo->skb; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + + int recvlength = urb->actual_length; + u8 *recvbuff = NULL; + u32 recvtype; + + ENTER(); + + if (recvlength) { + if (urb->status) { + lbs_dev_dbg(1, &cardp->udev->dev, + "URB status is failed\n"); + kfree_skb(skb); + goto setup_for_next; + } + + recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; + memcpy(&recvtype, recvbuff, sizeof(u32)); + lbs_dev_dbg(1, &cardp->udev->dev, + "Recv length = 0x%x\n", recvlength); + lbs_dev_dbg(1, &cardp->udev->dev, + "Receive type = 0x%X\n", recvtype); + recvtype = le32_to_cpu(recvtype); + lbs_dev_dbg(1, &cardp->udev->dev, + "Receive type after = 0x%X\n", recvtype); + } else if (urb->status) + goto rx_exit; + + + switch (recvtype) { + case CMD_TYPE_DATA: + process_cmdtypedata(recvlength, skb, cardp, priv); + break; + + case CMD_TYPE_REQUEST: + process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); + break; + + case CMD_TYPE_INDICATION: + /* Event cause handling */ + spin_lock(&priv->adapter->driver_lock); + cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN); + lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n", + cardp->usb_event_cause); + if (cardp->usb_event_cause & 0xffff0000) { + libertas_send_tx_feedback(priv); + break; + } + cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3; + cardp->usb_int_cause |= his_cardevent; + kfree_skb(skb); + libertas_interrupt(priv->wlan_dev.netdev); + spin_unlock(&priv->adapter->driver_lock); + goto rx_exit; + default: + kfree_skb(skb); + break; + } + +setup_for_next: + if_usb_submit_rx_urb(priv); +rx_exit: + LEAVE(); + return; +} + +/** + * @brief This function downloads data to FW + * @param priv pointer to wlan_private structure + * @param type type of data + * @param buf pointer to data buffer + * @param len number of bytes + * @return 0 or -1 + */ +int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) +{ + int ret = -1; + u32 tmp; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + + lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type); + lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb); + + if (type == MVMS_CMD) { + tmp = cpu_to_le32(CMD_TYPE_REQUEST); + priv->wlan_dev.dnld_sent = DNLD_CMD_SENT; + memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, + MESSAGE_HEADER_LEN); + + } else { + tmp = cpu_to_le32(CMD_TYPE_DATA); + priv->wlan_dev.dnld_sent = DNLD_DATA_SENT; + memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, + MESSAGE_HEADER_LEN); + } + + memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); + + ret = + usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); + + return ret; +} + +/* called with adapter->driver_lock held */ +int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + + *ireg = cardp->usb_int_cause; + cardp->usb_int_cause = 0; + + lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg); + + return 0; +} + +int libertas_sbi_read_event_cause(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + priv->adapter->eventcause = cardp->usb_event_cause; + /* Re-submit rx urb here to avoid event lost issue */ + if_usb_submit_rx_urb(priv); + return 0; +} + +int reset_device(wlan_private *priv) +{ + int ret; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, + cmd_act_halt, 0, 0, NULL); + msleep_interruptible(10); + + return ret; +} + +int libertas_sbi_unregister_dev(wlan_private * priv) +{ + int ret = 0; + + /* Need to send a Reset command to device before USB resources freed + * and wlan_remove_card() called, then device can handle FW download + * again. + */ + if (priv) + reset_device(priv); + + return ret; +} + + +/** + * @brief This function register usb device and initialize parameter + * @param priv pointer to wlan_private + * @return 0 or -1 + */ +int libertas_sbi_register_dev(wlan_private * priv) +{ + + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + ENTER(); + + cardp->priv = priv; + cardp->eth_dev = priv->wlan_dev.netdev; + priv->hotplug_device = &(cardp->udev->dev); + + SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev)); + + lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n", + cardp->udev); + + LEAVE(); + return 0; +} + + + +int libertas_sbi_prog_firmware(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + int i = 0; + static int reset_count = 10; + + ENTER(); + + cardp->rinfo.priv = priv; + +restart: + if (if_usb_submit_rx_urb_fwload(priv) < 0) { + lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n"); + LEAVE(); + return -1; + } + +#ifdef SUPPORT_BOOT_COMMAND + cardp->bootcmdresp = 0; + do { + int j = 0; + i++; + /* Issue Boot command = 1, Boot from Download-FW */ + if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); + /* wait for command response */ + do { + j++; + msleep_interruptible(100); + } while (cardp->bootcmdresp == 0 && j < 10); + } while (cardp->bootcmdresp == 0 && i < 5); + + if (cardp->bootcmdresp == 0) { + if (--reset_count >= 0) { + libertas_do_reset(priv); + goto restart; + } + return -1; + } +#endif + + i = 0; + priv->adapter->fw_ready = 0; + + cardp->totalbytes = 0; + cardp->fwlastblksent = 0; + cardp->CRC_OK = 1; + cardp->fwdnldover = 0; + cardp->fwseqnum = -1; + cardp->totalbytes = 0; + cardp->fwfinalblk = 0; + + if_prog_firmware(priv); + + do { + lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n"); + i++; + msleep_interruptible(100); + if (priv->adapter->surpriseremoved || i >= 20) + break; + } while (!cardp->fwdnldover); + + if (!cardp->fwdnldover) { + lbs_pr_info("failed to load fw, resetting device!\n"); + if (--reset_count >= 0) { + libertas_do_reset(priv); + goto restart; + } + + lbs_pr_info("FW download failure, time = %d ms\n", i * 100); + LEAVE(); + return -1; + } + + if_usb_submit_rx_urb(priv); + + /* Delay 200 ms to waiting for the FW ready */ + msleep_interruptible(200); + + priv->adapter->fw_ready = 1; + + LEAVE(); + return 0; +} + +/** + * @brief Given a usb_card_rec return its wlan_private + * @param card pointer to a usb_card_rec + * @return pointer to wlan_private + */ +wlan_private *libertas_sbi_get_priv(void *card) +{ + struct usb_card_rec *cardp = card; + return cardp->priv; +} + +#ifdef ENABLE_PM +int libertas_sbi_suspend(wlan_private * priv) +{ + return 0; +} + +int libertas_sbi_resume(wlan_private * priv) +{ + return 0; +} +#endif + +#ifdef CONFIG_PM +static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + wlan_private *priv = cardp->priv; + + ENTER(); + + if (priv->adapter->psstate != PS_STATE_FULL_POWER) + return -1; + + netif_device_detach(cardp->eth_dev); + + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + + cardp->rx_urb_recall = 1; + + LEAVE(); + return 0; +} + +static int if_usb_resume(struct usb_interface *intf) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + + ENTER(); + + cardp->rx_urb_recall = 0; + + if_usb_submit_rx_urb(cardp->priv); + + netif_device_attach(cardp->eth_dev); + + LEAVE(); + return 0; +} +#else +#define if_usb_suspend NULL +#define if_usb_resume NULL +#endif + +static struct usb_driver if_usb_driver = { + /* driver name */ + .name = usbdriver_name, + /* probe function name */ + .probe = if_usb_probe, + /* disconnect function name */ + .disconnect = if_usb_disconnect, + /* device signature table */ + .id_table = if_usb_table, + .suspend = if_usb_suspend, + .resume = if_usb_resume, +}; + +/** + * @brief This function registers driver. + * @param add pointer to add_card callback function + * @param remove pointer to remove card callback function + * @param arg pointer to call back function parameter + * @return dummy success variable + */ +int libertas_sbi_register(void) +{ + /* + * API registers the Marvell USB driver + * to the USB system + */ + usb_register(&if_usb_driver); + + /* Return success to wlan layer */ + return 0; +} + +/** + * @brief This function removes usb driver. + * @return N/A + */ +void libertas_sbi_unregister(void) +{ + /* API unregisters the driver from USB subsystem */ + usb_deregister(&if_usb_driver); + return; +} diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h new file mode 100644 index 0000000..7851167 --- /dev/null +++ b/drivers/net/wireless/libertas/if_usb.h @@ -0,0 +1,109 @@ +/** + * This file contains definition for USB interface. + */ +#define CMD_TYPE_REQUEST 0xF00DFACE +#define CMD_TYPE_DATA 0xBEADC0DE +#define CMD_TYPE_INDICATION 0xBEEFFACE + +#define IPFIELD_ALIGN_OFFSET 2 + +#define USB8388_VID_1 0x1286 +#define USB8388_PID_1 0x2001 +#define USB8388_VID_2 0x05a3 +#define USB8388_PID_2 0x8388 + +#ifdef SUPPORT_BOOT_COMMAND +#define BOOT_CMD_FW_BY_USB 0x01 +#define BOOT_CMD_FW_IN_EEPROM 0x02 +#define BOOT_CMD_UPDATE_BOOT2 0x03 +#define BOOT_CMD_UPDATE_FW 0x04 +#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */ + +struct bootcmdstr +{ + u32 u32magicnumber; + u8 u8cmd_tag; + u8 au8dumy[11]; +}; + +#define BOOT_CMD_RESP_OK 0x0001 +#define BOOT_CMD_RESP_FAIL 0x0000 + +struct bootcmdrespStr +{ + u32 u32magicnumber; + u8 u8cmd_tag; + u8 u8result; + u8 au8dumy[2]; +}; +#endif /* SUPPORT_BOOT_COMMAND */ + +/* read callback private data */ +struct read_cb_info { + wlan_private *priv; + struct sk_buff *skb; +}; + +/** USB card description structure*/ +struct usb_card_rec { + struct net_device *eth_dev; + struct usb_device *udev; + struct urb *rx_urb, *tx_urb; + void *priv; + struct read_cb_info rinfo; + + int bulk_in_size; + u8 bulk_in_endpointAddr; + + u8 *bulk_out_buffer; + int bulk_out_size; + u8 bulk_out_endpointAddr; + + u8 CRC_OK; + u32 fwseqnum; + u32 lastseqnum; + u32 totalbytes; + u32 fwlastblksent; + u8 fwdnldover; + u8 fwfinalblk; + + u32 usb_event_cause; + u8 usb_int_cause; + + u8 rx_urb_recall; + + u8 bootcmdresp; +}; + +/** fwheader */ +struct fwheader { + u32 dnldcmd; + u32 baseaddr; + u32 datalength; + u32 CRC; +}; + +#define FW_MAX_DATA_BLK_SIZE 600 +/** FWData */ +struct FWData { + struct fwheader fwheader; + u32 seqnum; + u8 data[FW_MAX_DATA_BLK_SIZE]; +}; + +/** fwsyncheader */ +struct fwsyncheader { + u32 cmd; + u32 seqnum; +}; + +#define FW_HAS_DATA_TO_RECV 0x00000001 +#define FW_HAS_LAST_BLOCK 0x00000004 + +#define FW_DATA_XMIT_SIZE \ + sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32) + +int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); +void if_usb_free(struct usb_card_rec *cardp); +int if_usb_issue_boot_command(wlan_private *priv, int ivalue); + diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c new file mode 100644 index 0000000..82b3964 --- /dev/null +++ b/drivers/net/wireless/libertas/ioctl.c @@ -0,0 +1,2500 @@ +/** + * This file contains ioctl functions + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "host.h" +#include "radiotap.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "wext.h" + +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ + IW_ESSID_MAX_SIZE + \ + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ + IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ + IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ + +#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) + +static int setrxantenna(wlan_private * priv, int mode) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2 + && mode != RF_ANTENNA_AUTO) { + return -EINVAL; + } + + adapter->rxantennamode = mode; + + lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_set_rx, + cmd_option_waitforrsp, 0, + &adapter->rxantennamode); + return ret; +} + +static int settxantenna(wlan_private * priv, int mode) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2) + && (mode != RF_ANTENNA_AUTO)) { + return -EINVAL; + } + + adapter->txantennamode = mode; + + lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_set_tx, + cmd_option_waitforrsp, 0, + &adapter->txantennamode); + + return ret; +} + +static int getrxantenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + // clear it, so we will know if the value + // returned below is correct or not. + adapter->rxantennamode = 0; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_get_rx, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode); + + return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1; +} + +static int gettxantenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + // clear it, so we will know if the value + // returned below is correct or not. + adapter->txantennamode = 0; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, + cmd_act_get_tx, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode); + + return sprintf(buf, "0x%04x", adapter->txantennamode) + 1; +} + +static int wlan_set_region(wlan_private * priv, u16 region_code) +{ + int i; + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + // use the region code to search for the index + if (region_code == libertas_region_code_to_index[i]) { + priv->adapter->regiontableindex = (u16) i; + priv->adapter->regioncode = region_code; + break; + } + } + + // if it's unidentified region code + if (i >= MRVDRV_MAX_REGION_CODE) { + lbs_pr_debug(1, "region Code not identified\n"); + LEAVE(); + return -1; + } + + if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { + LEAVE(); + return -EINVAL; + } + + return 0; +} + +/** + * @brief Get/Set Firmware wakeup method + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + if (copy_to_user + (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) { + lbs_pr_alert("copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + lbs_pr_alert("ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_alert("Copy from user failed\n"); + return -EFAULT; + } + + adapter->pkttxctrl = (u32) data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return 0; +} + +/** + * @brief Get/Set NULL Package generation interval + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + data = adapter->nullpktinterval; + + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + lbs_pr_alert( "copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + lbs_pr_alert( "ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + adapter->nullpktinterval = data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return 0; +} + +static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data[2]; + ENTER(); + data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[1] = adapter->rxpd_rate; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 2; + LEAVE(); + return 0; +} + +static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int data[4]; + + ENTER(); + memset(data, 0, sizeof(data)); + if (wrq->u.data.length) { + if (copy_from_user(data, wrq->u.data.pointer, + min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) + return -EFAULT; + } + if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { + if (adapter->connect_status == libertas_connected) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, + cmd_option_waitforrsp, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + } + + if (wrq->u.data.length == 0) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; + data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) + return -EFAULT; + wrq->u.data.length = 4; + } else if (data[0] == 0) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 1) { + data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 2) { + data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else if (data[0] == 3) { + data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) + return -EFAULT; + wrq->u.data.length = 1; + } else + return -ENOTSUPP; + + LEAVE(); + return 0; +} + +static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *adapter = priv->adapter; + + if (wrq->u.data.length > 0) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) + return -EFAULT; + + lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data); + if ((data > MRVDRV_MAX_BEACON_INTERVAL) + || (data < MRVDRV_MIN_BEACON_INTERVAL)) + return -ENOTSUPP; + adapter->beaconperiod = data; + } + data = adapter->beaconperiod; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) + return -EFAULT; + + wrq->u.data.length = 1; + + return 0; +} + +static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + ENTER(); + data = SUBCMD_DATA(wrq); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, cmd_option_waitforrsp, + 0, NULL); + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + + temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + break; + case 1: + temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG], + adapter->NF[TYPE_BEACON][TYPE_AVG]); + break; + case 2: + temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], + adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + break; + case 3: + temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + break; + default: + return -ENOTSUPP; + } + val = (int *)wrq->u.name; + *val = temp; + + LEAVE(); + return 0; +} + +static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + data = SUBCMD_DATA(wrq); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, cmd_option_waitforrsp, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG]; + break; + case 1: + temp = adapter->NF[TYPE_BEACON][TYPE_AVG]; + break; + case 2: + temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG]; + break; + case 3: + temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + break; + default: + return -ENOTSUPP; + } + + temp = CAL_NF(temp); + + lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp); + val = (int *)wrq->u.name; + *val = temp; + return 0; +} + +static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) +{ + wlan_adapter *adapter = priv->adapter; + int *pdata; + struct iwreq *wrq = (struct iwreq *)req; + int ret = 0; + adapter->txrate = 0; + lbs_pr_debug(1, "wlan_get_txrate_ioctl\n"); + ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query, + cmd_act_get, cmd_option_waitforrsp, + 0, NULL); + if (ret) + return ret; + + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->txrate; + return 0; +} + +static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + char status[64]; + wlan_adapter *adapter = priv->adapter; + + memset(status, 0, sizeof(status)); + + switch (adapter->inframode) { + case wlan802_11ibss: + if (adapter->connect_status == libertas_connected) { + if (adapter->adhoccreate) + memcpy(&status, "AdhocStarted", sizeof(status)); + else + memcpy(&status, "AdhocJoined", sizeof(status)); + } else { + memcpy(&status, "AdhocIdle", sizeof(status)); + } + break; + case wlan802_11infrastructure: + memcpy(&status, "Inframode", sizeof(status)); + break; + default: + memcpy(&status, "AutoUnknownmode", sizeof(status)); + break; + } + + lbs_pr_debug(1, "status = %s\n", status); + wrq->u.data.length = strlen(status) + 1; + + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + &status, wrq->u.data.length)) + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Set/Get WPA IE + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (wrq->u.data.length > sizeof(adapter->wpa_ie)) { + lbs_pr_debug(1, "failed to copy WPA IE, too big \n"); + return -EFAULT; + } + if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer, + wrq->u.data.length)) { + lbs_pr_debug(1, "failed to copy WPA IE \n"); + return -EFAULT; + } + adapter->wpa_ie_len = wrq->u.data.length; + lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len, + adapter->wpa_ie[0]); + lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len); + if (adapter->wpa_ie[0] == WPA_IE) + adapter->secinfo.WPAenabled = 1; + else if (adapter->wpa_ie[0] == WPA2_IE) + adapter->secinfo.WPA2enabled = 1; + else { + adapter->secinfo.WPAenabled = 0; + adapter->secinfo.WPA2enabled = 0; + } + } else { + memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie)); + adapter->wpa_ie_len = wrq->u.data.length; + lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n", + adapter->wpa_ie_len, adapter->wpa_ie[0]); + adapter->secinfo.WPAenabled = 0; + adapter->secinfo.WPA2enabled = 0; + } + + // enable/disable RSN in firmware if WPA is enabled/disabled + // depending on variable adapter->secinfo.WPAenabled is set or not + ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, + cmd_act_set, cmd_option_waitforrsp, + 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief Set Auto prescan + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *adapter = priv->adapter; + int *val; + + data = SUBCMD_DATA(wrq); + lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); + adapter->prescan = data; + + val = (int *)wrq->u.name; + *val = data; + return 0; +} + +static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + u32 mdtim; + int idata; + int ret = -EINVAL; + + ENTER(); + + idata = SUBCMD_DATA(wrq); + mdtim = (u32) idata; + if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) + && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) + || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { + priv->adapter->multipledtim = mdtim; + ret = 0; + } + if (ret) + lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n"); + + LEAVE(); + return ret; +} + +/** + * @brief Set authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *adapter = priv->adapter; + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + + lbs_pr_debug(1, "auth alg is %#x\n", alg); + + switch (alg) { + case AUTH_ALG_SHARED_KEY: + adapter->secinfo.authmode = wlan802_11authmodeshared; + break; + case AUTH_ALG_NETWORK_EAP: + adapter->secinfo.authmode = + wlan802_11authmodenetworkEAP; + break; + case AUTH_ALG_OPEN_SYSTEM: + default: + adapter->secinfo.authmode = wlan802_11authmodeopen; + break; + } + return 0; +} + +/** + * @brief Set 802.1x authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg); + priv->adapter->secinfo.auth1xalg = alg; + return 0; +} + +static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + mode = SUBCMD_DATA(wrq); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + } + lbs_pr_debug(1, "encryption mode is %#x\n", mode); + priv->adapter->secinfo.Encryptionmode = mode; + + LEAVE(); + return 0; +} + +static void adjust_mtu(wlan_private * priv) +{ + int mtu_increment = 0; + + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + mtu_increment += sizeof(struct ieee80211_hdr_4addr); + + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) + mtu_increment += max(sizeof(struct tx_radiotap_hdr), + sizeof(struct rx_radiotap_hdr)); + priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN + - sizeof(struct ethhdr) + + mtu_increment; +} + +/** + * @brief Set Link-Layer Layer mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_LINKMODE_802_3: + priv->adapter->linkmode = mode; + break; + case WLAN_LINKMODE_802_11: + priv->adapter->linkmode = mode; + break; + default: + lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n", + mode); + return -EINVAL; + break; + } + lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode); + + adjust_mtu(priv); + + return 0; +} + +/** + * @brief Set Radio header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_RADIOMODE_NONE: + priv->adapter->radiomode = mode; + break; + case WLAN_RADIOMODE_RADIOTAP: + priv->adapter->radiomode = mode; + break; + default: + lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n", + mode); + return -EINVAL; + } + lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode); + + adjust_mtu(priv); + return 0; +} + +/** + * @brief Set Debug header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + priv->adapter->debugmode = (int)((struct ifreq *) + ((u8 *) req + 4))->ifr_data; + return 0; +} + +static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n"); + len = getrxantenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + lbs_pr_debug(1, "CopyToUser failed\n"); + return -EFAULT; + } + } + + return 0; +} + +static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n"); + len = gettxantenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + lbs_pr_debug(1, "CopyToUser failed\n"); + return -EFAULT; + } + } + return 0; +} + +/** + * @brief Get the MAC TSF value from the firmware + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure containing buffer + * space to store a TSF value retrieved from the firmware + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u64 tsfval; + int ret; + + ret = libertas_prepare_and_send_command(priv, + cmd_get_tsf, + 0, cmd_option_waitforrsp, 0, &tsfval); + + lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval); + + if (ret != 0) { + lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n"); + ret = -EFAULT; + } else { + if (copy_to_user(wrq->u.data.pointer, + &tsfval, + min_t(size_t, wrq->u.data.length, + sizeof(tsfval))) != 0) { + + lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n"); + ret = -EFAULT; + } else { + ret = 0; + } + } + return ret; +} + +/** + * @brief Get/Set adapt rate + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + wlan_adapter *adapter = priv->adapter; + int data[2]; + + memset(data, 0, sizeof(data)); + if (!wrq->u.data.length) { + lbs_pr_debug(1, "Get ADAPT RATE SET\n"); + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rate_adapt_rateset, + cmd_act_get, + cmd_option_waitforrsp, 0, NULL); + data[0] = adapter->enablehwauto; + data[1] = adapter->ratebitmap; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } +#define GET_TWO_INT 2 + wrq->u.data.length = GET_TWO_INT; + } else { + lbs_pr_debug(1, "Set ADAPT RATE SET\n"); + if (wrq->u.data.length > 2) + return -EINVAL; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + adapter->enablehwauto = data[0]; + adapter->ratebitmap = data[1]; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rate_adapt_rateset, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + } + return ret; +} + +/** + * @brief Get/Set inactivity timeout + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + int data = 0; + u16 timeout = 0; + + ENTER(); + if (wrq->u.data.length > 1) + return -ENOTSUPP; + + if (wrq->u.data.length == 0) { + /* Get */ + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_inactivity_timeout, + cmd_act_get, + cmd_option_waitforrsp, 0, + &timeout); + data = timeout; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + } else { + /* Set */ + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + timeout = data; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_inactivity_timeout, + cmd_act_set, + cmd_option_waitforrsp, 0, + &timeout); + } + + wrq->u.data.length = 1; + + LEAVE(); + return ret; +} + +static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + char buf[GETLOG_BUFSIZE - 1]; + wlan_adapter *adapter = priv->adapter; + + lbs_pr_debug(1, " GET STATS\n"); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log, + 0, cmd_option_waitforrsp, 0, NULL); + + if (ret) { + return ret; + } + + if (wrq->u.data.pointer) { + sprintf(buf, "\n mcasttxframe %u failed %u retry %u " + "multiretry %u framedup %u " + "rtssuccess %u rtsfailure %u ackfailure %u\n" + "rxfrag %u mcastrxframe %u fcserror %u " + "txframe %u wepundecryptable %u ", + adapter->logmsg.mcasttxframe, + adapter->logmsg.failed, + adapter->logmsg.retry, + adapter->logmsg.multiretry, + adapter->logmsg.framedup, + adapter->logmsg.rtssuccess, + adapter->logmsg.rtsfailure, + adapter->logmsg.ackfailure, + adapter->logmsg.rxfrag, + adapter->logmsg.mcastrxframe, + adapter->logmsg.fcserror, + adapter->logmsg.txframe, + adapter->logmsg.wepundecryptable); + wrq->u.data.length = strlen(buf) + 1; + if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + } + + return 0; +} + +static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u8 buf[12]; + u8 *option[] = { "active", "passive", "get", }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + if (priv->adapter->enable11d) { + lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n"); + return -EFAULT; + } + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) + return -EFAULT; + + lbs_pr_debug(1, "Scan type Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + case 0: + adapter->scantype = cmd_scan_type_active; + break; + case 1: + adapter->scantype = cmd_scan_type_passive; + break; + case 2: + wrq->u.data.length = strlen(option[adapter->scantype]) + 1; + + if (copy_to_user(wrq->u.data.pointer, + option[adapter->scantype], + wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + ret = -EFAULT; + } + + break; + default: + lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + u8 buf[12]; + u8 *option[] = { "bss", "ibss", "any", "get" }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = 0; + + ENTER(); + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + lbs_pr_debug(1, "Scan mode Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + + case 0: + adapter->scanmode = cmd_bss_type_bss; + break; + case 1: + adapter->scanmode = cmd_bss_type_ibss; + break; + case 2: + adapter->scanmode = cmd_bss_type_any; + break; + case 3: + + wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1; + + lbs_pr_debug(1, "Get Scan mode Option = %s\n", + option[adapter->scanmode - 1]); + + lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length); + + if (copy_to_user(wrq->u.data.pointer, + option[adapter->scanmode - 1], + wrq->u.data.length)) { + lbs_pr_debug(1, "Copy to user failed\n"); + ret = -EFAULT; + } + lbs_pr_debug(1, "GET Scan type Option after copy = %s\n", + (char *)wrq->u.data.pointer); + + break; + + default: + lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n"); + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set Adhoc G Rate + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return 0--success, otherwise fail + */ +static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *adapter = priv->adapter; + int data, data1; + int *val; + + ENTER(); + + data1 = SUBCMD_DATA(wrq); + switch (data1) { + case 0: + adapter->adhoc_grate_enabled = 0; + break; + case 1: + adapter->adhoc_grate_enabled = 1; + break; + case 2: + break; + default: + return -EINVAL; + } + data = adapter->adhoc_grate_enabled; + val = (int *)wrq->u.name; + *val = data; + LEAVE(); + return 0; +} + +static inline int hex2int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + return -1; +} + +/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") + into binary format (6 bytes). + + This function expects that each byte is represented with 2 characters + (e.g., 11:2:11:11:11:11 is invalid) + + */ +static char *eth_str2addr(char *ethstr, u8 * addr) +{ + int i, val, val2; + char *pos = ethstr; + + /* get rid of initial blanks */ + while (*pos == ' ' || *pos == '\t') + ++pos; + + for (i = 0; i < 6; i++) { + val = hex2int(*pos++); + if (val < 0) + return NULL; + val2 = hex2int(*pos++); + if (val2 < 0) + return NULL; + addr[i] = (val * 16 + val2) & 0xff; + + if (i < 5 && *pos++ != ':') + return NULL; + } + return pos; +} + +/* this writes xx:xx:xx:xx:xx:xx into ethstr + (ethstr must have space for 18 chars) */ +static int eth_addr2str(u8 * addr, char *ethstr) +{ + int i; + char *pos = ethstr; + + for (i = 0; i < 6; i++) { + sprintf(pos, "%02x", addr[i] & 0xff); + pos += 2; + if (i < 5) + *pos++ = ':'; + } + return 17; +} + +/** + * @brief Add an entry to the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + char *pos; + u8 ethaddr[ETH_ALEN]; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + lbs_pr_info("BT_ADD: Invalid MAC address\n"); + return -EINVAL; + } + + lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str); + LEAVE(); + return (libertas_prepare_and_send_command(priv, cmd_bt_access, + cmd_act_bt_access_add, + cmd_option_waitforrsp, 0, ethaddr)); +} + +/** + * @brief Delete an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + u8 ethaddr[ETH_ALEN]; + char *pos; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + lbs_pr_info("Invalid MAC address\n"); + return -EINVAL; + } + + lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str); + + return (libertas_prepare_and_send_command(priv, + cmd_bt_access, + cmd_act_bt_access_del, + cmd_option_waitforrsp, 0, ethaddr)); + LEAVE(); + return 0; +} + +/** + * @brief Reset all entries from the BT table + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_reset_ioctl(wlan_private * priv) +{ + ENTER(); + + lbs_pr_alert( "BT: resetting\n"); + + return (libertas_prepare_and_send_command(priv, + cmd_bt_access, + cmd_act_bt_access_reset, + cmd_option_waitforrsp, 0, NULL)); + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + int pos; + char *addr1; + struct iwreq *wrq = (struct iwreq *)req; + /* used to pass id and store the bt entry returned by the FW */ + union { + int id; + char addr1addr2[2 * ETH_ALEN]; + } param; + static char outstr[64]; + char *pbuf = outstr; + int ret; + + ENTER(); + + if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -1; + } + param.id = simple_strtoul(outstr, NULL, 10); + pos = sprintf(pbuf, "%d: ", param.id); + pbuf += pos; + + ret = libertas_prepare_and_send_command(priv, cmd_bt_access, + cmd_act_bt_access_list, + cmd_option_waitforrsp, 0, + (char *)¶m); + + if (ret == 0) { + addr1 = param.addr1addr2; + + pos = sprintf(pbuf, "ignoring traffic from "); + pbuf += pos; + pos = eth_addr2str(addr1, pbuf); + pbuf += pos; + } else { + sprintf(pbuf, "(null)"); + pbuf += pos; + } + + wrq->u.data.length = strlen(outstr); + if (copy_to_user(wrq->u.data.pointer, (char *)outstr, + wrq->u.data.length)) { + lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Find the next parameter in an input string + * @param ptr A pointer to the input parameter string + * @return A pointer to the next parameter, or 0 if no parameters left. + */ +static char * next_param(char * ptr) +{ + if (!ptr) return NULL; + while (*ptr == ' ' || *ptr == '\t') ++ptr; + return (*ptr == '\0') ? NULL : ptr; +} + +/** + * @brief Add an entry to the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[128]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); + return -EINVAL; + } + + if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { + lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); + return -EINVAL; + } + + if ((ptr = next_param(ptr))) + fwt_access.metric = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.metric = FWT_DEFAULT_METRIC; + + if ((ptr = next_param(ptr))) + fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.dir = FWT_DEFAULT_DIR; + + if ((ptr = next_param(ptr))) + fwt_access.ssn = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.ssn = FWT_DEFAULT_SSN; + + if ((ptr = next_param(ptr))) + fwt_access.dsn = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.dsn = FWT_DEFAULT_DSN; + + if ((ptr = next_param(ptr))) + fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); + else + fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; + + if ((ptr = next_param(ptr))) + fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); + else + fwt_access.ttl = FWT_DEFAULT_TTL; + + if ((ptr = next_param(ptr))) + fwt_access.expiration = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.expiration = FWT_DEFAULT_EXPIRATION; + + if ((ptr = next_param(ptr))) + fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; + + if ((ptr = next_param(ptr))) + fwt_access.snr = + cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + else + fwt_access.snr = FWT_DEFAULT_SNR; + +#ifdef DEBUG + { + char ethaddr1_str[18], ethaddr2_str[18]; + eth_addr2str(fwt_access.da, ethaddr1_str); + eth_addr2str(fwt_access.ra, ethaddr2_str); + lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, + fwt_access.dir, ethaddr2_str); + lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", + fwt_access.ssn, fwt_access.dsn, fwt_access.metric, + fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, + fwt_access.sleepmode, fwt_access.snr); + } +#endif + + LEAVE(); + return (libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_add, + cmd_option_waitforrsp, 0, + (void *)&fwt_access)); +} + +/** + * @brief Delete an entry from the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); + return -EINVAL; + } + + if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { + lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); + return -EINVAL; + } + + if ((ptr = next_param(ptr))) + fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); + else + fwt_access.dir = FWT_DEFAULT_DIR; + +#ifdef DEBUG + { + char ethaddr1_str[18], ethaddr2_str[18]; + lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str); + eth_addr2str(fwt_access.da, ethaddr1_str); + eth_addr2str(fwt_access.ra, ethaddr2_str); + lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, + ethaddr2_str, fwt_access.dir); + } +#endif + + LEAVE(); + return (libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_del, + cmd_option_waitforrsp, 0, + (void *)&fwt_access)); +} + + +/** + * @brief Print route parameters + * @param fwt_access struct cmd_ds_fwt_access with route info + * @param buf destination buffer for route info + */ +static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) +{ + buf += sprintf(buf, " "); + buf += eth_addr2str(fwt_access.da, buf); + buf += sprintf(buf, " "); + buf += eth_addr2str(fwt_access.ra, buf); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); + buf += sprintf(buf, " %u", fwt_access.dir); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); + buf += sprintf(buf, " %u", fwt_access.hopcount); + buf += sprintf(buf, " %u", fwt_access.ttl); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); + buf += sprintf(buf, " %u", fwt_access.sleepmode); + buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr)); +} + +/** + * @brief Lookup an entry in the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + char *ptr; + static struct cmd_ds_fwt_access fwt_access; + static char out_str[128]; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { + lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); + return -EINVAL; + } + +#ifdef DEBUG + { + char ethaddr1_str[18]; + lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str); + eth_addr2str(fwt_access.da, ethaddr1_str); + lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); + } +#endif + + ret = libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_lookup, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + print_route(fwt_access, out_str); + else + sprintf(out_str, "(null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Reset all entries from the FWT table + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_reset_ioctl(wlan_private * priv) +{ + lbs_pr_debug(1, "FWT: resetting\n"); + + return (libertas_prepare_and_send_command(priv, + cmd_fwt_access, + cmd_act_fwt_access_reset, + cmd_option_waitforrsp, 0, NULL)); +} + +/** + * @brief List an entry from the FWT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[8]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list, + cmd_option_waitforrsp, 0, (void *)&fwt_access); + + if (ret == 0) + print_route(fwt_access, pbuf); + else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the FRT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[64]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list_route, + cmd_option_waitforrsp, 0, (void *)&fwt_access); + + if (ret == 0) { + pbuf += sprintf(pbuf, " "); + pbuf += eth_addr2str(fwt_access.da, pbuf); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric)); + pbuf += sprintf(pbuf, " %u", fwt_access.dir); + /* note that the firmware returns the nid in the id field */ + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id)); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn)); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn)); + pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount); + pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl); + pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration)); + } else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief List an entry from the FNT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char in_str[8]; + static struct cmd_ds_fwt_access fwt_access; + char *ptr = in_str; + static char out_str[128]; + char *pbuf = out_str; + int ret; + + ENTER(); + if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) + return -EFAULT; + + memset(&fwt_access, 0, sizeof(fwt_access)); + fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); + +#ifdef DEBUG + { + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str); + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); + } +#endif + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_list_neighbor, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) { + pbuf += sprintf(pbuf, " ra "); + pbuf += eth_addr2str(fwt_access.ra, pbuf); + pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); + pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); + pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); + } else + pbuf += sprintf(pbuf, " (null)"); + + wrq->u.data.length = strlen(out_str); + if (copy_to_user(wrq->u.data.pointer, (char *)out_str, + wrq->u.data.length)) { + lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return 0; +} + +/** + * @brief Cleans up the route (FRT) and neighbor (FNT) tables + * (Garbage Collection) + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) +{ + static struct cmd_ds_fwt_access fwt_access; + int ret; + + ENTER(); + + lbs_pr_debug(1, "FWT: cleaning up\n"); + + memset(&fwt_access, 0, sizeof(fwt_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_cleanup, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets firmware internal time (debug purposes) + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) +{ + static struct cmd_ds_fwt_access fwt_access; + int ret; + + ENTER(); + + lbs_pr_debug(1, "FWT: getting time\n"); + + memset(&fwt_access, 0, sizeof(fwt_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, + cmd_act_fwt_access_time, + cmd_option_waitforrsp, 0, + (void *)&fwt_access); + + if (ret == 0) + req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets mesh ttl from firmware + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct cmd_ds_mesh_access mesh_access; + int ret; + + ENTER(); + + memset(&mesh_access, 0, sizeof(mesh_access)); + + ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, + cmd_act_mesh_get_ttl, + cmd_option_waitforrsp, 0, + (void *)&mesh_access); + + if (ret == 0) { + req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0])); + } + else + return -EFAULT; + + LEAVE(); + return 0; +} + +/** + * @brief Gets mesh ttl from firmware + * @param priv A pointer to wlan_private structure + * @param ttl New ttl value + * @return 0 --success, otherwise fail + */ +static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) +{ + struct cmd_ds_mesh_access mesh_access; + int ret; + + ENTER(); + + if( (ttl > 0xff) || (ttl < 0) ) + return -EINVAL; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = ttl; + + ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, + cmd_act_mesh_set_ttl, + cmd_option_waitforrsp, 0, + (void *)&mesh_access); + + if (ret != 0) + ret = -EFAULT; + + LEAVE(); + return ret; +} + +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd command + * @return 0--success, otherwise fail + */ +int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int subcmd = 0; + int idata = 0; + int *pdata; + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { + case WLANSCAN_TYPE: + lbs_pr_debug(1, "Scan type Ioctl\n"); + ret = wlan_scan_type_ioctl(priv, wrq); + break; + + case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ + switch (wrq->u.data.flags) { + case WLANDEAUTH: + lbs_pr_debug(1, "Deauth\n"); + libertas_send_deauth(priv); + break; + + case WLANADHOCSTOP: + lbs_pr_debug(1, "Adhoc stop\n"); + ret = libertas_do_adhocstop_ioctl(priv); + break; + + case WLANRADIOON: + wlan_radio_ioctl(priv, 1); + break; + + case WLANRADIOOFF: + wlan_radio_ioctl(priv, 0); + break; + case WLANWLANIDLEON: + libertas_idle_on(priv); + break; + case WLANWLANIDLEOFF: + libertas_idle_off(priv); + break; + case WLAN_SUBCMD_BT_RESET: /* bt_reset */ + wlan_bt_reset_ioctl(priv); + break; + case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ + wlan_fwt_reset_ioctl(priv); + break; + } /* End of switch */ + break; + + case WLANSETWPAIE: + ret = wlan_setwpaie_ioctl(priv, req); + break; + case WLAN_SETINT_GETINT: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = (int)req->ifr_data; //from iwpriv subcmd + switch (subcmd) { + case WLANNF: + ret = wlan_get_nf(priv, wrq); + break; + case WLANRSSI: + ret = wlan_get_rssi(priv, wrq); + break; + case WLANENABLE11D: + ret = libertas_cmd_enable_11d(priv, wrq); + break; + case WLANADHOCGRATE: + ret = wlan_do_set_grate_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_SET_PRESCAN: + ret = wlan_subcmd_setprescan_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SETONEINT_GETONEINT: + switch (wrq->u.data.flags) { + case WLAN_BEACON_INTERVAL: + ret = wlan_beacon_interval(priv, wrq); + break; + + case WLAN_LISTENINTRVL: + if (!wrq->u.data.length) { + int data; + lbs_pr_debug(1, "Get locallisteninterval value\n"); +#define GET_ONE_INT 1 + data = adapter->locallisteninterval; + if (copy_to_user(wrq->u.data.pointer, + &data, sizeof(int))) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = GET_ONE_INT; + } else { + int data; + if (copy_from_user + (&data, wrq->u.data.pointer, sizeof(int))) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + + lbs_pr_debug(1, "Set locallisteninterval = %d\n", + data); +#define MAX_U16_VAL 65535 + if (data > MAX_U16_VAL) { + lbs_pr_debug(1, "Exceeds U16 value\n"); + return -EINVAL; + } + adapter->locallisteninterval = data; + } + break; + case WLAN_TXCONTROL: + ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl + break; + + case WLAN_NULLPKTINTERVAL: + ret = wlan_null_pkt_interval(priv, wrq); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + break; + + case WLAN_SETONEINT_GETNONE: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd + + if (!subcmd) + subcmd = (int)req->ifr_data; //from iwpriv subcmd + + switch (subcmd) { + case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ + idata = SUBCMD_DATA(wrq); + ret = setrxantenna(priv, idata); + break; + case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ + idata = SUBCMD_DATA(wrq); + ret = settxantenna(priv, idata); + break; + case WLAN_SET_ATIM_WINDOW: + adapter->atimwindow = SUBCMD_DATA(wrq); + adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50); + break; + case WLANSETBCNAVG: + adapter->bcn_avg_factor = SUBCMD_DATA(wrq); + if (adapter->bcn_avg_factor == 0) + adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) + adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + break; + case WLANSETDATAAVG: + adapter->data_avg_factor = SUBCMD_DATA(wrq); + if (adapter->data_avg_factor == 0) + adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) + adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + break; + case WLANSETREGION: + idata = SUBCMD_DATA(wrq); + ret = wlan_set_region(priv, (u16) idata); + break; + + case WLAN_SET_LISTEN_INTERVAL: + idata = SUBCMD_DATA(wrq); + adapter->listeninterval = (u16) idata; + break; + + case WLAN_SET_MULTIPLE_DTIM: + ret = wlan_set_multiple_dtim_ioctl(priv, req); + break; + + case WLANSETAUTHALG: + ret = wlan_setauthalg_ioctl(priv, req); + break; + + case WLANSET8021XAUTHALG: + ret = wlan_set8021xauthalg_ioctl(priv, req); + break; + + case WLANSETENCRYPTIONMODE: + ret = wlan_setencryptionmode_ioctl(priv, req); + break; + + case WLAN_SET_LINKMODE: + ret = wlan_set_linkmode_ioctl(priv, req); + break; + + case WLAN_SET_RADIOMODE: + ret = wlan_set_radiomode_ioctl(priv, req); + break; + + case WLAN_SET_DEBUGMODE: + ret = wlan_set_debugmode_ioctl(priv, req); + break; + + case WLAN_SUBCMD_MESH_SET_TTL: + idata = SUBCMD_DATA(wrq); + ret = wlan_mesh_set_ttl_ioctl(priv, idata); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + break; + + case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ + /* + * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is + * in flags of iwreq structure, otherwise it will be in + * mode member of iwreq structure. + */ + switch ((int)wrq->u.data.flags) { + case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ + ret = wlan_subcmd_getrxantenna_ioctl(priv, req); + break; + + case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ + ret = wlan_subcmd_gettxantenna_ioctl(priv, req); + break; + + case WLAN_GET_TSF: + ret = wlan_get_tsf_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SET128CHAR_GET128CHAR: + switch ((int)wrq->u.data.flags) { + + case WLANSCAN_MODE: + lbs_pr_debug(1, "Scan mode Ioctl\n"); + ret = wlan_scan_mode_ioctl(priv, wrq); + break; + + case WLAN_GET_ADHOC_STATUS: + ret = wlan_get_adhoc_status_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_BT_ADD: + ret = wlan_bt_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_DEL: + ret = wlan_bt_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_LIST: + ret = wlan_bt_list_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_ADD: + ret = wlan_fwt_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_DEL: + ret = wlan_fwt_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LOOKUP: + ret = wlan_fwt_lookup_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: + ret = wlan_fwt_list_neighbor_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST: + ret = wlan_fwt_list_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_LIST_ROUTE: + ret = wlan_fwt_list_route_ioctl(priv, req); + break; + } + break; + + case WLAN_SETNONE_GETONEINT: + switch ((int)req->ifr_data) { + case WLANGETBCNAVG: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->bcn_avg_factor; + break; + + case WLANGETREGION: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->regioncode; + break; + + case WLAN_GET_LISTEN_INTERVAL: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->listeninterval; + break; + + case WLAN_GET_LINKMODE: + req->ifr_data = (char *)((u32) adapter->linkmode); + break; + + case WLAN_GET_RADIOMODE: + req->ifr_data = (char *)((u32) adapter->radiomode); + break; + + case WLAN_GET_DEBUGMODE: + req->ifr_data = (char *)((u32) adapter->debugmode); + break; + + case WLAN_GET_MULTIPLE_DTIM: + pdata = (int *)wrq->u.name; + *pdata = (int)adapter->multipledtim; + break; + case WLAN_GET_TX_RATE: + ret = wlan_get_txrate_ioctl(priv, req); + break; + case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ + ret = wlan_fwt_cleanup_ioctl(priv, req); + break; + + case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ + ret = wlan_fwt_time_ioctl(priv, req); + break; + + case WLAN_SUBCMD_MESH_GET_TTL: + ret = wlan_mesh_get_ttl_ioctl(priv, req); + break; + + default: + ret = -EOPNOTSUPP; + + } + + break; + + case WLANGETLOG: + ret = wlan_do_getlog_ioctl(priv, wrq); + break; + + case WLAN_SET_GET_SIXTEEN_INT: + switch ((int)wrq->u.data.flags) { + case WLAN_TPCCFG: + { + int data[5]; + struct cmd_ds_802_11_tpc_cfg cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 5)) + return -1; + + if (wrq->u.data.length == 0) { + cfg.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 5)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.action = + cpu_to_le16 + (cmd_act_set); + cfg.enable = data[0]; + cfg.usesnr = data[1]; + cfg.P0 = data[2]; + cfg.P1 = data[3]; + cfg.P2 = data[4]; + } + + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_tpc_cfg, + 0, + cmd_option_waitforrsp, + 0, (void *)&cfg); + + data[0] = cfg.enable; + data[1] = cfg.usesnr; + data[2] = cfg.P0; + data[3] = cfg.P1; + data[4] = cfg.P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 5)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 5; + } + break; + + case WLAN_POWERCFG: + { + int data[4]; + struct cmd_ds_802_11_pwr_cfg cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 4)) + return -1; + if (wrq->u.data.length == 0) { + cfg.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 4)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.action = + cpu_to_le16 + (cmd_act_set); + cfg.enable = data[0]; + cfg.PA_P0 = data[1]; + cfg.PA_P1 = data[2]; + cfg.PA_P2 = data[3]; + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_pwr_cfg, + 0, + cmd_option_waitforrsp, + 0, (void *)&cfg); + data[0] = cfg.enable; + data[1] = cfg.PA_P0; + data[2] = cfg.PA_P1; + data[3] = cfg.PA_P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 4)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 4; + } + break; + case WLAN_AUTO_FREQ_SET: + { + int data[3]; + struct cmd_ds_802_11_afc afc; + memset(&afc, 0, sizeof(afc)); + if (wrq->u.data.length != 3) + return -1; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 3)) { + lbs_pr_debug(1, "Copy from user failed\n"); + return -EFAULT; + } + afc.afc_auto = data[0]; + + if (afc.afc_auto != 0) { + afc.threshold = data[1]; + afc.period = data[2]; + } else { + afc.timing_offset = data[1]; + afc.carrier_offset = data[2]; + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_set_afc, + 0, + cmd_option_waitforrsp, + 0, (void *)&afc); + } + break; + case WLAN_AUTO_FREQ_GET: + { + int data[3]; + struct cmd_ds_802_11_afc afc; + memset(&afc, 0, sizeof(afc)); + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_get_afc, + 0, + cmd_option_waitforrsp, + 0, (void *)&afc); + data[0] = afc.afc_auto; + data[1] = afc.timing_offset; + data[2] = afc.carrier_offset; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 3)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 3; + } + break; + case WLAN_SCANPROBES: + { + int data; + if (wrq->u.data.length > 0) { + if (copy_from_user + (&data, wrq->u.data.pointer, + sizeof(int))) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + adapter->scanprobes = data; + } else { + data = adapter->scanprobes; + if (copy_to_user + (wrq->u.data.pointer, &data, + sizeof(int))) { + lbs_pr_debug(1, + "Copy to user failed\n"); + return -EFAULT; + } + } + wrq->u.data.length = 1; + } + break; + case WLAN_LED_GPIO_CTRL: + { + int i; + int data[16]; + + struct cmd_ds_802_11_led_ctrl ctrl; + struct mrvlietypes_ledgpio *gpio = + (struct mrvlietypes_ledgpio *) ctrl.data; + + memset(&ctrl, 0, sizeof(ctrl)); + if (wrq->u.data.length > MAX_LEDS * 2) + return -ENOTSUPP; + if ((wrq->u.data.length % 2) != 0) + return -ENOTSUPP; + if (wrq->u.data.length == 0) { + ctrl.action = + cpu_to_le16 + (cmd_act_get); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * + wrq->u.data.length)) { + lbs_pr_debug(1, + "Copy from user failed\n"); + return -EFAULT; + } + + ctrl.action = + cpu_to_le16 + (cmd_act_set); + ctrl.numled = cpu_to_le16(0); + gpio->header.type = + cpu_to_le16(TLV_TYPE_LED_GPIO); + gpio->header.len = wrq->u.data.length; + for (i = 0; i < wrq->u.data.length; + i += 2) { + gpio->ledpin[i / 2].led = + data[i]; + gpio->ledpin[i / 2].pin = + data[i + 1]; + } + } + ret = + libertas_prepare_and_send_command(priv, + cmd_802_11_led_gpio_ctrl, + 0, + cmd_option_waitforrsp, + 0, (void *)&ctrl); + for (i = 0; i < gpio->header.len; i += 2) { + data[i] = gpio->ledpin[i / 2].led; + data[i + 1] = gpio->ledpin[i / 2].pin; + } + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * + gpio->header.len)) { + lbs_pr_debug(1, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = gpio->header.len; + } + break; + case WLAN_ADAPT_RATESET: + ret = wlan_adapt_rateset(priv, wrq); + break; + case WLAN_INACTIVITY_TIMEOUT: + ret = wlan_inactivity_timeout(priv, wrq); + break; + case WLANSNR: + ret = wlan_get_snr(priv, wrq); + break; + case WLAN_GET_RXINFO: + ret = wlan_get_rxinfo(priv, wrq); + } + break; + + default: + ret = -EINVAL; + break; + } + LEAVE(); + return ret; +} + + diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c new file mode 100644 index 0000000..11682cb --- /dev/null +++ b/drivers/net/wireless/libertas/join.c @@ -0,0 +1,1055 @@ +/** + * Functions implementing wlan infrastructure and adhoc join routines, + * IOCTL handlers as well as command preperation and response routines + * for sending adhoc start, adhoc join, and association commands + * to the firmware. + */ +#include +#include +#include + +#include + +#include "host.h" +#include "decl.h" +#include "join.h" +#include "dev.h" + +/** + * @brief This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param adapter A pointer to wlan_adapter structure + * @param rate1 the buffer which keeps input and output + * @param rate1_size the size of rate1 buffer + * @param rate2 the buffer which keeps rate2 + * @param rate2_size the size of rate2 buffer. + * + * @return 0 or -1 + */ +static int get_common_rates(wlan_adapter * adapter, u8 * rate1, + int rate1_size, u8 * rate2, int rate2_size) +{ + u8 *ptr = rate1; + int ret = 0; + u8 tmp[30]; + int i; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); + memset(rate1, 0, rate1_size); + + /* Mask the top bit of the original values */ + for (i = 0; tmp[i] && i < sizeof(tmp); i++) + tmp[i] &= 0x7F; + + for (i = 0; rate2[i] && i < rate2_size; i++) { + /* Check for Card Rate in tmp, excluding the top bit */ + if (strchr(tmp, rate2[i] & 0x7F)) { + /* values match, so copy the Card Rate to rate1 */ + *rate1++ = rate2[i]; + } + } + + lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); + lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); + lbs_dbg_hex("Common rates:", ptr, rate1_size); + lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate); + + if (!adapter->is_datarate_auto) { + while (*ptr) { + if ((*ptr & 0x7f) == adapter->datarate) { + ret = 0; + goto done; + } + ptr++; + } + lbs_pr_alert( "Previously set fixed data rate %#x isn't " + "compatible with the network.\n", adapter->datarate); + + ret = -1; + goto done; + } + + ret = 0; +done: + return ret; +} + +int libertas_send_deauth(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + if (adapter->inframode == wlan802_11infrastructure && + adapter->connect_status == libertas_connected) + ret = libertas_send_deauthentication(priv); + else + ret = -ENOTSUPP; + + return ret; +} + +int libertas_do_adhocstop_ioctl(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + if (adapter->inframode == wlan802_11ibss && + adapter->connect_status == libertas_connected) + ret = libertas_stop_adhoc_network(priv); + else + ret = -ENOTSUPP; + + return ret; +} + +/** + * @brief Associate to a specific BSS discovered in a scan + * + * @param priv A pointer to wlan_private structure + * @param pbssdesc Pointer to the BSS descriptor to associate with. + * + * @return 0-success, otherwise fail + */ +int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc) +{ + wlan_adapter *adapter = priv->adapter; + int ret; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, + 0, cmd_option_waitforrsp, + 0, pbssdesc->macaddress); + + if (ret) { + LEAVE(); + return ret; + } + + /* set preamble to firmware */ + if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble) + adapter->preamble = cmd_type_short_preamble; + else + adapter->preamble = cmd_type_long_preamble; + + libertas_set_radio_control(priv); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, + 0, cmd_option_waitforrsp, 0, pbssdesc); + + LEAVE(); + return ret; +} + +/** + * @brief Start an Adhoc Network + * + * @param priv A pointer to wlan_private structure + * @param adhocssid The ssid of the Adhoc Network + * @return 0--success, -1--fail + */ +int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + adapter->adhoccreate = 1; + + if (!adapter->capinfo.shortpreamble) { + lbs_pr_debug(1, "AdhocStart: Long preamble\n"); + adapter->preamble = cmd_type_long_preamble; + } else { + lbs_pr_debug(1, "AdhocStart: Short preamble\n"); + adapter->preamble = cmd_type_short_preamble; + } + + libertas_set_radio_control(priv); + + lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel); + lbs_pr_debug(1, "curbssparams.channel = %d\n", + adapter->curbssparams.channel); + lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, + 0, cmd_option_waitforrsp, 0, adhocssid); + + return ret; +} + +/** + * @brief Join an adhoc network found in a previous scan + * + * @param priv A pointer to wlan_private structure + * @param pbssdesc Pointer to a BSS descriptor found in a previous scan + * to attempt to join + * + * @return 0--success, -1--fail + */ +int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n", + adapter->curbssparams.ssid.ssid); + lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n", + adapter->curbssparams.ssid.ssidlength); + lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid); + lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n", + pbssdesc->ssid.ssidlength); + + /* check if the requested SSID is already joined */ + if (adapter->curbssparams.ssid.ssidlength + && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid) + && (adapter->curbssparams.bssdescriptor.inframode == + wlan802_11ibss)) { + + lbs_pr_debug(1, + "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " + "not attempting to re-join"); + + return -1; + } + + /*Use shortpreamble only when both creator and card supports + short preamble */ + if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) { + lbs_pr_debug(1, "AdhocJoin: Long preamble\n"); + adapter->preamble = cmd_type_long_preamble; + } else { + lbs_pr_debug(1, "AdhocJoin: Short preamble\n"); + adapter->preamble = cmd_type_short_preamble; + } + + libertas_set_radio_control(priv); + + lbs_pr_debug(1, "curbssparams.channel = %d\n", + adapter->curbssparams.channel); + lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band); + + adapter->adhoccreate = 0; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, + 0, cmd_option_waitforrsp, + OID_802_11_SSID, pbssdesc); + + return ret; +} + +int libertas_stop_adhoc_network(wlan_private * priv) +{ + return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, + 0, cmd_option_waitforrsp, 0, NULL); +} + +/** + * @brief Send Deauthentication Request + * + * @param priv A pointer to wlan_private structure + * @return 0--success, -1--fail + */ +int libertas_send_deauthentication(wlan_private * priv) +{ + return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, + 0, cmd_option_waitforrsp, 0, NULL); +} + +/** + * @brief Set Idle Off + * + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +int libertas_idle_off(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 }; + int i; + + ENTER(); + + if (adapter->connect_status == libertas_disconnected) { + if (adapter->inframode == wlan802_11infrastructure) { + if (memcmp(adapter->previousbssid, zeromac, + sizeof(zeromac)) != 0) { + + lbs_pr_debug(1, "Previous SSID = %s\n", + adapter->previousssid.ssid); + lbs_pr_debug(1, "Previous BSSID = " + "%02x:%02x:%02x:%02x:%02x:%02x:\n", + adapter->previousbssid[0], + adapter->previousbssid[1], + adapter->previousbssid[2], + adapter->previousbssid[3], + adapter->previousbssid[4], + adapter->previousbssid[5]); + + i = libertas_find_SSID_in_list(adapter, + &adapter->previousssid, + adapter->previousbssid, + adapter->inframode); + + if (i < 0) { + libertas_send_specific_BSSID_scan(priv, + adapter-> + previousbssid, + 1); + i = libertas_find_SSID_in_list(adapter, + &adapter-> + previousssid, + adapter-> + previousbssid, + adapter-> + inframode); + } + + if (i < 0) { + /* If the BSSID could not be found, try just the SSID */ + i = libertas_find_SSID_in_list(adapter, + &adapter-> + previousssid, NULL, + adapter-> + inframode); + } + + if (i < 0) { + libertas_send_specific_SSID_scan(priv, + &adapter-> + previousssid, + 1); + i = libertas_find_SSID_in_list(adapter, + &adapter-> + previousssid, NULL, + adapter-> + inframode); + } + + if (i >= 0) { + ret = + wlan_associate(priv, + &adapter-> + scantable[i]); + } + } + } else if (adapter->inframode == wlan802_11ibss) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_ad_hoc_start, + 0, + cmd_option_waitforrsp, + 0, &adapter->previousssid); + } + } + /* else it is connected */ + + lbs_pr_debug(1, "\nwlanidle is off"); + LEAVE(); + return ret; +} + +/** + * @brief Set Idle On + * + * @param priv A pointer to wlan_private structure + * @return 0 --success, otherwise fail + */ +int libertas_idle_on(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + if (adapter->connect_status == libertas_connected) { + if (adapter->inframode == wlan802_11infrastructure) { + lbs_pr_debug(1, "Previous SSID = %s\n", + adapter->previousssid.ssid); + memmove(&adapter->previousssid, + &adapter->curbssparams.ssid, + sizeof(struct WLAN_802_11_SSID)); + libertas_send_deauth(priv); + + } else if (adapter->inframode == wlan802_11ibss) { + ret = libertas_stop_adhoc_network(priv); + } + + } + + lbs_pr_debug(1, "\nwlanidle is on"); + + return ret; +} + +/** + * @brief This function prepares command of authenticate. + * + * @param priv A pointer to wlan_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 libertas_cmd_80211_authenticate(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pdata_buf) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_authenticate *pauthenticate = + &cmd->params.auth; + u8 *bssid = pdata_buf; + + cmd->command = cpu_to_le16(cmd_802_11_authenticate); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) + + S_DS_GEN); + + pauthenticate->authtype = adapter->secinfo.authmode; + memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); + + lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + return 0; +} + +int libertas_cmd_80211_deauthenticate(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + + ENTER(); + + cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + + S_DS_GEN); + + /* set AP MAC address */ + memmove(dauth->macaddr, adapter->curbssparams.bssid, + ETH_ALEN); + + /* Reason code 3 = Station is leaving */ +#define REASON_CODE_STA_LEAVING 3 + dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + + LEAVE(); + return 0; +} + +int libertas_cmd_80211_associate(wlan_private * priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_associate *passo = &cmd->params.associate; + int ret = 0; + struct bss_descriptor *pbssdesc; + u8 *card_rates; + u8 *pos; + int card_rates_size; + u16 tmpcap; + struct mrvlietypes_ssidparamset *ssid; + struct mrvlietypes_phyparamset *phy; + struct mrvlietypes_ssparamset *ss; + struct mrvlietypes_ratesparamset *rates; + struct mrvlietypes_rsnparamset *rsn; + + ENTER(); + + pbssdesc = pdata_buf; + pos = (u8 *) passo; + + if (!adapter) { + ret = -1; + goto done; + } + + cmd->command = cpu_to_le16(cmd_802_11_associate); + + /* Save so we know which BSS Desc to use in the response handler */ + adapter->pattemptedbssdesc = pbssdesc; + + memcpy(passo->peerstaaddr, + pbssdesc->macaddress, sizeof(passo->peerstaaddr)); + pos += sizeof(passo->peerstaaddr); + + /* set the listen interval */ + passo->listeninterval = adapter->listeninterval; + + pos += sizeof(passo->capinfo); + 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); + ssid->header.len = pbssdesc->ssid.ssidlength; + memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len); + pos += sizeof(ssid->header) + ssid->header.len; + ssid->header.len = cpu_to_le16(ssid->header.len); + + phy = (struct mrvlietypes_phyparamset *) pos; + phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); + phy->header.len = sizeof(phy->fh_ds.dsparamset); + memcpy(&phy->fh_ds.dsparamset, + &pbssdesc->phyparamset.dsparamset.currentchan, + sizeof(phy->fh_ds.dsparamset)); + pos += sizeof(phy->header) + phy->header.len; + phy->header.len = cpu_to_le16(phy->header.len); + + ss = (struct mrvlietypes_ssparamset *) pos; + ss->header.type = cpu_to_le16(TLV_TYPE_CF); + ss->header.len = sizeof(ss->cf_ibss.cfparamset); + pos += sizeof(ss->header) + ss->header.len; + ss->header.len = cpu_to_le16(ss->header.len); + + rates = (struct mrvlietypes_ratesparamset *) pos; + rates->header.type = cpu_to_le16(TLV_TYPE_RATES); + + memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES); + + card_rates = libertas_supported_rates; + card_rates_size = sizeof(libertas_supported_rates); + + if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, + card_rates, card_rates_size)) { + ret = -1; + goto done; + } + + rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); + adapter->curbssparams.numofrates = rates->header.len; + + pos += sizeof(rates->header) + rates->header.len; + rates->header.len = cpu_to_le16(rates->header.len); + + if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { + rsn = (struct mrvlietypes_rsnparamset *) pos; + rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */ + rsn->header.type = cpu_to_le16(rsn->header.type); + rsn->header.len = (u16) adapter->wpa_ie[1]; + memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len); + lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, + sizeof(rsn->header) + rsn->header.len); + pos += sizeof(rsn->header) + rsn->header.len; + rsn->header.len = cpu_to_le16(rsn->header.len); + } + + /* update curbssparams */ + adapter->curbssparams.channel = + (pbssdesc->phyparamset.dsparamset.currentchan); + + /* Copy the infra. association rates into Current BSS state structure */ + memcpy(&adapter->curbssparams.datarates, &rates->rates, + min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len)); + + lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len); + + /* set IBSS field */ + if (pbssdesc->inframode == wlan802_11infrastructure) { +#define CAPINFO_ESS_MODE 1 + passo->capinfo.ess = CAPINFO_ESS_MODE; + } + + if (libertas_parse_dnld_countryinfo_11d(priv)) { + ret = -1; + goto done; + } + + cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); + + /* set the capability info at last */ + memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo)); + tmpcap &= CAPINFO_MASK; + lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + tmpcap, CAPINFO_MASK); + tmpcap = cpu_to_le16(tmpcap); + memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); + + done: + LEAVE(); + return ret; +} + +int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, + struct cmd_ds_command *cmd, void *pssid) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; + int ret = 0; + int cmdappendsize = 0; + int i; + u16 tmpcap; + struct bss_descriptor *pbssdesc; + struct WLAN_802_11_SSID *ssid = pssid; + + ENTER(); + + if (!adapter) { + ret = -1; + goto done; + } + + cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); + + pbssdesc = &adapter->curbssparams.bssdescriptor; + adapter->pattemptedbssdesc = pbssdesc; + + /* + * Fill in the parameters for 2 data structures: + * 1. cmd_ds_802_11_ad_hoc_start command + * 2. adapter->scantable[i] + * + * Driver will fill up SSID, bsstype,IBSS param, Physical Param, + * probe delay, and cap info. + * + * Firmware will fill up beacon period, DTIM, Basic rates + * and operational rates. + */ + + memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); + + memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength); + + lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID); + + memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE); + memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength); + + pbssdesc->ssid.ssidlength = ssid->ssidlength; + + /* set the BSS type */ + adhs->bsstype = cmd_bss_type_ibss; + pbssdesc->inframode = wlan802_11ibss; + adhs->beaconperiod = adapter->beaconperiod; + + /* set Physical param set */ +#define DS_PARA_IE_ID 3 +#define DS_PARA_IE_LEN 1 + + adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; + adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; + + WARN_ON(!adapter->adhocchannel); + + lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n", + adapter->adhocchannel); + + adapter->curbssparams.channel = adapter->adhocchannel; + + pbssdesc->channel = adapter->adhocchannel; + adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel; + + memcpy(&pbssdesc->phyparamset, + &adhs->phyparamset, sizeof(union ieeetypes_phyparamset)); + + /* set IBSS param set */ +#define IBSS_PARA_IE_ID 6 +#define IBSS_PARA_IE_LEN 2 + + adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; + adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; + adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow; + memcpy(&pbssdesc->ssparamset, + &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset)); + + /* set capability info */ + adhs->cap.ess = 0; + adhs->cap.ibss = 1; + pbssdesc->cap.ibss = 1; + + /* probedelay */ + adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); + + /* set up privacy in adapter->scantable[i] */ + if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { + +#define AD_HOC_CAP_PRIVACY_ON 1 + lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n"); + pbssdesc->privacy = wlan802_11privfilter8021xWEP; + adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; + } else { + lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting " + "privacy to ACCEPT ALL\n"); + pbssdesc->privacy = wlan802_11privfilteracceptall; + } + + memset(adhs->datarate, 0, sizeof(adhs->datarate)); + + if (adapter->adhoc_grate_enabled) { + memcpy(adhs->datarate, libertas_adhoc_rates_g, + min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); + } else { + memcpy(adhs->datarate, libertas_adhoc_rates_b, + min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); + } + + /* Find the last non zero */ + for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; + + adapter->curbssparams.numofrates = i; + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memcpy(&adapter->curbssparams.datarates, + &adhs->datarate, adapter->curbssparams.numofrates); + + lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", + adhs->datarate[0], adhs->datarate[1], + adhs->datarate[2], adhs->datarate[3]); + + lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n"); + + if (libertas_create_dnld_countryinfo_11d(priv)) { + lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); + ret = -1; + goto done; + } + + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + + S_DS_GEN + cmdappendsize); + + memcpy(&tmpcap, &adhs->cap, sizeof(u16)); + tmpcap = cpu_to_le16(tmpcap); + memcpy(&adhs->cap, &tmpcap, sizeof(u16)); + + ret = 0; +done: + LEAVE(); + return ret; +} + +int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, + struct cmd_ds_command *cmd) +{ + cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); + cmd->size = cpu_to_le16(S_DS_GEN); + + return 0; +} + +int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; + struct bss_descriptor *pbssdesc = pdata_buf; + int cmdappendsize = 0; + int ret = 0; + u8 *card_rates; + int card_rates_size; + u16 tmpcap; + int i; + + ENTER(); + + adapter->pattemptedbssdesc = pbssdesc; + + cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); + + padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; + + padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod; + + memcpy(&padhocjoin->bssdescriptor.BSSID, + &pbssdesc->macaddress, ETH_ALEN); + + memcpy(&padhocjoin->bssdescriptor.SSID, + &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength); + + memcpy(&padhocjoin->bssdescriptor.phyparamset, + &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset)); + + memcpy(&padhocjoin->bssdescriptor.ssparamset, + &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset)); + + memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo)); + tmpcap &= CAPINFO_MASK; + + lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + tmpcap, CAPINFO_MASK); + memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, + sizeof(struct ieeetypes_capinfo)); + + /* information on BSSID descriptor passed to FW */ + lbs_pr_debug(1, + "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n", + padhocjoin->bssdescriptor.BSSID[0], + padhocjoin->bssdescriptor.BSSID[1], + padhocjoin->bssdescriptor.BSSID[2], + padhocjoin->bssdescriptor.BSSID[3], + padhocjoin->bssdescriptor.BSSID[4], + padhocjoin->bssdescriptor.BSSID[5], + padhocjoin->bssdescriptor.SSID); + + lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n", + (u32) padhocjoin->bssdescriptor.datarates); + + /* failtimeout */ + padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + + /* probedelay */ + padhocjoin->probedelay = + cpu_to_le16(cmd_scan_probe_delay_time); + + /* Copy Data rates from the rates recorded in scan response */ + memset(padhocjoin->bssdescriptor.datarates, 0, + sizeof(padhocjoin->bssdescriptor.datarates)); + memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates, + min(sizeof(padhocjoin->bssdescriptor.datarates), + sizeof(pbssdesc->datarates))); + + card_rates = libertas_supported_rates; + card_rates_size = sizeof(libertas_supported_rates); + + adapter->curbssparams.channel = pbssdesc->channel; + + if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, + sizeof(padhocjoin->bssdescriptor.datarates), + card_rates, card_rates_size)) { + lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n"); + ret = -1; + goto done; + } + + /* Find the last non zero */ + for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) + && padhocjoin->bssdescriptor.datarates[i]; i++) ; + + adapter->curbssparams.numofrates = i; + + /* + * Copy the adhoc joining rates to Current BSS State structure + */ + memcpy(adapter->curbssparams.datarates, + padhocjoin->bssdescriptor.datarates, + adapter->curbssparams.numofrates); + + padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = + cpu_to_le16(pbssdesc->atimwindow); + + if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { + padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; + } + + if (adapter->psmode == wlan802_11powermodemax_psp) { + /* wake up first */ + enum WLAN_802_11_POWER_MODE Localpsmode; + + Localpsmode = wlan802_11powermodecam; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_ps_mode, + cmd_act_set, + 0, 0, &Localpsmode); + + if (ret) { + ret = -1; + goto done; + } + } + + if (libertas_parse_dnld_countryinfo_11d(priv)) { + ret = -1; + goto done; + } + + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + + S_DS_GEN + cmdappendsize); + + memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap, + sizeof(struct ieeetypes_capinfo)); + tmpcap = cpu_to_le16(tmpcap); + + memcpy(&padhocjoin->bssdescriptor.cap, + &tmpcap, sizeof(struct ieeetypes_capinfo)); + + done: + LEAVE(); + return ret; +} + +int libertas_ret_80211_associate(wlan_private * priv, + struct cmd_ds_command *resp) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + union iwreq_data wrqu; + struct ieeetypes_assocrsp *passocrsp; + struct bss_descriptor *pbssdesc; + + ENTER(); + + passocrsp = (struct ieeetypes_assocrsp *) & resp->params; + + if (passocrsp->statuscode) { + + libertas_mac_event_disconnected(priv); + + lbs_pr_debug(1, + "ASSOC_RESP: Association failed, status code = %d\n", + passocrsp->statuscode); + + ret = -1; + goto done; + } + + lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, + le16_to_cpu(resp->size) - S_DS_GEN); + + /* Send a Media Connected event, according to the Spec */ + adapter->connect_status = libertas_connected; + + /* Set the attempted BSSID Index to current */ + pbssdesc = adapter->pattemptedbssdesc; + + lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid); + + /* Set the new SSID to current SSID */ + memcpy(&adapter->curbssparams.ssid, + &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); + + /* Set the new BSSID (AP's MAC address) to current BSSID */ + memcpy(adapter->curbssparams.bssid, + pbssdesc->macaddress, ETH_ALEN); + + /* Make a copy of current BSSID descriptor */ + memcpy(&adapter->curbssparams.bssdescriptor, + pbssdesc, sizeof(struct bss_descriptor)); + + lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n", + adapter->currentpacketfilter); + + adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; + adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); + memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); + adapter->nextSNRNF = 0; + adapter->numSNRNF = 0; + + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + + lbs_pr_debug(1, "ASSOC_RESP: Associated \n"); + + memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + done: + LEAVE(); + return ret; +} + +int libertas_ret_80211_disassociate(wlan_private * priv, + struct cmd_ds_command *resp) +{ + ENTER(); + + libertas_mac_event_disconnected(priv); + + LEAVE(); + return 0; +} + +int libertas_ret_80211_ad_hoc_start(wlan_private * priv, + struct cmd_ds_command *resp) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + u16 command = le16_to_cpu(resp->command); + u16 result = le16_to_cpu(resp->result); + struct cmd_ds_802_11_ad_hoc_result *padhocresult; + union iwreq_data wrqu; + struct bss_descriptor *pbssdesc; + + ENTER(); + + padhocresult = &resp->params.result; + + lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size)); + lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command); + lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result); + + pbssdesc = adapter->pattemptedbssdesc; + + /* + * Join result code 0 --> SUCCESS + */ + if (result) { + lbs_pr_debug(1, "ADHOC_RESP failed\n"); + if (adapter->connect_status == libertas_connected) { + libertas_mac_event_disconnected(priv); + } + + memset(&adapter->curbssparams.bssdescriptor, + 0x00, sizeof(adapter->curbssparams.bssdescriptor)); + + LEAVE(); + return -1; + } + + /* + * Now the join cmd should be successful + * If BSSID has changed use SSID to compare instead of BSSID + */ + lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid); + + /* Send a Media Connected event, according to the Spec */ + adapter->connect_status = libertas_connected; + + if (command == cmd_ret_802_11_ad_hoc_start) { + /* Update the created network descriptor with the new BSSID */ + memcpy(pbssdesc->macaddress, + padhocresult->BSSID, ETH_ALEN); + } else { + + /* Make a copy of current BSSID descriptor, only needed for join since + * the current descriptor is already being used for adhoc start + */ + memmove(&adapter->curbssparams.bssdescriptor, + pbssdesc, sizeof(struct bss_descriptor)); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&adapter->curbssparams.bssid, + pbssdesc->macaddress, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&adapter->curbssparams.ssid, + &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); + + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n"); + lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel); + lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", + padhocresult->BSSID[0], padhocresult->BSSID[1], + padhocresult->BSSID[2], padhocresult->BSSID[3], + padhocresult->BSSID[4], padhocresult->BSSID[5]); + + LEAVE(); + return ret; +} + +int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, + struct cmd_ds_command *resp) +{ + ENTER(); + + libertas_mac_event_disconnected(priv); + + LEAVE(); + return 0; +} diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h new file mode 100644 index 0000000..8efa245 --- /dev/null +++ b/drivers/net/wireless/libertas/join.h @@ -0,0 +1,64 @@ +/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** + * Interface for the wlan infrastructure and adhoc join routines + * + * Driver interface functions and type declarations for the join module + * implemented in wlan_join.c. Process all start/join requests for + * both adhoc and infrastructure networks + */ +#ifndef _WLAN_JOIN_H +#define _WLAN_JOIN_H + +#include "defs.h" + +struct cmd_ds_command; +extern int libertas_cmd_80211_authenticate(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pdata_buf); +extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, + struct cmd_ds_command *cmd); +extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pssid); +extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, + struct cmd_ds_command *cmd); +extern int libertas_cmd_80211_associate(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pdata_buf); + +extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, + struct cmd_ds_command *resp); +extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, + struct cmd_ds_command *resp); +extern int libertas_ret_80211_disassociate(wlan_private * priv, + struct cmd_ds_command *resp); +extern int libertas_ret_80211_associate(wlan_private * priv, + struct cmd_ds_command *resp); + +extern int libertas_idle_on(wlan_private * priv); +extern int libertas_idle_off(wlan_private * priv); + +extern int libertas_do_adhocstop_ioctl(wlan_private * priv); +extern int libertas_reassociation_thread(void *data); + +struct WLAN_802_11_SSID; +struct bss_descriptor; + +extern int libertas_start_adhoc_network(wlan_private * priv, + struct WLAN_802_11_SSID *adhocssid); +extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc); +extern int libertas_stop_adhoc_network(wlan_private * priv); + +extern int libertas_send_deauthentication(wlan_private * priv); +extern int libertas_send_deauth(wlan_private * priv); + +extern int libertas_do_adhocstop_ioctl(wlan_private * priv); + +int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc); + +#endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c new file mode 100644 index 0000000..dcbf102 --- /dev/null +++ b/drivers/net/wireless/libertas/main.c @@ -0,0 +1,1258 @@ +/** + * This file contains the major functions in WLAN + * driver. It includes init, exit, open, close and main + * thread etc.. + */ + +#include +#include +#include +#include +#include + +#include + +#include "host.h" +#include "sbi.h" +#include "decl.h" +#include "dev.h" +#include "fw.h" +#include "wext.h" +#include "debugfs.h" +#include "assoc.h" + +#ifdef ENABLE_PM +static struct pm_dev *wlan_pm_dev = NULL; +#endif + +#define WLAN_TX_PWR_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */ +#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */ + +/* Format { channel, frequency (MHz), maxtxpower } */ +/* band: 'B/G', region: USA FCC/Canada IC */ +static struct chan_freq_power channel_freq_power_US_BG[] = { + {1, 2412, WLAN_TX_PWR_US_DEFAULT}, + {2, 2417, WLAN_TX_PWR_US_DEFAULT}, + {3, 2422, WLAN_TX_PWR_US_DEFAULT}, + {4, 2427, WLAN_TX_PWR_US_DEFAULT}, + {5, 2432, WLAN_TX_PWR_US_DEFAULT}, + {6, 2437, WLAN_TX_PWR_US_DEFAULT}, + {7, 2442, WLAN_TX_PWR_US_DEFAULT}, + {8, 2447, WLAN_TX_PWR_US_DEFAULT}, + {9, 2452, WLAN_TX_PWR_US_DEFAULT}, + {10, 2457, WLAN_TX_PWR_US_DEFAULT}, + {11, 2462, WLAN_TX_PWR_US_DEFAULT} +}; + +/* band: 'B/G', region: Europe ETSI */ +static struct chan_freq_power channel_freq_power_EU_BG[] = { + {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, + {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, + {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, + {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, + {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, + {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, + {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, + {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, + {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, + {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, + {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, + {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, + {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT} +}; + +/* band: 'B/G', region: Spain */ +static struct chan_freq_power channel_freq_power_SPN_BG[] = { + {10, 2457, WLAN_TX_PWR_DEFAULT}, + {11, 2462, WLAN_TX_PWR_DEFAULT} +}; + +/* band: 'B/G', region: France */ +static struct chan_freq_power channel_freq_power_FR_BG[] = { + {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, + {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, + {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, + {13, 2472, WLAN_TX_PWR_FR_DEFAULT} +}; + +/* band: 'B/G', region: Japan */ +static struct chan_freq_power channel_freq_power_JPN_BG[] = { + {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, + {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, + {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, + {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, + {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, + {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, + {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, + {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, + {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, + {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, + {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, + {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, + {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, + {14, 2484, WLAN_TX_PWR_JP_DEFAULT} +}; + +/** + * the structure for channel, frequency and power + */ +struct region_cfp_table { + u8 region; + struct chan_freq_power *cfp_BG; + int cfp_no_BG; +}; + +/** + * the structure for the mapping between region and CFP + */ +static struct region_cfp_table region_cfp_table[] = { + {0x10, /*US FCC */ + channel_freq_power_US_BG, + sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + } + , + {0x20, /*CANADA IC */ + channel_freq_power_US_BG, + sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + } + , + {0x30, /*EU*/ channel_freq_power_EU_BG, + sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), + } + , + {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, + sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), + } + , + {0x32, /*FRANCE*/ channel_freq_power_FR_BG, + sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), + } + , + {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, + sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), + } + , +/*Add new region here */ +}; + +/** + * the rates supported by the card + */ +u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = + { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, + 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 +}; + +/** + * the rates supported + */ +u8 libertas_supported_rates[G_SUPPORTED_RATES] = + { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0 }; + +/** + * the rates supported for ad-hoc G mode + */ +u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = + { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0 }; + +/** + * the rates supported for ad-hoc B mode + */ +u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; + +/** + * the global variable of a pointer to wlan_private + * structure variable + */ +static wlan_private *wlanpriv = NULL; + +#define MAX_DEVS 5 +static struct net_device *libertas_devs[MAX_DEVS]; +static int libertas_found = 0; + +/** + * the table to keep region code + */ +u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = + { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; + +static u8 *default_fw_name = "usb8388.bin"; + +/** + * Attributes exported through sysfs + */ + +/** + * @brief Get function for sysfs attribute libertas_mpp + */ +static ssize_t libertas_mpp_get(struct device * dev, + struct device_attribute *attr, char * buf) { + struct cmd_ds_mesh_access mesh_access; + + memset(&mesh_access, 0, sizeof(mesh_access)); + libertas_prepare_and_send_command(to_net_dev(dev)->priv, + cmd_mesh_access, + cmd_act_mesh_get_mpp, + cmd_option_waitforrsp, 0, (void *)&mesh_access); + + return snprintf(buf, 3, "%d\n", mesh_access.data[0]); +} + +/** + * @brief Set function for sysfs attribute libertas_mpp + */ +static ssize_t libertas_mpp_set(struct device * dev, + struct device_attribute *attr, const char * buf, size_t count) { + struct cmd_ds_mesh_access mesh_access; + + + memset(&mesh_access, 0, sizeof(mesh_access)); + sscanf(buf, "%d", &(mesh_access.data[0])); + libertas_prepare_and_send_command((to_net_dev(dev))->priv, + cmd_mesh_access, + cmd_act_mesh_set_mpp, + cmd_option_waitforrsp, 0, (void *)&mesh_access); + return strlen(buf); +} + +/** + * libertas_mpp attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/libertas-mpp) + */ +static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get, + libertas_mpp_set ); + +/** + * @brief Check if the device can be open and wait if necessary. + * + * @param dev A pointer to net_device structure + * @return 0 + * + * For USB adapter, on some systems the device open handler will be + * called before FW ready. Use the following flag check and wait + * function to work around the issue. + * + */ +static int pre_open_check(struct net_device *dev) { + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *adapter = priv->adapter; + int i = 0; + + while (!adapter->fw_ready && i < 20) { + i++; + msleep_interruptible(100); + } + if (!adapter->fw_ready) { + lbs_pr_info("FW not ready, pre_open_check() return failure\n"); + LEAVE(); + return -1; + } + + return 0; +} + +/** + * @brief This function opens the device + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int wlan_dev_open(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + + priv->open = 1; + + if (adapter->connect_status == libertas_connected) { + netif_carrier_on(priv->wlan_dev.netdev); + } else + netif_carrier_off(priv->wlan_dev.netdev); + + LEAVE(); + return 0; +} +/** + * @brief This function opens the mshX interface + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int mesh_open(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv ; + + if(pre_open_check(dev) == -1) + return -1; + priv->mesh_open = 1 ; + netif_start_queue(priv->mesh_dev); + if (priv->infra_open == 0) + return wlan_dev_open(priv->wlan_dev.netdev) ; + return 0; +} + +/** + * @brief This function opens the ethX interface + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int wlan_open(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv ; + + if(pre_open_check(dev) == -1) + return -1; + priv->infra_open = 1 ; + netif_wake_queue(priv->wlan_dev.netdev); + if (priv->open == 0) + return wlan_dev_open(priv->wlan_dev.netdev) ; + return 0; +} + +static int wlan_dev_close(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + + ENTER(); + + netif_carrier_off(priv->wlan_dev.netdev); + priv->open = 0; + + LEAVE(); + return 0; +} + +/** + * @brief This function closes the mshX interface + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int mesh_close(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) (dev->priv); + + priv->mesh_open = 0; + netif_stop_queue(priv->mesh_dev); + if (priv->infra_open == 0) + return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; + else + return 0; +} + +/** + * @brief This function closes the ethX interface + * + * @param dev A pointer to net_device structure + * @return 0 + */ +static int wlan_close(struct net_device *dev) { + wlan_private *priv = (wlan_private *) dev->priv; + + netif_stop_queue(priv->wlan_dev.netdev); + priv->infra_open = 0; + if (priv->mesh_open == 0) + return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; + else + return 0; +} + + +#ifdef ENABLE_PM + +/** + * @brief This function is a callback function. it is called by + * kernel to enter or exit power saving mode. + * + * @param pmdev A pointer to pm_dev + * @param pmreq pm_request_t + * @param pmdata A pointer to pmdata + * @return 0 or -1 + */ +static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq, + void *pmdata) +{ + wlan_private *priv = wlanpriv; + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->wlan_dev.netdev; + + lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq); + + switch (pmreq) { + case PM_SUSPEND: + lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n"); + + /* in associated mode */ + if (adapter->connect_status == libertas_connected) { + if ((adapter->psstate != PS_STATE_SLEEP) + ) { + lbs_pr_debug(1, + "wlan_pm_callback: can't enter sleep mode\n"); + return -1; + } else { + + /* + * Detach the network interface + * if the network is running + */ + if (netif_running(dev)) { + netif_device_detach(dev); + lbs_pr_debug(1, + "netif_device_detach().\n"); + } + libertas_sbi_suspend(priv); + } + break; + } + + /* in non associated mode */ + + /* + * Detach the network interface + * if the network is running + */ + if (netif_running(dev)) + netif_device_detach(dev); + + /* + * Storing and restoring of the regs be taken care + * at the driver rest will be done at wlan driver + * this makes driver independent of the card + */ + + libertas_sbi_suspend(priv); + + break; + + case PM_RESUME: + /* in associated mode */ + if (adapter->connect_status == libertas_connected) { + { + /* + * Bring the inteface up first + * This case should not happen still ... + */ + libertas_sbi_resume(priv); + + /* + * Attach the network interface + * if the network is running + */ + if (netif_running(dev)) { + netif_device_attach(dev); + lbs_pr_debug(1, + "after netif_device_attach().\n"); + } + lbs_pr_debug(1, + "After netif attach, in associated mode.\n"); + } + break; + } + + /* in non associated mode */ + + /* + * Bring the inteface up first + * This case should not happen still ... + */ + + libertas_sbi_resume(priv); + + if (netif_running(dev)) + netif_device_attach(dev); + + lbs_pr_debug(1, "after netif attach, in NON associated mode.\n"); + break; + } + + return 0; +} +#endif /* ENABLE_PM */ + +static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret = 0; + wlan_private *priv = dev->priv; + + ENTER(); + + if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) { + priv->stats.tx_dropped++; + goto done; + } + + netif_stop_queue(priv->wlan_dev.netdev); + + if (libertas_process_tx(priv, skb) == 0) + dev->trans_start = jiffies; +done: + LEAVE(); + return ret; +} + +/** + * @brief Mark mesh packets and handover them to wlan_hard_start_xmit + * + */ +static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + wlan_private *priv = dev->priv; + ENTER(); + SET_MESH_FRAME(skb); + LEAVE(); + + return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev); +} + +/** + * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit + * + */ +static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { + ENTER(); + UNSET_MESH_FRAME(skb); + LEAVE(); + return wlan_hard_start_xmit(skb, dev); +} + +static void wlan_tx_timeout(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + + ENTER(); + + lbs_pr_err("tx watch dog timeout!\n"); + + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + dev->trans_start = jiffies; + + if (priv->adapter->currenttxskb) { + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + /* If we are here, we have not received feedback from + the previous packet. Assume TX_FAIL and move on. */ + priv->adapter->eventcause = 0x01000000; + libertas_send_tx_feedback(priv); + } else + wake_up_interruptible(&priv->mainthread.waitq); + } else if (priv->adapter->connect_status == libertas_connected) + netif_wake_queue(priv->wlan_dev.netdev); + + LEAVE(); +} + +/** + * @brief This function returns the network statistics + * + * @param dev A pointer to wlan_private structure + * @return A pointer to net_device_stats structure + */ +static struct net_device_stats *wlan_get_stats(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + + return &priv->stats; +} + +static int wlan_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = 0; + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *adapter = priv->adapter; + struct sockaddr *phwaddr = addr; + + ENTER(); + + memset(adapter->current_addr, 0, ETH_ALEN); + + /* dev->dev_addr is 8 bytes */ + lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN); + + lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); + memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + lbs_pr_debug(1, "set mac address failed.\n"); + ret = -1; + goto done; + } + + lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN); + memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); + memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); + +done: + LEAVE(); + return ret; +} + +static int wlan_copy_multicast_address(wlan_adapter * adapter, + struct net_device *dev) +{ + int i = 0; + struct dev_mc_list *mcptr = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++) { + memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); + mcptr = mcptr->next; + } + + return i; + +} + +static void wlan_set_multicast_list(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int oldpacketfilter; + + ENTER(); + + oldpacketfilter = adapter->currentpacketfilter; + + if (dev->flags & IFF_PROMISC) { + lbs_pr_debug(1, "enable Promiscuous mode\n"); + adapter->currentpacketfilter |= + cmd_act_mac_promiscuous_enable; + adapter->currentpacketfilter &= + ~(cmd_act_mac_all_multicast_enable | + cmd_act_mac_multicast_enable); + } else { + /* Multicast */ + adapter->currentpacketfilter &= + ~cmd_act_mac_promiscuous_enable; + + if (dev->flags & IFF_ALLMULTI || dev->mc_count > + MRVDRV_MAX_MULTICAST_LIST_SIZE) { + lbs_pr_debug(1, "Enabling All Multicast!\n"); + adapter->currentpacketfilter |= + cmd_act_mac_all_multicast_enable; + adapter->currentpacketfilter &= + ~cmd_act_mac_multicast_enable; + } else { + adapter->currentpacketfilter &= + ~cmd_act_mac_all_multicast_enable; + + if (!dev->mc_count) { + lbs_pr_debug(1, "No multicast addresses - " + "disabling multicast!\n"); + adapter->currentpacketfilter &= + ~cmd_act_mac_multicast_enable; + } else { + int i; + + adapter->currentpacketfilter |= + cmd_act_mac_multicast_enable; + + adapter->nr_of_multicastmacaddr = + wlan_copy_multicast_address(adapter, dev); + + lbs_pr_debug(1, "Multicast addresses: %d\n", + dev->mc_count); + + for (i = 0; i < dev->mc_count; i++) { + lbs_pr_debug(1, "Multicast address %d:" + "%x %x %x %x %x %x\n", i, + adapter->multicastlist[i][0], + adapter->multicastlist[i][1], + adapter->multicastlist[i][2], + adapter->multicastlist[i][3], + adapter->multicastlist[i][4], + adapter->multicastlist[i][5]); + } + /* set multicast addresses to firmware */ + libertas_prepare_and_send_command(priv, + cmd_mac_multicast_adr, + cmd_act_set, 0, 0, + NULL); + } + } + } + + if (adapter->currentpacketfilter != oldpacketfilter) { + libertas_set_mac_packet_filter(priv); + } + + LEAVE(); +} + +/** + * @brief This function hanldes the major job in WLAN driver. + * it handles the event generated by firmware, rx data received + * from firmware and tx data sent from kernel. + * + * @param data A pointer to wlan_thread structure + * @return 0 + */ +static int wlan_service_main_thread(void *data) +{ + struct wlan_thread *thread = data; + wlan_private *priv = thread->priv; + wlan_adapter *adapter = priv->adapter; + wait_queue_t wait; + u8 ireg = 0; + + ENTER(); + + wlan_activate_thread(thread); + + init_waitqueue_entry(&wait, current); + + for (;;) { + lbs_pr_debug(1, "main-thread 111: intcounter=%d " + "currenttxskb=%p dnld_sent=%d\n", + adapter->intcounter, + adapter->currenttxskb, priv->wlan_dev.dnld_sent); + + add_wait_queue(&thread->waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irq(&adapter->driver_lock); + if ((adapter->psstate == PS_STATE_SLEEP) || + (!adapter->intcounter + && (priv->wlan_dev.dnld_sent || adapter->cur_cmd || + list_empty(&adapter->cmdpendingq)))) { + lbs_pr_debug(1, + "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", + adapter->connect_status, adapter->intcounter, + adapter->psmode, adapter->psstate); + spin_unlock_irq(&adapter->driver_lock); + schedule(); + } else + spin_unlock_irq(&adapter->driver_lock); + + + lbs_pr_debug(1, + "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " + "dnld_sent=%d\n", adapter->intcounter, + adapter->currenttxskb, priv->wlan_dev.dnld_sent); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&thread->waitq, &wait); + try_to_freeze(); + + lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p " + "dnld_sent=%d\n", + adapter->intcounter, + adapter->currenttxskb, priv->wlan_dev.dnld_sent); + + if (kthread_should_stop() + || adapter->surpriseremoved) { + lbs_pr_debug(1, + "main-thread: break from main thread: surpriseremoved=0x%x\n", + adapter->surpriseremoved); + break; + } + + + spin_lock_irq(&adapter->driver_lock); + if (adapter->intcounter) { + u8 int_status; + adapter->intcounter = 0; + int_status = libertas_sbi_get_int_status(priv, &ireg); + + if (int_status) { + lbs_pr_debug(1, + "main-thread: reading HOST_INT_STATUS_REG failed\n"); + spin_unlock_irq(&adapter->driver_lock); + continue; + } + adapter->hisregcpy |= ireg; + } + + lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p " + "dnld_sent=%d\n", + adapter->intcounter, + adapter->currenttxskb, priv->wlan_dev.dnld_sent); + + /* command response? */ + if (adapter->hisregcpy & his_cmdupldrdy) { + lbs_pr_debug(1, "main-thread: cmd response ready.\n"); + + adapter->hisregcpy &= ~his_cmdupldrdy; + spin_unlock_irq(&adapter->driver_lock); + libertas_process_rx_command(priv); + spin_lock_irq(&adapter->driver_lock); + } + + /* Any Card Event */ + if (adapter->hisregcpy & his_cardevent) { + lbs_pr_debug(1, "main-thread: Card Event Activity.\n"); + + adapter->hisregcpy &= ~his_cardevent; + + if (libertas_sbi_read_event_cause(priv)) { + lbs_pr_alert( + "main-thread: libertas_sbi_read_event_cause failed.\n"); + spin_unlock_irq(&adapter->driver_lock); + continue; + } + spin_unlock_irq(&adapter->driver_lock); + libertas_process_event(priv); + } else + spin_unlock_irq(&adapter->driver_lock); + + /* Check if we need to confirm Sleep Request received previously */ + if (adapter->psstate == PS_STATE_PRE_SLEEP) { + if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) { + if (adapter->connect_status == + libertas_connected) { + lbs_pr_debug(1, + "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " + "dnld_sent=%d cur_cmd=%p, confirm now\n", + adapter->intcounter, + adapter->currenttxskb, + priv->wlan_dev.dnld_sent, + adapter->cur_cmd); + + libertas_ps_confirm_sleep(priv, + (u16) adapter->psmode); + } else { + /* workaround for firmware sending + * deauth/linkloss event immediately + * after sleep request, remove this + * after firmware fixes it + */ + adapter->psstate = PS_STATE_AWAKE; + lbs_pr_alert( + "main-thread: ignore PS_SleepConfirm in non-connected state\n"); + } + } + } + + /* The PS state is changed during processing of Sleep Request + * event above + */ + if ((priv->adapter->psstate == PS_STATE_SLEEP) || + (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) + continue; + + /* Execute the next command */ + if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd) + libertas_execute_next_command(priv); + + /* Wake-up command waiters which can't sleep in + * libertas_prepare_and_send_command + */ + if (!adapter->nr_cmd_pending) + wake_up_all(&adapter->cmd_pending); + + libertas_tx_runqueue(priv); + } + + del_timer(&adapter->command_timer); + adapter->nr_cmd_pending = 0; + wake_up_all(&adapter->cmd_pending); + wlan_deactivate_thread(thread); + + LEAVE(); + return 0; +} + +/** + * @brief This function adds the card. it will probe the + * card, allocate the wlan_priv and initialize the device. + * + * @param card A pointer to card + * @return A pointer to wlan_private structure + */ +wlan_private *wlan_add_card(void *card) +{ + struct net_device *dev = NULL; + struct net_device *mesh_dev = NULL; + wlan_private *priv = NULL; + + ENTER(); + + /* Allocate an Ethernet device and register it */ + if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { + lbs_pr_alert( "Init ethernet device failed!\n"); + return NULL; + } + + priv = dev->priv; + + /* allocate buffer for wlan_adapter */ + if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) { + lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n"); + goto err_kmalloc; + } + + /* Allocate a virtual mesh device */ + if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { + lbs_pr_debug(1, "Init ethernet device failed!\n"); + return NULL; + } + + /* Both intervaces share the priv structure */ + mesh_dev->priv = priv; + + /* init wlan_adapter */ + memset(priv->adapter, 0, sizeof(wlan_adapter)); + + priv->wlan_dev.netdev = dev; + priv->wlan_dev.card = card; + priv->mesh_open = 0; + priv->infra_open = 0; + priv->mesh_dev = mesh_dev; + wlanpriv = priv; + + SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(mesh_dev); + + /* Setup the OS Interface to our functions */ + dev->open = wlan_open; + dev->hard_start_xmit = wlan_pre_start_xmit; + dev->stop = wlan_close; + dev->do_ioctl = libertas_do_ioctl; + dev->set_mac_address = wlan_set_mac_address; + mesh_dev->open = mesh_open; + mesh_dev->hard_start_xmit = mesh_pre_start_xmit; + mesh_dev->stop = mesh_close; + mesh_dev->do_ioctl = libertas_do_ioctl; + memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr, + sizeof(wlanpriv->wlan_dev.netdev->dev_addr)); + +#define WLAN_WATCHDOG_TIMEOUT (5 * HZ) + + dev->tx_timeout = wlan_tx_timeout; + dev->get_stats = wlan_get_stats; + dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT; + dev->ethtool_ops = &libertas_ethtool_ops; + mesh_dev->get_stats = wlan_get_stats; + mesh_dev->ethtool_ops = &libertas_ethtool_ops; + +#ifdef WIRELESS_EXT + dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; + mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; +#endif +#define NETIF_F_DYNALLOC 16 + dev->features |= NETIF_F_DYNALLOC; + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->set_multicast_list = wlan_set_multicast_list; + + INIT_LIST_HEAD(&priv->adapter->cmdfreeq); + INIT_LIST_HEAD(&priv->adapter->cmdpendingq); + + spin_lock_init(&priv->adapter->driver_lock); + init_waitqueue_head(&priv->adapter->cmd_pending); + priv->adapter->nr_cmd_pending = 0; + + lbs_pr_debug(1, "Starting kthread...\n"); + priv->mainthread.priv = priv; + wlan_create_thread(wlan_service_main_thread, + &priv->mainthread, "wlan_main_service"); + + priv->assoc_thread = + create_singlethread_workqueue("libertas_assoc"); + INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker); + + /* + * Register the device. Fillup the private data structure with + * relevant information from the card and request for the required + * IRQ. + */ + if (libertas_sbi_register_dev(priv) < 0) { + lbs_pr_info("failed to register wlan device!\n"); + goto err_registerdev; + } + + /* init FW and HW */ + if (libertas_init_fw(priv)) { + lbs_pr_debug(1, "Firmware Init failed\n"); + goto err_registerdev; + } + + if (register_netdev(dev)) { + lbs_pr_err("Cannot register network device!\n"); + goto err_init_fw; + } + + /* Register virtual mesh interface */ + if (register_netdev(mesh_dev)) { + lbs_pr_info("Cannot register mesh virtual interface!\n"); + goto err_init_fw; + } + + lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name); + + libertas_debugfs_init_one(priv, dev); + + if (libertas_found == MAX_DEVS) + goto err_init_fw; + libertas_devs[libertas_found] = dev; + libertas_found++; +#ifdef ENABLE_PM + if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback))) + lbs_pr_alert( "failed to register PM callback\n"); +#endif + if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp)) + goto err_create_file; + + LEAVE(); + return priv; + +err_create_file: + device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); +err_init_fw: + libertas_sbi_unregister_dev(priv); +err_registerdev: + destroy_workqueue(priv->assoc_thread); + /* Stop the thread servicing the interrupts */ + wake_up_interruptible(&priv->mainthread.waitq); + wlan_terminate_thread(&priv->mainthread); + kfree(priv->adapter); +err_kmalloc: + free_netdev(dev); + free_netdev(mesh_dev); + wlanpriv = NULL; + + LEAVE(); + return NULL; +} + +static void wake_pending_cmdnodes(wlan_private *priv) +{ + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + + spin_lock_irqsave(&priv->adapter->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { + cmdnode->cmdwaitqwoken = 1; + wake_up_interruptible(&cmdnode->cmdwait_q); + } + spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); +} + + +int wlan_remove_card(void *card) +{ + wlan_private *priv = libertas_sbi_get_priv(card); + wlan_adapter *adapter; + struct net_device *dev; + struct net_device *mesh_dev; + union iwreq_data wrqu; + int i; + + ENTER(); + + if (!priv) { + LEAVE(); + return 0; + } + + adapter = priv->adapter; + + if (!adapter) { + LEAVE(); + return 0; + } + + dev = priv->wlan_dev.netdev; + mesh_dev = priv->mesh_dev; + + netif_stop_queue(mesh_dev); + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + + wake_pending_cmdnodes(priv); + + device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); + unregister_netdev(mesh_dev); + unregister_netdev(dev); + + cancel_delayed_work(&priv->assoc_work); + destroy_workqueue(priv->assoc_thread); + + if (adapter->psmode == wlan802_11powermodemax_psp) { + adapter->psmode = wlan802_11powermodecam; + libertas_ps_wakeup(priv, cmd_option_waitforrsp); + } + + memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + +#ifdef ENABLE_PM + pm_unregister(wlan_pm_dev); +#endif + + adapter->surpriseremoved = 1; + + /* Stop the thread servicing the interrupts */ + wlan_terminate_thread(&priv->mainthread); + + libertas_debugfs_remove_one(priv); + + lbs_pr_debug(1, "Free adapter\n"); + libertas_free_adapter(priv); + + for (i = 0; iwlan_dev.netdev) { + libertas_devs[i] = libertas_devs[--libertas_found]; + libertas_devs[libertas_found] = NULL ; + break ; + } + } + + lbs_pr_debug(1, "Unregister finish\n"); + + priv->wlan_dev.netdev = NULL; + priv->mesh_dev = NULL ; + free_netdev(mesh_dev); + free_netdev(dev); + wlanpriv = NULL; + + LEAVE(); + return 0; +} + +/** + * @brief This function finds the CFP in + * region_cfp_table based on region and band parameter. + * + * @param region The region code + * @param band The band + * @param cfp_no A pointer to CFP number + * @return A pointer to CFP + */ +struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no) +{ + int i, end; + + ENTER(); + + end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); + + for (i = 0; i < end ; i++) { + lbs_pr_debug(1, "region_cfp_table[i].region=%d\n", + region_cfp_table[i].region); + if (region_cfp_table[i].region == region) { + *cfp_no = region_cfp_table[i].cfp_no_BG; + LEAVE(); + return region_cfp_table[i].cfp_BG; + } + } + + LEAVE(); + return NULL; +} + +int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) +{ + wlan_adapter *adapter = priv->adapter; + int i = 0; + + struct chan_freq_power *cfp; + int cfp_no; + + ENTER(); + + memset(adapter->region_channel, 0, sizeof(adapter->region_channel)); + + { + cfp = libertas_get_region_cfp_table(region, band, &cfp_no); + if (cfp != NULL) { + adapter->region_channel[i].nrcfp = cfp_no; + adapter->region_channel[i].CFP = cfp; + } else { + lbs_pr_debug(1, "wrong region code %#x in band B-G\n", + region); + return -1; + } + adapter->region_channel[i].valid = 1; + adapter->region_channel[i].region = region; + adapter->region_channel[i].band = band; + i++; + } + LEAVE(); + return 0; +} + +/** + * @brief This function handles the interrupt. it will change PS + * state if applicable. it will wake up main_thread to handle + * the interrupt event as well. + * + * @param dev A pointer to net_device structure + * @return n/a + */ +void libertas_interrupt(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + + ENTER(); + + lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n", + priv->adapter->intcounter); + + priv->adapter->intcounter++; + + if (priv->adapter->psstate == PS_STATE_SLEEP) { + priv->adapter->psstate = PS_STATE_AWAKE; + netif_wake_queue(dev); + } + + wake_up_interruptible(&priv->mainthread.waitq); + + LEAVE(); +} + +static int wlan_init_module(void) +{ + int ret = 0; + + ENTER(); + + if (libertas_fw_name == NULL) { + libertas_fw_name = default_fw_name; + } + + libertas_debugfs_init(); + + if (libertas_sbi_register()) { + ret = -1; + libertas_debugfs_remove(); + goto done; + } + +done: + LEAVE(); + return ret; +} + +static void wlan_cleanup_module(void) +{ + int i; + + ENTER(); + + for (i = 0; ipriv; + reset_device(priv); + } + + libertas_sbi_unregister(); + libertas_debugfs_remove(); + + LEAVE(); +} + +module_init(wlan_init_module); +module_exit(wlan_cleanup_module); + +MODULE_DESCRIPTION("M-WLAN Driver"); +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h new file mode 100644 index 0000000..5d118f4 --- /dev/null +++ b/drivers/net/wireless/libertas/radiotap.h @@ -0,0 +1,57 @@ +#include + +struct tx_radiotap_hdr { + struct ieee80211_radiotap_header hdr; + u8 rate; + u8 txpower; + u8 rts_retries; + u8 data_retries; +#if 0 + u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; +#endif +} __attribute__ ((packed)); + +#define TX_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ + (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \ + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ + 0) + +#define IEEE80211_FC_VERSION_MASK 0x0003 +#define IEEE80211_FC_TYPE_MASK 0x000c +#define IEEE80211_FC_TYPE_MGT 0x0000 +#define IEEE80211_FC_TYPE_CTL 0x0004 +#define IEEE80211_FC_TYPE_DATA 0x0008 +#define IEEE80211_FC_SUBTYPE_MASK 0x00f0 +#define IEEE80211_FC_TOFROMDS_MASK 0x0300 +#define IEEE80211_FC_TODS_MASK 0x0100 +#define IEEE80211_FC_FROMDS_MASK 0x0200 +#define IEEE80211_FC_NODS 0x0000 +#define IEEE80211_FC_TODS 0x0100 +#define IEEE80211_FC_FROMDS 0x0200 +#define IEEE80211_FC_DSTODS 0x0300 + +struct rx_radiotap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + u16 chan_freq; + u16 chan_flags; + u8 antenna; + u8 antsignal; + u16 rx_flags; +#if 0 + u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18]; +#endif +} __attribute__ ((packed)); + +#define RX_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ + (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \ + 0) + diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c new file mode 100644 index 0000000..7e3f78f --- /dev/null +++ b/drivers/net/wireless/libertas/rx.c @@ -0,0 +1,459 @@ +/** + * This file contains the handling of RX in wlan driver. + */ +#include +#include + +#include "hostcmd.h" +#include "radiotap.h" +#include "decl.h" +#include "dev.h" +#include "wext.h" + +struct eth803hdr { + u8 dest_addr[6]; + u8 src_addr[6]; + u16 h803_len; +} __attribute__ ((packed)); + +struct rfc1042hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + u16 snap_type; +} __attribute__ ((packed)); + +struct rxpackethdr { + struct rxpd rx_pd; + struct eth803hdr eth803_hdr; + struct rfc1042hdr rfc1042_hdr; +} __attribute__ ((packed)); + +struct rx80211packethdr { + struct rxpd rx_pd; + void *eth80211_hdr; +} __attribute__ ((packed)); + +static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb); + +/** + * @brief This function computes the avgSNR . + * + * @param priv A pointer to wlan_private structure + * @return avgSNR + */ +static u8 wlan_getavgsnr(wlan_private * priv) +{ + u8 i; + u16 temp = 0; + wlan_adapter *adapter = priv->adapter; + if (adapter->numSNRNF == 0) + return 0; + for (i = 0; i < adapter->numSNRNF; i++) + temp += adapter->rawSNR[i]; + return (u8) (temp / adapter->numSNRNF); + +} + +/** + * @brief This function computes the AvgNF + * + * @param priv A pointer to wlan_private structure + * @return AvgNF + */ +static u8 wlan_getavgnf(wlan_private * priv) +{ + u8 i; + u16 temp = 0; + wlan_adapter *adapter = priv->adapter; + if (adapter->numSNRNF == 0) + return 0; + for (i = 0; i < adapter->numSNRNF; i++) + temp += adapter->rawNF[i]; + return (u8) (temp / adapter->numSNRNF); + +} + +/** + * @brief This function save the raw SNR/NF to our internel buffer + * + * @param priv A pointer to wlan_private structure + * @param prxpd A pointer to rxpd structure of received packet + * @return n/a + */ +static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) +{ + wlan_adapter *adapter = priv->adapter; + if (adapter->numSNRNF < adapter->data_avg_factor) + adapter->numSNRNF++; + adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; + adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; + adapter->nextSNRNF++; + if (adapter->nextSNRNF >= adapter->data_avg_factor) + adapter->nextSNRNF = 0; + return; +} + +/** + * @brief This function computes the RSSI in received packet. + * + * @param priv A pointer to wlan_private structure + * @param prxpd A pointer to rxpd structure of received packet + * @return n/a + */ +static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) +{ + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf); + lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n", + adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; + adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; + wlan_save_rawSNRNF(priv, p_rx_pd); + + adapter->rxpd_rate = p_rx_pd->rx_rate; + + adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; + adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; + lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n", + adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = + CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], + adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + + adapter->RSSI[TYPE_RXPD][TYPE_AVG] = + CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + LEAVE(); +} + +int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) +{ + lbs_pr_debug(1, "skb->data=%p\n", skb->data); + + if(IS_MESH_FRAME(skb)) + skb->dev = priv->mesh_dev; + else + skb->dev = priv->wlan_dev.netdev; + skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); + + return 0; +} + +/** + * @brief This function processes received packet and forwards it + * to kernel/upper layer + * + * @param priv A pointer to wlan_private + * @param skb A pointer to skb which includes the received packet + * @return 0 or -1 + */ +int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + struct rxpackethdr *p_rx_pkt; + struct rxpd *p_rx_pd; + + int hdrchop; + struct ethhdr *p_ethhdr; + + const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + ENTER(); + + if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) + lbs_dbg_hex("RX packet: ", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + return process_rxed_802_11_packet(priv, skb); + + p_rx_pkt = (struct rxpackethdr *) skb->data; + p_rx_pd = &p_rx_pkt->rx_pd; + if (p_rx_pd->rx_control & RxPD_MESH_FRAME) + SET_MESH_FRAME(skb); + else + UNSET_MESH_FRAME(skb); + + lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { + lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); + priv->stats.rx_length_errors++; + ret = 0; + goto done; + } + + /* + * Check rxpd status and update 802.3 stat, + */ + if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) { + lbs_pr_debug(1, "RX error: frame received with bad status\n"); + lbs_pr_alert("rxpd Not OK\n"); + priv->stats.rx_errors++; + ret = 0; + goto done; + } + + lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", + skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); + + lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, + sizeof(p_rx_pkt->eth803_hdr.dest_addr)); + lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, + sizeof(p_rx_pkt->eth803_hdr.src_addr)); + + if (memcmp(&p_rx_pkt->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { + /* + * Replace the 803 header and rfc1042 header (llc/snap) with an + * EthernetII header, keep the src/dst and snap_type (ethertype) + * + * The firmware only passes up SNAP frames converting + * all RX Data from 802.11 to 802.2/LLC/SNAP frames. + * + * To create the Ethernet II, just move the src, dst address right + * before the snap_type. + */ + p_ethhdr = (struct ethhdr *) + ((u8 *) & p_rx_pkt->eth803_hdr + + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) + - sizeof(p_rx_pkt->eth803_hdr.dest_addr) + - sizeof(p_rx_pkt->eth803_hdr.src_addr) + - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); + + memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, + sizeof(p_ethhdr->h_source)); + memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, + sizeof(p_ethhdr->h_dest)); + + /* 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; + } else { + lbs_dbg_hex("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; + } + + /* Chop off the leading header bytes so the skb points to the start of + * either the reconstructed EthII frame or the 802.2/llc/snap frame + */ + skb_pull(skb, hdrchop); + + /* Take the data rate from the rxpd structure + * only if the rate is auto + */ + if (adapter->is_datarate_auto) + adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); + + wlan_compute_rssi(priv, p_rx_pd); + + lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); + if (libertas_upload_rx_packet(priv, skb)) { + lbs_pr_debug(1, "RX error: libertas_upload_rx_packet" + " returns failure\n"); + ret = -1; + goto done; + } + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + ret = 0; +done: + LEAVE(); + + return ret; +} + +/** + * @brief This function converts Tx/Rx rates from the Marvell WLAN format + * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * + * @param rate Input rate + * @return Output Rate (0 if invalid) + */ +static u8 convert_mv_rate_to_radiotap(u8 rate) +{ + switch (rate) { + case 0: /* 1 Mbps */ + return 2; + case 1: /* 2 Mbps */ + return 4; + case 2: /* 5.5 Mbps */ + return 11; + case 3: /* 11 Mbps */ + return 22; + case 4: /* 6 Mbps */ + return 12; + case 5: /* 9 Mbps */ + return 18; + case 6: /* 12 Mbps */ + return 24; + case 7: /* 18 Mbps */ + return 36; + case 8: /* 24 Mbps */ + return 48; + case 9: /* 36 Mbps */ + return 72; + case 10: /* 48 Mbps */ + return 96; + case 11: /* 54 Mbps */ + return 108; + } + lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate); + return 0; +} + +/** + * @brief This function processes a received 802.11 packet and forwards it + * to kernel/upper layer + * + * @param priv A pointer to wlan_private + * @param skb A pointer to skb which includes the received packet + * @return 0 or -1 + */ +static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + struct rx80211packethdr *p_rx_pkt; + struct rxpd *prxpd; + struct rx_radiotap_hdr radiotap_hdr; + struct rx_radiotap_hdr *pradiotap_hdr; + + ENTER(); + + p_rx_pkt = (struct rx80211packethdr *) skb->data; + prxpd = &p_rx_pkt->rx_pd; + + // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); + + if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { + lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); + priv->stats.rx_length_errors++; + ret = 0; + goto done; + } + + /* + * Check rxpd status and update 802.3 stat, + */ + if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) { + //lbs_pr_debug(1, "RX error: frame received with bad status\n"); + priv->stats.rx_errors++; + } + + lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", + skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); + + /* create the exported radio header */ + switch (priv->adapter->radiomode) { + case WLAN_RADIOMODE_NONE: + /* no radio header */ + /* chop the rxpd */ + skb_pull(skb, sizeof(struct rxpd)); + break; + + case WLAN_RADIOMODE_RADIOTAP: + /* radiotap header */ + radiotap_hdr.hdr.it_version = 0; + /* XXX must check this value for pad */ + radiotap_hdr.hdr.it_pad = 0; + radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr); + radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; + /* unknown values */ + radiotap_hdr.flags = 0; + radiotap_hdr.chan_freq = 0; + radiotap_hdr.chan_flags = 0; + radiotap_hdr.antenna = 0; + /* known values */ + radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); + /* XXX must check no carryout */ + radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; + radiotap_hdr.rx_flags = 0; + if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) + radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; + //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); + + // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); + + /* chop the rxpd */ + skb_pull(skb, sizeof(struct rxpd)); + + /* add space for the new radio header */ + if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && + pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, + GFP_ATOMIC)) { + lbs_pr_alert( "%s: couldn't pskb_expand_head\n", + __func__); + } + + pradiotap_hdr = + (struct rx_radiotap_hdr *)skb_push(skb, + sizeof(struct + rx_radiotap_hdr)); + memcpy(pradiotap_hdr, &radiotap_hdr, + sizeof(struct rx_radiotap_hdr)); + //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); + break; + + default: + /* unknown header */ + lbs_pr_alert( "Unknown radiomode (%i)\n", + priv->adapter->radiomode); + /* don't export any header */ + /* chop the rxpd */ + skb_pull(skb, sizeof(struct rxpd)); + break; + } + + /* Take the data rate from the rxpd structure + * only if the rate is auto + */ + if (adapter->is_datarate_auto) { + adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); + } + + wlan_compute_rssi(priv, prxpd); + + lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); + + if (libertas_upload_rx_packet(priv, skb)) { + lbs_pr_debug(1, "RX error: libertas_upload_rx_packet " + "returns failure\n"); + ret = -1; + goto done; + } + + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + ret = 0; +done: + LEAVE(); + + skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ + + return (ret); +} diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h new file mode 100644 index 0000000..59d3a59 --- /dev/null +++ b/drivers/net/wireless/libertas/sbi.h @@ -0,0 +1,40 @@ +/** + * This file contains IF layer definitions. + */ + +#ifndef _SBI_H_ +#define _SBI_H_ + +#include + +#include "defs.h" + +/** INT status Bit Definition*/ +#define his_cmddnldrdy 0x01 +#define his_cardevent 0x02 +#define his_cmdupldrdy 0x04 + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +#define SBI_EVENT_CAUSE_SHIFT 3 + +/* Probe and Check if the card is present*/ +int libertas_sbi_register_dev(wlan_private * priv); +int libertas_sbi_unregister_dev(wlan_private *); +int libertas_sbi_get_int_status(wlan_private * priv, u8 *); +int libertas_sbi_register(void); +void libertas_sbi_unregister(void); +int libertas_sbi_prog_firmware(wlan_private *); + +int libertas_sbi_read_event_cause(wlan_private *); +int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); +wlan_private *libertas_sbi_get_priv(void *card); + +#ifdef ENABLE_PM +int libertas_sbi_suspend(wlan_private *); +int libertas_sbi_resume(wlan_private *); +#endif + +#endif /* _SBI_H */ diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c new file mode 100644 index 0000000..e187062 --- /dev/null +++ b/drivers/net/wireless/libertas/scan.c @@ -0,0 +1,2044 @@ +/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** + * Functions implementing wlan scan IOCTL and firmware command APIs + * + * IOCTL handlers as well as command preperation and response routines + * for sending scan commands to the firmware. + */ +#include +#include +#include +#include + +#include +#include + +#include "host.h" +#include "decl.h" +#include "dev.h" +#include "scan.h" + +//! Approximate amount of data needed to pass a scan result back to iwlist +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ + + IW_ESSID_MAX_SIZE \ + + IW_EV_UINT_LEN \ + + IW_EV_FREQ_LEN \ + + IW_EV_QUAL_LEN \ + + IW_ESSID_MAX_SIZE \ + + IW_EV_PARAM_LEN \ + + 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) \ + + (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)) + +//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max +#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ + + sizeof(struct mrvlietypes_numprobes) \ + + CHAN_TLV_MAX_SIZE \ + + SSID_TLV_MAX_SIZE) + +//! The maximum number of channels the firmware can scan per command +#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 + +/** + * @brief Number of channels to scan per firmware scan command issuance. + * + * Number restricted to prevent hitting the limit on the amount of scan data + * returned in a single firmware scan command. + */ +#define MRVDRV_CHANNELS_PER_SCAN_CMD 4 + +//! Scan time specified in the channel TLV for each channel for passive scans +#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 + +//! Scan time specified in the channel TLV for each channel for active scans +#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 + +//! Macro to enable/disable SSID checking before storing a scan table +#ifdef DISCARD_BAD_SSID +#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid) +#else +#define CHECK_SSID_IS_VALID(x) 1 +#endif + +/** + * @brief Check if a scanned network compatible with the driver settings + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * 0 1 0 0 x 1x 1 x yes WPA + * 0 0 1 0 x 1x x 1 yes WPA2 + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * + * @param adapter A pointer to wlan_adapter + * @param index Index in scantable to check against current driver settings + * @param mode Network mode: Infrastructure or IBSS + * + * @return Index in scantable, or error code if negative + */ +static int is_network_compatible(wlan_adapter * adapter, int index, int mode) +{ + ENTER(); + + if (adapter->scantable[index].inframode == mode) { + if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled + && !adapter->secinfo.WPAenabled + && !adapter->secinfo.WPA2enabled + && adapter->scantable[index].wpa_supplicant.wpa_ie[0] != + WPA_IE + && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] != + WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE + && !adapter->scantable[index].privacy) { + /* no security */ + LEAVE(); + return index; + } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled + && !adapter->secinfo.WPAenabled + && !adapter->secinfo.WPA2enabled + && adapter->scantable[index].privacy) { + /* static WEP enabled */ + LEAVE(); + return index; + } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled + && adapter->secinfo.WPAenabled + && !adapter->secinfo.WPA2enabled + && (adapter->scantable[index].wpa_supplicant. + wpa_ie[0] + == WPA_IE) + /* privacy bit may NOT be set in some APs like LinkSys WRT54G + && adapter->scantable[index].privacy */ + ) { + /* WPA enabled */ + lbs_pr_debug(1, + "is_network_compatible() WPA: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " + "privacy=%#x\n", index, + adapter->scantable[index].wpa_supplicant. + wpa_ie[0], + adapter->scantable[index].wpa2_supplicant. + wpa_ie[0], + (adapter->secinfo.WEPstatus == + wlan802_11WEPenabled) ? "e" : "d", + (adapter->secinfo.WPAenabled) ? "e" : "d", + (adapter->secinfo.WPA2enabled) ? "e" : "d", + adapter->secinfo.Encryptionmode, + adapter->scantable[index].privacy); + LEAVE(); + return index; + } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled + && !adapter->secinfo.WPAenabled + && adapter->secinfo.WPA2enabled + && (adapter->scantable[index].wpa2_supplicant. + wpa_ie[0] + == WPA2_IE) + /* privacy bit may NOT be set in some APs like LinkSys WRT54G + && adapter->scantable[index].privacy */ + ) { + /* WPA2 enabled */ + lbs_pr_debug(1, + "is_network_compatible() WPA2: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " + "privacy=%#x\n", index, + adapter->scantable[index].wpa_supplicant. + wpa_ie[0], + adapter->scantable[index].wpa2_supplicant. + wpa_ie[0], + (adapter->secinfo.WEPstatus == + wlan802_11WEPenabled) ? "e" : "d", + (adapter->secinfo.WPAenabled) ? "e" : "d", + (adapter->secinfo.WPA2enabled) ? "e" : "d", + adapter->secinfo.Encryptionmode, + adapter->scantable[index].privacy); + LEAVE(); + return index; + } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled + && !adapter->secinfo.WPAenabled + && !adapter->secinfo.WPA2enabled + && (adapter->scantable[index].wpa_supplicant. + wpa_ie[0] + != WPA_IE) + && (adapter->scantable[index].wpa2_supplicant. + wpa_ie[0] + != WPA2_IE) + && adapter->secinfo.Encryptionmode != CIPHER_NONE + && adapter->scantable[index].privacy) { + /* dynamic WEP enabled */ + lbs_pr_debug(1, + "is_network_compatible() dynamic WEP: index=%d " + "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n", + index, + adapter->scantable[index].wpa_supplicant. + wpa_ie[0], + adapter->scantable[index].wpa2_supplicant. + wpa_ie[0], adapter->secinfo.Encryptionmode, + adapter->scantable[index].privacy); + LEAVE(); + return index; + } + + /* security doesn't match */ + lbs_pr_debug(1, + "is_network_compatible() FAILED: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n", + index, + adapter->scantable[index].wpa_supplicant.wpa_ie[0], + adapter->scantable[index].wpa2_supplicant.wpa_ie[0], + (adapter->secinfo.WEPstatus == + wlan802_11WEPenabled) ? "e" : "d", + (adapter->secinfo.WPAenabled) ? "e" : "d", + (adapter->secinfo.WPA2enabled) ? "e" : "d", + adapter->secinfo.Encryptionmode, + adapter->scantable[index].privacy); + LEAVE(); + return -ECONNREFUSED; + } + + /* mode doesn't match */ + LEAVE(); + return -ENETUNREACH; +} + +/** + * @brief This function validates a SSID as being able to be printed + * + * @param pssid SSID structure to validate + * + * @return TRUE or FALSE + */ +static u8 ssid_valid(struct WLAN_802_11_SSID *pssid) +{ + int ssididx; + + for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) { + if (!isprint(pssid->ssid[ssididx])) { + return 0; + } + } + + return 1; +} + +/** + * @brief Post process the scan table after a new scan command has completed + * + * Inspect each entry of the scan table and try to find an entry that + * matches our current associated/joined network from the scan. If + * one is found, update the stored copy of the bssdescriptor for our + * current network. + * + * Debug dump the current scan table contents if compiled accordingly. + * + * @param priv A pointer to wlan_private structure + * + * @return void + */ +static void wlan_scan_process_results(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + int foundcurrent; + int i; + + foundcurrent = 0; + + if (adapter->connect_status == libertas_connected) { + /* try to find the current BSSID in the new scan list */ + for (i = 0; i < adapter->numinscantable; i++) { + if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, + &adapter->curbssparams.ssid) && + !memcmp(adapter->curbssparams.bssid, + adapter->scantable[i].macaddress, + ETH_ALEN)) { + foundcurrent = 1; + } + } + + if (foundcurrent) { + /* Make a copy of current BSSID descriptor */ + memcpy(&adapter->curbssparams.bssdescriptor, + &adapter->scantable[i], + sizeof(adapter->curbssparams.bssdescriptor)); + } + } + + for (i = 0; i < adapter->numinscantable; i++) { + lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, " + "RSSI[%03d], SSID[%s]\n", + i, + adapter->scantable[i].macaddress[0], + adapter->scantable[i].macaddress[1], + adapter->scantable[i].macaddress[2], + adapter->scantable[i].macaddress[3], + adapter->scantable[i].macaddress[4], + adapter->scantable[i].macaddress[5], + (s32) adapter->scantable[i].rssi, + adapter->scantable[i].ssid.ssid); + } +} + +/** + * @brief Create a channel list for the driver to scan based on region info + * + * Use the driver region/band information to construct a comprehensive list + * of channels to scan. This routine is used for any scan that is not + * provided a specific channel list to scan. + * + * @param priv A pointer to wlan_private structure + * @param scanchanlist Output parameter: resulting channel list to scan + * @param filteredscan Flag indicating whether or not a BSSID or SSID filter + * is being sent in the command to firmware. Used to + * increase the number of channels sent in a scan + * command and to disable the firmware channel scan + * filter. + * + * @return void + */ +static void wlan_scan_create_channel_list(wlan_private * priv, + struct chanscanparamset * scanchanlist, + u8 filteredscan) +{ + + wlan_adapter *adapter = priv->adapter; + struct region_channel *scanregion; + struct chan_freq_power *cfp; + int rgnidx; + int chanidx; + int nextchan; + u8 scantype; + + chanidx = 0; + + /* Set the default scan type to the user specified type, will later + * be changed to passive on a per channel basis if restricted by + * regulatory requirements (11d or 11h) + */ + scantype = adapter->scantype; + + for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { + if (priv->adapter->enable11d && + adapter->connect_status != libertas_connected) { + /* Scan all the supported chan for the first scan */ + if (!adapter->universal_channel[rgnidx].valid) + continue; + scanregion = &adapter->universal_channel[rgnidx]; + + /* clear the parsed_region_chan for the first scan */ + memset(&adapter->parsed_region_chan, 0x00, + sizeof(adapter->parsed_region_chan)); + } else { + if (!adapter->region_channel[rgnidx].valid) + continue; + scanregion = &adapter->region_channel[rgnidx]; + } + + for (nextchan = 0; + nextchan < scanregion->nrcfp; nextchan++, chanidx++) { + + cfp = scanregion->CFP + nextchan; + + if (priv->adapter->enable11d) { + scantype = + libertas_get_scan_type_11d(cfp->channel, + &adapter-> + parsed_region_chan); + } + + switch (scanregion->band) { + case BAND_B: + case BAND_G: + default: + scanchanlist[chanidx].radiotype = + cmd_scan_radio_type_bg; + break; + } + + if (scantype == cmd_scan_type_passive) { + scanchanlist[chanidx].maxscantime = + cpu_to_le16 + (MRVDRV_PASSIVE_SCAN_CHAN_TIME); + scanchanlist[chanidx].chanscanmode.passivescan = + 1; + } else { + scanchanlist[chanidx].maxscantime = + cpu_to_le16 + (MRVDRV_ACTIVE_SCAN_CHAN_TIME); + scanchanlist[chanidx].chanscanmode.passivescan = + 0; + } + + scanchanlist[chanidx].channumber = cfp->channel; + + if (filteredscan) { + scanchanlist[chanidx].chanscanmode. + disablechanfilt = 1; + } + } + } +} + +/** + * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds + * + * Application layer or other functions can invoke wlan_scan_networks + * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. + * This structure is used as the basis of one or many wlan_scan_cmd_config + * commands that are sent to the command processing module and sent to + * firmware. + * + * Create a wlan_scan_cmd_config based on the following user supplied + * parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - channel list + * + * If the SSID or BSSID filter is not present, disable/clear the filter. + * If the number of probes is not set, use the adapter default setting + * Qualify the channel + * + * @param priv A pointer to wlan_private structure + * @param puserscanin NULL or pointer to scan configuration parameters + * @param ppchantlvout Output parameter: Pointer to the start of the + * channel TLV portion of the output scan config + * @param pscanchanlist Output parameter: Pointer to the resulting channel + * list to scan + * @param pmaxchanperscan Output parameter: Number of channels to scan for + * each issuance of the firmware scan command + * @param pfilteredscan Output parameter: Flag indicating whether or not + * a BSSID or SSID filter is being sent in the + * command to firmware. Used to increase the number + * of channels sent in a scan command and to + * disable the firmware channel scan filter. + * @param pscancurrentonly Output parameter: Flag indicating whether or not + * we are only scanning our current active channel + * + * @return resulting scan configuration + */ +static struct wlan_scan_cmd_config * +wlan_scan_setup_scan_config(wlan_private * priv, + const struct wlan_ioctl_user_scan_cfg * puserscanin, + struct mrvlietypes_chanlistparamset ** ppchantlvout, + struct chanscanparamset * pscanchanlist, + int *pmaxchanperscan, + u8 * pfilteredscan, + u8 * pscancurrentonly) +{ + wlan_adapter *adapter = priv->adapter; + const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + struct mrvlietypes_numprobes *pnumprobestlv; + struct mrvlietypes_ssidparamset *pssidtlv; + struct wlan_scan_cmd_config * pscancfgout = NULL; + u8 *ptlvpos; + u16 numprobes; + u16 ssidlen; + int chanidx; + int scantype; + int scandur; + int channel; + int radiotype; + + pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); + if (pscancfgout == NULL) + goto out; + + /* The tlvbufferlen is calculated for each scan command. The TLVs added + * in this routine will be preserved since the routine that sends + * the command will append channelTLVs at *ppchantlvout. The difference + * between the *ppchantlvout and the tlvbuffer start will be used + * to calculate the size of anything we add in this routine. + */ + pscancfgout->tlvbufferlen = 0; + + /* Running tlv pointer. Assigned to ppchantlvout at end of function + * so later routines know where channels can be added to the command buf + */ + ptlvpos = pscancfgout->tlvbuffer; + + /* + * Set the initial scan paramters for progressive scanning. If a specific + * BSSID or SSID is used, the number of channels in the scan command + * will be increased to the absolute maximum + */ + *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD; + + /* Initialize the scan as un-filtered by firmware, set to TRUE below if + * a SSID or BSSID filter is sent in the command + */ + *pfilteredscan = 0; + + /* Initialize the scan as not being only on the current channel. If + * the channel list is customized, only contains one channel, and + * is the active channel, this is set true and data flow is not halted. + */ + *pscancurrentonly = 0; + + if (puserscanin) { + + /* Set the bss type scan filter, use adapter setting if unset */ + pscancfgout->bsstype = + (puserscanin->bsstype ? puserscanin->bsstype : adapter-> + scanmode); + + /* Set the number of probes to send, use adapter setting if unset */ + numprobes = (puserscanin->numprobes ? puserscanin->numprobes : + adapter->scanprobes); + + /* + * Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled (all zeros). + */ + memcpy(pscancfgout->specificBSSID, + puserscanin->specificBSSID, + sizeof(pscancfgout->specificBSSID)); + + ssidlen = strlen(puserscanin->specificSSID); + + if (ssidlen) { + pssidtlv = + (struct mrvlietypes_ssidparamset *) pscancfgout-> + tlvbuffer; + pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); + pssidtlv->header.len = cpu_to_le16(ssidlen); + memcpy(pssidtlv->ssid, puserscanin->specificSSID, + ssidlen); + ptlvpos += sizeof(pssidtlv->header) + ssidlen; + } + + /* + * The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not truncate + * scan results. That is not an issue with an SSID or BSSID + * filter applied to the scan results in the firmware. + */ + if (ssidlen || (memcmp(pscancfgout->specificBSSID, + &zeromac, sizeof(zeromac)) != 0)) { + *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; + *pfilteredscan = 1; + } + } else { + pscancfgout->bsstype = adapter->scanmode; + numprobes = adapter->scanprobes; + } + + /* If the input config or adapter has the number of Probes set, add tlv */ + if (numprobes) { + pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; + pnumprobestlv->header.type = + cpu_to_le16(TLV_TYPE_NUMPROBES); + pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes); + pnumprobestlv->numprobes = cpu_to_le16(numprobes); + + ptlvpos += + sizeof(pnumprobestlv->header) + pnumprobestlv->header.len; + + pnumprobestlv->header.len = + cpu_to_le16(pnumprobestlv->header.len); + } + + /* + * Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this fuction (SSID, numprobes). + * channel TLVs will be added past this for each scan command, preserving + * the TLVs that were previously added. + */ + *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; + + if (puserscanin && puserscanin->chanlist[0].channumber) { + + lbs_pr_debug(1, "Scan: Using supplied channel list\n"); + + for (chanidx = 0; + chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX + && puserscanin->chanlist[chanidx].channumber; chanidx++) { + + channel = puserscanin->chanlist[chanidx].channumber; + (pscanchanlist + chanidx)->channumber = channel; + + radiotype = puserscanin->chanlist[chanidx].radiotype; + (pscanchanlist + chanidx)->radiotype = radiotype; + + scantype = puserscanin->chanlist[chanidx].scantype; + + if (scantype == cmd_scan_type_passive) { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 1; + } else { + (pscanchanlist + + chanidx)->chanscanmode.passivescan = 0; + } + + if (puserscanin->chanlist[chanidx].scantime) { + scandur = + puserscanin->chanlist[chanidx].scantime; + } else { + if (scantype == cmd_scan_type_passive) { + scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; + } else { + scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; + } + } + + (pscanchanlist + chanidx)->minscantime = + cpu_to_le16(scandur); + (pscanchanlist + chanidx)->maxscantime = + cpu_to_le16(scandur); + } + + /* Check if we are only scanning the current channel */ + if ((chanidx == 1) && (puserscanin->chanlist[0].channumber + == + priv->adapter->curbssparams.channel)) { + *pscancurrentonly = 1; + lbs_pr_debug(1, "Scan: Scanning current channel only"); + } + + } else { + lbs_pr_debug(1, "Scan: Creating full region channel list\n"); + wlan_scan_create_channel_list(priv, pscanchanlist, + *pfilteredscan); + } + +out: + return pscancfgout; +} + +/** + * @brief Construct and send multiple scan config commands to the firmware + * + * Previous routines have created a wlan_scan_cmd_config with any requested + * TLVs. This function splits the channel TLV into maxchanperscan lists + * and sends the portion of the channel TLV along with the other TLVs + * to the wlan_cmd routines for execution in the firmware. + * + * @param priv A pointer to wlan_private structure + * @param maxchanperscan Maximum number channels to be included in each + * scan command sent to firmware + * @param filteredscan Flag indicating whether or not a BSSID or SSID + * filter is being used for the firmware command + * scan command sent to firmware + * @param pscancfgout Scan configuration used for this scan. + * @param pchantlvout Pointer in the pscancfgout where the channel TLV + * should start. This is past any other TLVs that + * must be sent down in each firmware command. + * @param pscanchanlist List of channels to scan in maxchanperscan segments + * + * @return 0 or error return otherwise + */ +static int wlan_scan_channel_list(wlan_private * priv, + int maxchanperscan, + u8 filteredscan, + struct wlan_scan_cmd_config * pscancfgout, + struct mrvlietypes_chanlistparamset * pchantlvout, + struct chanscanparamset * pscanchanlist) +{ + struct chanscanparamset *ptmpchan; + struct chanscanparamset *pstartchan; + u8 scanband; + int doneearly; + int tlvidx; + int ret = 0; + + ENTER(); + + if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) { + lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n", + pscancfgout, pchantlvout, pscanchanlist); + return -1; + } + + pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired list */ + ptmpchan = pscanchanlist; + + /* Loop through the desired channel list, sending a new firmware scan + * commands for each maxchanperscan channels (or for 1,6,11 individually + * if configured accordingly) + */ + while (ptmpchan->channumber) { + + tlvidx = 0; + pchantlvout->header.len = 0; + scanband = ptmpchan->radiotype; + pstartchan = ptmpchan; + doneearly = 0; + + /* Construct the channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlvidx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel list) + * - doneearly is set (controlling individual scanning of 1,6,11) + */ + while (tlvidx < maxchanperscan && ptmpchan->channumber + && !doneearly) { + + lbs_pr_debug(1, + "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", + ptmpchan->channumber, ptmpchan->radiotype, + ptmpchan->chanscanmode.passivescan, + ptmpchan->chanscanmode.disablechanfilt, + ptmpchan->maxscantime); + + /* Copy the current channel TLV to the command being prepared */ + memcpy(pchantlvout->chanscanparam + tlvidx, + ptmpchan, sizeof(pchantlvout->chanscanparam)); + + /* Increment the TLV header length by the size appended */ + pchantlvout->header.len += + sizeof(pchantlvout->chanscanparam); + + /* + * The tlv buffer length is set to the number of bytes of the + * between the channel tlv pointer and the start of the + * tlv buffer. This compensates for any TLVs that were appended + * before the channel list. + */ + pscancfgout->tlvbufferlen = ((u8 *) pchantlvout + - pscancfgout->tlvbuffer); + + /* Add the size of the channel tlv header and the data length */ + pscancfgout->tlvbufferlen += + (sizeof(pchantlvout->header) + + pchantlvout->header.len); + + /* Increment the index to the channel tlv we are constructing */ + tlvidx++; + + doneearly = 0; + + /* Stop the loop if the *current* channel is in the 1,6,11 set + * and we are not filtering on a BSSID or SSID. + */ + if (!filteredscan && (ptmpchan->channumber == 1 + || ptmpchan->channumber == 6 + || ptmpchan->channumber == 11)) { + doneearly = 1; + } + + /* Increment the tmp pointer to the next channel to be scanned */ + ptmpchan++; + + /* Stop the loop if the *next* channel is in the 1,6,11 set. + * This will cause it to be the only channel scanned on the next + * interation + */ + if (!filteredscan && (ptmpchan->channumber == 1 + || ptmpchan->channumber == 6 + || ptmpchan->channumber == 11)) { + doneearly = 1; + } + } + + /* Send the scan command to the firmware with the specified cfg */ + ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0, + 0, 0, pscancfgout); + } + + LEAVE(); + return ret; +} + +/** + * @brief Internal function used to start a scan based on an input config + * + * Use the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table + * + * @param priv A pointer to wlan_private structure + * @param puserscanin Pointer to the input configuration for the requested + * scan. + * + * @return 0 or < 0 if error + */ +int wlan_scan_networks(wlan_private * priv, + const struct wlan_ioctl_user_scan_cfg * puserscanin) +{ + wlan_adapter *adapter = priv->adapter; + struct mrvlietypes_chanlistparamset *pchantlvout; + struct chanscanparamset * scan_chan_list = NULL; + struct wlan_scan_cmd_config * scan_cfg = NULL; + u8 keeppreviousscan; + u8 filteredscan; + u8 scancurrentchanonly; + int maxchanperscan; + int ret; + + ENTER(); + + scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * + WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); + if (scan_chan_list == NULL) { + ret = -ENOMEM; + goto out; + } + + scan_cfg = wlan_scan_setup_scan_config(priv, + puserscanin, + &pchantlvout, + scan_chan_list, + &maxchanperscan, + &filteredscan, + &scancurrentchanonly); + if (scan_cfg == NULL) { + ret = -ENOMEM; + goto out; + } + + keeppreviousscan = 0; + + if (puserscanin) { + keeppreviousscan = puserscanin->keeppreviousscan; + } + + if (!keeppreviousscan) { + memset(adapter->scantable, 0x00, + sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST); + adapter->numinscantable = 0; + } + + /* Keep the data path active if we are only scanning our current channel */ + if (!scancurrentchanonly) { + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + } + + ret = wlan_scan_channel_list(priv, + maxchanperscan, + filteredscan, + scan_cfg, + pchantlvout, + scan_chan_list); + + /* Process the resulting scan table: + * - Remove any bad ssids + * - Update our current BSS information from scan data + */ + wlan_scan_process_results(priv); + + if (priv->adapter->connect_status == libertas_connected) { + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + } + +out: + if (scan_cfg) + kfree(scan_cfg); + + if (scan_chan_list) + kfree(scan_chan_list); + + LEAVE(); + return ret; +} + +/** + * @brief Inspect the scan response buffer for pointers to expected TLVs + * + * TLVs can be included at the end of the scan response BSS information. + * Parse the data in the buffer for pointers to TLVs that can potentially + * be passed back in the response + * + * @param ptlv Pointer to the start of the TLV buffer to parse + * @param tlvbufsize size of the TLV buffer + * @param ptsftlv Output parameter: Pointer to the TSF TLV if found + * + * @return void + */ +static +void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, + int tlvbufsize, + struct mrvlietypes_tsftimestamp ** ptsftlv) +{ + struct mrvlietypes_data *pcurrenttlv; + int tlvbufleft; + u16 tlvtype; + u16 tlvlen; + + pcurrenttlv = ptlv; + tlvbufleft = tlvbufsize; + *ptsftlv = NULL; + + lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); + lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); + + while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { + tlvtype = le16_to_cpu(pcurrenttlv->header.type); + tlvlen = le16_to_cpu(pcurrenttlv->header.len); + + switch (tlvtype) { + case TLV_TYPE_TSFTIMESTAMP: + *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv; + break; + + default: + lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n", + tlvtype); + /* Give up, this seems corrupted */ + return; + } /* switch */ + + tlvbufleft -= (sizeof(ptlv->header) + tlvlen); + pcurrenttlv = + (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen); + } /* while */ +} + +/** + * @brief Interpret a BSS scan response returned from the firmware + * + * Parse the various fixed fields and IEs passed back for a a BSS probe + * response or beacon from the scan command. Record information as needed + * in the scan table struct bss_descriptor for that entry. + * + * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry + * + * @return 0 or -1 + */ +static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, + u8 ** pbeaconinfo, int *bytesleft) +{ + enum ieeetypes_elementid elemID; + struct ieeetypes_fhparamset *pFH; + struct ieeetypes_dsparamset *pDS; + struct ieeetypes_cfparamset *pCF; + struct ieeetypes_ibssparamset *pibss; + struct ieeetypes_capinfo *pcap; + struct WLAN_802_11_FIXED_IEs fixedie; + u8 *pcurrentptr; + u8 *pRate; + u8 elemlen; + u8 bytestocopy; + u8 ratesize; + u16 beaconsize; + u8 founddatarateie; + int bytesleftforcurrentbeacon; + + struct WPA_SUPPLICANT *pwpa_supplicant; + struct WPA_SUPPLICANT *pwpa2_supplicant; + struct IE_WPA *pIe; + const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; + + struct ieeetypes_countryinfoset *pcountryinfo; + + ENTER(); + + founddatarateie = 0; + ratesize = 0; + beaconsize = 0; + + if (*bytesleft >= sizeof(beaconsize)) { + /* Extract & convert beacon size from the command buffer */ + memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize)); + beaconsize = le16_to_cpu(beaconsize); + *bytesleft -= sizeof(beaconsize); + *pbeaconinfo += sizeof(beaconsize); + } + + if (beaconsize == 0 || beaconsize > *bytesleft) { + + *pbeaconinfo += *bytesleft; + *bytesleft = 0; + + return -1; + } + + /* Initialize the current working beacon pointer for this BSS iteration */ + pcurrentptr = *pbeaconinfo; + + /* Advance the return beacon pointer past the current beacon */ + *pbeaconinfo += beaconsize; + *bytesleft -= beaconsize; + + bytesleftforcurrentbeacon = beaconsize; + + pwpa_supplicant = &pBSSEntry->wpa_supplicant; + pwpa2_supplicant = &pBSSEntry->wpa2_supplicant; + + memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN); + lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n", + pBSSEntry->macaddress[0], pBSSEntry->macaddress[1], + pBSSEntry->macaddress[2], pBSSEntry->macaddress[3], + pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]); + + pcurrentptr += ETH_ALEN; + bytesleftforcurrentbeacon -= ETH_ALEN; + + if (bytesleftforcurrentbeacon < 12) { + lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n"); + return -1; + } + + /* + * next 4 fields are RSSI, time stamp, beacon interval, + * and capability information + */ + + /* RSSI is 1 byte long */ + pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr)); + lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr); + pcurrentptr += 1; + bytesleftforcurrentbeacon -= 1; + + /* time stamp is 8 bytes long */ + memcpy(fixedie.timestamp, pcurrentptr, 8); + memcpy(pBSSEntry->timestamp, pcurrentptr, 8); + pcurrentptr += 8; + bytesleftforcurrentbeacon -= 8; + + /* beacon interval is 2 bytes long */ + memcpy(&fixedie.beaconinterval, pcurrentptr, 2); + pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval); + pcurrentptr += 2; + bytesleftforcurrentbeacon -= 2; + + /* capability information is 2 bytes long */ + memcpy(&fixedie.capabilities, pcurrentptr, 2); + lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n", + fixedie.capabilities); + fixedie.capabilities = le16_to_cpu(fixedie.capabilities); + pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; + memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo)); + pcurrentptr += 2; + bytesleftforcurrentbeacon -= 2; + + /* rest of the current buffer are IE's */ + lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n", + bytesleftforcurrentbeacon); + + lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr, + bytesleftforcurrentbeacon); + + if (pcap->privacy) { + lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n"); + pBSSEntry->privacy = wlan802_11privfilter8021xWEP; + } else { + pBSSEntry->privacy = wlan802_11privfilteracceptall; + } + + if (pcap->ibss == 1) { + pBSSEntry->inframode = wlan802_11ibss; + } else { + pBSSEntry->inframode = wlan802_11infrastructure; + } + + /* process variable IE */ + while (bytesleftforcurrentbeacon >= 2) { + elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); + elemlen = *((u8 *) pcurrentptr + 1); + + if (bytesleftforcurrentbeacon < elemlen) { + lbs_pr_debug(1, "InterpretIE: error in processing IE, " + "bytes left < IE length\n"); + bytesleftforcurrentbeacon = 0; + continue; + } + + switch (elemID) { + + case SSID: + pBSSEntry->ssid.ssidlength = elemlen; + memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2), + elemlen); + lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid); + break; + + case SUPPORTED_RATES: + memcpy(pBSSEntry->datarates, (pcurrentptr + 2), + elemlen); + memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2), + elemlen); + ratesize = elemlen; + founddatarateie = 1; + break; + + case EXTRA_IE: + lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n"); + pBSSEntry->extra_ie = 1; + break; + + case FH_PARAM_SET: + pFH = (struct ieeetypes_fhparamset *) pcurrentptr; + memmove(&pBSSEntry->phyparamset.fhparamset, pFH, + sizeof(struct ieeetypes_fhparamset)); + pBSSEntry->phyparamset.fhparamset.dwelltime + = + le16_to_cpu(pBSSEntry->phyparamset.fhparamset. + dwelltime); + break; + + case DS_PARAM_SET: + pDS = (struct ieeetypes_dsparamset *) pcurrentptr; + + pBSSEntry->channel = pDS->currentchan; + + memcpy(&pBSSEntry->phyparamset.dsparamset, pDS, + sizeof(struct ieeetypes_dsparamset)); + break; + + case CF_PARAM_SET: + pCF = (struct ieeetypes_cfparamset *) pcurrentptr; + + memcpy(&pBSSEntry->ssparamset.cfparamset, pCF, + sizeof(struct ieeetypes_cfparamset)); + break; + + case IBSS_PARAM_SET: + pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; + pBSSEntry->atimwindow = + le32_to_cpu(pibss->atimwindow); + + memmove(&pBSSEntry->ssparamset.ibssparamset, pibss, + sizeof(struct ieeetypes_ibssparamset)); + + pBSSEntry->ssparamset.ibssparamset.atimwindow + = + le16_to_cpu(pBSSEntry->ssparamset.ibssparamset. + atimwindow); + break; + + /* Handle Country Info IE */ + case COUNTRY_INFO: + pcountryinfo = + (struct ieeetypes_countryinfoset *) pcurrentptr; + + if (pcountryinfo->len < + sizeof(pcountryinfo->countrycode) + || pcountryinfo->len > 254) { + lbs_pr_debug(1, "InterpretIE: 11D- Err " + "CountryInfo len =%d min=%d max=254\n", + pcountryinfo->len, + sizeof(pcountryinfo->countrycode)); + LEAVE(); + return -1; + } + + memcpy(&pBSSEntry->countryinfo, + pcountryinfo, pcountryinfo->len + 2); + lbs_dbg_hex("InterpretIE: 11D- CountryInfo:", + (u8 *) pcountryinfo, + (u32) (pcountryinfo->len + 2)); + break; + + case EXTENDED_SUPPORTED_RATES: + /* + * only process extended supported rate + * if data rate is already found. + * data rate IE should come before + * extended supported rate IE + */ + if (founddatarateie) { + if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) { + bytestocopy = + (WLAN_SUPPORTED_RATES - ratesize); + } else { + bytestocopy = elemlen; + } + + pRate = (u8 *) pBSSEntry->datarates; + pRate += ratesize; + memmove(pRate, (pcurrentptr + 2), bytestocopy); + + pRate = (u8 *) pBSSEntry->libertas_supported_rates; + + pRate += ratesize; + memmove(pRate, (pcurrentptr + 2), bytestocopy); + } + break; + + case VENDOR_SPECIFIC_221: +#define IE_ID_LEN_FIELDS_BYTES 2 + pIe = (struct IE_WPA *)pcurrentptr; + + if (!memcmp(pIe->oui, oui01, sizeof(oui01))) { + pwpa_supplicant->wpa_ie_len + = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, + sizeof(pwpa_supplicant->wpa_ie)); + memcpy(pwpa_supplicant->wpa_ie, + pcurrentptr, + pwpa_supplicant->wpa_ie_len); + lbs_dbg_hex("InterpretIE: Resp WPA_IE", + pwpa_supplicant->wpa_ie, elemlen); + } + break; + case WPA2_IE: + pIe = (struct IE_WPA *)pcurrentptr; + pwpa2_supplicant->wpa_ie_len + = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, + sizeof(pwpa2_supplicant->wpa_ie)); + memcpy(pwpa2_supplicant->wpa_ie, + pcurrentptr, pwpa2_supplicant->wpa_ie_len); + + lbs_dbg_hex("InterpretIE: Resp WPA2_IE", + pwpa2_supplicant->wpa_ie, elemlen); + break; + case TIM: + break; + + case CHALLENGE_TEXT: + break; + } + + pcurrentptr += elemlen + 2; + + /* need to account for IE ID and IE len */ + bytesleftforcurrentbeacon -= (elemlen + 2); + + } /* while (bytesleftforcurrentbeacon > 2) */ + + return 0; +} + +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0--ssid is same, otherwise is different + */ +int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2) +{ + if (!ssid1 || !ssid2) + return -1; + + if (ssid1->ssidlength != ssid2->ssidlength) + return -1; + + return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength); +} + +/** + * @brief This function finds a specific compatible BSSID in the scan list + * + * @param adapter A pointer to wlan_adapter + * @param bssid BSSID to find in the scan list + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list, or error return code (< 0) + */ +int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode) +{ + int ret = -ENETUNREACH; + int i; + + if (!bssid) + return -EFAULT; + + lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n", + adapter->numinscantable); + + /* Look through the scan table for a compatible match. The ret return + * variable will be equal to the index in the scan table (greater + * than zero) if the network is compatible. The loop will continue + * past a matched bssid that is not compatible in case there is an + * AP with multiple SSIDs assigned to the same BSSID + */ + for (i = 0; ret < 0 && i < adapter->numinscantable; i++) { + if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) { + switch (mode) { + case wlan802_11infrastructure: + case wlan802_11ibss: + ret = is_network_compatible(adapter, i, mode); + break; + default: + ret = i; + break; + } + } + } + + return ret; +} + +/** + * @brief This function finds ssid in ssid list. + * + * @param adapter A pointer to wlan_adapter + * @param ssid SSID to find in the list + * @param bssid BSSID to qualify the SSID selection (if provided) + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list + */ +int libertas_find_SSID_in_list(wlan_adapter * adapter, + struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode) +{ + int net = -ENETUNREACH; + u8 bestrssi = 0; + int i; + int j; + + lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable); + + for (i = 0; i < adapter->numinscantable; i++) { + if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) && + (!bssid || + !memcmp(adapter->scantable[i]. + macaddress, bssid, ETH_ALEN))) { + switch (mode) { + case wlan802_11infrastructure: + case wlan802_11ibss: + j = is_network_compatible(adapter, i, mode); + + if (j >= 0) { + if (bssid) { + return i; + } + + if (SCAN_RSSI + (adapter->scantable[i].rssi) + > bestrssi) { + bestrssi = + SCAN_RSSI(adapter-> + scantable[i]. + rssi); + net = i; + } + } else { + if (net == -ENETUNREACH) { + net = j; + } + } + break; + case wlan802_11autounknown: + default: + if (SCAN_RSSI(adapter->scantable[i].rssi) + > bestrssi) { + bestrssi = + SCAN_RSSI(adapter->scantable[i]. + rssi); + net = i; + } + break; + } + } + } + + return net; +} + +/** + * @brief This function finds the best SSID in the Scan List + * + * Search the scan table for the best SSID that also matches the current + * adapter network preference (infrastructure or adhoc) + * + * @param adapter A pointer to wlan_adapter + * + * @return index in BSSID list + */ +int libertas_find_best_SSID_in_list(wlan_adapter * adapter, + enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode) +{ + int bestnet = -ENETUNREACH; + u8 bestrssi = 0; + int i; + + ENTER(); + + lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable); + + for (i = 0; i < adapter->numinscantable; i++) { + switch (mode) { + case wlan802_11infrastructure: + case wlan802_11ibss: + if (is_network_compatible(adapter, i, mode) >= 0) { + if (SCAN_RSSI(adapter->scantable[i].rssi) > + bestrssi) { + bestrssi = + SCAN_RSSI(adapter->scantable[i]. + rssi); + bestnet = i; + } + } + break; + case wlan802_11autounknown: + default: + if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) { + bestrssi = + SCAN_RSSI(adapter->scantable[i].rssi); + bestnet = i; + } + break; + } + } + + LEAVE(); + return bestnet; +} + +/** + * @brief Find the AP with specific ssid in the scan list + * + * @param priv A pointer to wlan_private structure + * @param pSSID A pointer to AP's ssid + * + * @return 0--success, otherwise--fail + */ +int libertas_find_best_network_SSID(wlan_private * priv, + struct WLAN_802_11_SSID *pSSID, + enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, + enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct bss_descriptor *preqbssid; + int i; + + ENTER(); + + memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID)); + + wlan_scan_networks(priv, NULL); + if (adapter->surpriseremoved) + return -1; + wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); + + i = libertas_find_best_SSID_in_list(adapter, preferred_mode); + if (i < 0) { + ret = -1; + goto out; + } + + preqbssid = &adapter->scantable[i]; + memcpy(pSSID, &preqbssid->ssid, + sizeof(struct WLAN_802_11_SSID)); + *out_mode = preqbssid->inframode; + + if (!pSSID->ssidlength) { + ret = -1; + } + +out: + LEAVE(); + return ret; +} + +/** + * @brief Scan Network + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + union iwreq_data wrqu; + + ENTER(); + + if (!wlan_scan_networks(priv, NULL)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, + NULL); + } + + if (adapter->surpriseremoved) + return -1; + + LEAVE(); + return 0; +} + +/** + * @brief Send a scan command for all available channels filtered on a spec + * + * @param priv A pointer to wlan_private structure + * @param prequestedssid A pointer to AP's ssid + * @param keeppreviousscan Flag used to save/clear scan table before scan + * + * @return 0-success, otherwise fail + */ +int libertas_send_specific_SSID_scan(wlan_private * priv, + struct WLAN_802_11_SSID *prequestedssid, + u8 keeppreviousscan) +{ + wlan_adapter *adapter = priv->adapter; + struct wlan_ioctl_user_scan_cfg scancfg; + + ENTER(); + + if (prequestedssid == NULL) { + return -1; + } + + memset(&scancfg, 0x00, sizeof(scancfg)); + + memcpy(scancfg.specificSSID, prequestedssid->ssid, + prequestedssid->ssidlength); + scancfg.keeppreviousscan = keeppreviousscan; + + wlan_scan_networks(priv, &scancfg); + if (adapter->surpriseremoved) + return -1; + wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); + + LEAVE(); + return 0; +} + +/** + * @brief scan an AP with specific BSSID + * + * @param priv A pointer to wlan_private structure + * @param bssid A pointer to AP's bssid + * @param keeppreviousscan Flag used to save/clear scan table before scan + * + * @return 0-success, otherwise fail + */ +int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan) +{ + struct wlan_ioctl_user_scan_cfg scancfg; + + ENTER(); + + if (bssid == NULL) { + return -1; + } + + memset(&scancfg, 0x00, sizeof(scancfg)); + memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID)); + scancfg.keeppreviousscan = keeppreviousscan; + + wlan_scan_networks(priv, &scancfg); + if (priv->adapter->surpriseremoved) + return -1; + wait_event_interruptible(priv->adapter->cmd_pending, + !priv->adapter->nr_cmd_pending); + + LEAVE(); + return 0; +} + +/** + * @brief Retrieve the scan table entries via wireless tools IOCTL call + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + struct chan_freq_power *cfp; + struct bss_descriptor *pscantable; + char *current_val; /* For rates */ + struct iw_event iwe; /* Temporary buffer */ + int i; + int j; + int rate; +#define PERFECT_RSSI ((u8)50) +#define WORST_RSSI ((u8)0) +#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) + u8 rssi; + + u8 buf[16 + 256 * 2]; + u8 *ptr; + + ENTER(); + + /* + * if there's either commands in the queue or one being + * processed return -EAGAIN for iwlist to retry later. + */ + if (adapter->nr_cmd_pending) + return -EAGAIN; + + if (adapter->connect_status == libertas_connected) + lbs_pr_debug(1, "Current ssid: %32s\n", + adapter->curbssparams.ssid.ssid); + + lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n", + adapter->numinscantable); + + /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. + * The new API using SIOCGIWSCAN is only limited by buffer size + * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes + * which is 4096. + */ + for (i = 0; i < adapter->numinscantable; i++) { + if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { + lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p " + "MAX_SCAN_CELL_SIZE=%d\n", + i, current_ev, end_buf, MAX_SCAN_CELL_SIZE); + break; + } + + pscantable = &adapter->scantable[i]; + + lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid); + + cfp = + libertas_find_cfp_by_band_and_channel(adapter, 0, + pscantable->channel); + if (!cfp) { + lbs_pr_debug(1, "Invalid channel number %d\n", + pscantable->channel); + continue; + } + + if (!ssid_valid(&adapter->scantable[i].ssid)) { + continue; + } + + /* 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, + &adapter->scantable[i].macaddress, ETH_ALEN); + + iwe.len = IW_EV_ADDR_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + //Add the ESSID + iwe.u.data.length = adapter->scantable[i].ssid.ssidlength; + + if (iwe.u.data.length > 32) { + iwe.u.data.length = 32; + } + + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + adapter->scantable[i].ssid. + ssid); + + //Add mode + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = adapter->scantable[i].inframode + 1; + iwe.len = IW_EV_UINT_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + //frequency + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (long)cfp->freq * 100000; + iwe.u.freq.e = 1; + iwe.len = IW_EV_FREQ_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; + iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi); + + rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; + iwe.u.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / + (RSSI_DIFF * RSSI_DIFF); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + else if (iwe.u.qual.qual < 1) + iwe.u.qual.qual = 0; + + if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + } else { + iwe.u.qual.noise = + CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + } + if ((adapter->inframode == wlan802_11ibss) && + !libertas_SSID_cmp(&adapter->curbssparams.ssid, + &adapter->scantable[i].ssid) + && adapter->adhoccreate) { + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rssi, + 0, + cmd_option_waitforrsp, + 0, NULL); + + if (!ret) { + iwe.u.qual.level = + CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / + AVG_SCALE, + adapter->NF[TYPE_RXPD][TYPE_AVG] / + AVG_SCALE); + } + } + iwe.len = IW_EV_QUAL_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (adapter->scantable[i].privacy) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + adapter->scantable->ssid. + ssid); + + current_val = current_ev + IW_EV_LCP_LEN; + + iwe.cmd = SIOCGIWRATE; + + iwe.u.bitrate.fixed = 0; + iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = 0; + + /* Bit rate given in 500 kb/s units (+ 0x80) */ + for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates); + j++) { + if (adapter->scantable[i].libertas_supported_rates[j] == 0) { + break; + } + rate = + (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) * + 500000; + if (rate > iwe.u.bitrate.value) { + iwe.u.bitrate.value = rate; + } + + iwe.u.bitrate.value = + (adapter->scantable[i].libertas_supported_rates[j] + & 0x7f) * 500000; + iwe.len = IW_EV_PARAM_LEN; + current_ev = + iwe_stream_add_value(current_ev, current_val, + end_buf, &iwe, iwe.len); + + } + if ((adapter->scantable[i].inframode == wlan802_11ibss) + && !libertas_SSID_cmp(&adapter->curbssparams.ssid, + &adapter->scantable[i].ssid) + && adapter->adhoccreate) { + iwe.u.bitrate.value = 22 * 500000; + } + iwe.len = IW_EV_PARAM_LEN; + current_ev = + iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, + iwe.len); + + /* Add new value to event */ + current_val = current_ev + IW_EV_LCP_LEN; + + if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + memcpy(buf, adapter->scantable[i]. + wpa2_supplicant.wpa_ie, + adapter->scantable[i].wpa2_supplicant. + wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = adapter->scantable[i]. + wpa2_supplicant.wpa_ie_len; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + } + if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + memcpy(buf, adapter->scantable[i]. + wpa_supplicant.wpa_ie, + adapter->scantable[i].wpa_supplicant. + wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = adapter->scantable[i]. + wpa_supplicant.wpa_ie_len; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + } + + + if (adapter->scantable[i].extra_ie != 0) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + ptr = buf; + ptr += sprintf(ptr, "extra_ie"); + iwe.u.data.length = strlen(buf); + + lbs_pr_debug(1, "iwe.u.data.length %d\n", + iwe.u.data.length); + lbs_pr_debug(1, "BUF: %s \n", buf); + + iwe.cmd = IWEVCUSTOM; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = + iwe_stream_add_point(current_ev, end_buf, &iwe, + buf); + } + + current_val = current_ev + IW_EV_LCP_LEN; + + /* + * Check if we added any event + */ + if ((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + } + + dwrq->length = (current_ev - extra); + dwrq->flags = 0; + + LEAVE(); + return 0; +} + +/** + * @brief Prepare a scan command to be sent to the firmware + * + * Use the wlan_scan_cmd_config sent to the command processing module in + * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command + * struct to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to cmd_ds_command structure to be sent to + * firmware with the cmd_DS_801_11_SCAN structure + * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used + * to set the fields/TLVs for the command sent to firmware + * + * @return 0 or -1 + * + * @sa wlan_scan_create_channel_list + */ +int libertas_cmd_80211_scan(wlan_private * priv, + struct cmd_ds_command *cmd, void *pdata_buf) +{ + struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; + struct wlan_scan_cmd_config *pscancfg; + + ENTER(); + + pscancfg = pdata_buf; + + /* Set fixed field variables in scan command */ + pscan->bsstype = pscancfg->bsstype; + memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID)); + memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); + + cmd->command = cpu_to_le16(cmd_802_11_scan); + + /* size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + + sizeof(pscan->BSSID) + + pscancfg->tlvbufferlen + S_DS_GEN); + + lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n", + cmd->command, cmd->size, cmd->seqnum); + LEAVE(); + return 0; +} + +/** + * @brief This function handles the command response of scan + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-----------------------------------------------------------. + * | header (4 * sizeof(u16)): Standard command response hdr | + * .-----------------------------------------------------------. + * | bufsize (u16) : sizeof the BSS Description data | + * .-----------------------------------------------------------. + * | NumOfSet (u8) : Number of BSS Descs returned | + * .-----------------------------------------------------------. + * | BSSDescription data (variable, size given in bufsize) | + * .-----------------------------------------------------------. + * | TLV data (variable, size calculated using header->size, | + * | bufsize and sizeof the fixed fields above) | + * .-----------------------------------------------------------. + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to cmd_ds_command + * + * @return 0 or -1 + */ +int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) +{ + wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_scan_rsp *pscan; + struct bss_descriptor newbssentry; + struct mrvlietypes_data *ptlv; + struct mrvlietypes_tsftimestamp *ptsftlv; + u8 *pbssinfo; + u16 scanrespsize; + int bytesleft; + int numintable; + int bssIdx; + int idx; + int tlvbufsize; + u64 tsfval; + + ENTER(); + + pscan = &resp->params.scanresp; + + if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) { + lbs_pr_debug(1, + "SCAN_RESP: Invalid number of AP returned (%d)!!\n", + pscan->nr_sets); + LEAVE(); + return -1; + } + + bytesleft = le16_to_cpu(pscan->bssdescriptsize); + lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft); + + scanrespsize = le16_to_cpu(resp->size); + lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n", + pscan->nr_sets); + + numintable = adapter->numinscantable; + pbssinfo = pscan->bssdesc_and_tlvbuffer; + + /* The size of the TLV buffer is equal to the entire command response + * size (scanrespsize) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (bssdescriptsize as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) + + sizeof(pscan->nr_sets) + + S_DS_GEN); + + ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft); + + /* Search the TLV buffer space in the scan response for any valid TLVs */ + wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv); + + /* + * Process each scan response returned (pscan->nr_sets). Save + * the information in the newbssentry and then insert into the + * driver scan table either as an update to an existing entry + * or as an addition at the end of the table + */ + for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { + /* Zero out the newbssentry we are about to store info in */ + memset(&newbssentry, 0x00, sizeof(newbssentry)); + + /* Process the data fields and IEs returned for this BSS */ + if ((InterpretBSSDescriptionWithIE(&newbssentry, + &pbssinfo, + &bytesleft) == + 0) + && CHECK_SSID_IS_VALID(&newbssentry.ssid)) { + + lbs_pr_debug(1, + "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", + newbssentry.macaddress[0], + newbssentry.macaddress[1], + newbssentry.macaddress[2], + newbssentry.macaddress[3], + newbssentry.macaddress[4], + newbssentry.macaddress[5]); + + /* + * Search the scan table for the same bssid + */ + for (bssIdx = 0; bssIdx < numintable; bssIdx++) { + if (memcmp(newbssentry.macaddress, + adapter->scantable[bssIdx]. + macaddress, + sizeof(newbssentry.macaddress)) == + 0) { + /* + * If the SSID matches as well, it is a duplicate of + * this entry. Keep the bssIdx set to this + * entry so we replace the old contents in the table + */ + if ((newbssentry.ssid.ssidlength == + adapter->scantable[bssIdx].ssid. + ssidlength) + && + (memcmp + (newbssentry.ssid.ssid, + adapter->scantable[bssIdx].ssid. + ssid, + newbssentry.ssid.ssidlength) == + 0)) { + lbs_pr_debug(1, + "SCAN_RESP: Duplicate of index: %d\n", + bssIdx); + break; + } + } + } + /* + * If the bssIdx is equal to the number of entries in the table, + * the new entry was not a duplicate; append it to the scan + * table + */ + if (bssIdx == numintable) { + /* Range check the bssIdx, keep it limited to the last entry */ + if (bssIdx == MRVDRV_MAX_BSSID_LIST) { + bssIdx--; + } else { + numintable++; + } + } + + /* + * If the TSF TLV was appended to the scan results, save the + * this entries TSF value in the networktsf field. The + * networktsf is the firmware's TSF value at the time the + * beacon or probe response was received. + */ + if (ptsftlv) { + memcpy(&tsfval, &ptsftlv->tsftable[idx], + sizeof(tsfval)); + tsfval = le64_to_cpu(tsfval); + + memcpy(&newbssentry.networktsf, + &tsfval, sizeof(newbssentry.networktsf)); + } + + /* Copy the locally created newbssentry to the scan table */ + memcpy(&adapter->scantable[bssIdx], + &newbssentry, + sizeof(adapter->scantable[bssIdx])); + + } else { + + /* error parsing/interpreting the scan response, skipped */ + lbs_pr_debug(1, "SCAN_RESP: " + "InterpretBSSDescriptionWithIE returned ERROR\n"); + } + } + + lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", + pscan->nr_sets, numintable - adapter->numinscantable, + numintable); + + /* Update the total number of BSSIDs in the scan table */ + adapter->numinscantable = numintable; + + LEAVE(); + return 0; +} diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h new file mode 100644 index 0000000..d93aa7f --- /dev/null +++ b/drivers/net/wireless/libertas/scan.h @@ -0,0 +1,216 @@ +/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** + * Interface for the wlan network scan routines + * + * Driver interface functions and type declarations for the scan module + * implemented in wlan_scan.c. + */ +#ifndef _WLAN_SCAN_H +#define _WLAN_SCAN_H + +#include "hostcmd.h" + +/** + * @brief Maximum number of channels that can be sent in a setuserscan ioctl + * + * @sa wlan_ioctl_user_scan_cfg + */ +#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 + +//! Infrastructure BSS scan type in wlan_scan_cmd_config +#define WLAN_SCAN_BSS_TYPE_BSS 1 + +//! Adhoc BSS scan type in wlan_scan_cmd_config +#define WLAN_SCAN_BSS_TYPE_IBSS 2 + +//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter +#define WLAN_SCAN_BSS_TYPE_ANY 3 + +/** + * @brief Structure used internally in the wlan driver to configure a scan. + * + * Sent to the command processing module to configure the firmware + * scan command prepared by libertas_cmd_80211_scan. + * + * @sa wlan_scan_networks + * + */ +struct wlan_scan_cmd_config { + /** + * @brief BSS type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. valid settings are: + * + * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) + * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) + * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bsstype; + + /** + * @brief Specific BSSID used to filter scan results in the firmware + */ + u8 specificBSSID[ETH_ALEN]; + + /** + * @brief length of TLVs sent in command starting at tlvBuffer + */ + int tlvbufferlen; + + /** + * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t + * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t + */ + u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here +}; + +/** + * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg + * + * Multiple instances of this structure are included in the IOCTL command + * to configure a instance of a scan on the specific channel. + */ +struct wlan_ioctl_user_scan_chan { + u8 channumber; //!< channel Number to scan + u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1 + u8 scantype; //!< Scan type: Active = 0, Passive = 1 + u16 scantime; //!< Scan duration in milliseconds; if 0 default used +}; + +/** + * @brief IOCTL input structure to configure an immediate scan cmd to firmware + * + * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies + * a number of parameters to be used in general for the scan as well + * as a channel list (wlan_ioctl_user_scan_chan) for each scan period + * desired. + * + * @sa libertas_set_user_scan_ioctl + */ +struct wlan_ioctl_user_scan_cfg { + + /** + * @brief Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + u8 keeppreviousscan; //!< Do not erase the existing scan results + + /** + * @brief BSS type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. valid settings are: + * + * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) + * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) + * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bsstype; + + /** + * @brief Configure the number of probe requests for active chan scans + */ + u8 numprobes; + + /** + * @brief BSSID filter sent in the firmware command to limit the results + */ + u8 specificBSSID[ETH_ALEN]; + + /** + * @brief SSID filter sent in the firmware command to limit the results + */ + char specificSSID[IW_ESSID_MAX_SIZE + 1]; + + /** + * @brief Variable number (fixed maximum) of channels to scan up + */ + struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; +}; + +/** + * @brief Structure used to store information for each beacon/probe response + */ +struct bss_descriptor { + u8 macaddress[ETH_ALEN]; + + struct WLAN_802_11_SSID ssid; + + /* WEP encryption requirement */ + u32 privacy; + + /* receive signal strength in dBm */ + long rssi; + + u32 channel; + + u16 beaconperiod; + + u32 atimwindow; + + enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; + u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; + + int extra_ie; + + u8 timestamp[8]; //!< TSF value included in the beacon/probe response + union ieeetypes_phyparamset phyparamset; + union IEEEtypes_ssparamset ssparamset; + struct ieeetypes_capinfo cap; + u8 datarates[WLAN_SUPPORTED_RATES]; + + __le64 networktsf; //!< TSF timestamp from the current firmware TSF + + struct ieeetypes_countryinfofullset countryinfo; + + struct WPA_SUPPLICANT wpa_supplicant; + struct WPA_SUPPLICANT wpa2_supplicant; + +}; + +extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, + struct WLAN_802_11_SSID *ssid2); +extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid, + u8 * bssid, int mode); +int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode); +extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode); + +int libertas_find_best_network_SSID(wlan_private * priv, + struct WLAN_802_11_SSID *pSSID, + enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, + enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode); + +extern int libertas_send_specific_SSID_scan(wlan_private * priv, + struct WLAN_802_11_SSID *prequestedssid, + u8 keeppreviousscan); +extern int libertas_send_specific_BSSID_scan(wlan_private * priv, + u8 * bssid, u8 keeppreviousscan); + +extern int libertas_cmd_80211_scan(wlan_private * priv, + struct cmd_ds_command *cmd, + void *pdata_buf); + +extern int libertas_ret_80211_scan(wlan_private * priv, + struct cmd_ds_command *resp); + +int wlan_scan_networks(wlan_private * priv, + const struct wlan_ioctl_user_scan_cfg * puserscanin); + +struct ifreq; + +struct iw_point; +struct iw_param; +struct iw_request_info; +extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra); +extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra); + +#endif /* _WLAN_SCAN_H */ diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h new file mode 100644 index 0000000..207b8a6 --- /dev/null +++ b/drivers/net/wireless/libertas/thread.h @@ -0,0 +1,52 @@ +#ifndef __WLAN_THREAD_H_ +#define __WLAN_THREAD_H_ + +#include + +struct wlan_thread { + struct task_struct *task; + wait_queue_head_t waitq; + pid_t pid; + void *priv; +}; + +static inline void wlan_activate_thread(struct wlan_thread * thr) +{ + /** Record the thread pid */ + thr->pid = current->pid; + + /** Initialize the wait queue */ + init_waitqueue_head(&thr->waitq); +} + +static inline void wlan_deactivate_thread(struct wlan_thread * thr) +{ + ENTER(); + + thr->pid = 0; + + LEAVE(); +} + +static inline void wlan_create_thread(int (*wlanfunc) (void *), + struct wlan_thread * thr, char *name) +{ + thr->task = kthread_run(wlanfunc, thr, "%s", name); +} + +static inline int wlan_terminate_thread(struct wlan_thread * thr) +{ + ENTER(); + + /* Check if the thread is active or not */ + if (!thr->pid) { + printk(KERN_ERR "Thread does not exist\n"); + return -1; + } + kthread_stop(thr->task); + + LEAVE(); + return 0; +} + +#endif diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c new file mode 100644 index 0000000..82d0622 --- /dev/null +++ b/drivers/net/wireless/libertas/tx.c @@ -0,0 +1,285 @@ +/** + * This file contains the handling of TX in wlan driver. + */ +#include + +#include "hostcmd.h" +#include "radiotap.h" +#include "sbi.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "wext.h" + +/** + * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE + * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * + * @param rate Input rate + * @return Output Rate (0 if invalid) + */ +static u32 convert_radiotap_rate_to_mv(u8 rate) +{ + switch (rate) { + case 2: /* 1 Mbps */ + return 0 | (1 << 4); + case 4: /* 2 Mbps */ + return 1 | (1 << 4); + case 11: /* 5.5 Mbps */ + return 2 | (1 << 4); + case 22: /* 11 Mbps */ + return 3 | (1 << 4); + case 12: /* 6 Mbps */ + return 4 | (1 << 4); + case 18: /* 9 Mbps */ + return 5 | (1 << 4); + case 24: /* 12 Mbps */ + return 6 | (1 << 4); + case 36: /* 18 Mbps */ + return 7 | (1 << 4); + case 48: /* 24 Mbps */ + return 8 | (1 << 4); + case 72: /* 36 Mbps */ + return 9 | (1 << 4); + case 96: /* 48 Mbps */ + return 10 | (1 << 4); + case 108: /* 54 Mbps */ + return 11 | (1 << 4); + } + return 0; +} + +/** + * @brief This function processes a single packet and sends + * to IF layer + * + * @param priv A pointer to wlan_private structure + * @param skb A pointer to skb which includes TX packet + * @return 0 or -1 + */ +static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct txpd localtxpd; + struct txpd *plocaltxpd = &localtxpd; + u8 *p802x_hdr; + struct tx_radiotap_hdr *pradiotap_hdr; + u32 new_rate; + u8 *ptr = priv->adapter->tmptxbuf; + + ENTER(); + + if (priv->adapter->surpriseremoved) + return -1; + + if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) + lbs_dbg_hex("TX packet: ", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { + lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n", + skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); + ret = -1; + goto done; + } + + memset(plocaltxpd, 0, sizeof(struct txpd)); + + plocaltxpd->tx_packet_length = skb->len; + + /* offset of actual data */ + plocaltxpd->tx_packet_location = sizeof(struct txpd); + + /* TxCtrl set by user or default */ + plocaltxpd->tx_control = adapter->pkttxctrl; + + p802x_hdr = skb->data; + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + + /* locate radiotap header */ + pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; + + /* set txpd fields from the radiotap header */ + new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); + if (new_rate != 0) { + /* erase tx_control[4:0] */ + plocaltxpd->tx_control &= ~0x1f; + /* write new tx_control[4:0] */ + plocaltxpd->tx_control |= new_rate; + } + + /* skip the radiotap header */ + p802x_hdr += sizeof(struct tx_radiotap_hdr); + plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr); + + } + /* copy destination address from 802.3 or 802.11 header */ + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); + else + memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); + + lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); + + if (IS_MESH_FRAME(skb)) { + plocaltxpd->tx_control |= TxPD_MESH_FRAME; + } + + memcpy(ptr, plocaltxpd, sizeof(struct txpd)); + + ptr += sizeof(struct txpd); + + lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length); + memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length); + ret = libertas_sbi_host_to_card(priv, MVMS_DAT, + priv->adapter->tmptxbuf, + plocaltxpd->tx_packet_length + + sizeof(struct txpd)); + + if (ret) { + lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret); + goto done; + } + + lbs_pr_debug(1, "SendSinglePacket succeeds\n"); + + done: + if (!ret) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + } + + if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + /* Keep the skb to echo it back once Tx feedback is + received from FW */ + skb_orphan(skb); + /* stop processing outgoing pkts */ + netif_stop_queue(priv->wlan_dev.netdev); + /* freeze any packets already in our queues */ + priv->adapter->TxLockFlag = 1; + } else { + dev_kfree_skb_any(skb); + priv->adapter->currenttxskb = NULL; + } + + LEAVE(); + return ret; +} + + +void libertas_tx_runqueue(wlan_private *priv) +{ + wlan_adapter *adapter = priv->adapter; + int i; + + spin_lock(&adapter->txqueue_lock); + for (i = 0; i < adapter->tx_queue_idx; i++) { + struct sk_buff *skb = adapter->tx_queue_ps[i]; + spin_unlock(&adapter->txqueue_lock); + SendSinglePacket(priv, skb); + spin_lock(&adapter->txqueue_lock); + } + adapter->tx_queue_idx = 0; + spin_unlock(&adapter->txqueue_lock); +} + +static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) +{ + wlan_adapter *adapter = priv->adapter; + + spin_lock(&adapter->txqueue_lock); + + WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE); + adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; + if (adapter->tx_queue_idx == NR_TX_QUEUE) + netif_stop_queue(priv->wlan_dev.netdev); + else + netif_start_queue(priv->wlan_dev.netdev); + + spin_unlock(&adapter->txqueue_lock); +} + +/** + * @brief This function checks the conditions and sends packet to IF + * layer if everything is ok. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) +{ + int ret = -1; + + ENTER(); + + lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); + + if (priv->wlan_dev.dnld_sent) { + lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", + priv->wlan_dev.dnld_sent); + goto done; + } + + if ((priv->adapter->psstate == PS_STATE_SLEEP) || + (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) { + wlan_tx_queue(priv, skb); + return ret; + } + + priv->adapter->currenttxskb = skb; + + ret = SendSinglePacket(priv, skb); +done: + LEAVE(); + return ret; +} + +/** + * @brief This function sends to the host the last transmitted packet, + * filling the radiotap headers with transmission information. + * + * @param priv A pointer to wlan_private structure + * @param status A 32 bit value containing transmission status. + * + * @returns void + */ +void libertas_send_tx_feedback(wlan_private * priv) +{ + wlan_adapter *adapter = priv->adapter; + struct tx_radiotap_hdr *radiotap_hdr; + u32 status = adapter->eventcause; + int txfail; + int try_count; + + if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || + adapter->currenttxskb == NULL) + return; + + radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; + + if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) + lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr, + min_t(unsigned int, adapter->currenttxskb->len, 100)); + + txfail = (status >> 24); + +#if 0 + /* The version of roofnet that we've tested does not use this yet + * But it may be used in the future. + */ + if (txfail) + radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL; +#endif + try_count = (status >> 16) & 0xff; + radiotap_hdr->data_retries = (try_count) ? + (1 + adapter->txretrycount - try_count) : 0; + libertas_upload_rx_packet(priv, adapter->currenttxskb); + adapter->currenttxskb = NULL; + priv->adapter->TxLockFlag = 0; + if (priv->adapter->connect_status == libertas_connected) + netif_wake_queue(priv->wlan_dev.netdev); +} diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h new file mode 100644 index 0000000..09d62f8 --- /dev/null +++ b/drivers/net/wireless/libertas/types.h @@ -0,0 +1,289 @@ +/** + * This header file contains definition for global types + */ +#ifndef _WLAN_TYPES_ +#define _WLAN_TYPES_ + +#include + +/** IEEE type definitions */ +enum ieeetypes_elementid { + SSID = 0, + SUPPORTED_RATES, + FH_PARAM_SET, + DS_PARAM_SET, + CF_PARAM_SET, + TIM, + IBSS_PARAM_SET, + COUNTRY_INFO = 7, + + CHALLENGE_TEXT = 16, + + EXTENDED_SUPPORTED_RATES = 50, + + VENDOR_SPECIFIC_221 = 221, + + WPA_IE = 221, + WPA2_IE = 48, + + EXTRA_IE = 133, +} __attribute__ ((packed)); + +#define CAPINFO_MASK (~(0xda00)) + +struct ieeetypes_capinfo { + u8 ess:1; + u8 ibss:1; + u8 cfpollable:1; + u8 cfpollrqst:1; + u8 privacy:1; + u8 shortpreamble:1; + u8 pbcc:1; + u8 chanagility:1; + u8 spectrummgmt:1; + u8 rsrvd3:1; + u8 shortslottime:1; + u8 apsd:1; + u8 rsvrd2:1; + u8 dsssofdm:1; + u8 rsrvd1:2; +} __attribute__ ((packed)); + +struct ieeetypes_cfparamset { + u8 elementid; + u8 len; + u8 cfpcnt; + u8 cfpperiod; + u16 cfpmaxduration; + u16 cfpdurationremaining; +} __attribute__ ((packed)); + + +struct ieeetypes_ibssparamset { + u8 elementid; + u8 len; + u16 atimwindow; +} __attribute__ ((packed)); + +union IEEEtypes_ssparamset { + struct ieeetypes_cfparamset cfparamset; + struct ieeetypes_ibssparamset ibssparamset; +} __attribute__ ((packed)); + +struct ieeetypes_fhparamset { + u8 elementid; + u8 len; + u16 dwelltime; + u8 hopset; + u8 hoppattern; + u8 hopindex; +} __attribute__ ((packed)); + +struct ieeetypes_dsparamset { + u8 elementid; + u8 len; + u8 currentchan; +} __attribute__ ((packed)); + +union ieeetypes_phyparamset { + struct ieeetypes_fhparamset fhparamset; + struct ieeetypes_dsparamset dsparamset; +} __attribute__ ((packed)); + +struct ieeetypes_assocrsp { + struct ieeetypes_capinfo capability; + u16 statuscode; + u16 aid; + u8 iebuffer[1]; +} __attribute__ ((packed)); + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 + +/* Terminating TLV type */ +#define MRVL_TERMINATE_TLV_ID 0xffff + +#define TLV_TYPE_SSID 0x0000 +#define TLV_TYPE_RATES 0x0001 +#define TLV_TYPE_PHY_FH 0x0002 +#define TLV_TYPE_PHY_DS 0x0003 +#define TLV_TYPE_CF 0x0004 +#define TLV_TYPE_IBSS 0x0006 + +#define TLV_TYPE_DOMAIN 0x0007 + +#define TLV_TYPE_POWER_CAPABILITY 0x0021 + +#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) +#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) +#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) +#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) +#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) +#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) +#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8) +#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) +#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) +#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11) +#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) +#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) +#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14) +#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15) +#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) +#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17) +#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) +#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) + +/** TLV related data structures*/ +struct mrvlietypesheader { + u16 type; + u16 len; +} __attribute__ ((packed)); + +struct mrvlietypes_data { + struct mrvlietypesheader header; + u8 Data[1]; +} __attribute__ ((packed)); + +struct mrvlietypes_ratesparamset { + struct mrvlietypesheader header; + u8 rates[1]; +} __attribute__ ((packed)); + +struct mrvlietypes_ssidparamset { + struct mrvlietypesheader header; + u8 ssid[1]; +} __attribute__ ((packed)); + +struct mrvlietypes_wildcardssidparamset { + struct mrvlietypesheader header; + u8 MaxSsidlength; + u8 ssid[1]; +} __attribute__ ((packed)); + +struct chanscanmode { + u8 passivescan:1; + u8 disablechanfilt:1; + u8 reserved_2_7:6; +} __attribute__ ((packed)); + +struct chanscanparamset { + u8 radiotype; + u8 channumber; + struct chanscanmode chanscanmode; + u16 minscantime; + u16 maxscantime; +} __attribute__ ((packed)); + +struct mrvlietypes_chanlistparamset { + struct mrvlietypesheader header; + struct chanscanparamset chanscanparam[1]; +} __attribute__ ((packed)); + +struct cfparamset { + u8 cfpcnt; + u8 cfpperiod; + u16 cfpmaxduration; + u16 cfpdurationremaining; +} __attribute__ ((packed)); + +struct ibssparamset { + u16 atimwindow; +} __attribute__ ((packed)); + +struct mrvlietypes_ssparamset { + struct mrvlietypesheader header; + union { + struct cfparamset cfparamset[1]; + struct ibssparamset ibssparamset[1]; + } cf_ibss; +} __attribute__ ((packed)); + +struct fhparamset { + u16 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; + u8 rsnie[1]; +} __attribute__ ((packed)); + +struct mrvlietypes_tsftimestamp { + struct mrvlietypesheader header; + __le64 tsftable[1]; +} __attribute__ ((packed)); + +/** Local Power capability */ +struct mrvlietypes_powercapability { + struct mrvlietypesheader header; + s8 minpower; + s8 maxpower; +} __attribute__ ((packed)); + +struct mrvlietypes_rssithreshold { + struct mrvlietypesheader header; + u8 rssivalue; + u8 rssifreq; +} __attribute__ ((packed)); + +struct mrvlietypes_snrthreshold { + struct mrvlietypesheader header; + u8 snrvalue; + u8 snrfreq; +} __attribute__ ((packed)); + +struct mrvlietypes_failurecount { + struct mrvlietypesheader header; + u8 failvalue; + u8 Failfreq; +} __attribute__ ((packed)); + +struct mrvlietypes_beaconsmissed { + struct mrvlietypesheader header; + u8 beaconmissed; + u8 reserved; +} __attribute__ ((packed)); + +struct mrvlietypes_numprobes { + struct mrvlietypesheader header; + u16 numprobes; +} __attribute__ ((packed)); + +struct mrvlietypes_bcastprobe { + struct mrvlietypesheader header; + u16 bcastprobe; +} __attribute__ ((packed)); + +struct mrvlietypes_numssidprobe { + struct mrvlietypesheader header; + u16 numssidprobe; +} __attribute__ ((packed)); + +struct led_pin { + u8 led; + u8 pin; +} __attribute__ ((packed)); + +struct mrvlietypes_ledgpio { + struct mrvlietypesheader header; + struct led_pin ledpin[1]; +} __attribute__ ((packed)); + +#endif /* _WLAN_TYPES_ */ diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h new file mode 100644 index 0000000..e86f65a --- /dev/null +++ b/drivers/net/wireless/libertas/version.h @@ -0,0 +1,8 @@ +#define DRIVER_RELEASE_VERSION "320.p0" +const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION +#ifdef DEBUG + "-dbg" +#endif + ""; + + diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c new file mode 100644 index 0000000..4a52336 --- /dev/null +++ b/drivers/net/wireless/libertas/wext.c @@ -0,0 +1,2769 @@ +/** + * This file contains ioctl functions + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "host.h" +#include "radiotap.h" +#include "decl.h" +#include "defs.h" +#include "dev.h" +#include "join.h" +#include "version.h" +#include "wext.h" +#include "assoc.h" + + +/** + * @brief Convert mw value to dbm value + * + * @param mw the value of mw + * @return the value of dbm + */ +static int mw_to_dbm(int mw) +{ + if (mw < 2) + return 0; + else if (mw < 3) + return 3; + else if (mw < 4) + return 5; + else if (mw < 6) + return 7; + else if (mw < 7) + return 8; + else if (mw < 8) + return 9; + else if (mw < 10) + return 10; + else if (mw < 13) + return 11; + else if (mw < 16) + return 12; + else if (mw < 20) + return 13; + else if (mw < 25) + return 14; + else if (mw < 32) + return 15; + else if (mw < 40) + return 16; + else if (mw < 50) + return 17; + else if (mw < 63) + return 18; + else if (mw < 79) + return 19; + else if (mw < 100) + return 20; + else + return 21; +} + +/** + * @brief Find the channel frequency power info with specific channel + * + * @param adapter A pointer to wlan_adapter structure + * @param band it can be BAND_A, BAND_G or BAND_B + * @param channel the channel for looking + * @return A pointer to struct chan_freq_power structure or NULL if not find. + */ +struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter, + u8 band, u16 channel) +{ + struct chan_freq_power *cfp = NULL; + struct region_channel *rc; + int count = sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0]); + int i, j; + + for (j = 0; !cfp && (j < count); j++) { + rc = &adapter->region_channel[j]; + + if (adapter->enable11d) + rc = &adapter->universal_channel[j]; + if (!rc->valid || !rc->CFP) + continue; + if (rc->band != band) + continue; + for (i = 0; i < rc->nrcfp; i++) { + if (rc->CFP[i].channel == channel) { + cfp = &rc->CFP[i]; + break; + } + } + } + + if (!cfp && channel) + lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find " + "cfp by band %d & channel %d\n", band, channel); + + return cfp; +} + +/** + * @brief Find the channel frequency power info with specific frequency + * + * @param adapter A pointer to wlan_adapter structure + * @param band it can be BAND_A, BAND_G or BAND_B + * @param freq the frequency for looking + * @return A pointer to struct chan_freq_power structure or NULL if not find. + */ +static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, + u8 band, u32 freq) +{ + struct chan_freq_power *cfp = NULL; + struct region_channel *rc; + int count = sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0]); + int i, j; + + for (j = 0; !cfp && (j < count); j++) { + rc = &adapter->region_channel[j]; + + if (adapter->enable11d) + rc = &adapter->universal_channel[j]; + if (!rc->valid || !rc->CFP) + continue; + if (rc->band != band) + continue; + for (i = 0; i < rc->nrcfp; i++) { + if (rc->CFP[i].freq == freq) { + cfp = &rc->CFP[i]; + break; + } + } + } + + if (!cfp && freq) + lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by " + "band %d & freq %d\n", band, freq); + + return cfp; +} + +static int updatecurrentchannel(wlan_private * priv) +{ + int ret; + + /* + ** the channel in f/w could be out of sync, get the current channel + */ + ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, + cmd_opt_802_11_rf_channel_get, + cmd_option_waitforrsp, 0, NULL); + + lbs_pr_debug(1, "Current channel = %d\n", + priv->adapter->curbssparams.channel); + + return ret; +} + +static int setcurrentchannel(wlan_private * priv, int channel) +{ + lbs_pr_debug(1, "Set channel = %d\n", channel); + + /* + ** Current channel is not set to adhocchannel requested, set channel + */ + return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, + cmd_opt_802_11_rf_channel_set, + cmd_option_waitforrsp, 0, &channel)); +} + +static int changeadhocchannel(wlan_private * priv, int channel) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + adapter->adhocchannel = channel; + + updatecurrentchannel(priv); + + if (adapter->curbssparams.channel == adapter->adhocchannel) { + /* adhocchannel is set to the current channel already */ + LEAVE(); + return 0; + } + + lbs_pr_debug(1, "Updating channel from %d to %d\n", + adapter->curbssparams.channel, adapter->adhocchannel); + + setcurrentchannel(priv, adapter->adhocchannel); + + updatecurrentchannel(priv); + + if (adapter->curbssparams.channel != adapter->adhocchannel) { + lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n", + adapter->adhocchannel, adapter->curbssparams.channel); + LEAVE(); + return -1; + } + + if (adapter->connect_status == libertas_connected) { + int i; + struct WLAN_802_11_SSID curadhocssid; + + lbs_pr_debug(1, "channel Changed while in an IBSS\n"); + + /* Copy the current ssid */ + memcpy(&curadhocssid, &adapter->curbssparams.ssid, + sizeof(struct WLAN_802_11_SSID)); + + /* Exit Adhoc mode */ + lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n"); + ret = libertas_stop_adhoc_network(priv); + + if (ret) { + LEAVE(); + return ret; + } + /* Scan for the network, do not save previous results. Stale + * scan data will cause us to join a non-existant adhoc network + */ + libertas_send_specific_SSID_scan(priv, &curadhocssid, 0); + + // find out the BSSID that matches the current SSID + i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL, + wlan802_11ibss); + + if (i >= 0) { + lbs_pr_debug(1, "SSID found at %d in List," + "so join\n", i); + libertas_join_adhoc_network(priv, &adapter->scantable[i]); + } else { + // else send START command + lbs_pr_debug(1, "SSID not found in list, " + "so creating adhoc with ssid = %s\n", + curadhocssid.ssid); + libertas_start_adhoc_network(priv, &curadhocssid); + } // end of else (START command) + } + + LEAVE(); + return 0; +} + +/** + * @brief Set Radio On/OFF + * + * @param priv A pointer to wlan_private structure + * @option Radio Option + * @return 0 --success, otherwise fail + */ +int wlan_radio_ioctl(wlan_private * priv, u8 option) +{ + int ret = 0; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (adapter->radioon != option) { + lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off"); + adapter->radioon = option; + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_radio_control, + cmd_act_set, + cmd_option_waitforrsp, 0, NULL); + } + + LEAVE(); + return ret; +} + +/** + * @brief Copy rates + * + * @param dest A pointer to Dest Buf + * @param src A pointer to Src Buf + * @param len The len of Src Buf + * @return Number of rates copyed + */ +static inline int copyrates(u8 * dest, int pos, u8 * src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/** + * @brief Get active data rates + * + * @param adapter A pointer to wlan_adapter structure + * @param rate The buf to return the active rates + * @return The number of rates + */ +static int get_active_data_rates(wlan_adapter * adapter, + u8* rates) +{ + int k = 0; + + ENTER(); + + if (adapter->connect_status != libertas_connected) { + if (adapter->inframode == wlan802_11infrastructure) { + //Infra. mode + lbs_pr_debug(1, "Infra\n"); + k = copyrates(rates, k, libertas_supported_rates, + sizeof(libertas_supported_rates)); + } else { + //ad-hoc mode + lbs_pr_debug(1, "Adhoc G\n"); + k = copyrates(rates, k, libertas_adhoc_rates_g, + sizeof(libertas_adhoc_rates_g)); + } + } else { + k = copyrates(rates, 0, adapter->curbssparams.datarates, + adapter->curbssparams.numofrates); + } + + LEAVE(); + + return k; +} + +static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + const char *cp; + char comm[6] = { "COMM-" }; + char mrvl[6] = { "MRVL-" }; + int cnt; + + ENTER(); + + strcpy(cwrq, mrvl); + + cp = strstr(libertas_driver_version, comm); + if (cp == libertas_driver_version) //skip leading "COMM-" + cp = libertas_driver_version + strlen(comm); + else + cp = libertas_driver_version; + + cnt = strlen(mrvl); + cwrq += cnt; + while (cnt < 16 && (*cp != '-')) { + *cwrq++ = toupper(*cp++); + cnt++; + } + *cwrq = '\0'; + + LEAVE(); + + return 0; +} + +static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct chan_freq_power *cfp; + + ENTER(); + + cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, + adapter->curbssparams.channel); + + if (!cfp) { + if (adapter->curbssparams.channel) + lbs_pr_debug(1, "Invalid channel=%d\n", + adapter->curbssparams.channel); + return -EINVAL; + } + + fwrq->m = (long)cfp->freq * 100000; + fwrq->e = 1; + + lbs_pr_debug(1, "freq=%u\n", fwrq->m); + + LEAVE(); + return 0; +} + +static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (adapter->connect_status == libertas_connected) { + memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); + } else { + memset(awrq->sa_data, 0, ETH_ALEN); + } + awrq->sa_family = ARPHRD_ETHER; + + LEAVE(); + return 0; +} + +static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* + * Check the size of the string + */ + + if (dwrq->length > 16) { + return -E2BIG; + } + + mutex_lock(&adapter->lock); + memset(adapter->nodename, 0, sizeof(adapter->nodename)); + memcpy(adapter->nodename, extra, dwrq->length); + mutex_unlock(&adapter->lock); + + LEAVE(); + return 0; +} + +static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* + * Get the Nick Name saved + */ + + mutex_lock(&adapter->lock); + strncpy(extra, adapter->nodename, 16); + mutex_unlock(&adapter->lock); + + extra[16] = '\0'; + + /* + * If none, we may want to get the one that was set + */ + + /* + * Push it out ! + */ + dwrq->length = strlen(extra) + 1; + + LEAVE(); + return 0; +} + +static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int rthr = vwrq->value; + + ENTER(); + + if (vwrq->disabled) { + adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; + } else { + if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) + return -EINVAL; + adapter->rtsthsd = rthr; + } + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, + cmd_act_set, cmd_option_waitforrsp, + OID_802_11_RTS_THRESHOLD, &rthr); + + LEAVE(); + return ret; +} + +static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + adapter->rtsthsd = 0; + ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, + cmd_act_get, cmd_option_waitforrsp, + OID_802_11_RTS_THRESHOLD, NULL); + if (ret) { + LEAVE(); + return ret; + } + + vwrq->value = adapter->rtsthsd; + vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) + || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); + vwrq->fixed = 1; + + LEAVE(); + return 0; +} + +static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + int fthr = vwrq->value; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (vwrq->disabled) { + adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; + } else { + if (fthr < MRVDRV_FRAG_MIN_VALUE + || fthr > MRVDRV_FRAG_MAX_VALUE) + return -EINVAL; + adapter->fragthsd = fthr; + } + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, + cmd_act_set, cmd_option_waitforrsp, + OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); + LEAVE(); + return ret; +} + +static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + adapter->fragthsd = 0; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_snmp_mib, + cmd_act_get, cmd_option_waitforrsp, + OID_802_11_FRAGMENTATION_THRESHOLD, NULL); + if (ret) { + LEAVE(); + return ret; + } + + vwrq->value = adapter->fragthsd; + vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) + || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + LEAVE(); + return ret; +} + +static int wlan_get_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + switch (adapter->inframode) { + case wlan802_11ibss: + *uwrq = IW_MODE_ADHOC; + break; + + case wlan802_11infrastructure: + *uwrq = IW_MODE_INFRA; + break; + + default: + case wlan802_11autounknown: + *uwrq = IW_MODE_AUTO; + break; + } + + LEAVE(); + return 0; +} + +static int wlan_get_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rf_tx_power, + cmd_act_tx_power_opt_get, + cmd_option_waitforrsp, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel); + vwrq->value = adapter->txpowerlevel; + vwrq->fixed = 1; + if (adapter->radioon) { + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + } else { + vwrq->disabled = 1; + } + + LEAVE(); + return 0; +} + +static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (vwrq->flags == IW_RETRY_LIMIT) { + /* The MAC has a 4-bit Total_Tx_Count register + Total_Tx_Count = 1 + Tx_Retry_Count */ +#define TX_RETRY_MIN 0 +#define TX_RETRY_MAX 14 + if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) + return -EINVAL; + + /* Adding 1 to convert retry count to try count */ + adapter->txretrycount = vwrq->value + 1; + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, + cmd_act_set, + cmd_option_waitforrsp, + OID_802_11_TX_RETRYCOUNT, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } else { + return -EOPNOTSUPP; + } + + LEAVE(); + return 0; +} + +static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + + ENTER(); + adapter->txretrycount = 0; + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_snmp_mib, + cmd_act_get, cmd_option_waitforrsp, + OID_802_11_TX_RETRYCOUNT, NULL); + if (ret) { + LEAVE(); + return ret; + } + vwrq->disabled = 0; + if (!vwrq->flags) { + vwrq->flags = IW_RETRY_LIMIT; + /* Subtract 1 to convert try count to retry count */ + vwrq->value = adapter->txretrycount - 1; + } + + LEAVE(); + return 0; +} + +static inline void sort_channels(struct iw_freq *freq, int num) +{ + int i, j; + struct iw_freq temp; + + for (i = 0; i < num; i++) + for (j = i + 1; j < num; j++) + if (freq[i].i > freq[j].i) { + temp.i = freq[i].i; + temp.m = freq[i].m; + + freq[i].i = freq[j].i; + freq[i].m = freq[j].m; + + freq[j].i = temp.i; + freq[j].m = temp.m; + } +} + +/* data rate listing + MULTI_BANDS: + abg a b b/g + Infra G(12) A(8) B(4) G(12) + Adhoc A+B(12) A(8) B(4) B(4) + + non-MULTI_BANDS: + b b/g + Infra B(4) G(12) + Adhoc B(4) B(4) + */ +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int i, j; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct iw_range *range = (struct iw_range *)extra; + struct chan_freq_power *cfp; + u8 rates[WLAN_SUPPORTED_RATES]; + + u8 flag = 0; + + ENTER(); + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + memset(rates, 0, sizeof(rates)); + range->num_bitrates = get_active_data_rates(adapter, rates); + + for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; + i++) { + range->bitrate[i] = (rates[i] & 0x7f) * 500000; + } + range->num_bitrates = i; + lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES, + range->num_bitrates); + + range->num_frequency = 0; + if (priv->adapter->enable11d && + adapter->connect_status == libertas_connected) { + u8 chan_no; + u8 band; + + struct parsed_region_chan_11d *parsed_region_chan = + &adapter->parsed_region_chan; + + if (parsed_region_chan == NULL) { + lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n"); + LEAVE(); + return 0; + } + band = parsed_region_chan->band; + lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band, + parsed_region_chan->nr_chan); + + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (i < parsed_region_chan->nr_chan); i++) { + chan_no = parsed_region_chan->chanpwr[i].chan; + lbs_pr_debug(1, "chan_no=%d\n", chan_no); + range->freq[range->num_frequency].i = (long)chan_no; + range->freq[range->num_frequency].m = + (long)libertas_chan_2_freq(chan_no, band) * 100000; + range->freq[range->num_frequency].e = 1; + range->num_frequency++; + } + flag = 1; + } + if (!flag) { + for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (j < sizeof(adapter->region_channel) + / sizeof(adapter->region_channel[0])); j++) { + cfp = adapter->region_channel[j].CFP; + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && adapter->region_channel[j].valid + && cfp + && (i < adapter->region_channel[j].nrcfp); i++) { + range->freq[range->num_frequency].i = + (long)cfp->channel; + range->freq[range->num_frequency].m = + (long)cfp->freq * 100000; + range->freq[range->num_frequency].e = 1; + cfp++; + range->num_frequency++; + } + } + } + + lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", + IW_MAX_FREQUENCIES, range->num_frequency); + + range->num_channels = range->num_frequency; + + sort_channels(&range->freq[0], range->num_frequency); + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + if (i > 2) + range->throughput = 5000 * 1000; + else + range->throughput = 1500 * 1000; + + range->min_rts = MRVDRV_RTS_MIN_VALUE; + range->max_rts = MRVDRV_RTS_MAX_VALUE; + range->min_frag = MRVDRV_FRAG_MIN_VALUE; + range->max_frag = MRVDRV_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + range->min_pmp = 1000000; + range->max_pmp = 120000000; + range->min_pmt = 1000; + range->max_pmt = 1000000; + 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; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = TX_RETRY_MIN; + range->max_retry = TX_RETRY_MAX; + + /* + * Set the qual, level and noise range values + */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->avg_qual.qual = 70; + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->sensitivity = 0; + + /* + * Setup the supported power level ranges + */ + memset(range->txpower, 0, sizeof(range->txpower)); + range->txpower[0] = 5; + range->txpower[1] = 7; + range->txpower[2] = 9; + range->txpower[3] = 11; + range->txpower[4] = 13; + range->txpower[5] = 15; + range->txpower[6] = 17; + range->txpower[7] = 19; + + range->num_txpower = 8; + range->txpower_capa = IW_TXPOW_DBM; + range->txpower_capa |= IW_TXPOW_RANGE; + + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + if (adapter->fwcapinfo & FW_CAPINFO_WPA) { + range->enc_capa = IW_ENC_CAPA_WPA + | IW_ENC_CAPA_WPA2 + | IW_ENC_CAPA_CIPHER_TKIP + | IW_ENC_CAPA_CIPHER_CCMP; + } + + LEAVE(); + return 0; +} + +static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + /* PS is currently supported only in Infrastructure mode + * Remove this check if it is to be supported in IBSS mode also + */ + + if (vwrq->disabled) { + adapter->psmode = wlan802_11powermodecam; + if (adapter->psstate != PS_STATE_FULL_POWER) { + libertas_ps_wakeup(priv, cmd_option_waitforrsp); + } + + return 0; + } + + if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + lbs_pr_debug(1, + "Setting power timeout command is not supported\n"); + return -EINVAL; + } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { + lbs_pr_debug(1, "Setting power period command is not supported\n"); + return -EINVAL; + } + + if (adapter->psmode != wlan802_11powermodecam) { + return 0; + } + + adapter->psmode = wlan802_11powermodemax_psp; + + if (adapter->connect_status == libertas_connected) { + libertas_ps_sleep(priv, cmd_option_waitforrsp); + } + + LEAVE(); + return 0; +} + +static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int mode; + + ENTER(); + + mode = adapter->psmode; + + if ((vwrq->disabled = (mode == wlan802_11powermodecam)) + || adapter->connect_status == libertas_disconnected) { + LEAVE(); + return 0; + } + + vwrq->value = 0; + + LEAVE(); + return 0; +} + +/* + * iwpriv settable callbacks + */ + +static const iw_handler wlan_private_handler[] = { + NULL, /* SIOCIWFIRSTPRIV */ +}; + +static const struct iw_priv_args wlan_private_args[] = { + /* + * { cmd, set_args, get_args, name } + */ + { + WLANSCAN_TYPE, + IW_PRIV_TYPE_CHAR | 8, + IW_PRIV_TYPE_CHAR | 8, + "scantype"}, + + { + WLAN_SETINT_GETINT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + { + WLANNF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getNF"}, + { + WLANRSSI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getRSSI"}, + { + WLANENABLE11D, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "enable11d"}, + { + WLANADHOCGRATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "adhocgrate"}, + + { + WLAN_SUBCMD_SET_PRESCAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "prescan"}, + { + WLAN_SETONEINT_GETONEINT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + ""}, + { + WLAN_BEACON_INTERVAL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "bcninterval"}, + { + WLAN_LISTENINTRVL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "lolisteninter"}, + { + WLAN_TXCONTROL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "txcontrol"}, + { + WLAN_NULLPKTINTERVAL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "psnullinterval"}, + /* Using iwpriv sub-command feature */ + { + WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */ + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + ""}, + + { + WLAN_SUBCMD_SETRXANTENNA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setrxant"}, + { + WLAN_SUBCMD_SETTXANTENNA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "settxant"}, + { + WLANSETAUTHALG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "authalgs", + }, + { + WLANSET8021XAUTHALG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "8021xauthalgs", + }, + { + WLANSETENCRYPTIONMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "encryptionmode", + }, + { + WLANSETREGION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setregioncode"}, + { + WLAN_SET_LISTEN_INTERVAL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setlisteninter"}, + { + WLAN_SET_MULTIPLE_DTIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setmultipledtim"}, + { + WLAN_SET_ATIM_WINDOW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "atimwindow"}, + { + WLANSETBCNAVG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setbcnavg"}, + { + WLANSETDATAAVG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setdataavg"}, + { + WLAN_SET_LINKMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "linkmode"}, + { + WLAN_SET_RADIOMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "radiomode"}, + { + WLAN_SET_DEBUGMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "debugmode"}, + { + WLAN_SUBCMD_MESH_SET_TTL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "mesh_set_ttl"}, + { + WLAN_SETNONE_GETONEINT, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + { + WLANGETREGION, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getregioncode"}, + { + WLAN_GET_LISTEN_INTERVAL, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getlisteninter"}, + { + WLAN_GET_MULTIPLE_DTIM, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getmultipledtim"}, + { + WLAN_GET_TX_RATE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "gettxrate"}, + { + WLANGETBCNAVG, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getbcnavg"}, + { + WLAN_GET_LINKMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_linkmode"}, + { + WLAN_GET_RADIOMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_radiomode"}, + { + WLAN_GET_DEBUGMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_debugmode"}, + { + WLAN_SUBCMD_FWT_CLEANUP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "fwt_cleanup"}, + { + WLAN_SUBCMD_FWT_TIME, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "fwt_time"}, + { + WLAN_SUBCMD_MESH_GET_TTL, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "mesh_get_ttl"}, + { + WLAN_SETNONE_GETTWELVE_CHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + ""}, + { + WLAN_SUBCMD_GETRXANTENNA, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "getrxant"}, + { + WLAN_SUBCMD_GETTXANTENNA, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "gettxant"}, + { + WLAN_GET_TSF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "gettsf"}, + { + WLAN_SETNONE_GETNONE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + ""}, + { + WLANDEAUTH, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "deauth"}, + { + WLANADHOCSTOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "adhocstop"}, + { + WLANRADIOON, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "radioon"}, + { + WLANRADIOOFF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "radiooff"}, + { + WLANWLANIDLEON, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "wlanidle-on"}, + { + WLANWLANIDLEOFF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "wlanidle-off"}, + { + WLAN_SUBCMD_FWT_RESET, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "fwt_reset"}, + { + WLAN_SUBCMD_BT_RESET, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "bt_reset"}, + { + WLAN_SET128CHAR_GET128CHAR, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + ""}, + /* BT Management */ + { + WLAN_SUBCMD_BT_ADD, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "bt_add"}, + { + WLAN_SUBCMD_BT_DEL, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "bt_del"}, + { + WLAN_SUBCMD_BT_LIST, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "bt_list"}, + /* FWT Management */ + { + WLAN_SUBCMD_FWT_ADD, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_add"}, + { + WLAN_SUBCMD_FWT_DEL, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_del"}, + { + WLAN_SUBCMD_FWT_LOOKUP, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_lookup"}, + { + WLAN_SUBCMD_FWT_LIST_NEIGHBOR, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_list_neigh"}, + { + WLAN_SUBCMD_FWT_LIST, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_list"}, + { + WLAN_SUBCMD_FWT_LIST_ROUTE, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "fwt_list_route"}, + { + WLANSCAN_MODE, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "scanmode"}, + { + WLAN_GET_ADHOC_STATUS, + IW_PRIV_TYPE_CHAR | 128, + IW_PRIV_TYPE_CHAR | 128, + "getadhocstatus"}, + { + WLAN_SETNONE_GETWORDCHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 128, + ""}, + { + WLANSETWPAIE, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24, + IW_PRIV_TYPE_NONE, + "setwpaie"}, + { + WLANGETLOG, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE, + "getlog"}, + { + WLAN_SET_GET_SIXTEEN_INT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + ""}, + { + WLAN_TPCCFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "tpccfg"}, + { + WLAN_POWERCFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "powercfg"}, + { + WLAN_AUTO_FREQ_SET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "setafc"}, + { + WLAN_AUTO_FREQ_GET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getafc"}, + { + WLAN_SCANPROBES, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "scanprobes"}, + { + WLAN_LED_GPIO_CTRL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "ledgpio"}, + { + WLAN_ADAPT_RATESET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "rateadapt"}, + { + WLAN_INACTIVITY_TIMEOUT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "inactivityto"}, + { + WLANSNR, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getSNR"}, + { + WLAN_GET_RATE, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getrate"}, + { + WLAN_GET_RXINFO, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getrxinfo"}, +}; + +static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) +{ + enum { + POOR = 30, + FAIR = 60, + GOOD = 80, + VERY_GOOD = 90, + EXCELLENT = 95, + PERFECT = 100 + }; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + u32 rssi_qual; + u32 tx_qual; + u32 quality = 0; + int stats_valid = 0; + u8 rssi; + u32 tx_retries; + + ENTER(); + + priv->wstats.status = adapter->inframode; + + /* If we're not associated, all quality values are meaningless */ + if (adapter->connect_status != libertas_connected) + goto out; + + /* Quality by RSSI */ + priv->wstats.qual.level = + CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + + if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + } else { + priv->wstats.qual.noise = + CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + } + + lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level); + lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise); + + rssi = priv->wstats.qual.level - priv->wstats.qual.noise; + if (rssi < 15) + rssi_qual = rssi * POOR / 10; + else if (rssi < 20) + rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; + else if (rssi < 30) + rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; + else if (rssi < 40) + rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / + 10 + GOOD; + else + rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / + 10 + VERY_GOOD; + quality = rssi_qual; + + /* Quality by TX errors */ + priv->wstats.discard.retries = priv->stats.tx_errors; + + tx_retries = adapter->logmsg.retry; + + if (tx_retries > 75) + tx_qual = (90 - tx_retries) * POOR / 15; + else if (tx_retries > 70) + tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; + else if (tx_retries > 65) + tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; + else if (tx_retries > 50) + tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / + 15 + GOOD; + else + tx_qual = (50 - tx_retries) * + (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; + quality = min(quality, tx_qual); + + priv->wstats.discard.code = adapter->logmsg.wepundecryptable; + priv->wstats.discard.fragment = adapter->logmsg.fcserror; + priv->wstats.discard.retries = tx_retries; + priv->wstats.discard.misc = adapter->logmsg.ackfailure; + + /* Calculate quality */ + priv->wstats.qual.qual = max(quality, (u32)100); + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + stats_valid = 1; + + /* update stats asynchronously for future calls */ + libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, + 0, 0, NULL); + libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0, + 0, 0, NULL); +out: + if (!stats_valid) { + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + + LEAVE (); + return &priv->wstats; + + +} + +static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int rc = -EINPROGRESS; /* Call commit handler */ + struct chan_freq_power *cfp; + + ENTER(); + + /* + * If setting by frequency, convert to a channel + */ + if (fwrq->e == 1) { + + long f = fwrq->m / 100000; + int c = 0; + + cfp = find_cfp_by_band_and_freq(adapter, 0, f); + if (!cfp) { + lbs_pr_debug(1, "Invalid freq=%ld\n", f); + return -EINVAL; + } + + c = (int)cfp->channel; + + if (c < 0) + return -EINVAL; + + fwrq->e = 0; + fwrq->m = c; + } + + /* + * Setting by channel number + */ + if (fwrq->m > 1000 || fwrq->e > 0) { + rc = -EOPNOTSUPP; + } else { + int channel = fwrq->m; + + cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel); + if (!cfp) { + rc = -EINVAL; + } else { + if (adapter->inframode == wlan802_11ibss) { + rc = changeadhocchannel(priv, channel); + /* If station is WEP enabled, send the + * command to set WEP in firmware + */ + if (adapter->secinfo.WEPstatus == + wlan802_11WEPenabled) { + lbs_pr_debug(1, "set_freq: WEP enabled\n"); + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_set_wep, + cmd_act_add, + cmd_option_waitforrsp, + 0, + NULL); + + if (ret) { + LEAVE(); + return ret; + } + + adapter->currentpacketfilter |= + cmd_act_mac_wep_enable; + + libertas_set_mac_packet_filter(priv); + } + } else { + rc = -EOPNOTSUPP; + } + } + } + + LEAVE(); + return rc; +} + +/** + * @brief use index to get the data rate + * + * @param index The index of data rate + * @return data rate or 0 + */ +u32 libertas_index_to_data_rate(u8 index) +{ + if (index >= sizeof(libertas_wlan_data_rates)) + index = 0; + + return libertas_wlan_data_rates[index]; +} + +/** + * @brief use rate to get the index + * + * @param rate data rate + * @return index or 0 + */ +u8 libertas_data_rate_to_index(u32 rate) +{ + u8 *ptr; + + if (rate) + if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, + sizeof(libertas_wlan_data_rates)))) + return (ptr - libertas_wlan_data_rates); + + return 0; +} + +static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + u32 data_rate; + u16 action; + int ret = 0; + u8 rates[WLAN_SUPPORTED_RATES]; + u8 *rate; + + ENTER(); + + lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value); + + if (vwrq->value == -1) { + action = cmd_act_set_tx_auto; // Auto + adapter->is_datarate_auto = 1; + adapter->datarate = 0; + } else { + if (vwrq->value % 100000) { + return -EINVAL; + } + + data_rate = vwrq->value / 500000; + + memset(rates, 0, sizeof(rates)); + get_active_data_rates(adapter, rates); + rate = rates; + while (*rate) { + lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate, + data_rate); + if ((*rate & 0x7f) == (data_rate & 0x7f)) + break; + rate++; + } + if (!*rate) { + lbs_pr_alert( "The fixed data rate 0x%X is out " + "of range.\n", data_rate); + return -EINVAL; + } + + adapter->datarate = data_rate; + action = cmd_act_set_tx_fix_rate; + adapter->is_datarate_auto = 0; + } + + ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, + action, cmd_option_waitforrsp, 0, NULL); + + LEAVE(); + return ret; +} + +static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (adapter->is_datarate_auto) { + vwrq->fixed = 0; + } else { + vwrq->fixed = 1; + } + + vwrq->value = adapter->datarate * 500000; + + LEAVE(); + return 0; +} + +static int wlan_set_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct assoc_request * assoc_req; + enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; + + ENTER(); + + switch (*uwrq) { + case IW_MODE_ADHOC: + lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n", + adapter->datarate); + new_mode = wlan802_11ibss; + adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; + break; + + case IW_MODE_INFRA: + lbs_pr_debug(1, "Wanted mode is Infrastructure\n"); + new_mode = wlan802_11infrastructure; + break; + + case IW_MODE_AUTO: + lbs_pr_debug(1, "Wanted mode is Auto\n"); + new_mode = wlan802_11autounknown; + break; + + default: + lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq); + return -EINVAL; + } + + mutex_lock(&adapter->lock); + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + } else { + assoc_req->mode = new_mode; + } + + if (ret == 0) { + set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); + wlan_postpone_association_work(priv); + } else { + wlan_cancel_association_work(priv); + } + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + + +/** + * @brief Get Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, u8 * extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + ENTER(); + + lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n", + dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx); + + dwrq->flags = 0; + + /* Authentication method */ + switch (adapter->secinfo.authmode) { + case wlan802_11authmodeopen: + dwrq->flags = IW_ENCODE_OPEN; + break; + + case wlan802_11authmodeshared: + case wlan802_11authmodenetworkEAP: + dwrq->flags = IW_ENCODE_RESTRICTED; + break; + default: + dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; + break; + } + + if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) + || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + memset(extra, 0, 16); + + mutex_lock(&adapter->lock); + + /* Default to returning current transmit key */ + if (index < 0) + index = adapter->wep_tx_keyidx; + + if ((adapter->wep_keys[index].len) && + (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) { + memcpy(extra, adapter->wep_keys[index].key, + adapter->wep_keys[index].len); + dwrq->length = adapter->wep_keys[index].len; + + dwrq->flags |= (index + 1); + /* Return WEP enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else if ((adapter->secinfo.WPAenabled) + || (adapter->secinfo.WPA2enabled)) { + /* return WPA enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + mutex_unlock(&adapter->lock); + + dwrq->flags |= IW_ENCODE_NOKEY; + + lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n", + extra[0], extra[1], extra[2], + extra[3], extra[4], extra[5], dwrq->length); + + lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags); + + LEAVE(); + return 0; +} + +/** + * @brief Set Encryption key (internal) + * + * @param priv A pointer to private card structure + * @param key_material A pointer to key material + * @param key_length length of key material + * @param index key index to set + * @param set_tx_key Force set TX key (1 = yes, 0 = no) + * @return 0 --success, otherwise fail + */ +static int wlan_set_wep_key(struct assoc_request *assoc_req, + const char *key_material, + u16 key_length, + u16 index, + int set_tx_key) +{ + struct WLAN_802_11_KEY *pkey; + + ENTER(); + + /* Paranoid validation of key index */ + if (index > 3) { + LEAVE(); + return -EINVAL; + } + + /* validate max key length */ + if (key_length > KEY_LEN_WEP_104) { + LEAVE(); + return -EINVAL; + } + + pkey = &assoc_req->wep_keys[index]; + + if (key_length > 0) { + memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); + pkey->type = KEY_TYPE_ID_WEP; + + /* Standardize the key length */ + pkey->len = (key_length > KEY_LEN_WEP_40) ? + KEY_LEN_WEP_104 : KEY_LEN_WEP_40; + memcpy(pkey->key, key_material, key_length); + } + + if (set_tx_key) { + /* Ensure the chosen key is valid */ + if (!pkey->len) { + lbs_pr_debug(1, "key not set, so cannot enable it\n"); + LEAVE(); + return -EINVAL; + } + assoc_req->wep_tx_keyidx = index; + } + + assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled; + + LEAVE(); + return 0; +} + +static int validate_key_index(u16 def_index, u16 raw_index, + u16 *out_index, u16 *is_default) +{ + if (!out_index || !is_default) + return -EINVAL; + + /* Verify index if present, otherwise use default TX key index */ + if (raw_index > 0) { + if (raw_index > 4) + return -EINVAL; + *out_index = raw_index - 1; + } else { + *out_index = def_index; + *is_default = 1; + } + return 0; +} + +static void disable_wep(struct assoc_request *assoc_req) +{ + int i; + + /* Set Open System auth mode */ + assoc_req->secinfo.authmode = wlan802_11authmodeopen; + + /* Clear WEP keys and mark WEP as disabled */ + assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; + for (i = 0; i < 4; i++) + assoc_req->wep_keys[i].len = 0; + + set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); + set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); +} + +/** + * @brief Set Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct assoc_request * assoc_req; + u16 is_default = 0, index = 0, set_tx_key = 0; + + ENTER(); + + mutex_lock(&adapter->lock); + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + goto out; + } + + if (dwrq->flags & IW_ENCODE_DISABLED) { + disable_wep (assoc_req); + goto out; + } + + ret = validate_key_index(assoc_req->wep_tx_keyidx, + (dwrq->flags & IW_ENCODE_INDEX), + &index, &is_default); + if (ret) { + ret = -EINVAL; + goto out; + } + + /* If WEP isn't enabled, or if there is no key data but a valid + * index, set the TX key. + */ + if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) + || (dwrq->length == 0 && !is_default)) + set_tx_key = 1; + + ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); + if (ret) + goto out; + + if (dwrq->length) + set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); + if (set_tx_key) + set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + assoc_req->secinfo.authmode = wlan802_11authmodeshared; + } else if (dwrq->flags & IW_ENCODE_OPEN) { + assoc_req->secinfo.authmode = wlan802_11authmodeopen; + } + +out: + if (ret == 0) { + set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); + wlan_postpone_association_work(priv); + } else { + wlan_cancel_association_work(priv); + } + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + +/** + * @brief Get Extended Encryption key (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int wlan_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + int ret = -EINVAL; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int index, max_key_len; + + ENTER(); + + max_key_len = dwrq->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + index = dwrq->flags & IW_ENCODE_INDEX; + if (index) { + if (index < 1 || index > 4) + goto out; + index--; + } else { + index = adapter->wep_tx_keyidx; + } + + if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY && + ext->alg != IW_ENCODE_ALG_WEP) { + if (index != 0 || adapter->inframode != wlan802_11infrastructure) + goto out; + } + + dwrq->flags = index + 1; + memset(ext, 0, sizeof(*ext)); + + if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) + && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + dwrq->flags |= IW_ENCODE_DISABLED; + } else { + u8 *key = NULL; + + if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) + && !adapter->secinfo.WPAenabled + && !adapter->secinfo.WPA2enabled) { + ext->alg = IW_ENCODE_ALG_WEP; + ext->key_len = adapter->wep_keys[index].len; + key = &adapter->wep_keys[index].key[0]; + } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) && + (adapter->secinfo.WPAenabled || + adapter->secinfo.WPA2enabled)) { + /* WPA */ + ext->alg = IW_ENCODE_ALG_TKIP; + ext->key_len = 0; + } else { + goto out; + } + + if (ext->key_len > max_key_len) { + ret = -E2BIG; + goto out; + } + + if (ext->key_len) + memcpy(ext->key, key, ext->key_len); + else + dwrq->flags |= IW_ENCODE_NOKEY; + dwrq->flags |= IW_ENCODE_ENABLED; + } + ret = 0; + +out: + LEAVE(); + return ret; +} + +/** + * @brief Set Encryption key Extended (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int alg = ext->alg; + struct assoc_request * assoc_req; + + ENTER(); + + mutex_lock(&adapter->lock); + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + goto out; + } + + if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { + disable_wep (assoc_req); + } else if (alg == IW_ENCODE_ALG_WEP) { + u16 is_default = 0, index, set_tx_key = 0; + + ret = validate_key_index(assoc_req->wep_tx_keyidx, + (dwrq->flags & IW_ENCODE_INDEX), + &index, &is_default); + if (ret) + goto out; + + /* If WEP isn't enabled, or if there is no key data but a valid + * index, or if the set-TX-key flag was passed, set the TX key. + */ + if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) + || (dwrq->length == 0 && !is_default) + || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) + set_tx_key = 1; + + /* Copy key to driver */ + ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index, + set_tx_key); + if (ret) + goto out; + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + assoc_req->secinfo.authmode = + wlan802_11authmodeshared; + } else if (dwrq->flags & IW_ENCODE_OPEN) { + assoc_req->secinfo.authmode = + wlan802_11authmodeopen; + } + + /* Mark the various WEP bits as modified */ + set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); + if (dwrq->length) + set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); + if (set_tx_key) + set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); + + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { + struct WLAN_802_11_KEY * pkey; + + /* validate key length */ + if (((alg == IW_ENCODE_ALG_TKIP) + && (ext->key_len != KEY_LEN_WPA_TKIP)) + || ((alg == IW_ENCODE_ALG_CCMP) + && (ext->key_len != KEY_LEN_WPA_AES))) { + lbs_pr_debug(1, "Invalid size %d for key of alg" + "type %d.\n", + ext->key_len, + alg); + ret = -EINVAL; + goto out; + } + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + pkey = &assoc_req->wpa_mcast_key; + else + pkey = &assoc_req->wpa_unicast_key; + + memset(pkey, 0, sizeof (struct WLAN_802_11_KEY)); + memcpy(pkey->key, ext->key, ext->key_len); + pkey->len = ext->key_len; + pkey->flags = KEY_INFO_WPA_ENABLED; + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey->flags |= KEY_INFO_WPA_MCAST; + set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); + } + + if (alg == IW_ENCODE_ALG_TKIP) + pkey->type = KEY_TYPE_ID_TKIP; + else if (alg == IW_ENCODE_ALG_CCMP) + pkey->type = KEY_TYPE_ID_AES; + + /* If WPA isn't enabled yet, do that now */ + if ( assoc_req->secinfo.WPAenabled == 0 + && assoc_req->secinfo.WPA2enabled == 0) { + assoc_req->secinfo.WPAenabled = 1; + assoc_req->secinfo.WPA2enabled = 1; + set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); + } + + disable_wep (assoc_req); + } + +out: + if (ret == 0) { + wlan_postpone_association_work(priv); + } else { + wlan_cancel_association_work(priv); + } + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + + +static int wlan_set_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct assoc_request * assoc_req; + + ENTER(); + + mutex_lock(&adapter->lock); + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + goto out; + } + + if (dwrq->length > MAX_WPA_IE_LEN || + (dwrq->length && extra == NULL)) { + ret = -EINVAL; + goto out; + } + + if (dwrq->length) { + memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); + assoc_req->wpa_ie_len = dwrq->length; + } else { + memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie)); + assoc_req->wpa_ie_len = 0; + } + +out: + if (ret == 0) { + set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); + wlan_postpone_association_work(priv); + } else { + wlan_cancel_association_work(priv); + } + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + +static int wlan_get_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (adapter->wpa_ie_len == 0) { + dwrq->length = 0; + LEAVE(); + return 0; + } + + if (dwrq->length < adapter->wpa_ie_len) { + LEAVE(); + return -E2BIG; + } + + dwrq->length = adapter->wpa_ie_len; + memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len); + + LEAVE(); + return 0; +} + + +static int wlan_set_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, + char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct assoc_request * assoc_req; + int ret = 0; + int updated = 0; + + ENTER(); + + mutex_lock(&adapter->lock); + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + goto out; + } + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * libertas does not use these parameters + */ + break; + + case IW_AUTH_WPA_VERSION: + if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { + assoc_req->secinfo.WPAenabled = 0; + assoc_req->secinfo.WPA2enabled = 0; + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { + assoc_req->secinfo.WPAenabled = 1; + assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; + assoc_req->secinfo.authmode = + wlan802_11authmodeopen; + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { + assoc_req->secinfo.WPA2enabled = 1; + assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; + assoc_req->secinfo.authmode = + wlan802_11authmodeopen; + } + updated = 1; + break; + + case IW_AUTH_DROP_UNENCRYPTED: + if (dwrq->value) { + adapter->currentpacketfilter |= + cmd_act_mac_strict_protection_enable; + } else { + adapter->currentpacketfilter &= + ~cmd_act_mac_strict_protection_enable; + } + updated = 1; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { + assoc_req->secinfo.authmode = + wlan802_11authmodeshared; + } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + assoc_req->secinfo.authmode = + wlan802_11authmodeopen; + } else if (dwrq->value & IW_AUTH_ALG_LEAP) { + assoc_req->secinfo.authmode = + wlan802_11authmodenetworkEAP; + } else { + ret = -EINVAL; + } + updated = 1; + break; + + case IW_AUTH_WPA_ENABLED: + if (dwrq->value) { + if (!assoc_req->secinfo.WPAenabled && + !assoc_req->secinfo.WPA2enabled) { + assoc_req->secinfo.WPAenabled = 1; + assoc_req->secinfo.WPA2enabled = 1; + assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; + assoc_req->secinfo.authmode = + wlan802_11authmodeopen; + } + } else { + assoc_req->secinfo.WPAenabled = 0; + assoc_req->secinfo.WPA2enabled = 0; + } + updated = 1; + break; + + default: + ret = -EOPNOTSUPP; + break; + } + +out: + if (ret == 0) { + if (updated) + set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); + wlan_postpone_association_work(priv); + } else if (ret != -EOPNOTSUPP) { + wlan_cancel_association_work(priv); + } + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + +static int wlan_get_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, + char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + dwrq->value = 0; + if (adapter->secinfo.WPAenabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA; + if (adapter->secinfo.WPA2enabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; + if (!dwrq->value) + dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; + break; + + case IW_AUTH_DROP_UNENCRYPTED: + dwrq->value = 0; + if (adapter->currentpacketfilter & + cmd_act_mac_strict_protection_enable) + dwrq->value = 1; + break; + + case IW_AUTH_80211_AUTH_ALG: + switch (adapter->secinfo.authmode) { + case wlan802_11authmodeshared: + dwrq->value = IW_AUTH_ALG_SHARED_KEY; + break; + case wlan802_11authmodeopen: + dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case wlan802_11authmodenetworkEAP: + dwrq->value = IW_AUTH_ALG_LEAP; + break; + default: + break; + } + break; + + case IW_AUTH_WPA_ENABLED: + if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled) + dwrq->value = 1; + break; + + default: + LEAVE(); + return -EOPNOTSUPP; + } + + LEAVE(); + return 0; +} + + +static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + u16 dbm; + + ENTER(); + + if (vwrq->disabled) { + wlan_radio_ioctl(priv, RADIO_OFF); + return 0; + } + + adapter->preamble = cmd_type_auto_preamble; + + wlan_radio_ioctl(priv, RADIO_ON); + + if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { + dbm = (u16) mw_to_dbm(vwrq->value); + } else + dbm = (u16) vwrq->value; + + /* auto tx power control */ + + if (vwrq->fixed == 0) + dbm = 0xffff; + + lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm); + + ret = libertas_prepare_and_send_command(priv, + cmd_802_11_rf_tx_power, + cmd_act_tx_power_opt_set_low, + cmd_option_waitforrsp, 0, (void *)&dbm); + + LEAVE(); + return ret; +} + +static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + /* + * Note : if dwrq->flags != 0, we should get the relevant SSID from + * the SSID list... + */ + + /* + * Get the current SSID + */ + if (adapter->connect_status == libertas_connected) { + memcpy(extra, adapter->curbssparams.ssid.ssid, + adapter->curbssparams.ssid.ssidlength); + extra[adapter->curbssparams.ssid.ssidlength] = '\0'; + } else { + memset(extra, 0, 32); + extra[adapter->curbssparams.ssid.ssidlength] = '\0'; + } + /* + * If none, we may want to get the one that was set + */ + + /* To make the driver backward compatible with WPA supplicant v0.2.4 */ + if (dwrq->length == 32) /* check with WPA supplicant buffer size */ + dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength, + IW_ESSID_MAX_SIZE); + else + dwrq->length = adapter->curbssparams.ssid.ssidlength + 1; + + dwrq->flags = 1; /* active */ + + LEAVE(); + return 0; +} + +static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int ret = 0; + struct WLAN_802_11_SSID ssid; + struct assoc_request * assoc_req; + int ssid_len = dwrq->length; + + ENTER(); + + /* + * WE-20 and earlier NULL pad the end of the SSID and increment + * SSID length so it can be used like a string. WE-21 and later don't, + * but some userspace tools aren't able to cope with the change. + */ + if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0')) + ssid_len--; + + /* Check the size of the string */ + if (ssid_len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; + } + + memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID)); + + if (!dwrq->flags || !ssid_len) { + /* "any" SSID requested; leave SSID blank */ + } else { + /* Specific SSID requested */ + memcpy(&ssid.ssid, extra, ssid_len); + ssid.ssidlength = ssid_len; + } + + lbs_pr_debug(1, "Requested new SSID = %s\n", + (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any"); + +out: + mutex_lock(&adapter->lock); + if (ret == 0) { + /* Get or create the current association request */ + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + ret = -ENOMEM; + } else { + /* Copy the SSID to the association request */ + memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID)); + set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); + wlan_postpone_association_work(priv); + } + } + + /* Cancel the association request if there was an error */ + if (ret != 0) { + wlan_cancel_association_work(priv); + } + + mutex_unlock(&adapter->lock); + + LEAVE(); + return ret; +} + +/** + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + struct assoc_request * assoc_req; + int ret = 0; + + ENTER(); + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data)); + + mutex_lock(&adapter->lock); + + /* Get or create the current association request */ + assoc_req = wlan_get_association_request(adapter); + if (!assoc_req) { + wlan_cancel_association_work(priv); + ret = -ENOMEM; + } else { + /* Copy the BSSID to the association request */ + memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); + set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); + wlan_postpone_association_work(priv); + } + + mutex_unlock(&adapter->lock); + + return ret; +} + +void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen) +{ + union { + u32 l; + u8 c[4]; + } ver; + char fwver[32]; + + mutex_lock(&adapter->lock); + ver.l = adapter->fwreleasenumber; + mutex_unlock(&adapter->lock); + + if (ver.c[3] == 0) + sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]); + else + sprintf(fwver, "%u.%u.%u.p%u", + ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(fwversion, maxlen, fwver); +} + + +/* + * iwconfig settable callbacks + */ +static const iw_handler wlan_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) wlan_set_wap, /* SIOCSIWAP */ + (iw_handler) wlan_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ + (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ + (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ + (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ + (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ + (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ + (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ + (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ + (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ + (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ + (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ + (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ + (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */ + (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ +}; + +struct iw_handler_def libertas_handler_def = { + .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), + .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), + .num_private_args = sizeof(wlan_private_args) / + sizeof(struct iw_priv_args), + .standard = (iw_handler *) wlan_handler, + .private = (iw_handler *) wlan_private_handler, + .private_args = (struct iw_priv_args *)wlan_private_args, + .get_wireless_stats = wlan_get_wireless_stats, +}; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h new file mode 100644 index 0000000..39f367c --- /dev/null +++ b/drivers/net/wireless/libertas/wext.h @@ -0,0 +1,147 @@ +/** + * This file contains definition for IOCTL call. + */ +#ifndef _WLAN_WEXT_H_ +#define _WLAN_WEXT_H_ + +#define SUBCMD_OFFSET 4 +#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) + +/** PRIVATE CMD ID */ +#define WLANIOCTL SIOCIWFIRSTPRIV + +#define WLANSETWPAIE (WLANIOCTL + 0) + +#define WLAN_SETINT_GETINT (WLANIOCTL + 7) +#define WLANNF 1 +#define WLANRSSI 2 +#define WLANENABLE11D 5 +#define WLANADHOCGRATE 6 +#define WLAN_SUBCMD_SET_PRESCAN 11 + +#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) +#define WLANDEAUTH 1 +#define WLANRADIOON 2 +#define WLANRADIOOFF 3 +#define WLANREMOVEADHOCAES 4 +#define WLANADHOCSTOP 5 +#define WLANCIPHERTEST 6 +#define WLANCRYPTOTEST 7 + +#define WLANWLANIDLEON 10 +#define WLANWLANIDLEOFF 11 +#define WLAN_SUBCMD_BT_RESET 13 +#define WLAN_SUBCMD_FWT_RESET 14 + +#define WLANGETLOG (WLANIOCTL + 9) +#define GETLOG_BUFSIZE 300 + +#define WLANSCAN_TYPE (WLANIOCTL + 11) + +#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15) +#define WLANGETREGION 1 +#define WLAN_GET_LISTEN_INTERVAL 2 +#define WLAN_GET_MULTIPLE_DTIM 3 +#define WLAN_GET_TX_RATE 4 +#define WLANGETBCNAVG 5 + +#define WLAN_GET_LINKMODE 6 +#define WLAN_GET_RADIOMODE 7 +#define WLAN_GET_DEBUGMODE 8 +#define WLAN_SUBCMD_FWT_CLEANUP 15 +#define WLAN_SUBCMD_FWT_TIME 16 +#define WLAN_SUBCMD_MESH_GET_TTL 17 + +#define WLANREGCFRDWR (WLANIOCTL + 18) + +#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19) +#define WLAN_SUBCMD_GETRXANTENNA 1 +#define WLAN_SUBCMD_GETTXANTENNA 2 +#define WLAN_GET_TSF 3 + +#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21) +#define WLANGETADHOCAES 1 + +#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23) +#define WLAN_BEACON_INTERVAL 1 +#define WLAN_LISTENINTRVL 4 + +#define WLAN_TXCONTROL 6 +#define WLAN_NULLPKTINTERVAL 7 + +#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24) +#define WLAN_SUBCMD_SETRXANTENNA 1 +#define WLAN_SUBCMD_SETTXANTENNA 2 +#define WLANSETAUTHALG 5 +#define WLANSET8021XAUTHALG 6 +#define WLANSETENCRYPTIONMODE 7 +#define WLANSETREGION 8 +#define WLAN_SET_LISTEN_INTERVAL 9 + +#define WLAN_SET_MULTIPLE_DTIM 10 +#define WLAN_SET_ATIM_WINDOW 11 +#define WLANSETBCNAVG 13 +#define WLANSETDATAAVG 14 +#define WLAN_SET_LINKMODE 15 +#define WLAN_SET_RADIOMODE 16 +#define WLAN_SET_DEBUGMODE 17 +#define WLAN_SUBCMD_MESH_SET_TTL 18 + +#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25) +#define WLANSCAN_MODE 6 + +#define WLAN_GET_ADHOC_STATUS 9 + +#define WLAN_SUBCMD_BT_ADD 18 +#define WLAN_SUBCMD_BT_DEL 19 +#define WLAN_SUBCMD_BT_LIST 20 +#define WLAN_SUBCMD_FWT_ADD 21 +#define WLAN_SUBCMD_FWT_DEL 22 +#define WLAN_SUBCMD_FWT_LOOKUP 23 +#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24 +#define WLAN_SUBCMD_FWT_LIST 25 +#define WLAN_SUBCMD_FWT_LIST_ROUTE 26 + +#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29) +#define WLAN_TPCCFG 1 +#define WLAN_POWERCFG 2 + +#define WLAN_AUTO_FREQ_SET 3 +#define WLAN_AUTO_FREQ_GET 4 +#define WLAN_LED_GPIO_CTRL 5 +#define WLAN_SCANPROBES 6 +#define WLAN_ADAPT_RATESET 8 +#define WLAN_INACTIVITY_TIMEOUT 9 +#define WLANSNR 10 +#define WLAN_GET_RATE 11 +#define WLAN_GET_RXINFO 12 + +#define WLANCMD52RDWR (WLANIOCTL + 30) +#define WLANCMD53RDWR (WLANIOCTL + 31) +#define CMD53BUFLEN 32 + +#define REG_MAC 0x19 +#define REG_BBP 0x1a +#define REG_RF 0x1b +#define REG_EEPROM 0x59 +#define WLAN_LINKMODE_802_3 0 +#define WLAN_LINKMODE_802_11 2 +#define WLAN_RADIOMODE_NONE 0 +#define WLAN_RADIOMODE_RADIOTAP 2 + +/** wlan_ioctl_regrdwr */ +struct wlan_ioctl_regrdwr { + /** Which register to access */ + u16 whichreg; + /** Read or Write */ + u16 action; + u32 offset; + u16 NOB; + u32 value; +}; + +extern struct iw_handler_def libertas_handler_def; +int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i); +int wlan_radio_ioctl(wlan_private * priv, u8 option); + +#endif /* _WLAN_WEXT_H_ */ diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt deleted file mode 100644 index 3223401..0000000 --- a/drivers/net/wireless/todo.txt +++ /dev/null @@ -1,15 +0,0 @@ - Wireless Todo - ------------- - -1) Bring other kernel Wireless LAN drivers here - Completed - -2) Bring new Wireless LAN driver not yet in the kernel there - See my web page for details - In particular : HostAP - -3) Misc - o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete - o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete - - Jean II diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 9c64f89..f6861da 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *c i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); - i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type, + i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, chip->patch_cck_gain ? 'g' : '-', chip->patch_cr157 ? '7' : '-', chip->patch_6m_band_edge ? '6' : '-', - chip->new_phy_layout ? 'N' : '-'); + chip->new_phy_layout ? 'N' : '-', + chip->al2230s_bit ? 'S' : '-'); return i; } @@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip * /* Allocate a single memory block for values and addresses. */ count16 = 2*count; a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), - GFP_NOFS); + GFP_KERNEL); if (!a16) { dev_dbg_f(zd_chip_dev(chip), "error ENOMEM in allocation of a16\n"); @@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip /* Allocate a single memory block for values and addresses. */ count16 = 2*count; - ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS); + ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL); if (!ioreqs16) { r = -ENOMEM; dev_dbg_f(zd_chip_dev(chip), @@ -337,6 +338,7 @@ static int read_pod(struct zd_chip *chip chip->patch_cr157 = (value >> 13) & 0x1; chip->patch_6m_band_edge = (value >> 21) & 0x1; chip->new_phy_layout = (value >> 31) & 0x1; + chip->al2230s_bit = (value >> 7) & 0x1; chip->link_led = ((value >> 4) & 1) ? LED1 : LED2; chip->supports_tx_led = 1; if (value & (1 << 24)) { /* LED scenario */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index b07569e..ae39c22 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -711,7 +711,7 @@ struct zd_chip { u16 link_led; unsigned int pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, - new_phy_layout:1, + new_phy_layout:1, al2230s_bit:1, is_zd1211b:1, supports_tx_led:1; }; diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 4c5f78e..19172f5 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -974,14 +974,14 @@ static int is_data_packet_for_us(struct switch (ieee->iw_mode) { case IW_MODE_ADHOC: if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || - memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0) + compare_ether_addr(hdr->addr3, ieee->bssid) != 0) return 0; break; case IW_MODE_AUTO: case IW_MODE_INFRA: if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != IEEE80211_FCTL_FROMDS || - memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0) + compare_ether_addr(hdr->addr2, ieee->bssid) != 0) return 0; break; default: @@ -989,9 +989,9 @@ static int is_data_packet_for_us(struct return 0; } - return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || + return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 || (is_multicast_ether_addr(hdr->addr1) && - memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || + compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) || (netdev->flags & IFF_PROMISC); } @@ -1047,7 +1047,7 @@ static void update_qual_rssi(struct zd_m hdr = (struct ieee80211_hdr_3addr *)buffer; if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) return; - if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0) + if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0) return; spin_lock_irqsave(&mac->lock, flags); diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index f50cff3..e6d604b 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -34,7 +34,7 @@ static const char *rfs[] = { [AL2210_RF] = "AL2210_RF", [MAXIM_NEW_RF] = "MAXIM_NEW_RF", [UW2453_RF] = "UW2453_RF", - [AL2230S_RF] = "AL2230S_RF", + [UNKNOWN_A_RF] = "UNKNOWN_A_RF", [RALINK_RF] = "RALINK_RF", [INTERSIL_RF] = "INTERSIL_RF", [RF2959_RF] = "RF2959_RF", diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index a57732e..ee8ac3a 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -26,7 +26,7 @@ #define THETA_RF 0x6 #define AL2210_RF 0x7 #define MAXIM_NEW_RF 0x8 #define UW2453_RF 0x9 -#define AL2230S_RF 0xa +#define UNKNOWN_A_RF 0xa #define RALINK_RF 0xb #define INTERSIL_RF 0xc #define RF2959_RF 0xd diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 25323a1..85a9ad2 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_i { CR240, 0x57 }, { CR9, 0xe0 }, }; +static const struct zd_ioreq16 ioreqs_init_al2230s[] = { + { CR47, 0x1e }, /* MARK_002 */ + { CR106, 0x22 }, + { CR107, 0x2a }, /* MARK_002 */ + { CR109, 0x13 }, /* MARK_002 */ + { CR118, 0xf8 }, /* MARK_002 */ + { CR119, 0x12 }, { CR122, 0xe0 }, + { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ + { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ + { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ +}; + static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; @@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct int r; struct zd_chip *chip = zd_rf_to_chip(rf); - static const struct zd_ioreq16 ioreqs[] = { + static const struct zd_ioreq16 ioreqs_init[] = { { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, @@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, { CR253, 0xff }, + }; - /* These following happen separately in the vendor driver */ - { }, - + static const struct zd_ioreq16 ioreqs_pll[] = { /* shdnb(PLL_ON)=0 */ { CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ @@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct { CR138, 0x28 }, { CR203, 0x06 }, }; - static const u32 rv[] = { + static const u32 rv1[] = { /* Channel 1 */ 0x03f790, 0x033331, @@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct 0x0b3331, 0x03b812, 0x00fff3, + }; + + static const u32 rv2[] = { 0x000da4, 0x0f4dc5, /* fix freq shift, 0x04edc5 */ 0x0805b6, @@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct 0x0bdffc, 0x00000d, 0x00500f, + }; - /* These writes happen separately in the vendor driver */ + static const u32 rv3[] = { 0x00d00f, 0x004c0f, 0x00540f, @@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct 0x00500f, }; - r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init)); + if (r) + return r; + + if (chip->al2230s_bit) { + r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, + ARRAY_SIZE(ioreqs_init_al2230s)); + if (r) + return r; + } + + r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS); + if (r) + return r; + + /* improve band edge for AL2230S */ + if (chip->al2230s_bit) + r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); + else + r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); if (r) return r; - r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); + r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll)); + if (r) + return r; + + r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS); if (r) return r; @@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct 0x481dc0, 0xcfff00, 0x25a000, + }; + static const u32 rv2[] = { /* To improve AL2230 yield, improve phase noise, 4713 */ 0x25a000, 0xa3b2f0, @@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; - static const u32 rv2[] = { + static const u32 rv3[] = { /* To improve AL2230 yield, 4713 */ 0xf01b00, 0xf01e00, @@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); if (r) return r; + + if (chip->al2230s_bit) { + r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, + ARRAY_SIZE(ioreqs_init_al2230s)); + if (r) + return r; + } + r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); if (r) return r; r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); + + if (chip->al2230s_bit) + r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); + else + r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); if (r) return r; + r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); if (r) return r; + r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); + if (r) + return r; + r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3)); + if (r) + return r; r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); if (r) return r; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index aac8a1c..145ad61 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -62,6 +62,9 @@ static struct usb_device_id usb_ids[] = { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} @@ -412,7 +415,7 @@ int zd_usb_enable_int(struct zd_usb *usb dev_dbg_f(zd_usb_dev(usb), "\n"); - urb = usb_alloc_urb(0, GFP_NOFS); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { r = -ENOMEM; goto out; @@ -430,7 +433,7 @@ int zd_usb_enable_int(struct zd_usb *usb /* TODO: make it a DMA buffer */ r = -ENOMEM; - transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS); + transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL); if (!transfer_buffer) { dev_dbg_f(zd_usb_dev(usb), "couldn't allocate transfer_buffer\n"); @@ -444,7 +447,7 @@ int zd_usb_enable_int(struct zd_usb *usb intr->interval); dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); - r = usb_submit_urb(urb, GFP_NOFS); + r = usb_submit_urb(urb, GFP_KERNEL); if (r) { dev_dbg_f(zd_usb_dev(usb), "Couldn't submit urb. Error number %d\n", r); @@ -593,10 +596,10 @@ static struct urb *alloc_urb(struct zd_u struct urb *urb; void *buffer; - urb = usb_alloc_urb(0, GFP_NOFS); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return NULL; - buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS, + buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL, &urb->transfer_dma); if (!buffer) { usb_free_urb(urb); @@ -629,7 +632,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "\n"); r = -ENOMEM; - urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS); + urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); if (!urbs) goto error; for (i = 0; i < URBS_COUNT; i++) { @@ -650,7 +653,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) spin_unlock_irq(&rx->lock); for (i = 0; i < URBS_COUNT; i++) { - r = usb_submit_urb(urbs[i], GFP_NOFS); + r = usb_submit_urb(urbs[i], GFP_KERNEL); if (r) goto error_submit; } @@ -1156,7 +1159,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, } req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); - req = kmalloc(req_len, GFP_NOFS); + req = kmalloc(req_len, GFP_KERNEL); if (!req) return -ENOMEM; req->id = cpu_to_le16(USB_REQ_READ_REGS); @@ -1219,7 +1222,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb req_len = sizeof(struct usb_req_write_regs) + count * sizeof(struct reg_data); - req = kmalloc(req_len, GFP_NOFS); + req = kmalloc(req_len, GFP_KERNEL); if (!req) return -ENOMEM; @@ -1299,7 +1302,7 @@ #endif /* DEBUG */ bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); - req = kmalloc(req_len, GFP_NOFS); + req = kmalloc(req_len, GFP_KERNEL); if (!req) return -ENOMEM; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 600308f..247b5e6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1459,6 +1459,8 @@ #define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0 #define PCI_VENDOR_ID_TOSHIBA_2 0x102f #define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031 +#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index 429b738..c6e0d81 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -168,6 +168,23 @@ struct ieee80211_radiotap_header { * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * + * IEEE80211_RADIOTAP_RX_FLAGS u_int16_t bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS u_int16_t bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES u_int8_t data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES u_int8_t data + * + * Number of unicast retries a transmitted frame used. + * + * * IEEE80211_RADIOTAP_FCS u32 data * * FCS from frame in network byte order. @@ -187,7 +204,11 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_EXT = 31, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + IEEE80211_RADIOTAP_EXT = 31 }; /* Channel flags. */ @@ -219,6 +240,14 @@ #define IEEE80211_RADIOTAP_F_DATAPAD 0x2 * 802.11 header and payload * (to 32-bit boundary) */ +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ /* Ugly macro to convert literal channel numbers into their mhz equivalents * There are certianly some conditions that will break this (like feeding it '30')