GIT 9c1d82d70fb45176657bb488ee52b0078cdbeada git+ssh://master.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git#ALL commit 85a7ea1b0a3263f3ad423b789a841d03c9acbb65 Author: Brice Goglin Date: Mon Aug 21 17:36:56 2006 -0400 [PATCH] myri10ge: use multicast support in the firmware Some recent myri10ge firmwares support multicast filtering as well as an extended mcp_irq_data structure (64 instead of 40 bytes). The new command MXGEFW_CMD_SET_STATS_DMA_V2 is used to check whether the firmware support those. mgp->fw_multicast_support is defined accordingly. When fw_multicast_support is set, some new multicast filtering commands is passed to the board in myri10ge_set_multicast_list(). Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik commit c58ac5caeb32ef17c2e4fc208f7dc93f6de32b7d Author: Brice Goglin Date: Mon Aug 21 17:36:49 2006 -0400 [PATCH] myri10ge: use netif_msg_link Add msg_enable and use netif_msg_link to enable/disable reporting of link status changes since some Ethernet switches seem to generate a lot of status changes under some circumstances and some people want to avoid useless flooding in the logs. Also add a counter for link status changes to statistics. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik commit c5ab964debe92d0ec7af330f350a3433c1b5b61e Author: Richard Purdie Date: Tue Aug 22 18:55:44 2006 +0100 [PATCH] spectrum_cs: Fix firmware uploading errors spectrum_cs: Fix the logic so we error when the device is *not* present! This fixes firmware upload failures which prevent the driver from working (the bug is also present in 2.6.17). Signed-off-by: Richard Purdie Signed-off-by: Jeff Garzik commit 8d91626636ed9ce8b742edb52ae48f2faefd5864 Author: Don Fry Date: Tue Aug 22 10:22:37 2006 -0700 [PATCH] pcnet32: break in 2.6.18-rc1 identified A change I made for 2.6.17 and another for 2.6.18 do not work on older pcnet32 chips which I do not have access to. If the chip is a 79C970 or 79C965, do not try and suspend or check the link status. I have tested with a 79C970A, 79C971, 79C972, 79C973, 79C975, 79C976, and 79C978. Signed-off-by: Don Fry Signed-off-by: Jeff Garzik commit 9a469abe9c6bab3ce237ee433541931bbd827faf Author: Joerg Ahrens Date: Sun Aug 20 21:51:57 2006 +0100 [PATCH] xirc2ps_cs: Cannot reset card in atomic context I am using a Xircom CEM33 pcmcia NIC which has occasional hardware problems. If the netdev watchdog detects a transmit timeout, do_reset is called which msleeps - this is illegal in atomic context. This patch schedules the timeout handling as a workqueue item. Signed-off-by: Daniel Drake Signed-off-by: Jeff Garzik commit cb958186ed543d1a4f074ceb1c783fe8b0908437 Author: Eric Sesterhenn Date: Sat Aug 19 19:37:57 2006 +0200 [PATCH] Signedness issue in drivers/net/3c515.c while playing with gcc 4.1 -Wextra warnings, I came across this one: drivers/net/3c515.c:1027: warning: comparison of unsigned expression >= 0 is always true Since i is unsigned the >= 0 check in the for loop is always true, so we might spin there forever unless the if condition triggers. Since i is only used in this loop, this patch changes it to an integer. Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik commit 9b5cce07648d059a013444116bd0140b047b25a1 Author: Pavel Roskin Date: Tue Aug 15 21:41:39 2006 -0400 [PATCH] hostap: Restore antenna selection settings after port reset Intersil firmware 1.7.4 (and possibly others) loses the antenna selection settings when the port is reset. Signed-off-by: David Acker Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville commit 794ccda61c7dc2aa6c66e8ef18a44d865d3c3a7d Author: Pavel Roskin Date: Tue Aug 15 20:42:20 2006 -0400 [PATCH] spectrum_cs: Fix incorrect use of pcmcia_dev_present() This bug was introduced during the PCMCIA API conversion and broke spectrum_cs completely. Tracked down by Fredrik Tolf Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville commit c67eebd67400c4c2ae1389317f1de0cbb3b7a1ca Author: Komuro Date: Wed Aug 16 13:54:11 2006 +0900 [PATCH] network: axnet_cs.c: add new id (0x021b, 0x0202) Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Jeff Garzik commit a76b044af147135b5fb7570aba35d4908f143cc9 Author: Krzysztof Halasa Date: Wed Aug 16 01:52:23 2006 +0200 [PATCH] WAN: fix C101 card carrier handling Hi, One of my recent changes broke C101 carrier handling, this patch fixes it. Also fixes an old TX underrun checking bug. 2.6.18 material. Please apply. Thanks. Signed-off-by: Krzysztof Halasa Signed-off-by: Jeff Garzik commit 299176206b266f204be859adf9e66efd06628ab2 Author: Jeff Garzik Date: Sat Aug 19 17:48:59 2006 -0400 drivers/net: Remove deprecated use of pci_module_init() From: Michal Piotrowski Signed-off-by: Michal Piotrowski Signed-off-by: Jeff Garzik commit 5243a37b7991c85e3ea3afb6e3e13eea7ec2927d Author: Henrik Kretzschmar Date: Tue Aug 15 11:41:11 2006 +0200 [PATCH] remove an unused function from the header Removes an unused function from the via-velocity-driver. It doesn't make the binary smaller, but the source cleaner. Signed-off-by: Henrik Kretzschmar Signed-off-by: Jeff Garzik commit fd6746daade513bf7f887625c107878b6aacccfd Author: Brice Goglin Date: Mon Aug 14 17:53:15 2006 -0400 [PATCH] myri10ge: convert to netdev_alloc_skb Convert the myri10ge driver to use netdev_alloc_skb instead of dev_alloc_skb, which requires to propagate the net_device across several functions. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik commit e700f9f4a208bf6c5d2b4dd67816555930524476 Author: Brice Goglin Date: Mon Aug 14 17:52:54 2006 -0400 [PATCH] myri10ge: define some previously hardwired firmware constants Define some previously hardwired firmware constants. Signed-off-by: Brice Goglin Signed-off-by: Jeff Garzik commit 2ca2d5e84c19ddbc0126087af6288533a05f1799 Author: Vitaly Bordug Date: Mon Aug 14 23:00:31 2006 -0700 [PATCH] ppc32: board-specific part of fs_enet update This contains board-specific portion to respect driver changes (for 8272ads , 885ads and 866ads). Altered platform_data structures as well as initial setup routines relevant to fs_enet. Changes to the mpc8560ads ppc/ code are also introduced, but mainly as reference, since the entire board support is going to appear in arch/powerpc. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5b4b8454344a0391bb0f69fda0f4ec8e1f0d2fed Author: Vitaly Bordug Date: Mon Aug 14 23:00:30 2006 -0700 [PATCH] FS_ENET: use PAL for mii management This patch should update the fs_enet infrastructure to utilize Phy Abstraction Layer subsystem. Along with the above, there are apparent bugfixes, overhaul and improvements. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 11b0bacd717c285c94dbb56505a28434b34f0639 Author: Vitaly Bordug Date: Mon Aug 14 23:00:29 2006 -0700 [PATCH] PAL: Support of the fixed PHY This makes it possible for HW PHY-less boards to utilize PAL goodies. Generic routines to connect to fixed PHY are provided, as well as ability to specify software callback that fills up link, speed, etc. information into PHY descriptor (the latter feature not tested so far). Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit ec42cdb624059bb9d9d1accca5ed4345bf8f5fda Author: Alexey Dobriyan Date: Mon Aug 14 23:00:28 2006 -0700 [PATCH] xircom_cb: wire up errors from pci_register_driver() Signed-off-by: Alexey Dobriyan Cc: Jeff Garzik Cc: Dominik Brodowski Cc: Valerie Henson Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 3d8f3f3c3697a7603a802427c9226f5dfe6d67ad Author: Heiko Carstens Date: Mon Aug 14 23:00:27 2006 -0700 [PATCH] s390: fix arp_tbl lock usage in qeth qeth: bhs must be disabled when accessing neighbour tables. ================================= [ INFO: inconsistent lock state ] Signed-off-by: Jeff Garzik commit 239e44e1f05e2163ee066c07a753f9fb445979b2 Author: Edgar E. Iglesias Date: Mon Aug 14 23:00:24 2006 -0700 [PATCH] skge: remember to run netif_poll_disable() Signed-off-by: Edgar E. Iglesias Cc: Stephen Hemminger Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b68a60e598c0d1e738c807c47cb181e8cc52a0d8 Author: Jim Lewis Date: Mon Aug 14 23:00:23 2006 -0700 [PATCH] Add ethtool -g support to Spidernet network driver Add ethtool -g (show ring sizes) support to the Spidernet network driver. Signed-off-by: James K Lewis Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 7e29f8bf39de372e3903a0b12f34285d30a8a244 Author: David Brownell Date: Mon Aug 14 23:00:22 2006 -0700 [PATCH] build fixes: smc91x Unclear how these bugs arrived, presumably from incorrect cleanup of the 16-bit-only paths, but smc91x wouldn't build for OMAP. Signed-off-by: David Brownell Cc: Nicolas Pitre Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b933b4d93888b584eda826bffa68a3a1283f8411 Author: Roger Luethi Date: Mon Aug 14 23:00:21 2006 -0700 [PATCH] via-rhine: add option avoid_D3 (work around broken BIOSes) It looks like broken BIOSes controlling Rhine chips will remain in use in significant numbers; such systems fail to come up via PXE after they have been put into D3 (power-saving) mode. This patch adds a module option for disabling the call that puts the chip to sleep. Signed-off-by: Roger Luethi Cc: Jeff Garzik Cc: Joerg Bashir Cc: Tim Phipps Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 76cb4fe7c0926c2c59f4a36ab169aa2d547c93d1 Author: Russell King Date: Mon Aug 14 23:00:20 2006 -0700 [PATCH] lockdep: fix smc91x When booting using root-nfs, I'm seeing (independently) two lockdep dumps in the smc91x driver. The patch below fixes both. Both dumps look like real locking issues. Nico - please review and ack if you think the patch is correct. Dump 1: Sending DHCP requests . ================================= [ INFO: inconsistent lock state ] Signed-off-by: Jeff Garzik commit ab1976682f31661a898b92593bccfeae14d0a0ae Author: Stephen Hemminger Date: Mon Aug 14 23:00:18 2006 -0700 [PATCH] via-rhine: NAPI poll enable The poll_enable should be in init_registers before enabling interrupts, not in tx_timeout. Thanks for spotting it Roger. Signed-off-by: Stephen Hemminger Cc: Roger Luethi Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 633949a145df19d6d338b0f227f033a0a1c5562a Author: Roger Luethi Date: Mon Aug 14 23:00:17 2006 -0700 [PATCH] via-rhine: NAPI support Add NAPI support to the via-rhine driver so that it can handle higher speeds and doesn't get overloaded by interrupts as easily. Signed-off-by: Stephen Hemminger Signed-off-by: Roger Luethi Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit a4d09272480e57cd4aa1156cac7aba9b08885bf9 Author: Peter Korsgaard Date: Mon Aug 14 23:00:17 2006 -0700 [PATCH] smc911x: Re-release spinlock on spurious interrupt The smc911x driver forgets to release the spinlock on spurious interrupts. This little patch fixes it. Cc: Jeff Garzik Signed-off-by: Peter Korsgaard Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 2fd0e33f4f967022ef2f3249b6c512b309734384 Author: Kevin Hao Date: Mon Aug 14 23:00:15 2006 -0700 [PATCH] net: Add netconsole support to dm9000 driver Add netconsole support to dm9000 driver. Cc: Jeff Garzik Cc: Sascha Hauer Cc: Ben Dooks Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 330ce0de93fd7cc0f72fa57a7ec892befe7035d2 Author: Andrew Morton Date: Mon Aug 14 23:00:14 2006 -0700 [PATCH] s2io build fix sparc32: drivers/net/s2io.c:2636: warning: implicit declaration of function 'disable_irq' drivers/net/s2io.c:2656: warning: implicit declaration of function 'enable_irq' Cc: Ananda Raju Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 6fd7587bc284af61f92e547287aa5cd616a9c7ba Author: Deepak Saxena Date: Mon Aug 14 23:00:13 2006 -0700 [PATCH] Update smc91x driver with ARM Versatile board info We need to specify a Versatile-specific SMC_IRQ_FLAGS value or the new generic IRQ layer will complain thusly: No IRQF_TRIGGER set_type function for IRQ 25 () Signed-off-by: Deepak Saxena Cc: Jeff Garzik Cc: Russell King Cc: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit ce973b141dfac4a0f160c7435d65e3ea47753ce8 Author: Li Yang Date: Mon Aug 14 23:00:11 2006 -0700 [PATCH] Freescale QE UCC gigabit ethernet driver QE(QUICC Engine) is a new generation communication coprocessor, which can be found on some of the latest Freescale PowerQUICC CPUs(e.g. MPC8360). The UCC(Unified Communications Controller) module of QE can work as gigabit Ethernet device. This patch provides driver for the device. Signed-off-by: Shlomi Gridish Signed-off-by: Li Yang Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit e4c780b1ffc7d7bc27b7dc57fcf17ebb8d3006bc Author: Adrian Bunk Date: Mon Aug 14 23:00:10 2006 -0700 [PATCH] drivers/net/e1000/: possible cleanups - make needlessly global functions static - #if 0 the following unused global functions: - e1000_hw.c: e1000_mc_addr_list_update() - e1000_hw.c: e1000_read_reg_io() - e1000_hw.c: e1000_enable_pciex_master() - e1000_hw.c: e1000_ife_disable_dynamic_power_down() - e1000_hw.c: e1000_ife_enable_dynamic_power_down() - e1000_hw.c: e1000_write_ich8_word() - e1000_hw.c: e1000_duplex_reversal() - e1000_main.c: e1000_io_read() Signed-off-by: Adrian Bunk Cc: John Ronciak Cc: Jesse Brandeburg Cc: Jeff Kirsher Cc: Auke Kok Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 3418e469ebaebec16f7df83074087eb901fb76b9 Author: Andrew Morton Date: Mon Aug 14 23:00:10 2006 -0700 [PATCH] sundance section fix drivers/net/sundance.c:110: error: version causes a section type conflict I don't understand this error. It's referred to from both __init and __devinit code. With CONFIG_HOTPLUG=n, version[] is placed in .init.data and is referred to from .init.text. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 90d5aed2d9c7d2f3915b75342988114fd7b6c13d Author: Andrew Morton Date: Mon Aug 14 23:00:09 2006 -0700 [PATCH] fealnx section fix With CONFIG_HOTPLUG=n it won't compile: distcc[25607] ERROR: compile drivers/net/fealnx.c on g5/64 failed version[] is referred to from both __init code and from __devinit code, so move it out of __init altogether. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit c9d26c9785d900d8547b268f0c0507f252879c48 Author: Andrew Morton Date: Mon Aug 14 23:00:08 2006 -0700 [PATCH] winbond-840 section fix With CONFIG_HOTPLUG=n it won't compile: drivers/net/tulip/winbond-840.c:141: error: version causes a section type conflict (For some reason it gets the same error if marked __initdata. Give up.) Cc: Valerie Henson Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit c971ef46cb94b8bb4a12555fa757e5f67934fcd9 Author: Andrew Morton Date: Mon Aug 14 23:00:08 2006 -0700 [PATCH] seeq8005 section fix WARNING: drivers/net/seeq8005.o - Section mismatch: reference to .init.text:seeq8005_probe from .text between 'init_module' (at offset 0x106) and 'seeq8005_open' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 1e13b0d82d24ac3c8b2f16a09dd9ce537cad134c Author: Andrew Morton Date: Mon Aug 14 23:00:07 2006 -0700 [PATCH] ni65 section fix WARNING: drivers/net/ni65.o - Section mismatch: reference to .init.text:ni65_probe from .text between 'init_module' (at offset 0x54a) and 'ni65_stop_start' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5e5fa01d55e9949660a89b23f4a43884eaf49097 Author: Andrew Morton Date: Mon Aug 14 23:00:06 2006 -0700 [PATCH] wd section fix WARNING: drivers/net/wd.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xfd) and 'wd_open' WARNING: drivers/net/wd.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x14b) and 'wd_open' WARNING: drivers/net/wd.o - Section mismatch: reference to .init.data:wd_portlist from .text between 'init_module' (at offset 0x17f) and 'wd_open' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit daca7cd7612639848c39744e02dab537755b31a1 Author: Andrew Morton Date: Mon Aug 14 23:00:06 2006 -0700 [PATCH] smctr section fix WARNING: drivers/net/tokenring/smctr.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x2ba0) and 'smctr_reset_adapter' WARNING: drivers/net/tokenring/smctr.o - Section mismatch: reference to .init.text:smctr_probe from .text between 'init_module' (at offset 0x2bf4) and 'smctr_reset_adapter' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 6d2cdb4fd1cc1b15ad070a57c9b2bc40bb1565e7 Author: Andrew Morton Date: Mon Aug 14 23:00:05 2006 -0700 [PATCH] ibmtr section fix WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x6e6) and 'ibmtr_probe_card' WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x74a) and 'ibmtr_probe_card' WARNING: drivers/net/tokenring/ibmtr.o - Section mismatch: reference to .init.data:ibmtr_mem_base from .text between 'ibmtr_probe1' (at offset 0x7fd) and 'ibmtr_probe_card' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 19a8664d8a05f75cab3cd4eb8022d22d3f0c53c3 Author: Andrew Morton Date: Mon Aug 14 23:00:05 2006 -0700 [PATCH] ni52 section fix WARNING: drivers/net/ni52.o - Section mismatch: reference to .init.text:ni52_probe from .text between 'init_module' (at offset 0x997) and 'ni52_close' WARNING: drivers/net/ni65.o - Section mismatch: reference to .init.text:ni65_probe from .text between 'init_module' (at offset 0x54a) and 'ni65_stop_start' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit dab3d02ec05d16aab680de471cb5d20c5d4852e8 Author: Andrew Morton Date: Mon Aug 14 23:00:04 2006 -0700 [PATCH] lne390 section fix WARNING: drivers/net/lne390.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x100) and 'lne390_close' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 3805f0e28ca313893b87e881201561d5c1857dd8 Author: Andrew Morton Date: Mon Aug 14 23:00:03 2006 -0700 [PATCH] lance section fix WARNING: drivers/net/lance.o - Section mismatch: reference to .init.data:lance_portlist from .text between 'init_module' (at offset 0x8d3) and 'lance_purge_ring' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 58f149fc65ebced1148789cfb37457a8c7aaca75 Author: Andrew Morton Date: Mon Aug 14 23:00:03 2006 -0700 [PATCH] eth16i section fix WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x6d2) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x6ef) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x702) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x70e) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x71d) and 'eth16i_multicast' WARNING: drivers/net/eth16i.o - Section mismatch: reference to .init.data:cardname from .text between 'init_module' (at offset 0x729) and 'eth16i_multicast' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5757f5c6d7d9cbe4bf6a464f1842a767f505d440 Author: Andrew Morton Date: Mon Aug 14 23:00:02 2006 -0700 [PATCH] es3210 section fix WARNING: drivers/net/es3210.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xdf) and 'es_close' WARNING: drivers/net/es3210.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x100) and 'es_close' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b1176b95b4b851b05a2f541ef54e7ce3ed358d19 Author: Andrew Morton Date: Mon Aug 14 23:00:01 2006 -0700 [PATCH] eexpress section fix WARNING: drivers/net/eexpress.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x6c3) and 'eexp_hw_lasttxstat' WARNING: drivers/net/eexpress.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x74f) and 'eexp_hw_lasttxstat' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 02a3245fcf0911ff92100aa54823dc1c5950fba9 Author: Andrew Morton Date: Mon Aug 14 23:00:01 2006 -0700 [PATCH] eepro section fix WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x284) and 'eepro_ethtool_get_drvinfo' WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x2a7) and 'eepro_ethtool_get_drvinfo' WARNING: drivers/net/eepro.o - Section mismatch: reference to .init.data:eepro_portlist from .text between 'init_module' (at offset 0x2b3) and 'eepro_ethtool_get_drvinfo' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit d543cbb6d192313d9027ed09c7a1e085b1234082 Author: Andrew Morton Date: Mon Aug 14 23:00:00 2006 -0700 [PATCH] e2100 section fix WARNING: drivers/net/e2100.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xd9) and 'e21_reset_8390' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5d930108c914c04fbb0bfbb059d23a5fcaf0d1e7 Author: Andrew Morton Date: Mon Aug 14 22:59:59 2006 -0700 [PATCH] at1700 section fix WARNING: drivers/net/at1700.o - Section mismatch: reference to .init.text:at1700_probe from .text between 'init_module' (at offset 0x75) and 'net_get_stats' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit e26c129a49a7a4990f362a9cdb3084198b4d9d7b Author: Andrew Morton Date: Mon Aug 14 22:59:59 2006 -0700 [PATCH] cs89x0 section fix WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.data:version from .text between 'init_module' (at offset 0x13d8) and 'net_get_stats' WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x1634) and 'net_get_stats' WARNING: drivers/net/cs89x0.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0x1a1f) and 'net_get_stats' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5f3bc456ce190a963a8816be5a318df9998f3bc5 Author: Andrew Morton Date: Mon Aug 14 22:59:58 2006 -0700 [PATCH] cops section fix WARNING: drivers/net/appletalk/cops.o - Section mismatch: reference to .init.text:cops_probe from .text between 'init_module' (at offset 0xae) and 'cops_rx' Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 62a87b8051ded3d1fcb89773c9febd1bb34d3cbd Author: Andrew Morton Date: Mon Aug 14 22:59:57 2006 -0700 [PATCH] ac3200 section fixes WARNING: drivers/net/ac3200.o - Section mismatch: reference to .init.text: from .text between 'init_module' (at offset 0xf9) and 'ac_close_card' Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 864fe05dfa4ff3e230acf3b4ccf878b6f22603c4 Author: Andrew Morton Date: Mon Aug 14 22:59:57 2006 -0700 [PATCH] 82596 section fixes WARNING: drivers/net/82596.o - Section mismatch: reference to .init.text:i82596_probe from .text between 'init_module' (at offset 0x141) and 'i596_add_cmd' Also nail a couple of crazy inlines. Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 891b11f619dcfe045015394fa89041f02dac9428 Author: Auke Kok Date: Wed Aug 16 13:47:31 2006 -0700 ixgb: Increment version to 1.0.109-k4 Signed-off-by: Auke Kok commit 3ae84d9269592a1284892c93597a604a894f1102 Author: Jesse Brandeburg Date: Wed Aug 16 13:47:25 2006 -0700 ixgb: fix cache miss due to miscalculation Reduce writeback threshold by 1. We were instructing the hardware to wait until the 17th descriptor which went over the cache line limit. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok commit 0fe198a5e10229b269624a18bbd390001a8d3476 Author: Manasi Deval Date: Wed Aug 16 13:47:20 2006 -0700 ixgb: Add CX4 PHY type detection and subdevice ID. Signed-off-by: Manasi Deval Signed-off-by: Auke Kok commit dc335d9735220b3a9ece5ec2d95864b1e8ff06a0 Author: Auke Kok Date: Wed Aug 16 13:39:09 2006 -0700 e1000: Increment driver version to 7.1.9-k6 Signed-off-by: Auke Kok commit 600c977c0801210602d7502f9c978c2b8c31a209 Author: Jeff Kirsher Date: Wed Aug 16 13:39:04 2006 -0700 e1000: Disable aggressive clocking on esb2 with SERDES port Disable aggressive clocking on esb2 with SERDES port as it causes hardware problems. Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok commit 7820d4281a0d746a92992a9117aec007628ae3fe Author: Jeff Kirsher Date: Wed Aug 16 13:39:00 2006 -0700 e1000: Force full DMA clocking for 10/100 speed Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok commit c9c1b834c7b6e00badfd9a775682644f192f0357 Author: Jeff Kirsher Date: Wed Aug 16 13:38:54 2006 -0700 e1000: Allow NVM to setup LPLU for IGP2 and IGP3 Allow NVM to setup LPLU for IGP2 and IGP3. Only IGP needs LPLU D3 disabled during init here. Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok commit 1a821ca59593d307e564800c2f25ed1f9e1e2a6f Author: Jesse Brandeburg Date: Wed Aug 16 13:38:46 2006 -0700 e1000: explicit locking for two ethtool path functions Explicitly lock two more ethtool entry points completely instead of the hardware reset only to prevent a race condition. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok commit d658266ed6144f9dbc785c7d5bb6e8e5e2e7f3cf Author: Jesse Brandeburg Date: Wed Aug 16 13:31:33 2006 -0700 e1000: Explicitly power up the PHY during loopback testing. Signed-off-by: Jesse Brandeburg commit 673a052fde79ab5e9dce569b0336358812ddba2d Author: Jeff Kirsher Date: Wed Aug 16 11:28:49 2006 -0700 e1000: Remove 0x1000 as supported device Remove pci ID 8086:1000 from the list fo supported devices. This device has not functioned with the driver for very long (since v. 5.2.4!) and we lack the resources to come with a substantial fix. There are only few cards of this type out there. Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok commit e15fdd0391dfeb0d439ecac759fb88aca7930f2f Author: Auke Kok Date: Wed Aug 16 11:28:45 2006 -0700 e1000: Same cosmetic fix as earlier sent out for IPV4. Signed-off-by: Auke Kok commit 4e1dc97d5e0dd5b1cf78e67ea8f12ca9697c9eee Author: Auke Kok Date: Wed Aug 16 11:28:35 2006 -0700 e100: increment version to 3.5.10-k4 Increment the version of e100 to 3.5.10-k4, increment dates. Signed-off-by: Auke Kok commit 60ffa478759f39a2eb3be1ed179bc3764804b2c8 Author: Jeff Kirsher Date: Wed Aug 16 11:28:14 2006 -0700 e100: Fix MDIO/MDIO-X MDIO/MDIO-X was broken due to a wrong errata. Removing the workaround code fixes for affected NICs. Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok commit 113b898e38cb20e80847c24154ce62273b948c6a Author: Michael Wu Date: Sun Aug 13 23:27:17 2006 -0700 [PATCH] ray_cs: Remove dependency on ieee80211 This patch removes the dependency on ieee80211.h from the ray_cs driver. ray_cs only needs iw_handler.h. Signed-off-by: Michael Wu Signed-off-by: John W. Linville commit c48cf125146852424bfe8e02033c6065dd0a4021 Author: Ulrich Kunitz Date: Sat Aug 12 18:00:17 2006 +0100 [PATCH] zd1211rw: cleanups Add static to 2 internal functions. Thanks goes to Adrian Bunk, who found that. Also made some modifications to the clear functions: After a discussion on the mailing list, I implemented this code to have on the one hand sufficient test in debug mode, but on the other hand reduce the overhead for structure clearing to a minimum. A new macro ZD_MEMCLEAR is introduced, which produces code if DEBUG is set. Locks are not set anymore for structure clearing, but in debug mode, there is a verification, that the locks have not been set. Finally, removed a misleading comment regarding locking in the disconnect path. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 943599ee2c3a018fd09c25d7a9e8703792dd618e Author: Ulrich Kunitz Date: Sat Aug 12 18:00:05 2006 +0100 [PATCH] zd1211rw: USB id 1582:6003 for Longshine 8131G3 added The Longshine device is a ZD1211B and has a AL2230 RF. I tested it successfully with no encryption and WEP. Signed-off-by: Ulrich Kunitz Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit a1030e92c1507eb4a3c15d0a7d62987f671b609c Author: Daniel Drake Date: Sun Aug 13 12:15:29 2006 +0100 [PATCH] zd1211rw: Convert installer CDROM device into WLAN device Some devices identify themselves as a virtual USB CDROM drive. The virtual CD includes the windows driver. We aren't interested in this, so we eject the virtual CDROM and then the real wireless device appears. Patch fixed over the earlier version to not leak cmd, thanks to Michael Buesch for spotting that. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 4ceb7e9936dae67d6c553a4954fa410a99b3ea16 Author: Daniel Drake Date: Sat Aug 12 18:00:03 2006 +0100 [PATCH] zd1211rw: Add ID for ZyXEL G220F zd1211 chip 0586:3402 v4916 high 00-13-49 AL2230_RF pa0 ---- This device pops up after the virtual driver CD has been ejected. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit d066c2190de86d75e17dc35beba48b920cb125ee Author: Daniel Drake Date: Sat Aug 12 17:59:59 2006 +0100 [PATCH] zd1211rw: Firmware version vs bootcode version mismatch handling This is needed for my G220F, otherwise it fails to initialize after the existing firmware upload routine. The vendor driver actually does more than what I have done here: it downloads the firmware + boot code, modifies it, and uploads it again (really messy). I have not copied that part over, as my device can get on its feet without it. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 12f393089775ca33c53541eb67112fc04d799131 Author: Daniel Drake Date: Sat Aug 12 17:59:51 2006 +0100 [PATCH] zd1211rw: Add ID for Allnet ALLSPOT Hotspot finder Tested by Wonka on IRC. zd1211 chip 157e:3204 v4810 high 00-11-e0 AL7230B_RF pa0 g--- Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 1b865491fcbf9b865fb5cf48c94cbae2995c6589 Author: Daniel Drake Date: Sat Aug 12 17:59:50 2006 +0100 [PATCH] zd1211rw: Add ID for Senao NUB-8301 Tested by lyakh on IRC zd1211 chip 1740:2000 v4721 high 00-02-6f AL7230B_RF pa0 g--- Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit ec62bd91bbb58254dfddca3d290f5fe4aa1cb769 Author: Daniel Drake Date: Sat Aug 12 17:59:46 2006 +0100 [PATCH] zd1211rw: Support AL7230B RF This patch adds support for another Airoha RF which is present in some ZD1211 adapters. This RF supports 802.11a as well as 802.11b/g, but 802.11a connectivity is not yet supported by this driver. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 20fe2176e5edbeb5957f113df1282a917ef87b5d Author: Daniel Drake Date: Sat Aug 12 17:59:42 2006 +0100 [PATCH] zd1211rw: AL2230 ZD1211B vendor sync This patch synchronizes our code to some recent vendor driver modifications. A new PHY layout is supported, some values are tweaked, and the AL2230 is now programmed over a new interface which is many times faster. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 98227a90a727029613f23c5e53554f1f4d7a1c89 Author: Daniel Drake Date: Sat Aug 12 17:59:22 2006 +0100 [PATCH] zd1211rw: Match vendor driver IFS values The vendor driver resets the IFS value every time the channel changes, to this one. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit fe7215caa033814cee1e6808e44132b7cefb1a9e Author: Daniel Drake Date: Sat Aug 12 17:59:12 2006 +0100 [PATCH] zd1211rw: ZD1211B ASIC/FWT, not jointly decoder The vendor driver chooses this value based on an ifndef ASIC, and ASIC is never defined. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit bcd68373877e74d8ca5039c10dc5d699ba5dc7d0 Author: Dave Jones Date: Thu Aug 10 21:37:13 2006 -0400 [PATCH] remove unnecessary config.h includes from drivers/net/ config.h is automatically included by kbuild these days. Signed-off-by: Dave Jones Signed-off-by: Jeff Garzik commit 80a8003f9236992fce45e6b2d0f33098b55a3859 Author: Daniele Venzano Date: Sat Aug 12 11:17:03 2006 +0200 [PATCH] Add new PHY to sis900 supported list Please include the attached patch that adds support for a new PHY to the sis900 driver. See also Bugzilla 6919. Signed-off-by: Daniele Venzano -- Signed-off-by: Jeff Garzik commit 09e590e5d5a93f2eaa748a89c623258e6bad1648 Author: Lennert Buytenhek Date: Sat Aug 12 10:55:07 2006 +0200 [PATCH] smc91x: disable DMA mode on the logicpd pxa270 Enabling PXA DMA for the smc91x on the logicpd pxa270 produces unacceptable interference with the TFT panel, so disable it. Also delete the lpd270 versions of the SMC_{in,out}[bl]() macros, as they aren't used, since the board only supports 16bit accesses. Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik commit 8d3d35b4e20dc2e678fc7cb51165905b5a32fb76 Author: Stephen Hemminger Date: Wed Aug 9 14:14:50 2006 -0700 [PATCH] sky2: phy power problems on 88e805X chips On the 88E805X chipsets (used in laptops), the PHY was not getting powered out of shutdown properly. The variable reg1 was getting reused incorrectly. This is probably the cause of the bug. http://bugzilla.kernel.org/show_bug.cgi?id=6471 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit e714d99cacac976deac3239c89f2c9e3125649b6 Author: Philippe De Muyter Date: Thu Aug 3 18:42:15 2006 +0200 [PATCH] sundance: small cleanup This patch uses the sundance_reset function everywhere a reset is done, and adds a link to the archives of the original mailing list. Signed-off-by: Philippe De Muyter Signed-off-by: Jeff Garzik commit e27cdba53b8ad5c12c9281b3737e07f2a536c3a2 Author: Stephen Hemminger Date: Mon Jul 31 20:37:19 2006 -0700 [PATCH] forcdeth: revised NAPI support Revised version of the forcedeth NAPI support. This version is based against netdev-2.6#upstream (after the MAC patches from Ayaz today). Can't use nv_disable_hw_interrupts because NAPI only wants to mask off receive irq's and leave the others alone. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 5070d3408405ae1941f259acac7a9882045c3be4 Author: Ayaz Abdulla Date: Mon Jul 31 12:05:01 2006 -0400 [PATCH] forcedeth: mac address corrected This patch will correct the mac address and set a flag to indicate that it is already corrected in case nv_probe is called again. For example, when you use kexec to restart the kernel. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit f1489653e9c891f343d2034aad0ef6984d3ef5cb Author: Ayaz Abdulla Date: Mon Jul 31 12:04:45 2006 -0400 [PATCH] forcedeth: move mac address setup/teardown This patch moves the mac address setup/teardown to the nv_probe/nv_remove functions. This fixes WOL wakeup since on nv_close we would reverse the mac address. Also, bonding driver will reset address after nv_close is called. Signed-Off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik commit fcf194d19b7857c2467bebdb271bd079a0c0da81 Author: Komuro Date: Sun Jul 23 10:20:55 2006 +0900 [PATCH] network: pcnet_cs.c: remove unnecessary 'mdio_reset' 'mdio_reset' has bad side effects that moves the phy_id. DL10022-based cards work properly without 'mdio_reset'. Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Jeff Garzik commit 9835093d85ee454edb58283bb4f66a4504ca7378 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. commit fe2a24dfc577a05349a39c6c8a6312818d28bb59 Author: Stephen Hemminger Date: Tue Aug 1 11:55:23 2006 -0700 [PATCH] sky2: status interrupt handling improvement More changes to prevent losing status and causing hangs. The hardware is smarter than I gave it credit for. Clearing the status IRQ causes the status state machine to toggle an IRQ if needed and post any more transmits. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 57fa442c1e842e6ec18ec7cd8cca9e29b5189278 Author: Stephen Hemminger Date: Sat Jul 29 17:21:55 2006 -0700 [PATCH] sky2: more pci device ids Recent vendor driver and customer reports show more devices. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit 48c86da1a211ef13bbfb1c8f2e35dda44a66b8a1 Author: John W. Linville Date: Mon Jul 31 14:54:57 2006 -0400 [PATCH] bcm43xx: reduce mac_suspend delay loop count Drop the mac_suspend loop count to reduce the maximum delay to 10ms. Signed-off-by: John W. Linville commit 894b62748bec22a98e636ed40221b27d1b9094b7 Author: Larry Finger Date: Mon Jul 31 14:20:44 2006 -0400 [PATCH] bcm43xx: add missing mac_suspended initialization Fix-up missing mac_suspended initialization which resulted from Linville's sloppy patch mangling. Signed-off-by: John W. Linville commit e1c3e5014040869abd6ef2cdf987e7c74cb40ada Author: Henrik Kretzschmar Date: Mon Jul 24 14:42:01 2006 +0200 [PATCH] initialisation cleanup for ULI526x-net-driver removes the unneeded local variable rc replace pci_module_init() with pci_register_driver() two coding style issues on switch Signed-off-by: Henrik Kretzschmar Signed-off-by: Jeff Garzik commit a8bed49ecfb47a40cc401f5ec7c9a8a38098e728 Author: Stephen Hemminger Date: Thu Jul 27 18:50:09 2006 -0700 [PATCH] forcedeth: le32 annotation Use __le32 to indicate byte order of hardware ring elements Signed-off-by: Stephen Hemminger drivers/net/forcedeth.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) Signed-off-by: Jeff Garzik commit f82a9352f6b955d1dd9adc1124d6796be2c147df Author: Stephen Hemminger Date: Thu Jul 27 18:50:08 2006 -0700 [PATCH] forcedeth: coding style cleanups Fix the coding style of the nForce Ethernet driver. - typedef's should not be used - variable names should not be capitialized - structure tags should be lower case - add whitespace near keywords - don't add paren's to switch cases - remove paren's from return - don't use __constant_ntohs unless necessary. Signed-off-by: Stephen Hemminger drivers/net/forcedeth.c | 246 ++++++++++++++++++++++++------------------------ 1 file changed, 123 insertions(+), 123 deletions(-) Signed-off-by: Jeff Garzik commit 5a4faa873782d748960b02fdec95e3d4d2e3ae38 Author: Ron Mercer Date: Tue Jul 25 00:40:21 2006 -0700 [PATCH] qla3xxx NIC driver This is a complementary network driver for our ISP4XXX parts. There is a concurrent effort underway to get the iSCSI driver (qla4xxx) integrated upstream as well. I have been through several iterations with the linux-netdev list and have had much response from Stephen Hemminger. - Built and tested using kernel 2.6.17-rc4. - The chip supports two ethernet and two iSCSI functions. - The functions ql_sem_lock, ql_sem_spinlock, ql_sem_unlock, and ql_wait_for_drvr_lock are used to protect resources that are shared across the network and iSCSI functions. This protection is mostly during chip initialization and resets, but also include link management. - The PHY/MII are not exported through ethtool due to the fact that the iSCSI function will control the common link at least 50% of the time. This driver has been through several iterations on the netdev list and we feel this driver is ready for inclusion in the upstream kernel. It has been built and tested on x86 and PPC64 platforms. Cc: Jeff Garzik Cc: Stephen Hemminger Signed-off-by: Ron Mercer Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit f1207ba1a756610a9880fe4b70d7f0e9f0627073 Author: John W. Linville Date: Thu Jul 27 18:10:00 2006 -0400 [PATCH] bcm43xx: fix-up build breakage from merging patches out of order Signed-off-by: John W. Linville commit 27be44ff8ee29e945adad226cc360c9278239d17 Author: Larry Finger Date: Fri Jul 14 15:42:17 2006 -0500 [PATCH] bcm43xx: improved statistics This minor patch for wireless-2.6 (softmac) adjusts the parameters of the wireless statistics to improve the display of programs such as the "Wireless Network Information" applet of KDE. Thanks to Dan Williams and Jean Tourrilhes for valuable help in setting up the return of info in dBm. Signed-Off-By: Larry Finger Signed-off-by: John W. Linville commit 58e5528ee464d38040b9489e10033c9387a10d56 Author: Michael Buesch Date: Sat Jul 8 22:02:18 2006 +0200 [PATCH] bcm43xx: init routine rewrite Rewrite of the bcm43xx initialization routines. This fixes several issues: * up-down-up-down-up... stale data issue (May fix some DHCP issues) * Fix the init vs IRQ handler race (and remove the workaround) * Fix init for cards with multiple cores (APHY) As softmac has no internal PHY handling (unlike dscape), this adds the file "phymode" to sysfs. The active PHY can be selected by writing either a, b or g to this file. Current PHY can be determined by reading from it. * Fix the controller restart code. Controller restart can now also be triggered through echo 1 > /debug/bcm43xx/ethX/restart Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit 3234faa8abe0c3d6da12cc4a38ce790134c92564 Author: Michael Buesch Date: Wed Jun 28 20:35:17 2006 +0200 [PATCH] bcm43xx: fix mac_suspend refcount This fixes mac_suspend reference counting for ifconfig up ifconfig down ifconfig up Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit b8e7cdb391c50cfc243a387b6690f5a251537e50 Author: Michael Buesch Date: Tue Jun 27 17:56:44 2006 +0200 [PATCH] bcm43xx: lower mac_suspend udelay Microoptimization: This reduces the udelay in bcm43xx_mac_suspend. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit 062caf43d803771b660defe6b147711d8b730364 Author: Michael Buesch Date: Mon Jun 12 17:02:22 2006 +0200 [PATCH] bcm43xx: suspend MAC while executing long pwork Suspend MAC (and make MAC-suspend refcounting) when doing long periodic work. On long periodic work, we disable IRQs on the device, so we don't want the MAC to stay operating and probably miss packets due do non-delivery of interrupts. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit 8f0f850e240df5bea027caeb1723142c50e37e57 Author: Daniel Drake Date: Tue Jul 18 22:00:25 2006 +0100 [PATCH] softmac: Add MAINTAINERS entry Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville commit f2060f039e8a8bc83b10e6d0f8fb440425560569 Author: Daniel Drake Date: Tue Jul 18 21:38:05 2006 +0100 [PATCH] ieee80211: Make ieee80211_rx_any usable ieee80211_rx_any is new to 2.6.18-rc1, even though it appears this function was never completed: http://lists.sipsolutions.net/pipermail/softmac-dev/2006-February/000103.html This patch changes ieee80211_rx_any to always claim the skb, which avoids further driver complexity and the possibility of leaking management frames. It also exports the function so that people can actually use it. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville commit d7712ac254a4ae2e9c927e29e37b8c7ac334e6ad Author: Daniel Drake Date: Tue Jul 18 21:34:56 2006 +0100 [PATCH] softmac: export highest_supported_rate function zd1211 needs this functionality, no point duplicating it. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville commit 5acd0c4153be25269d7cb9a4b09fd6db571c5cc1 Author: Daniel Drake Date: Tue Jul 18 21:33:27 2006 +0100 [PATCH] softmac: ERP handling and driver-level notifications This patch implements ERP handling in softmac so that the drivers can support protection and preambles properly. I added a new struct, ieee80211softmac_bss_info, which is used for BSS-dependent variables like these. A new hook has been added (bssinfo_change), which allows the drivers to be notified when anything in bssinfo changes. I modified the txrates_change API to match the bssinfo_change API. The existing one is a little messy and the usefulness of providing the old rates is questionable (and can be implemented at driver level if really necessary). No drivers are using this API (yet), so this should be safe. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville commit d8e2be90d301a0381e9b2528fe2835cf2992bca3 Author: Daniel Drake Date: Tue Jul 18 21:30:34 2006 +0100 [PATCH] ieee80211: small ERP handling additions This adds a flag to the ieee80211_network structure which indicates whether the stored erp_value is valid (a check against 0 is not enough, since an ERP of 0 is valid and very meaningful). I also added the ERP IE bit-definitions to ieee80211.h. This is needed by some upcoming softmac patches. Signed-off-by: Daniel Drake Acked-by: Johannes Berg Signed-off-by: John W. Linville commit eab411f1e850af5acbd6ef278f4e669250f71915 Author: Dan Williams Date: Mon Jul 17 21:21:47 2006 -0400 [PATCH] prism54: update to WE-19 for WPA support Add WE-19 capabilities to prism54 fullmac driver so that it supports the necessary Wireless Extensions WPA calls. Convert reporting of WPA/RSN Generic Information Elements to IWEVGENIE rather than pre-WE-19 IWEVCUSTOM as well. Signed-off-by: Dan Williams Signed-off-by: John W. Linville commit 7c0c3afb6e67004648ca589445e073dba4040509 Author: Daniel Drake Date: Sun Jul 16 13:55:17 2006 +0100 [PATCH] Add zd1211rw MAINTAINERS entry Hopefully this will help people like Adrian Bunk send patches where the maintainers will see them :) Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 089f99d8ac398905f6dc75dd2ce5796ced5dd943 Author: Daniel Drake Date: Thu Jul 13 17:56:16 2006 +0100 [PATCH] zd1211rw: Implement SIOCGIWNICKN wireless.h discourages using SIOCGIWNAME to publish the driver name which the interface belongs to. Use SIOCGIWNICKN instead. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 67fd6b45231362a2f1ed6c74281a901105ae7d3e Author: Pavel Machek Date: Tue Jul 11 15:34:05 2006 +0200 [PATCH] cleanup // comments from ipw2200 ipw2200 uses // comments, and uses them for removing unneeded code. Clean it up a bit. Signed-off-by: Pavel Machek Signed-off-by: John W. Linville commit 13dca9b87edebd5aa1d9ea5811bcf0fa1e975b52 Author: Robert Schulze Date: Mon Jul 10 18:37:44 2006 +0200 [PATCH] airo: collapse debugging-messages in issuecommand to one line Signed-off-by: John W. Linville commit 22ad852b8297e5063fc50f54a77e13f6d9b16a6f Author: Arjan van de Ven Date: Wed Jul 5 20:36:40 2006 +0200 [PATCH] resend of 8390 patch for lockdep The 8390 drivers use disable_irq() as a locking primitive, which means these uses need lockdep specific annotation that they are used as such. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Jeff Garzik commit 3fac0613937dff488141c8ade3320fd815c38ed7 Author: Ralf Baechle Date: Thu Jul 13 12:14:55 2006 +0100 [PATCH] Remove useless #ifdef MODULE stuff and printout Get rid of the MODULE stuff. Could have rewritten to use modern interfaces but the copyright message of this BSD licensed code isn't interesting enough to be watched on every bootup, in every syslog. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit 79690602adc5b52ce224df6ac67bde0074b2aede Author: Ralf Baechle Date: Thu Jul 13 12:12:53 2006 +0100 [PATCH] Remove useless casts Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit 15880352659a363209c5ad9cfc796a9c8a7f5196 Author: Ralf Baechle Date: Thu Jul 13 12:10:48 2006 +0100 [PATCH] Convert to kzalloc Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit b6e37e55c250f5233401b2566b1a4b512a98bc7b Author: Ralf Baechle Date: Fri Jul 14 12:15:40 2006 +0100 [PATCH] Cleanup SLHC configuration Convert selection of serial line header compression to use CONFIG_SLHC rather than makefile ifeq uglyness. This makes it easier to select the SLHC module from other code. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik commit 5f5d83fdbfb50ffb6f5fbf5fd69bc791d9d5cd20 Author: Stephen Hemminger Date: Mon Jul 17 15:38:32 2006 -0400 [PATCH] sky2: add another PCI ID Yet another PCI ID for 88E8056 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik commit dd2f5538a157bda68bfa8efb39feaaccdda9e74e Author: Daniel Drake Date: Wed Jul 5 15:57:31 2006 +0100 [PATCH] zd1211rw: Add Sagem device ID's Based on a patch by Matthieu CASTET. zd1211 chip 079b:004a v4330 high 00-60-b3 AL2230_RF pa0 g-- zd1211b chip 079b:0062 v4810 high 00-60-b3 AL2230_RF pa0 g-- Signed-off-by: Daniel Drake Signed-off-by: John W. Linville commit 4221f980a4931364be7ffd81c4f16784990f6f8b Author: Larry Finger Date: Thu Jun 29 22:48:59 2006 -0500 [PATCH] bcm43xx: improved statistics This patch improves the statistics returned from bcm43xx_get_wireless_stats. The signal level comes from smoothing the "rssi" value returned by the firmware after it is converted into a dBm value by the driver. The quality value is a hack derived from the smoothed level and an assumed RX_POWER_MAX of -10 dBM. The noise value is still the one calculated from the clean-room formula. On my system, this is roughly -65 dBm, which seems too high. The revised version uses the ieee80211 spinlock to protect traversing of the network list. Signed-Off-By: Larry Finger Signed-off-by: John W. Linville commit 2087da5dc12c497123d5fb8949ceed9021b673ec Author: Michael Buesch Date: Wed Jun 28 20:17:57 2006 +0200 [PATCH] bcm43xx: voluntary preemtion in the calibration loops This patch adds voluntary preemption points into the PHY calibration loops to allow non-CONFIG_PREEMPT machines to not suffer from huge delays. CONFIG_PREEMPT machines are already fine, because all this code is run in non-atomic process context. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville commit efa6a370216f1816456b49aac03295071720f7eb Author: Michael Buesch Date: Tue Jun 27 21:38:40 2006 +0200 [PATCH] bcm43xx: opencoded locking As many people don't seem to like the locking "obfuscation" in the bcm43xx driver, this patch removes it. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- Signed-off-by: Andrew Morton --- Documentation/networking/LICENSE.qla3xxx | 46 MAINTAINERS | 27 arch/ppc/platforms/85xx/mpc8560_ads.c | 89 arch/ppc/platforms/85xx/mpc85xx_ads_common.h | 19 arch/ppc/platforms/mpc8272ads_setup.c | 154 arch/ppc/platforms/mpc866ads_setup.c | 192 arch/ppc/platforms/mpc885ads_setup.c | 179 arch/ppc/platforms/pq2ads_pd.h | 82 arch/ppc/syslib/mpc85xx_devices.c | 89 arch/ppc/syslib/mpc8xx_devices.c | 8 arch/ppc/syslib/mpc8xx_sys.c | 6 arch/ppc/syslib/pq2_devices.c | 5 arch/ppc/syslib/pq2_sys.c | 3 drivers/isdn/i4l/Kconfig | 1 drivers/net/3c501.c | 1 drivers/net/3c515.c | 3 drivers/net/3c59x.c | 2 drivers/net/8139cp.c | 2 drivers/net/8139too.c | 2 drivers/net/82596.c | 9 drivers/net/8390.c | 10 drivers/net/Kconfig | 74 drivers/net/Makefile | 14 drivers/net/ac3200.c | 3 drivers/net/acenic.c | 2 drivers/net/amd8111e.c | 2 drivers/net/appletalk/cops.c | 2 drivers/net/arcnet/com20020-pci.c | 2 drivers/net/at1700.c | 2 drivers/net/b44.c | 2 drivers/net/bnx2.c | 2 drivers/net/cassini.c | 2 drivers/net/chelsio/cxgb2.c | 2 drivers/net/cs89x0.c | 3 drivers/net/defxx.c | 2 drivers/net/dl2k.c | 2 drivers/net/dm9000.c | 14 drivers/net/e100.c | 96 drivers/net/e1000/e1000_ethtool.c | 40 drivers/net/e1000/e1000_hw.c | 113 drivers/net/e1000/e1000_hw.h | 32 drivers/net/e1000/e1000_main.c | 13 drivers/net/e2100.c | 4 drivers/net/eepro.c | 3 drivers/net/eepro100.c | 2 drivers/net/eexpress.c | 2 drivers/net/epic100.c | 2 drivers/net/es3210.c | 3 drivers/net/eth16i.c | 2 drivers/net/fealnx.c | 4 drivers/net/forcedeth.c | 463 - drivers/net/fs_enet/Makefile | 6 drivers/net/fs_enet/fec.h | 42 drivers/net/fs_enet/fs_enet-main.c | 207 drivers/net/fs_enet/fs_enet-mii.c | 505 - drivers/net/fs_enet/fs_enet.h | 40 drivers/net/fs_enet/mac-fcc.c | 32 drivers/net/fs_enet/mac-fec.c | 142 drivers/net/fs_enet/mac-scc.c | 4 drivers/net/fs_enet/mii-bitbang.c | 448 - drivers/net/fs_enet/mii-fec.c | 243 drivers/net/fs_enet/mii-fixed.c | 91 drivers/net/hp100.c | 1 drivers/net/irda/mcs7780.c | 1 drivers/net/irda/w83977af_ir.c | 1 drivers/net/ixgb/ixgb_hw.c | 11 drivers/net/ixgb/ixgb_ids.h | 1 drivers/net/ixgb/ixgb_main.c | 16 drivers/net/lance.c | 2 drivers/net/lne390.c | 2 drivers/net/myri10ge/myri10ge.c | 193 drivers/net/myri10ge/myri10ge_mcp.h | 47 drivers/net/natsemi.c | 2 drivers/net/ne2k-pci.c | 2 drivers/net/netx-eth.c | 1 drivers/net/ni52.c | 2 drivers/net/ni65.c | 2 drivers/net/ns83820.c | 2 drivers/net/pci-skeleton.c | 2 drivers/net/pcmcia/axnet_cs.c | 3 drivers/net/pcmcia/pcnet_cs.c | 15 drivers/net/pcmcia/xirc2ps_cs.c | 18 drivers/net/pcnet32.c | 27 drivers/net/phy/Kconfig | 17 drivers/net/phy/Makefile | 1 drivers/net/phy/fixed.c | 358 + drivers/net/phy/mdio_bus.c | 1 drivers/net/phy/phy_device.c | 51 drivers/net/phy/smsc.c | 1 drivers/net/phy/vitesse.c | 1 drivers/net/qla3xxx.c | 3537 +++++++++++ drivers/net/qla3xxx.h | 1194 +++ drivers/net/r8169.c | 2 drivers/net/rrunner.c | 2 drivers/net/s2io.c | 3 drivers/net/saa9730.c | 2 drivers/net/seeq8005.c | 2 drivers/net/sis190.c | 2 drivers/net/sis900.c | 3 drivers/net/sk98lin/skge.c | 2 drivers/net/skfp/skfddi.c | 2 drivers/net/skge.c | 4 drivers/net/sky2.c | 40 drivers/net/slhc.c | 28 drivers/net/smc911x.c | 3 drivers/net/smc91x.c | 8 drivers/net/smc91x.h | 29 drivers/net/spider_net.c | 12 drivers/net/spider_net.h | 3 drivers/net/spider_net_ethtool.c | 13 drivers/net/starfire.c | 2 drivers/net/sundance.c | 17 drivers/net/sungem.c | 2 drivers/net/tc35815.c | 2 drivers/net/tg3.c | 2 drivers/net/tokenring/3c359.c | 2 drivers/net/tokenring/ibmtr.c | 4 drivers/net/tokenring/lanstreamer.c | 2 drivers/net/tokenring/smctr.c | 5 drivers/net/tulip/de2104x.c | 2 drivers/net/tulip/de4x5.c | 2 drivers/net/tulip/dmfe.c | 2 drivers/net/tulip/tulip_core.c | 2 drivers/net/tulip/uli526x.c | 12 drivers/net/tulip/winbond-840.c | 4 drivers/net/tulip/xircom_cb.c | 3 drivers/net/tulip/xircom_tulip_cb.c | 2 drivers/net/typhoon.c | 2 drivers/net/ucc_geth.c | 4278 ++++++++++++++ drivers/net/ucc_geth.h | 1339 ++++ drivers/net/ucc_geth_phy.c | 801 ++ drivers/net/ucc_geth_phy.h | 217 drivers/net/via-rhine.c | 92 drivers/net/via-velocity.c | 2 drivers/net/via-velocity.h | 19 drivers/net/wan/c101.c | 9 drivers/net/wan/cycx_main.c | 1 drivers/net/wan/dlci.c | 1 drivers/net/wan/dscc4.c | 2 drivers/net/wan/farsync.c | 2 drivers/net/wan/lmc/lmc_main.c | 2 drivers/net/wan/pc300_drv.c | 2 drivers/net/wan/pci200syn.c | 2 drivers/net/wan/sdla.c | 1 drivers/net/wan/wanxl.c | 2 drivers/net/wd.c | 4 drivers/net/wireless/airo.c | 12 drivers/net/wireless/atmel_pci.c | 2 drivers/net/wireless/bcm43xx/bcm43xx.h | 116 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 80 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | 1 drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 10 drivers/net/wireless/bcm43xx/bcm43xx_main.c | 743 +- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 33 drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 4 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 104 drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 168 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 5 drivers/net/wireless/hostap/hostap_hw.c | 3 drivers/net/wireless/ipw2100.c | 2 drivers/net/wireless/ipw2200.c | 31 drivers/net/wireless/orinoco_nortel.c | 2 drivers/net/wireless/orinoco_pci.c | 2 drivers/net/wireless/orinoco_plx.c | 2 drivers/net/wireless/orinoco_tmd.c | 2 drivers/net/wireless/prism54/isl_ioctl.c | 573 + drivers/net/wireless/prism54/isl_ioctl.h | 6 drivers/net/wireless/prism54/islpci_dev.c | 4 drivers/net/wireless/prism54/islpci_dev.h | 2 drivers/net/wireless/prism54/islpci_hotplug.c | 2 drivers/net/wireless/ray_cs.c | 2 drivers/net/wireless/zd1211rw/Makefile | 1 drivers/net/wireless/zd1211rw/zd_chip.c | 62 drivers/net/wireless/zd1211rw/zd_chip.h | 15 drivers/net/wireless/zd1211rw/zd_def.h | 6 drivers/net/wireless/zd1211rw/zd_mac.c | 6 drivers/net/wireless/zd1211rw/zd_mac.h | 2 drivers/net/wireless/zd1211rw/zd_netdev.c | 17 drivers/net/wireless/zd1211rw/zd_rf.c | 7 drivers/net/wireless/zd1211rw/zd_rf.h | 1 drivers/net/wireless/zd1211rw/zd_rf_al2230.c | 153 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c | 274 drivers/net/wireless/zd1211rw/zd_usb.c | 122 drivers/net/wireless/zd1211rw/zd_usb.h | 1 drivers/net/yellowfin.c | 2 drivers/s390/net/qeth_main.c | 8 include/asm-ppc/cpm2.h | 95 include/asm-ppc/mpc8260.h | 1 include/asm-ppc/mpc8xx.h | 1 include/linux/fs_enet_pd.h | 50 include/linux/phy.h | 1 include/net/ieee80211.h | 9 include/net/ieee80211softmac.h | 60 net/ieee80211/ieee80211_rx.c | 39 net/ieee80211/softmac/ieee80211softmac_assoc.c | 21 net/ieee80211/softmac/ieee80211softmac_io.c | 14 net/ieee80211/softmac/ieee80211softmac_module.c | 90 net/ieee80211/softmac/ieee80211softmac_priv.h | 8 199 files changed, 16288 insertions(+), 2807 deletions(-) diff -puN /dev/null Documentation/networking/LICENSE.qla3xxx --- /dev/null +++ a/Documentation/networking/LICENSE.qla3xxx @@ -0,0 +1,46 @@ +Copyright (c) 2003-2006 QLogic Corporation +QLogic Linux Networking HBA Driver + +This program includes a device driver for Linux 2.6 that may be +distributed with QLogic hardware specific firmware binary file. +You may modify and redistribute the device driver code under the +GNU General Public License as published by the Free Software +Foundation (version 2 or a later version). + +You may redistribute the hardware specific firmware binary file +under the following terms: + + 1. Redistribution of source code (only if applicable), + must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistribution in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + + 3. The name of QLogic Corporation may not be used to + endorse or promote products derived from this software + without specific prior written permission + +REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE, +THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "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. + +USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT +CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR +OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT, +TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN +ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN +COMBINATION WITH THIS PROGRAM. + diff -puN MAINTAINERS~git-netdev-all MAINTAINERS --- a/MAINTAINERS~git-netdev-all +++ a/MAINTAINERS @@ -2384,6 +2384,12 @@ M: linux-driver@qlogic.com L: linux-scsi@vger.kernel.org S: Supported +QLOGIC QLA3XXX NETWORK DRIVER +P: Ron Mercer +M: linux-driver@qlogic.com +L: netdev@vger.kernel.org +S: Supported + QNX4 FILESYSTEM P: Anders Larsen M: al@alarsen.net @@ -2634,6 +2640,18 @@ P: Nicolas Pitre M: nico@cam.org S: Maintained +SOFTMAC LAYER (IEEE 802.11) +P: Johannes Berg +M: johannes@sipsolutions.net +P: Joe Jezak +M: josejx@gentoo.org +P: Daniel Drake +M: dsd@gentoo.org +W: http://softmac.sipsolutions.net/ +L: softmac-dev@sipsolutions.net +L: netdev@vger.kernel.org +S: Maintained + SOFTWARE RAID (Multiple Disks) SUPPORT P: Ingo Molnar M: mingo@redhat.com @@ -3358,6 +3376,15 @@ W: http://www.qsl.net/dl1bke/ L: linux-hams@vger.kernel.org S: Maintained +ZD1211RW WIRELESS DRIVER +P: Daniel Drake +M: dsd@gentoo.org +P: Ulrich Kunitz +M: kune@deine-taler.de +W: http://zd1211.ath.cx/wiki/DriverRewrite +L: zd1211-devs@lists.sourceforge.net (subscribers-only) +S: Maintained + ZF MACHZ WATCHDOG P: Fernando Fuganti M: fuganti@netbank.com.br diff -puN arch/ppc/platforms/85xx/mpc8560_ads.c~git-netdev-all arch/ppc/platforms/85xx/mpc8560_ads.c --- a/arch/ppc/platforms/85xx/mpc8560_ads.c~git-netdev-all +++ a/arch/ppc/platforms/85xx/mpc8560_ads.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,71 @@ * Setup the architecture * */ +static void init_fcc_ioports(void) +{ + struct immap *immap; + struct io_port *io; + u32 tempval; + + immap = cpm2_immr; + + io = &immap->im_ioport; + /* FCC2/3 are on the ports B/C. */ + tempval = in_be32(&io->iop_pdirb); + tempval &= ~PB2_DIRB0; + tempval |= PB2_DIRB1; + out_be32(&io->iop_pdirb, tempval); + + tempval = in_be32(&io->iop_psorb); + tempval &= ~PB2_PSORB0; + tempval |= PB2_PSORB1; + out_be32(&io->iop_psorb, tempval); + + tempval = in_be32(&io->iop_pparb); + tempval |= (PB2_DIRB0 | PB2_DIRB1); + out_be32(&io->iop_pparb, tempval); + + tempval = in_be32(&io->iop_pdirb); + tempval &= ~PB3_DIRB0; + tempval |= PB3_DIRB1; + out_be32(&io->iop_pdirb, tempval); + + tempval = in_be32(&io->iop_psorb); + tempval &= ~PB3_PSORB0; + tempval |= PB3_PSORB1; + out_be32(&io->iop_psorb, tempval); + + tempval = in_be32(&io->iop_pparb); + tempval |= (PB3_DIRB0 | PB3_DIRB1); + out_be32(&io->iop_pparb, tempval); + + tempval = in_be32(&io->iop_pdirc); + tempval |= PC3_DIRC1; + out_be32(&io->iop_pdirc, tempval); + + tempval = in_be32(&io->iop_pparc); + tempval |= PC3_DIRC1; + out_be32(&io->iop_pparc, tempval); + + /* Port C has clocks...... */ + tempval = in_be32(&io->iop_psorc); + tempval &= ~(CLK_TRX); + out_be32(&io->iop_psorc, tempval); + + tempval = in_be32(&io->iop_pdirc); + tempval &= ~(CLK_TRX); + out_be32(&io->iop_pdirc, tempval); + tempval = in_be32(&io->iop_pparc); + tempval |= (CLK_TRX); + out_be32(&io->iop_pparc, tempval); + + /* Configure Serial Interface clock routing. + * First, clear all FCC bits to zero, + * then set the ones we want. + */ + immap->im_cpmux.cmx_fcr &= ~(CPMUX_CLK_MASK); + immap->im_cpmux.cmx_fcr |= CPMUX_CLK_ROUTE; +} static void __init mpc8560ads_setup_arch(void) @@ -66,6 +132,7 @@ mpc8560ads_setup_arch(void) unsigned int freq; struct gianfar_platform_data *pdata; struct gianfar_mdio_data *mdata; + struct fs_platform_info *fpi; cpm2_reset(); @@ -110,6 +177,28 @@ mpc8560ads_setup_arch(void) memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6); } + init_fcc_ioports(); + ppc_sys_device_remove(MPC85xx_CPM_FCC1); + + fpi = (struct fs_platform_info *) ppc_sys_get_pdata(MPC85xx_CPM_FCC2); + if (fpi) { + memcpy(fpi->macaddr, binfo->bi_enet2addr, 6); + fpi->bus_id = "0:02"; + fpi->phy_addr = 2; + fpi->dpram_offset = (u32)cpm2_immr->im_dprambase; + fpi->fcc_regs_c = (u32)&cpm2_immr->im_fcc_c[1]; + } + + fpi = (struct fs_platform_info *) ppc_sys_get_pdata(MPC85xx_CPM_FCC3); + if (fpi) { + memcpy(fpi->macaddr, binfo->bi_enet2addr, 6); + fpi->macaddr[5] += 1; + fpi->bus_id = "0:03"; + fpi->phy_addr = 3; + fpi->dpram_offset = (u32)cpm2_immr->im_dprambase; + fpi->fcc_regs_c = (u32)&cpm2_immr->im_fcc_c[2]; + } + #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) ROOT_DEV = Root_RAM0; diff -puN arch/ppc/platforms/85xx/mpc85xx_ads_common.h~git-netdev-all arch/ppc/platforms/85xx/mpc85xx_ads_common.h --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h~git-netdev-all +++ a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h @@ -45,4 +45,23 @@ extern void mpc85xx_ads_map_io(void) __i #define MPC85XX_PCI1_IO_SIZE 0x01000000 +/* FCC1 Clock Source Configuration. These can be + * redefined in the board specific file. + * Can only choose from CLK9-12 */ +#define F1_RXCLK 12 +#define F1_TXCLK 11 + +/* FCC2 Clock Source Configuration. These can be + * redefined in the board specific file. + * Can only choose from CLK13-16 */ +#define F2_RXCLK 13 +#define F2_TXCLK 14 + +/* FCC3 Clock Source Configuration. These can be + * redefined in the board specific file. + * Can only choose from CLK13-16 */ +#define F3_RXCLK 15 +#define F3_TXCLK 16 + + #endif /* __MACH_MPC85XX_ADS_H__ */ diff -puN arch/ppc/platforms/mpc8272ads_setup.c~git-netdev-all arch/ppc/platforms/mpc8272ads_setup.c --- a/arch/ppc/platforms/mpc8272ads_setup.c~git-netdev-all +++ a/arch/ppc/platforms/mpc8272ads_setup.c @@ -56,64 +56,51 @@ static struct fs_uart_platform_info mpc8 }, }; -static struct fs_mii_bus_info mii_bus_info = { - .method = fsmii_bitbang, - .id = 0, - .i.bitbang = { - .mdio_port = fsiop_portc, - .mdio_bit = 18, - .mdc_port = fsiop_portc, - .mdc_bit = 19, - .delay = 1, - }, -}; - -static struct fs_platform_info mpc82xx_fcc1_pdata = { - .fs_no = fsid_fcc1, - .cp_page = CPM_CR_FCC1_PAGE, - .cp_block = CPM_CR_FCC1_SBLOCK, - .clk_trx = (PC_F1RXCLK | PC_F1TXCLK), - .clk_route = CMX1_CLK_ROUTE, - .clk_mask = CMX1_CLK_MASK, - .init_ioports = init_fcc1_ioports, - - .phy_addr = 0, -#ifdef PHY_INTERRUPT - .phy_irq = PHY_INTERRUPT, -#else - .phy_irq = -1; -#endif - .mem_offset = FCC1_MEM_OFFSET, - .bus_info = &mii_bus_info, - .rx_ring = 32, - .tx_ring = 32, - .rx_copybreak = 240, - .use_napi = 0, - .napi_weight = 17, +static struct fs_mii_bb_platform_info m82xx_mii_bb_pdata = { + .mdio_dat.bit = 18, + .mdio_dir.bit = 18, + .mdc_dat.bit = 19, + .delay = 1, }; -static struct fs_platform_info mpc82xx_fcc2_pdata = { - .fs_no = fsid_fcc2, - .cp_page = CPM_CR_FCC2_PAGE, - .cp_block = CPM_CR_FCC2_SBLOCK, - .clk_trx = (PC_F2RXCLK | PC_F2TXCLK), - .clk_route = CMX2_CLK_ROUTE, - .clk_mask = CMX2_CLK_MASK, - .init_ioports = init_fcc2_ioports, - - .phy_addr = 3, -#ifdef PHY_INTERRUPT - .phy_irq = PHY_INTERRUPT, -#else - .phy_irq = -1; -#endif - .mem_offset = FCC2_MEM_OFFSET, - .bus_info = &mii_bus_info, - .rx_ring = 32, - .tx_ring = 32, - .rx_copybreak = 240, - .use_napi = 0, - .napi_weight = 17, +static struct fs_platform_info mpc82xx_enet_pdata[] = { + [fsid_fcc1] = { + .fs_no = fsid_fcc1, + .cp_page = CPM_CR_FCC1_PAGE, + .cp_block = CPM_CR_FCC1_SBLOCK, + + .clk_trx = (PC_F1RXCLK | PC_F1TXCLK), + .clk_route = CMX1_CLK_ROUTE, + .clk_mask = CMX1_CLK_MASK, + .init_ioports = init_fcc1_ioports, + + .mem_offset = FCC1_MEM_OFFSET, + + .rx_ring = 32, + .tx_ring = 32, + .rx_copybreak = 240, + .use_napi = 0, + .napi_weight = 17, + .bus_id = "0:00", + }, + [fsid_fcc2] = { + .fs_no = fsid_fcc2, + .cp_page = CPM_CR_FCC2_PAGE, + .cp_block = CPM_CR_FCC2_SBLOCK, + .clk_trx = (PC_F2RXCLK | PC_F2TXCLK), + .clk_route = CMX2_CLK_ROUTE, + .clk_mask = CMX2_CLK_MASK, + .init_ioports = init_fcc2_ioports, + + .mem_offset = FCC2_MEM_OFFSET, + + .rx_ring = 32, + .tx_ring = 32, + .rx_copybreak = 240, + .use_napi = 0, + .napi_weight = 17, + .bus_id = "0:03", + }, }; static void init_fcc1_ioports(void) @@ -209,20 +196,21 @@ static void __init mpc8272ads_fixup_enet bd_t* bi = (void*)__res; int fs_no = fsid_fcc1+pdev->id-1; - mpc82xx_fcc1_pdata.dpram_offset = mpc82xx_fcc2_pdata.dpram_offset = (u32)cpm2_immr->im_dprambase; - mpc82xx_fcc1_pdata.fcc_regs_c = mpc82xx_fcc2_pdata.fcc_regs_c = (u32)cpm2_immr->im_fcc_c; - - switch(fs_no) { - case fsid_fcc1: - memcpy(&mpc82xx_fcc1_pdata.macaddr,bi->bi_enetaddr,6); - pdev->dev.platform_data = &mpc82xx_fcc1_pdata; - break; - case fsid_fcc2: - memcpy(&mpc82xx_fcc2_pdata.macaddr,bi->bi_enetaddr,6); - mpc82xx_fcc2_pdata.macaddr[5] ^= 1; - pdev->dev.platform_data = &mpc82xx_fcc2_pdata; - break; + if(fs_no > ARRAY_SIZE(mpc82xx_enet_pdata)) { + return; } + + mpc82xx_enet_pdata[fs_no].dpram_offset= + (u32)cpm2_immr->im_dprambase; + mpc82xx_enet_pdata[fs_no].fcc_regs_c = + (u32)cpm2_immr->im_fcc_c; + memcpy(&mpc82xx_enet_pdata[fs_no].macaddr,bi->bi_enetaddr,6); + + /* prevent dup mac */ + if(fs_no == fsid_fcc2) + mpc82xx_enet_pdata[fs_no].macaddr[5] ^= 1; + + pdev->dev.platform_data = &mpc82xx_enet_pdata[fs_no]; } static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev, @@ -274,6 +262,29 @@ static void init_scc4_uart_ioports(void) iounmap(immap); } +static void __init mpc8272ads_fixup_mdio_pdata(struct platform_device *pdev, + int idx) +{ + m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT; + m82xx_mii_bb_pdata.irq[1] = -1; + m82xx_mii_bb_pdata.irq[2] = -1; + m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT; + m82xx_mii_bb_pdata.irq[31] = -1; + + + m82xx_mii_bb_pdata.mdio_dat.offset = + (u32)&cpm2_immr->im_ioport.iop_pdatc; + + m82xx_mii_bb_pdata.mdio_dir.offset = + (u32)&cpm2_immr->im_ioport.iop_pdirc; + + m82xx_mii_bb_pdata.mdc_dat.offset = + (u32)&cpm2_immr->im_ioport.iop_pdatc; + + + pdev->dev.platform_data = &m82xx_mii_bb_pdata; +} + static int mpc8272ads_platform_notify(struct device *dev) { static const struct platform_notify_dev_map dev_map[] = { @@ -286,6 +297,10 @@ static int mpc8272ads_platform_notify(st .rtn = mpc8272ads_fixup_uart_pdata, }, { + .bus_id = "fsl-bb-mdio", + .rtn = mpc8272ads_fixup_mdio_pdata, + }, + { .bus_id = NULL } }; @@ -319,6 +334,7 @@ int __init mpc8272ads_init(void) ppc_sys_device_enable(MPC82xx_CPM_SCC4); #endif + ppc_sys_device_enable(MPC82xx_MDIO_BB); return 0; } diff -puN arch/ppc/platforms/mpc866ads_setup.c~git-netdev-all arch/ppc/platforms/mpc866ads_setup.c --- a/arch/ppc/platforms/mpc866ads_setup.c~git-netdev-all +++ a/arch/ppc/platforms/mpc866ads_setup.c @@ -1,10 +1,10 @@ -/*arch/ppc/platforms/mpc885ads-setup.c +/*arch/ppc/platforms/mpc866ads-setup.c * - * Platform setup for the Freescale mpc885ads board + * Platform setup for the Freescale mpc866ads board * * Vitaly Bordug * - * Copyright 2005 MontaVista Software Inc. + * Copyright 2005-2006 MontaVista Software Inc. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any @@ -42,49 +42,36 @@ static void setup_scc1_ioports(void); static void setup_smc1_ioports(void); static void setup_smc2_ioports(void); -static struct fs_mii_bus_info fec_mii_bus_info = { - .method = fsmii_fec, - .id = 0, -}; - -static struct fs_mii_bus_info scc_mii_bus_info = { - .method = fsmii_fixed, - .id = 0, - .i.fixed.speed = 10, - .i.fixed.duplex = 0, -}; +static struct fs_mii_fec_platform_info mpc8xx_mdio_fec_pdata; -static struct fs_platform_info mpc8xx_fec_pdata[] = { - { - .rx_ring = 128, - .tx_ring = 16, - .rx_copybreak = 240, - - .use_napi = 1, - .napi_weight = 17, +static struct fs_mii_fec_platform_info mpc8xx_mdio_fec_pdata; - .phy_addr = 15, - .phy_irq = -1, +static struct fs_platform_info mpc8xx_enet_pdata[] = { + [fsid_fec1] = { + .rx_ring = 128, + .tx_ring = 16, + .rx_copybreak = 240, - .use_rmii = 0, + .use_napi = 1, + .napi_weight = 17, - .bus_info = &fec_mii_bus_info, - } -}; + .init_ioports = setup_fec1_ioports, -static struct fs_platform_info mpc8xx_scc_pdata = { - .rx_ring = 64, - .tx_ring = 8, - .rx_copybreak = 240, + .bus_id = "0:0f", + .has_phy = 1, + }, + [fsid_scc1] = { + .rx_ring = 64, + .tx_ring = 8, + .rx_copybreak = 240, + .use_napi = 1, + .napi_weight = 17, - .use_napi = 1, - .napi_weight = 17, - .phy_addr = -1, - .phy_irq = -1, - - .bus_info = &scc_mii_bus_info, + .init_ioports = setup_scc1_ioports, + .bus_id = "fixed@100:1", + }, }; static struct fs_uart_platform_info mpc866_uart_pdata[] = { @@ -207,63 +194,6 @@ static void setup_scc1_ioports(void) } -static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no) -{ - struct fs_platform_info *fpi = pdev->dev.platform_data; - - volatile cpm8xx_t *cp; - bd_t *bd = (bd_t *) __res; - char *e; - int i; - - /* Get pointer to Communication Processor */ - cp = cpmp; - switch (fs_no) { - case fsid_fec1: - fpi = &mpc8xx_fec_pdata[0]; - fpi->init_ioports = &setup_fec1_ioports; - - break; - case fsid_scc1: - fpi = &mpc8xx_scc_pdata; - fpi->init_ioports = &setup_scc1_ioports; - - break; - default: - printk(KERN_WARNING"Device %s is not supported!\n", pdev->name); - return; - } - - pdev->dev.platform_data = fpi; - fpi->fs_no = fs_no; - - e = (unsigned char *)&bd->bi_enetaddr; - for (i = 0; i < 6; i++) - fpi->macaddr[i] = *e++; - - fpi->macaddr[5 - pdev->id]++; - -} - -static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev, - int idx) -{ - /* This is for FEC devices only */ - if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec"))) - return; - mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1); -} - -static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev, - int idx) -{ - /* This is for SCC devices only */ - if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc"))) - return; - - mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1); -} - static void setup_smc1_ioports(void) { immap_t *immap = (immap_t *) IMAP_ADDR; @@ -315,6 +245,56 @@ static void setup_smc2_ioports(void) } +static int ma_count = 0; + +static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no) +{ + struct fs_platform_info *fpi; + + volatile cpm8xx_t *cp; + bd_t *bd = (bd_t *) __res; + char *e; + int i; + + /* Get pointer to Communication Processor */ + cp = cpmp; + + if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) { + printk(KERN_ERR"No network-suitable #%d device on bus", fs_no); + return; + } + + + fpi = &mpc8xx_enet_pdata[fs_no]; + fpi->fs_no = fs_no; + pdev->dev.platform_data = fpi; + + e = (unsigned char *)&bd->bi_enetaddr; + for (i = 0; i < 6; i++) + fpi->macaddr[i] = *e++; + + fpi->macaddr[5] += ma_count++; +} + +static void mpc866ads_fixup_fec_enet_pdata(struct platform_device *pdev, + int idx) +{ + /* This is for FEC devices only */ + if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-fec"))) + return; + mpc866ads_fixup_enet_pdata(pdev, fsid_fec1 + pdev->id - 1); +} + +static void mpc866ads_fixup_scc_enet_pdata(struct platform_device *pdev, + int idx) +{ + /* This is for SCC devices only */ + if (!pdev || !pdev->name || (!strstr(pdev->name, "fsl-cpm-scc"))) + return; + + mpc866ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1); +} + static void __init mpc866ads_fixup_uart_pdata(struct platform_device *pdev, int idx) { @@ -359,6 +339,9 @@ static int mpc866ads_platform_notify(str int __init mpc866ads_init(void) { + bd_t *bd = (bd_t *) __res; + struct fs_mii_fec_platform_info* fmpi; + printk(KERN_NOTICE "mpc866ads: Init\n"); platform_notify = mpc866ads_platform_notify; @@ -366,11 +349,20 @@ int __init mpc866ads_init(void) ppc_sys_device_initfunc(); ppc_sys_device_disable_all(); -#ifdef MPC8xx_SECOND_ETH_SCC1 +#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC1 ppc_sys_device_enable(MPC8xx_CPM_SCC1); #endif ppc_sys_device_enable(MPC8xx_CPM_FEC1); + ppc_sys_device_enable(MPC8xx_MDIO_FEC); + + fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data = + &mpc8xx_mdio_fec_pdata; + + fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; + /* No PHY interrupt line here */ + fmpi->irq[0xf] = -1; + /* Since either of the uarts could be used as console, they need to ready */ #ifdef CONFIG_SERIAL_CPM_SMC1 ppc_sys_device_enable(MPC8xx_CPM_SMC1); @@ -381,6 +373,14 @@ int __init mpc866ads_init(void) ppc_sys_device_enable(MPC8xx_CPM_SMC2); ppc_sys_device_setfunc(MPC8xx_CPM_SMC2, PPC_SYS_FUNC_UART); #endif + ppc_sys_device_enable(MPC8xx_MDIO_FEC); + + fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data = + &mpc8xx_mdio_fec_pdata; + + fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; + /* No PHY interrupt line here */ + fmpi->irq[0xf] = -1; return 0; } diff -puN arch/ppc/platforms/mpc885ads_setup.c~git-netdev-all arch/ppc/platforms/mpc885ads_setup.c --- a/arch/ppc/platforms/mpc885ads_setup.c~git-netdev-all +++ a/arch/ppc/platforms/mpc885ads_setup.c @@ -38,7 +38,10 @@ extern unsigned char __res[]; static void setup_smc1_ioports(void); static void setup_smc2_ioports(void); -static void __init mpc885ads_scc_phy_init(char); +static struct fs_mii_fec_platform_info mpc8xx_mdio_fec_pdata; +static void setup_fec1_ioports(void); +static void setup_fec2_ioports(void); +static void setup_scc3_ioports(void); static struct fs_uart_platform_info mpc885_uart_pdata[] = { [fsid_smc1_uart] = { @@ -61,23 +64,8 @@ static struct fs_uart_platform_info mpc8 }, }; -static struct fs_mii_bus_info fec_mii_bus_info = { - .method = fsmii_fec, - .id = 0, -}; - -static struct fs_mii_bus_info scc_mii_bus_info = { -#ifdef CONFIG_SCC_ENET_8xx_FIXED - .method = fsmii_fixed, -#else - .method = fsmii_fec, -#endif - - .id = 0, -}; - -static struct fs_platform_info mpc8xx_fec_pdata[] = { - { +static struct fs_platform_info mpc8xx_enet_pdata[] = { + [fsid_fec1] = { .rx_ring = 128, .tx_ring = 16, .rx_copybreak = 240, @@ -85,11 +73,12 @@ static struct fs_platform_info mpc8xx_fe .use_napi = 1, .napi_weight = 17, - .phy_addr = 0, - .phy_irq = SIU_IRQ7, + .init_ioports = setup_fec1_ioports, - .bus_info = &fec_mii_bus_info, - }, { + .bus_id = "0:00", + .has_phy = 1, + }, + [fsid_fec2] = { .rx_ring = 128, .tx_ring = 16, .rx_copybreak = 240, @@ -97,35 +86,32 @@ static struct fs_platform_info mpc8xx_fe .use_napi = 1, .napi_weight = 17, - .phy_addr = 1, - .phy_irq = SIU_IRQ7, - - .bus_info = &fec_mii_bus_info, - } -}; + .init_ioports = setup_fec2_ioports, -static struct fs_platform_info mpc8xx_scc_pdata = { - .rx_ring = 64, - .tx_ring = 8, - .rx_copybreak = 240, - - .use_napi = 1, - .napi_weight = 17, - - .phy_addr = 2, -#ifdef CONFIG_MPC8xx_SCC_ENET_FIXED - .phy_irq = -1, + .bus_id = "0:01", + .has_phy = 1, + }, + [fsid_scc3] = { + .rx_ring = 64, + .tx_ring = 8, + .rx_copybreak = 240, + + .use_napi = 1, + .napi_weight = 17, + + .init_ioports = setup_scc3_ioports, +#ifdef CONFIG_FIXED_MII_10_FDX + .bus_id = "fixed@100:1", #else - .phy_irq = SIU_IRQ7, -#endif - - .bus_info = &scc_mii_bus_info, + .bus_id = "0:02", + #endif + }, }; void __init board_init(void) { - volatile cpm8xx_t *cp = cpmp; - unsigned int *bcsr_io; + cpm8xx_t *cp = cpmp; + unsigned int *bcsr_io; #ifdef CONFIG_FS_ENET immap_t *immap = (immap_t *) IMAP_ADDR; @@ -164,6 +150,14 @@ void __init board_init(void) /* use MDC for MII (common) */ setbits16(&immap->im_ioport.iop_pdpar, 0x0080); clrbits16(&immap->im_ioport.iop_pddir, 0x0080); + bcsr_io = ioremap(BCSR5, sizeof(unsigned long)); + clrbits32(bcsr_io,BCSR5_MII1_EN); + clrbits32(bcsr_io,BCSR5_MII1_RST); +#ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 + clrbits32(bcsr_io,BCSR5_MII2_EN); + clrbits32(bcsr_io,BCSR5_MII2_RST); +#endif + iounmap(bcsr_io); #endif } @@ -194,8 +188,8 @@ static void setup_fec2_ioports(void) /* configure FEC2 pins */ setbits32(&immap->im_cpm.cp_pepar, 0x0003fffc); setbits32(&immap->im_cpm.cp_pedir, 0x0003fffc); - setbits32(&immap->im_cpm.cp_peso, 0x00037800); clrbits32(&immap->im_cpm.cp_peso, 0x000087fc); + setbits32(&immap->im_cpm.cp_peso, 0x00037800); clrbits32(&immap->im_cpm.cp_cptr, 0x00000080); } @@ -213,6 +207,8 @@ static void setup_scc3_ioports(void) /* Enable the PHY. */ + clrbits32(bcsr_io+4, BCSR4_ETH10_RST); + udelay(1000); setbits32(bcsr_io+4, BCSR4_ETH10_RST); /* Configure port A pins for Txd and Rxd. */ @@ -254,37 +250,38 @@ static void setup_scc3_ioports(void) clrbits32(&immap->im_cpm.cp_pedir, PE_ENET_TENA); setbits32(&immap->im_cpm.cp_peso, PE_ENET_TENA); - setbits32(bcsr_io+1, BCSR1_ETHEN); + setbits32(bcsr_io+4, BCSR1_ETHEN); iounmap(bcsr_io); } +static int mac_count = 0; + static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no) { - struct fs_platform_info *fpi = pdev->dev.platform_data; - - volatile cpm8xx_t *cp; + struct fs_platform_info *fpi; bd_t *bd = (bd_t *) __res; char *e; int i; - /* Get pointer to Communication Processor */ - cp = cpmp; + if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) { + printk(KERN_ERR"No network-suitable #%d device on bus", fs_no); + return; + } + + fpi = &mpc8xx_enet_pdata[fs_no]; + switch (fs_no) { case fsid_fec1: - fpi = &mpc8xx_fec_pdata[0]; fpi->init_ioports = &setup_fec1_ioports; break; case fsid_fec2: - fpi = &mpc8xx_fec_pdata[1]; fpi->init_ioports = &setup_fec2_ioports; break; case fsid_scc3: - fpi = &mpc8xx_scc_pdata; fpi->init_ioports = &setup_scc3_ioports; - mpc885ads_scc_phy_init(fpi->phy_addr); break; default: - printk(KERN_WARNING"Device %s is not supported!\n", pdev->name); + printk(KERN_WARNING "Device %s is not supported!\n", pdev->name); return; } @@ -295,7 +292,7 @@ static void mpc885ads_fixup_enet_pdata(s for (i = 0; i < 6; i++) fpi->macaddr[i] = *e++; - fpi->macaddr[5 - pdev->id]++; + fpi->macaddr[5] += mac_count++; } @@ -318,58 +315,6 @@ static void __init mpc885ads_fixup_scc_e mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1); } -/* SCC ethernet controller does not have MII management channel. FEC1 MII - * channel is used to communicate with the 10Mbit PHY. - */ - -#define MII_ECNTRL_PINMUX 0x4 -#define FEC_ECNTRL_PINMUX 0x00000004 -#define FEC_RCNTRL_MII_MODE 0x00000004 - -/* Make MII read/write commands. - */ -#define mk_mii_write(REG, VAL, PHY_ADDR) (0x50020000 | (((REG) & 0x1f) << 18) | \ - ((VAL) & 0xffff) | ((PHY_ADDR) << 23)) - -static void mpc885ads_scc_phy_init(char phy_addr) -{ - volatile immap_t *immap; - volatile fec_t *fecp; - bd_t *bd; - - bd = (bd_t *) __res; - immap = (immap_t *) IMAP_ADDR; /* pointer to internal registers */ - fecp = &(immap->im_cpm.cp_fec); - - /* Enable MII pins of the FEC1 - */ - setbits16(&immap->im_ioport.iop_pdpar, 0x0080); - clrbits16(&immap->im_ioport.iop_pddir, 0x0080); - /* Set MII speed to 2.5 MHz - */ - out_be32(&fecp->fec_mii_speed, - ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1); - - /* Enable FEC pin MUX - */ - setbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX); - setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); - - out_be32(&fecp->fec_mii_data, - mk_mii_write(MII_BMCR, BMCR_ISOLATE, phy_addr)); - udelay(100); - out_be32(&fecp->fec_mii_data, - mk_mii_write(MII_ADVERTISE, - ADVERTISE_10HALF | ADVERTISE_CSMA, phy_addr)); - udelay(100); - - /* Disable FEC MII settings - */ - clrbits32(&fecp->fec_ecntrl, MII_ECNTRL_PINMUX); - clrbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); - out_be32(&fecp->fec_mii_speed, 0); -} - static void setup_smc1_ioports(void) { immap_t *immap = (immap_t *) IMAP_ADDR; @@ -462,6 +407,9 @@ static int mpc885ads_platform_notify(str int __init mpc885ads_init(void) { + struct fs_mii_fec_platform_info* fmpi; + bd_t *bd = (bd_t *) __res; + printk(KERN_NOTICE "mpc885ads: Init\n"); platform_notify = mpc885ads_platform_notify; @@ -471,8 +419,17 @@ int __init mpc885ads_init(void) ppc_sys_device_enable(MPC8xx_CPM_FEC1); + ppc_sys_device_enable(MPC8xx_MDIO_FEC); + fmpi = ppc_sys_platform_devices[MPC8xx_MDIO_FEC].dev.platform_data = + &mpc8xx_mdio_fec_pdata; + + fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; + + /* No PHY interrupt line here */ + fmpi->irq[0xf] = SIU_IRQ7; + #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 - ppc_sys_device_enable(MPC8xx_CPM_SCC1); + ppc_sys_device_enable(MPC8xx_CPM_SCC3); #endif #ifdef CONFIG_MPC8xx_SECOND_ETH_FEC2 diff -puN arch/ppc/platforms/pq2ads_pd.h~git-netdev-all arch/ppc/platforms/pq2ads_pd.h --- a/arch/ppc/platforms/pq2ads_pd.h~git-netdev-all +++ a/arch/ppc/platforms/pq2ads_pd.h @@ -29,86 +29,4 @@ #define F3_RXCLK 13 #define F3_TXCLK 14 -/* Automatically generates register configurations */ -#define PC_CLK(x) ((uint)(1<<(x-1))) /* FCC CLK I/O ports */ - -#define CMXFCR_RF1CS(x) ((uint)((x-5)<<27)) /* FCC1 Receive Clock Source */ -#define CMXFCR_TF1CS(x) ((uint)((x-5)<<24)) /* FCC1 Transmit Clock Source */ -#define CMXFCR_RF2CS(x) ((uint)((x-9)<<19)) /* FCC2 Receive Clock Source */ -#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16)) /* FCC2 Transmit Clock Source */ -#define CMXFCR_RF3CS(x) ((uint)((x-9)<<11)) /* FCC3 Receive Clock Source */ -#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8)) /* FCC3 Transmit Clock Source */ - -#define PC_F1RXCLK PC_CLK(F1_RXCLK) -#define PC_F1TXCLK PC_CLK(F1_TXCLK) -#define CMX1_CLK_ROUTE (CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK)) -#define CMX1_CLK_MASK ((uint)0xff000000) - -#define PC_F2RXCLK PC_CLK(F2_RXCLK) -#define PC_F2TXCLK PC_CLK(F2_TXCLK) -#define CMX2_CLK_ROUTE (CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK)) -#define CMX2_CLK_MASK ((uint)0x00ff0000) - -#define PC_F3RXCLK PC_CLK(F3_RXCLK) -#define PC_F3TXCLK PC_CLK(F3_TXCLK) -#define CMX3_CLK_ROUTE (CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK)) -#define CMX3_CLK_MASK ((uint)0x0000ff00) - -/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PA1_COL 0x00000001U -#define PA1_CRS 0x00000002U -#define PA1_TXER 0x00000004U -#define PA1_TXEN 0x00000008U -#define PA1_RXDV 0x00000010U -#define PA1_RXER 0x00000020U -#define PA1_TXDAT 0x00003c00U -#define PA1_RXDAT 0x0003c000U -#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) -#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ - PA1_RXDV | PA1_RXER) -#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) -#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) - - -/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PB2_TXER 0x00000001U -#define PB2_RXDV 0x00000002U -#define PB2_TXEN 0x00000004U -#define PB2_RXER 0x00000008U -#define PB2_COL 0x00000010U -#define PB2_CRS 0x00000020U -#define PB2_TXDAT 0x000003c0U -#define PB2_RXDAT 0x00003c00U -#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ - PB2_RXER | PB2_RXDV | PB2_TXER) -#define PB2_PSORB1 (PB2_TXEN) -#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) -#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) - - -/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PB3_RXDV 0x00004000U -#define PB3_RXER 0x00008000U -#define PB3_TXER 0x00010000U -#define PB3_TXEN 0x00020000U -#define PB3_COL 0x00040000U -#define PB3_CRS 0x00080000U -#define PB3_TXDAT 0x0f000000U -#define PB3_RXDAT 0x00f00000U -#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ - PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) -#define PB3_PSORB1 0 -#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) -#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) - -#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128)) -#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0) -#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) - #endif diff -puN arch/ppc/syslib/mpc85xx_devices.c~git-netdev-all arch/ppc/syslib/mpc85xx_devices.c --- a/arch/ppc/syslib/mpc85xx_devices.c~git-netdev-all +++ a/arch/ppc/syslib/mpc85xx_devices.c @@ -16,9 +16,11 @@ #include #include #include +#include #include #include #include +#include /* We use offsets for IORESOURCE_MEM since we do not know at compile time * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup @@ -82,6 +84,60 @@ static struct fsl_i2c_platform_data mpc8 .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR, }; +static struct fs_platform_info mpc85xx_fcc1_pdata = { + .fs_no = fsid_fcc1, + .cp_page = CPM_CR_FCC1_PAGE, + .cp_block = CPM_CR_FCC1_SBLOCK, + + .rx_ring = 32, + .tx_ring = 32, + .rx_copybreak = 240, + .use_napi = 0, + .napi_weight = 17, + + .clk_mask = CMX1_CLK_MASK, + .clk_route = CMX1_CLK_ROUTE, + .clk_trx = (PC_F1RXCLK | PC_F1TXCLK), + + .mem_offset = FCC1_MEM_OFFSET, +}; + +static struct fs_platform_info mpc85xx_fcc2_pdata = { + .fs_no = fsid_fcc2, + .cp_page = CPM_CR_FCC2_PAGE, + .cp_block = CPM_CR_FCC2_SBLOCK, + + .rx_ring = 32, + .tx_ring = 32, + .rx_copybreak = 240, + .use_napi = 0, + .napi_weight = 17, + + .clk_mask = CMX2_CLK_MASK, + .clk_route = CMX2_CLK_ROUTE, + .clk_trx = (PC_F2RXCLK | PC_F2TXCLK), + + .mem_offset = FCC2_MEM_OFFSET, +}; + +static struct fs_platform_info mpc85xx_fcc3_pdata = { + .fs_no = fsid_fcc3, + .cp_page = CPM_CR_FCC3_PAGE, + .cp_block = CPM_CR_FCC3_SBLOCK, + + .rx_ring = 32, + .tx_ring = 32, + .rx_copybreak = 240, + .use_napi = 0, + .napi_weight = 17, + + .clk_mask = CMX3_CLK_MASK, + .clk_route = CMX3_CLK_ROUTE, + .clk_trx = (PC_F3RXCLK | PC_F3TXCLK), + + .mem_offset = FCC3_MEM_OFFSET, +}; + static struct plat_serial8250_port serial_platform_data[] = { [0] = { .mapbase = 0x4500, @@ -318,19 +374,28 @@ struct platform_device ppc_sys_platform_ [MPC85xx_CPM_FCC1] = { .name = "fsl-cpm-fcc", .id = 1, - .num_resources = 3, + .num_resources = 4, + .dev.platform_data = &mpc85xx_fcc1_pdata, .resource = (struct resource[]) { { + .name = "fcc_regs", .start = 0x91300, .end = 0x9131F, .flags = IORESOURCE_MEM, }, { + .name = "fcc_regs_c", .start = 0x91380, .end = 0x9139F, .flags = IORESOURCE_MEM, }, { + .name = "fcc_pram", + .start = 0x88400, + .end = 0x884ff, + .flags = IORESOURCE_MEM, + }, + { .start = SIU_INT_FCC1, .end = SIU_INT_FCC1, .flags = IORESOURCE_IRQ, @@ -340,19 +405,28 @@ struct platform_device ppc_sys_platform_ [MPC85xx_CPM_FCC2] = { .name = "fsl-cpm-fcc", .id = 2, - .num_resources = 3, + .num_resources = 4, + .dev.platform_data = &mpc85xx_fcc2_pdata, .resource = (struct resource[]) { { + .name = "fcc_regs", .start = 0x91320, .end = 0x9133F, .flags = IORESOURCE_MEM, }, { + .name = "fcc_regs_c", .start = 0x913A0, .end = 0x913CF, .flags = IORESOURCE_MEM, }, { + .name = "fcc_pram", + .start = 0x88500, + .end = 0x885ff, + .flags = IORESOURCE_MEM, + }, + { .start = SIU_INT_FCC2, .end = SIU_INT_FCC2, .flags = IORESOURCE_IRQ, @@ -362,19 +436,28 @@ struct platform_device ppc_sys_platform_ [MPC85xx_CPM_FCC3] = { .name = "fsl-cpm-fcc", .id = 3, - .num_resources = 3, + .num_resources = 4, + .dev.platform_data = &mpc85xx_fcc3_pdata, .resource = (struct resource[]) { { + .name = "fcc_regs", .start = 0x91340, .end = 0x9135F, .flags = IORESOURCE_MEM, }, { + .name = "fcc_regs_c", .start = 0x913D0, .end = 0x913FF, .flags = IORESOURCE_MEM, }, { + .name = "fcc_pram", + .start = 0x88600, + .end = 0x886ff, + .flags = IORESOURCE_MEM, + }, + { .start = SIU_INT_FCC3, .end = SIU_INT_FCC3, .flags = IORESOURCE_IRQ, diff -puN arch/ppc/syslib/mpc8xx_devices.c~git-netdev-all arch/ppc/syslib/mpc8xx_devices.c --- a/arch/ppc/syslib/mpc8xx_devices.c~git-netdev-all +++ a/arch/ppc/syslib/mpc8xx_devices.c @@ -218,6 +218,14 @@ struct platform_device ppc_sys_platform_ }, }, }, + + [MPC8xx_MDIO_FEC] = { + .name = "fsl-cpm-fec-mdio", + .id = 0, + .num_resources = 0, + + }, + }; static int __init mach_mpc8xx_fixup(struct platform_device *pdev) diff -puN arch/ppc/syslib/mpc8xx_sys.c~git-netdev-all arch/ppc/syslib/mpc8xx_sys.c --- a/arch/ppc/syslib/mpc8xx_sys.c~git-netdev-all +++ a/arch/ppc/syslib/mpc8xx_sys.c @@ -22,7 +22,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "MPC86X", .mask = 0xFFFFFFFF, .value = 0x00000000, - .num_devices = 7, + .num_devices = 8, .device_list = (enum ppc_sys_devices[]) { MPC8xx_CPM_FEC1, @@ -32,13 +32,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC8xx_CPM_SCC4, MPC8xx_CPM_SMC1, MPC8xx_CPM_SMC2, + MPC8xx_MDIO_FEC, }, }, { .ppc_sys_name = "MPC885", .mask = 0xFFFFFFFF, .value = 0x00000000, - .num_devices = 8, + .num_devices = 9, .device_list = (enum ppc_sys_devices[]) { MPC8xx_CPM_FEC1, @@ -49,6 +50,7 @@ struct ppc_sys_spec ppc_sys_specs[] = { MPC8xx_CPM_SCC4, MPC8xx_CPM_SMC1, MPC8xx_CPM_SMC2, + MPC8xx_MDIO_FEC, }, }, { /* default match */ diff -puN arch/ppc/syslib/pq2_devices.c~git-netdev-all arch/ppc/syslib/pq2_devices.c --- a/arch/ppc/syslib/pq2_devices.c~git-netdev-all +++ a/arch/ppc/syslib/pq2_devices.c @@ -369,6 +369,11 @@ struct platform_device ppc_sys_platform_ }, }, }, + [MPC82xx_MDIO_BB] = { + .name = "fsl-bb-mdio", + .id = 0, + .num_resources = 0, + }, }; static int __init mach_mpc82xx_fixup(struct platform_device *pdev) diff -puN arch/ppc/syslib/pq2_sys.c~git-netdev-all arch/ppc/syslib/pq2_sys.c --- a/arch/ppc/syslib/pq2_sys.c~git-netdev-all +++ a/arch/ppc/syslib/pq2_sys.c @@ -139,13 +139,14 @@ struct ppc_sys_spec ppc_sys_specs[] = { .ppc_sys_name = "8272", .mask = 0x0000ff00, .value = 0x00000c00, - .num_devices = 12, + .num_devices = 13, .device_list = (enum ppc_sys_devices[]) { MPC82xx_CPM_FCC1, MPC82xx_CPM_FCC2, MPC82xx_CPM_SCC1, MPC82xx_CPM_SCC2, MPC82xx_CPM_SCC3, MPC82xx_CPM_SCC4, MPC82xx_CPM_SMC1, MPC82xx_CPM_SMC2, MPC82xx_CPM_SPI, MPC82xx_CPM_I2C, MPC82xx_CPM_USB, MPC82xx_SEC1, + MPC82xx_MDIO_BB, }, }, /* below is a list of the 8280 family of processors */ diff -puN drivers/isdn/i4l/Kconfig~git-netdev-all drivers/isdn/i4l/Kconfig --- a/drivers/isdn/i4l/Kconfig~git-netdev-all +++ a/drivers/isdn/i4l/Kconfig @@ -5,6 +5,7 @@ config ISDN_PPP bool "Support synchronous PPP" depends on INET + select SLHC help Over digital connections such as ISDN, there is no need to synchronize sender and recipient's clocks with start and stop bits diff -puN drivers/net/3c501.c~git-netdev-all drivers/net/3c501.c --- a/drivers/net/3c501.c~git-netdev-all +++ a/drivers/net/3c501.c @@ -120,7 +120,6 @@ static const char version[] = #include #include #include -#include /* for CONFIG_IP_MULTICAST */ #include #include #include diff -puN drivers/net/3c515.c~git-netdev-all drivers/net/3c515.c --- a/drivers/net/3c515.c~git-netdev-all +++ a/drivers/net/3c515.c @@ -1003,7 +1003,8 @@ static int corkscrew_start_xmit(struct s /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry; - unsigned long flags, i; + unsigned long flags; + int i; if (vp->tx_full) /* No room to transmit with */ return 1; diff -puN drivers/net/3c59x.c~git-netdev-all drivers/net/3c59x.c --- a/drivers/net/3c59x.c~git-netdev-all +++ a/drivers/net/3c59x.c @@ -3169,7 +3169,7 @@ static int __init vortex_init(void) { int pci_rc, eisa_rc; - pci_rc = pci_module_init(&vortex_driver); + pci_rc = pci_register_driver(&vortex_driver); eisa_rc = vortex_eisa_init(); if (pci_rc == 0) diff -puN drivers/net/8139cp.c~git-netdev-all drivers/net/8139cp.c --- a/drivers/net/8139cp.c~git-netdev-all +++ a/drivers/net/8139cp.c @@ -2098,7 +2098,7 @@ static int __init cp_init (void) #ifdef MODULE printk("%s", version); #endif - return pci_module_init (&cp_driver); + return pci_register_driver(&cp_driver); } static void __exit cp_exit (void) diff -puN drivers/net/8139too.c~git-netdev-all drivers/net/8139too.c --- a/drivers/net/8139too.c~git-netdev-all +++ a/drivers/net/8139too.c @@ -2629,7 +2629,7 @@ static int __init rtl8139_init_module (v printk (KERN_INFO RTL8139_DRIVER_NAME "\n"); #endif - return pci_module_init (&rtl8139_pci_driver); + return pci_register_driver(&rtl8139_pci_driver); } diff -puN drivers/net/82596.c~git-netdev-all drivers/net/82596.c --- a/drivers/net/82596.c~git-netdev-all +++ a/drivers/net/82596.c @@ -899,7 +899,7 @@ memory_squeeze: } -static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) +static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp) { struct i596_cmd *ptr; @@ -932,7 +932,8 @@ static inline void i596_cleanup_cmd(stru lp->scb.cmd = I596_NULL; } -static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr) +static void i596_reset(struct net_device *dev, struct i596_private *lp, + int ioaddr) { unsigned long flags; @@ -1578,7 +1579,7 @@ static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "i82596 debug mask"); -int init_module(void) +int __init init_module(void) { if (debug >= 0) i596_debug = debug; @@ -1588,7 +1589,7 @@ int init_module(void) return 0; } -void cleanup_module(void) +void __exit cleanup_module(void) { unregister_netdev(dev_82596); #ifdef __mc68000__ diff -puN drivers/net/8390.c~git-netdev-all drivers/net/8390.c --- a/drivers/net/8390.c~git-netdev-all +++ a/drivers/net/8390.c @@ -299,7 +299,7 @@ static int ei_start_xmit(struct sk_buff * Slow phase with lock held. */ - disable_irq_nosync(dev->irq); + disable_irq_nosync_lockdep(dev->irq); spin_lock(&ei_local->page_lock); @@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); + enable_irq_lockdep(dev->irq); ei_local->stat.tx_errors++; return 1; } @@ -379,7 +379,7 @@ static int ei_start_xmit(struct sk_buff outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); + enable_irq_lockdep(dev->irq); dev_kfree_skb (skb); ei_local->stat.tx_bytes += send_length; @@ -505,9 +505,9 @@ irqreturn_t ei_interrupt(int irq, void * #ifdef CONFIG_NET_POLL_CONTROLLER void ei_poll(struct net_device *dev) { - disable_irq(dev->irq); + disable_irq_lockdep(dev->irq); ei_interrupt(dev->irq, dev, NULL); - enable_irq(dev->irq); + enable_irq_lockdep(dev->irq); } #endif diff -puN drivers/net/Kconfig~git-netdev-all drivers/net/Kconfig --- a/drivers/net/Kconfig~git-netdev-all +++ a/drivers/net/Kconfig @@ -1411,6 +1411,22 @@ config FORCEDETH . The module will be called forcedeth. +config FORCEDETH_NAPI + bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)" + depends on FORCEDETH && EXPERIMENTAL + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. It is + still somewhat experimental and thus not yet enabled by default. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + + If in doubt, say N. config CS89x0 tristate "CS89x0 support" @@ -1724,6 +1740,20 @@ config VIA_RHINE_MMIO If unsure, say Y. +config VIA_RHINE_NAPI + bool "Use Rx Polling (NAPI)" + depends on VIA_RHINE + help + NAPI is a new driver API designed to reduce CPU and interrupt load + when the driver is receiving lots of packets from the card. + + If your estimated Rx load is 10kpps or more, or if the card will be + deployed on potentially unfriendly networks (e.g. in a firewall), + then say Y here. + + See for more + information. + config LAN_SAA9730 bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)" depends on NET_PCI && EXPERIMENTAL && MIPS @@ -2219,6 +2249,33 @@ config GFAR_NAPI bool "NAPI Support" depends on GIANFAR +config UCC_GETH + tristate "Freescale QE UCC GETH" + depends on QUICC_ENGINE && UCC_FAST + help + This driver supports the Gigabit Ethernet mode of QE UCC. + QE can be found on MPC836x CPUs. + +config UGETH_NAPI + bool "NAPI Support" + depends on UCC_GETH + +config UGETH_MAGIC_PACKET + bool "Magic Packet detection support" + depends on UCC_GETH + +config UGETH_FILTERING + bool "Mac address filtering support" + depends on UCC_GETH + +config UGETH_TX_ON_DEMOND + bool "Transmit on Demond support" + depends on UCC_GETH + +config UGETH_HAS_GIGA + bool + depends on UCC_GETH && MPC836x + config MV643XX_ETH tristate "MV-643XX Ethernet support" depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM @@ -2249,6 +2306,15 @@ config MV643XX_ETH_2 This enables support for Port 2 of the Marvell MV643XX Gigabit Ethernet. +config QLA3XXX + tristate "QLogic QLA3XXX Network Driver Support" + depends on PCI + help + This driver supports QLogic ISP3XXX gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called qla3xxx. + endmenu # @@ -2509,6 +2575,7 @@ config PLIP config PPP tristate "PPP (point-to-point protocol) support" + select SLHC ---help--- PPP (Point to Point Protocol) is a newer and better SLIP. It serves the same purpose: sending Internet traffic over telephone (and other @@ -2689,6 +2756,7 @@ config SLIP config SLIP_COMPRESSED bool "CSLIP compressed headers" depends on SLIP + select SLHC ---help--- This protocol is faster than SLIP because it uses compression on the TCP/IP headers (not on the data itself), but it has to be supported @@ -2701,6 +2769,12 @@ config SLIP_COMPRESSED , explains how to configure CSLIP. This won't enlarge your kernel. +config SLHC + tristate + help + This option enables Van Jacobsen serial line header compression + routines. + config SLIP_SMART bool "Keepalive and linefill" depends on SLIP diff -puN drivers/net/Makefile~git-netdev-all drivers/net/Makefile --- a/drivers/net/Makefile~git-netdev-all +++ a/drivers/net/Makefile @@ -2,10 +2,6 @@ # Makefile for the Linux network (ethercard) device drivers. # -ifeq ($(CONFIG_ISDN_PPP),y) - obj-$(CONFIG_ISDN) += slhc.o -endif - obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ @@ -18,6 +14,9 @@ gianfar_driver-objs := gianfar.o \ gianfar_mii.o \ gianfar_sysfs.o +obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o +ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o + # # link order important here # @@ -110,8 +109,9 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o +obj-$(CONFIG_QLA3XXX) += qla3xxx.o -obj-$(CONFIG_PPP) += ppp_generic.o slhc.o +obj-$(CONFIG_PPP) += ppp_generic.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o @@ -120,9 +120,7 @@ obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o obj-$(CONFIG_PPPOE) += pppox.o pppoe.o obj-$(CONFIG_SLIP) += slip.o -ifeq ($(CONFIG_SLIP_COMPRESSED),y) - obj-$(CONFIG_SLIP) += slhc.o -endif +obj-$(CONFIG_SLHC) += slhc.o obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_IFB) += ifb.o diff -puN drivers/net/ac3200.c~git-netdev-all drivers/net/ac3200.c --- a/drivers/net/ac3200.c~git-netdev-all +++ a/drivers/net/ac3200.c @@ -370,8 +370,7 @@ MODULE_PARM_DESC(mem, "Memory base addre MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver"); MODULE_LICENSE("GPL"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/acenic.c~git-netdev-all drivers/net/acenic.c --- a/drivers/net/acenic.c~git-netdev-all +++ a/drivers/net/acenic.c @@ -725,7 +725,7 @@ static struct pci_driver acenic_pci_driv static int __init acenic_init(void) { - return pci_module_init(&acenic_pci_driver); + return pci_register_driver(&acenic_pci_driver); } static void __exit acenic_exit(void) diff -puN drivers/net/amd8111e.c~git-netdev-all drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c~git-netdev-all +++ a/drivers/net/amd8111e.c @@ -2158,7 +2158,7 @@ static struct pci_driver amd8111e_driver static int __init amd8111e_init(void) { - return pci_module_init(&amd8111e_driver); + return pci_register_driver(&amd8111e_driver); } static void __exit amd8111e_cleanup(void) diff -puN drivers/net/appletalk/cops.c~git-netdev-all drivers/net/appletalk/cops.c --- a/drivers/net/appletalk/cops.c~git-netdev-all +++ a/drivers/net/appletalk/cops.c @@ -1030,7 +1030,7 @@ module_param(io, int, 0); module_param(irq, int, 0); module_param(board_type, int, 0); -int init_module(void) +int __init init_module(void) { if (io == 0) printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", diff -puN drivers/net/arcnet/com20020-pci.c~git-netdev-all drivers/net/arcnet/com20020-pci.c --- a/drivers/net/arcnet/com20020-pci.c~git-netdev-all +++ a/drivers/net/arcnet/com20020-pci.c @@ -177,7 +177,7 @@ static struct pci_driver com20020pci_dri static int __init com20020pci_init(void) { BUGLVL(D_NORMAL) printk(VERSION); - return pci_module_init(&com20020pci_driver); + return pci_register_driver(&com20020pci_driver); } static void __exit com20020pci_cleanup(void) diff -puN drivers/net/at1700.c~git-netdev-all drivers/net/at1700.c --- a/drivers/net/at1700.c~git-netdev-all +++ a/drivers/net/at1700.c @@ -901,7 +901,7 @@ MODULE_PARM_DESC(io, "AT1700/FMV18X I/O MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number"); MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)"); -int init_module(void) +int __init init_module(void) { if (io == 0) printk("at1700: You should not use auto-probing with insmod!\n"); diff -puN drivers/net/b44.c~git-netdev-all drivers/net/b44.c --- a/drivers/net/b44.c~git-netdev-all +++ a/drivers/net/b44.c @@ -2354,7 +2354,7 @@ static int __init b44_init(void) dma_desc_align_mask = ~(dma_desc_align_size - 1); dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); - return pci_module_init(&b44_driver); + return pci_register_driver(&b44_driver); } static void __exit b44_cleanup(void) diff -puN drivers/net/bnx2.c~git-netdev-all drivers/net/bnx2.c --- a/drivers/net/bnx2.c~git-netdev-all +++ a/drivers/net/bnx2.c @@ -6016,7 +6016,7 @@ static struct pci_driver bnx2_pci_driver static int __init bnx2_init(void) { - return pci_module_init(&bnx2_pci_driver); + return pci_register_driver(&bnx2_pci_driver); } static void __exit bnx2_cleanup(void) diff -puN drivers/net/cassini.c~git-netdev-all drivers/net/cassini.c --- a/drivers/net/cassini.c~git-netdev-all +++ a/drivers/net/cassini.c @@ -5245,7 +5245,7 @@ static int __init cas_init(void) else link_transition_timeout = 0; - return pci_module_init(&cas_driver); + return pci_register_driver(&cas_driver); } static void __exit cas_cleanup(void) diff -puN drivers/net/chelsio/cxgb2.c~git-netdev-all drivers/net/chelsio/cxgb2.c --- a/drivers/net/chelsio/cxgb2.c~git-netdev-all +++ a/drivers/net/chelsio/cxgb2.c @@ -1243,7 +1243,7 @@ static struct pci_driver driver = { static int __init t1_init_module(void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit t1_cleanup_module(void) diff -puN drivers/net/cs89x0.c~git-netdev-all drivers/net/cs89x0.c --- a/drivers/net/cs89x0.c~git-netdev-all +++ a/drivers/net/cs89x0.c @@ -1905,8 +1905,7 @@ MODULE_LICENSE("GPL"); */ -int -init_module(void) +int __init init_module(void) { struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); struct net_local *lp; diff -puN drivers/net/defxx.c~git-netdev-all drivers/net/defxx.c --- a/drivers/net/defxx.c~git-netdev-all +++ a/drivers/net/defxx.c @@ -3444,7 +3444,7 @@ static int __init dfx_init(void) { int rc_pci, rc_eisa; - rc_pci = pci_module_init(&dfx_driver); + rc_pci = pci_register_driver(&dfx_driver); if (rc_pci >= 0) dfx_have_pci = 1; rc_eisa = dfx_eisa_init(); diff -puN drivers/net/dl2k.c~git-netdev-all drivers/net/dl2k.c --- a/drivers/net/dl2k.c~git-netdev-all +++ a/drivers/net/dl2k.c @@ -1815,7 +1815,7 @@ static struct pci_driver rio_driver = { static int __init rio_init (void) { - return pci_module_init (&rio_driver); + return pci_register_driver(&rio_driver); } static void __exit diff -puN drivers/net/dm9000.c~git-netdev-all drivers/net/dm9000.c --- a/drivers/net/dm9000.c~git-netdev-all +++ a/drivers/net/dm9000.c @@ -339,6 +339,17 @@ static void dm9000_timeout(struct net_de spin_unlock_irqrestore(&db->lock,flags); } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + *Used by netconsole + */ +static void dm9000_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + dm9000_interrupt(dev->irq,dev,NULL); + enable_irq(dev->irq); +} +#endif /* dm9000_release_board * @@ -538,6 +549,9 @@ dm9000_probe(struct platform_device *pde ndev->stop = &dm9000_stop; ndev->get_stats = &dm9000_get_stats; ndev->set_multicast_list = &dm9000_hash_table; +#ifdef CONFIG_NET_POLL_CONTROLLER + ndev->poll_controller = &dm9000_poll_controller; +#endif #ifdef DM9000_PROGRAM_EEPROM program_eeprom(db); diff -puN drivers/net/e100.c~git-netdev-all drivers/net/e100.c --- a/drivers/net/e100.c~git-netdev-all +++ a/drivers/net/e100.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -158,10 +158,10 @@ #define DRV_NAME "e100" -#define DRV_EXT "-NAPI" -#define DRV_VERSION "3.5.10-k2"DRV_EXT +#define DRV_EXT "-NAPI" +#define DRV_VERSION "3.5.10-k4"DRV_EXT #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" #define PFX DRV_NAME ": " #define E100_WATCHDOG_PERIOD (2 * HZ) @@ -279,12 +279,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, @@ -526,7 +520,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; @@ -947,7 +940,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); @@ -1391,15 +1384,11 @@ static int e100_phy_init(struct nic *nic } if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) && - (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) { - /* enable/disable MDI/MDI-X auto-switching. - MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */ - if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) || - (nic->mac == mac_82551_10) || (nic->mii.force_media) || - !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled)) - mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0); - else - mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH); + (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) && + !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) { + /* enable/disable MDI/MDI-X auto-switching. */ + mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, + nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH); } return 0; @@ -1745,19 +1734,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 +1768,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 +1806,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 +1836,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 +1855,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 +1876,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 = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC))) return -ENOMEM; @@ -1944,7 +1891,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; } @@ -1964,10 +1910,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); @@ -2061,7 +2003,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))) @@ -2141,7 +2083,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 = dev_alloc_skb(ETH_DATA_LEN))) { err = -ENOMEM; @@ -2873,7 +2815,7 @@ static int __init e100_init_module(void) printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); } - return pci_module_init(&e100_driver); + return pci_register_driver(&e100_driver); } static void __exit e100_cleanup_module(void) diff -puN drivers/net/e1000/e1000_ethtool.c~git-netdev-all drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c~git-netdev-all +++ a/drivers/net/e1000/e1000_ethtool.c @@ -183,6 +183,9 @@ e1000_set_settings(struct net_device *ne return -EINVAL; } + while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) + msleep(1); + if (ecmd->autoneg == AUTONEG_ENABLE) { hw->autoneg = 1; if (hw->media_type == e1000_media_type_fiber) @@ -199,16 +202,20 @@ e1000_set_settings(struct net_device *ne ADVERTISED_TP; ecmd->advertising = hw->autoneg_advertised; } else - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) + if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + clear_bit(__E1000_RESETTING, &adapter->flags); return -EINVAL; + } /* reset the link */ - if (netif_running(adapter->netdev)) - e1000_reinit_locked(adapter); - else + if (netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else e1000_reset(adapter); + clear_bit(__E1000_RESETTING, &adapter->flags); return 0; } @@ -238,9 +245,13 @@ e1000_set_pauseparam(struct net_device * { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + int retval = 0; adapter->fc_autoneg = pause->autoneg; + while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) + msleep(1); + if (pause->rx_pause && pause->tx_pause) hw->fc = e1000_fc_full; else if (pause->rx_pause && !pause->tx_pause) @@ -253,15 +264,17 @@ e1000_set_pauseparam(struct net_device * hw->original_fc = hw->fc; if (adapter->fc_autoneg == AUTONEG_ENABLE) { - if (netif_running(adapter->netdev)) - e1000_reinit_locked(adapter); - else + if (netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else e1000_reset(adapter); } else - return ((hw->media_type == e1000_media_type_fiber) ? - e1000_setup_link(hw) : e1000_force_mac_fc(hw)); + retval = ((hw->media_type == e1000_media_type_fiber) ? + e1000_setup_link(hw) : e1000_force_mac_fc(hw)); - return 0; + clear_bit(__E1000_RESETTING, &adapter->flags); + return retval; } static uint32_t @@ -1590,6 +1603,8 @@ e1000_diag_test_count(struct net_device return E1000_TEST_LEN; } +extern void e1000_power_up_phy(struct e1000_adapter *); + static void e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data) @@ -1606,6 +1621,8 @@ e1000_diag_test(struct net_device *netde uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; + DPRINTK(HW, INFO, "offline testing starting\n"); + /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ if (e1000_link_test(adapter, &data[4])) @@ -1629,6 +1646,8 @@ e1000_diag_test(struct net_device *netde eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); + /* make sure the phy is powered up */ + e1000_power_up_phy(adapter); if (e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -1642,6 +1661,7 @@ e1000_diag_test(struct net_device *netde if (if_running) dev_open(netdev); } else { + DPRINTK(HW, INFO, "online testing starting\n"); /* Online tests */ if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; diff -puN drivers/net/e1000/e1000_hw.c~git-netdev-all drivers/net/e1000/e1000_hw.c --- a/drivers/net/e1000/e1000_hw.c~git-netdev-all +++ a/drivers/net/e1000/e1000_hw.c @@ -105,6 +105,33 @@ static int32_t e1000_configure_kmrn_for_ uint16_t duplex); static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw); +static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, + uint32_t segment); +static int32_t e1000_get_software_flag(struct e1000_hw *hw); +static int32_t e1000_get_software_semaphore(struct e1000_hw *hw); +static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw); +static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw); +static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t* data); +static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, + uint16_t *data); +static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, + uint16_t *data); +static void e1000_release_software_flag(struct e1000_hw *hw); +static void e1000_release_software_semaphore(struct e1000_hw *hw); +static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, + uint32_t no_snoop); +static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, + uint32_t index, uint8_t byte); +static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t data); +static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, + uint16_t data); + /* IGP cable length table */ static const uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = @@ -718,6 +745,17 @@ e1000_init_hw(struct e1000_hw *hw) DEBUGFUNC("e1000_init_hw"); + /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */ + if (hw->mac_type == e1000_ich8lan) { + reg_data = E1000_READ_REG(hw, TARC0); + reg_data |= 0x30000000; + E1000_WRITE_REG(hw, TARC0, reg_data); + + reg_data = E1000_READ_REG(hw, STATUS); + reg_data &= ~0x80000000; + E1000_WRITE_REG(hw, STATUS, reg_data); + } + /* Initialize Identification LED */ ret_val = e1000_id_led_init(hw); if(ret_val) { @@ -1324,11 +1362,14 @@ e1000_copper_link_igp_setup(struct e1000 E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } - /* disable lplu d3 during driver init */ - ret_val = e1000_set_d3_lplu_state(hw, FALSE); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - return ret_val; + /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */ + if (hw->phy_type == e1000_phy_igp) { + /* disable lplu d3 during driver init */ + ret_val = e1000_set_d3_lplu_state(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D3\n"); + return ret_val; + } } /* disable lplu d0 during driver init */ @@ -3233,7 +3274,7 @@ e1000_shift_in_mdi_bits(struct e1000_hw return data; } -int32_t +static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) { uint32_t swfw_sync = 0; @@ -3277,7 +3318,7 @@ e1000_swfw_sync_acquire(struct e1000_hw return E1000_SUCCESS; } -void +static void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) { uint32_t swfw_sync; @@ -3575,7 +3616,7 @@ e1000_write_phy_reg_ex(struct e1000_hw * return E1000_SUCCESS; } -int32_t +static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data) @@ -3608,7 +3649,7 @@ e1000_read_kmrn_reg(struct e1000_hw *hw, return E1000_SUCCESS; } -int32_t +static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data) @@ -3839,7 +3880,7 @@ e1000_phy_powerdown_workaround(struct e1 * * hw - struct containing variables accessed by shared code ******************************************************************************/ -int32_t +static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw) { int32_t ret_val; @@ -4086,7 +4127,7 @@ e1000_phy_igp_get_info(struct e1000_hw * * hw - Struct containing variables accessed by shared code * phy_info - PHY information structure ******************************************************************************/ -int32_t +static int32_t e1000_phy_ife_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) { @@ -5643,6 +5684,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * for the first 15 multicast addresses, and hashes the rest into the * multicast table. *****************************************************************************/ +#if 0 void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, @@ -5719,6 +5761,7 @@ e1000_mc_addr_list_update(struct e1000_h } DEBUGOUT("MC Update Complete\n"); } +#endif /* 0 */ /****************************************************************************** * Hashes an address to determine its location in the multicast table @@ -6587,6 +6630,7 @@ e1000_get_bus_info(struct e1000_hw *hw) * hw - Struct containing variables accessed by shared code * offset - offset to read from *****************************************************************************/ +#if 0 uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) @@ -6597,6 +6641,7 @@ e1000_read_reg_io(struct e1000_hw *hw, e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); } +#endif /* 0 */ /****************************************************************************** * Writes a value to one of the devices registers using port I/O (as opposed to @@ -7909,6 +7954,7 @@ e1000_set_pci_express_master_disable(str * returns: - none. * ***************************************************************************/ +#if 0 void e1000_enable_pciex_master(struct e1000_hw *hw) { @@ -7923,6 +7969,7 @@ e1000_enable_pciex_master(struct e1000_h ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; E1000_WRITE_REG(hw, CTRL, ctrl); } +#endif /* 0 */ /******************************************************************************* * @@ -8148,7 +8195,7 @@ e1000_put_hw_eeprom_semaphore(struct e10 * E1000_SUCCESS at any other case. * ***************************************************************************/ -int32_t +static int32_t e1000_get_software_semaphore(struct e1000_hw *hw) { int32_t timeout = hw->eeprom.word_size + 1; @@ -8183,7 +8230,7 @@ e1000_get_software_semaphore(struct e100 * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -void +static void e1000_release_software_semaphore(struct e1000_hw *hw) { uint32_t swsm; @@ -8265,7 +8312,7 @@ e1000_arc_subsystem_valid(struct e1000_h * returns: E1000_SUCCESS * *****************************************************************************/ -int32_t +static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop) { uint32_t gcr_reg = 0; @@ -8306,7 +8353,7 @@ e1000_set_pci_ex_no_snoop(struct e1000_h * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -int32_t +static int32_t e1000_get_software_flag(struct e1000_hw *hw) { int32_t timeout = PHY_CFG_TIMEOUT; @@ -8345,7 +8392,7 @@ e1000_get_software_flag(struct e1000_hw * hw: Struct containing variables accessed by shared code * ***************************************************************************/ -void +static void e1000_release_software_flag(struct e1000_hw *hw) { uint32_t extcnf_ctrl; @@ -8369,6 +8416,7 @@ e1000_release_software_flag(struct e1000 * hw: Struct containing variables accessed by shared code * ***************************************************************************/ +#if 0 int32_t e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw) { @@ -8388,6 +8436,7 @@ e1000_ife_disable_dynamic_power_down(str return ret_val; } +#endif /* 0 */ /*************************************************************************** * @@ -8397,6 +8446,7 @@ e1000_ife_disable_dynamic_power_down(str * hw: Struct containing variables accessed by shared code * ***************************************************************************/ +#if 0 int32_t e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw) { @@ -8416,6 +8466,7 @@ e1000_ife_enable_dynamic_power_down(stru return ret_val; } +#endif /* 0 */ /****************************************************************************** * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access @@ -8426,7 +8477,7 @@ e1000_ife_enable_dynamic_power_down(stru * data - word read from the EEPROM * words - number of words to read *****************************************************************************/ -int32_t +static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data) { @@ -8482,7 +8533,7 @@ e1000_read_eeprom_ich8(struct e1000_hw * * words - number of words to write * data - words to write to the EEPROM *****************************************************************************/ -int32_t +static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data) { @@ -8529,7 +8580,7 @@ e1000_write_eeprom_ich8(struct e1000_hw * * hw - The pointer to the hw structure ****************************************************************************/ -int32_t +static int32_t e1000_ich8_cycle_init(struct e1000_hw *hw) { union ich8_hws_flash_status hsfsts; @@ -8596,7 +8647,7 @@ e1000_ich8_cycle_init(struct e1000_hw *h * * hw - The pointer to the hw structure ****************************************************************************/ -int32_t +static int32_t e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout) { union ich8_hws_flash_ctrl hsflctl; @@ -8631,7 +8682,7 @@ e1000_ich8_flash_cycle(struct e1000_hw * * size - Size of data to read, 1=byte 2=word * data - Pointer to the word to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t* data) { @@ -8710,7 +8761,7 @@ e1000_read_ich8_data(struct e1000_hw *hw * size - Size of data to read, 1=byte 2=word * data - The byte(s) to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t data) { @@ -8785,7 +8836,7 @@ e1000_write_ich8_data(struct e1000_hw *h * index - The index of the byte to read. * data - Pointer to a byte to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data) { int32_t status = E1000_SUCCESS; @@ -8808,7 +8859,7 @@ e1000_read_ich8_byte(struct e1000_hw *hw * index - The index of the byte to write. * byte - The byte to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte) { int32_t error = E1000_SUCCESS; @@ -8839,7 +8890,7 @@ e1000_verify_write_ich8_byte(struct e100 * index - The index of the byte to read. * data - The byte to write to the NVM. *****************************************************************************/ -int32_t +static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data) { int32_t status = E1000_SUCCESS; @@ -8857,7 +8908,7 @@ e1000_write_ich8_byte(struct e1000_hw *h * index - The starting byte index of the word to read. * data - Pointer to a word to store the value read. *****************************************************************************/ -int32_t +static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data) { int32_t status = E1000_SUCCESS; @@ -8872,6 +8923,7 @@ e1000_read_ich8_word(struct e1000_hw *hw * index - The starting byte index of the word to read. * data - The word to write to the NVM. *****************************************************************************/ +#if 0 int32_t e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data) { @@ -8879,6 +8931,7 @@ e1000_write_ich8_word(struct e1000_hw *h status = e1000_write_ich8_data(hw, index, 2, data); return status; } +#endif /* 0 */ /****************************************************************************** * Erases the bank specified. Each bank is a 4k block. Segments are 0 based. @@ -8887,7 +8940,7 @@ e1000_write_ich8_word(struct e1000_hw *h * hw - pointer to e1000_hw structure * segment - 0 for first segment, 1 for second segment, etc. *****************************************************************************/ -int32_t +static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment) { union ich8_hws_flash_status hsfsts; @@ -8984,6 +9037,7 @@ e1000_erase_ich8_4k_segment(struct e1000 * hw: Struct containing variables accessed by shared code * *****************************************************************************/ +#if 0 int32_t e1000_duplex_reversal(struct e1000_hw *hw) { @@ -9012,8 +9066,9 @@ e1000_duplex_reversal(struct e1000_hw *h return ret_val; } +#endif /* 0 */ -int32_t +static int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size) { @@ -9047,7 +9102,7 @@ e1000_init_lcd_from_nvm_config_region(st } -int32_t +static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw) { uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop; diff -puN drivers/net/e1000/e1000_hw.h~git-netdev-all drivers/net/e1000/e1000_hw.h --- a/drivers/net/e1000/e1000_hw.h~git-netdev-all +++ a/drivers/net/e1000/e1000_hw.h @@ -323,13 +323,8 @@ int32_t e1000_write_phy_reg(struct e1000 int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); void e1000_phy_powerdown_workaround(struct e1000_hw *hw); -int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw); -int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size); -int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); -int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data); -int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); /* EEPROM Functions */ int32_t e1000_init_eeprom_params(struct e1000_hw *hw); @@ -400,13 +395,8 @@ int32_t e1000_update_eeprom_checksum(str int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num); int32_t e1000_read_mac_addr(struct e1000_hw * hw); -int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); -void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); -void e1000_release_software_flag(struct e1000_hw *hw); -int32_t e1000_get_software_flag(struct e1000_hw *hw); /* Filters (multicast, vlan, receive) */ -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -431,31 +421,9 @@ void e1000_pci_clear_mwi(struct e1000_hw void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); -uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); -void e1000_enable_pciex_master(struct e1000_hw *hw); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); -int32_t e1000_get_software_semaphore(struct e1000_hw *hw); -void e1000_release_software_semaphore(struct e1000_hw *hw); int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); -int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop); - -int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t *data); -int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t byte); -int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, - uint8_t byte); -int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, - uint16_t *data); -int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, - uint32_t size, uint16_t *data); -int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, - uint16_t words, uint16_t *data); -int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, - uint16_t words, uint16_t *data); -int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment); #define E1000_READ_REG_IO(a, reg) \ diff -puN drivers/net/e1000/e1000_main.c~git-netdev-all drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c~git-netdev-all +++ a/drivers/net/e1000/e1000_main.c @@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Int #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "7.1.9-k4"DRIVERNAPI +#define DRV_VERSION "7.1.9-k6"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -48,7 +48,6 @@ static char e1000_copyright[] = "Copyrig * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ static struct pci_device_id e1000_pci_tbl[] = { - INTEL_E1000_ETHERNET_DEVICE(0x1000), INTEL_E1000_ETHERNET_DEVICE(0x1001), INTEL_E1000_ETHERNET_DEVICE(0x1004), INTEL_E1000_ETHERNET_DEVICE(0x1008), @@ -245,7 +244,7 @@ e1000_init_module(void) printk(KERN_INFO "%s\n", e1000_copyright); - ret = pci_module_init(&e1000_driver); + ret = pci_register_driver(&e1000_driver); return ret; } @@ -485,7 +484,7 @@ e1000_up(struct e1000_adapter *adapter) * **/ -static void e1000_power_up_phy(struct e1000_adapter *adapter) +void e1000_power_up_phy(struct e1000_adapter *adapter) { uint16_t mii_reg = 0; @@ -1499,8 +1498,6 @@ e1000_configure_tx(struct e1000_adapter } else if (hw->mac_type == e1000_80003es2lan) { tarc = E1000_READ_REG(hw, TARC0); tarc |= 1; - if (hw->media_type == e1000_media_type_internal_serdes) - tarc |= (1 << 20); E1000_WRITE_REG(hw, TARC0, tarc); tarc = E1000_READ_REG(hw, TARC1); tarc |= 1; @@ -2545,7 +2542,7 @@ e1000_tso(struct e1000_adapter *adapter, cmd_length = E1000_TXD_CMD_IP; ipcse = skb->h.raw - skb->data - 1; #ifdef NETIF_F_TSO_IPV6 - } else if (skb->protocol == ntohs(ETH_P_IPV6)) { + } else if (skb->protocol == htons(ETH_P_IPV6)) { skb->nh.ipv6h->payload_len = 0; skb->h.th->check = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, @@ -4386,11 +4383,13 @@ e1000_write_pci_cfg(struct e1000_hw *hw, pci_write_config_word(adapter->pdev, reg, *value); } +#if 0 uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } +#endif /* 0 */ void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) diff -puN drivers/net/e2100.c~git-netdev-all drivers/net/e2100.c --- a/drivers/net/e2100.c~git-netdev-all +++ a/drivers/net/e2100.c @@ -425,8 +425,8 @@ MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ -int -init_module(void) + +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/eepro.c~git-netdev-all drivers/net/eepro.c --- a/drivers/net/eepro.c~git-netdev-all +++ a/drivers/net/eepro.c @@ -1807,8 +1807,7 @@ MODULE_PARM_DESC(irq, "EtherExpress Pro/ MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int i; diff -puN drivers/net/eepro100.c~git-netdev-all drivers/net/eepro100.c --- a/drivers/net/eepro100.c~git-netdev-all +++ a/drivers/net/eepro100.c @@ -2385,7 +2385,7 @@ static int __init eepro100_init_module(v #ifdef MODULE printk(version); #endif - return pci_module_init(&eepro100_driver); + return pci_register_driver(&eepro100_driver); } static void __exit eepro100_cleanup_module(void) diff -puN drivers/net/eexpress.c~git-netdev-all drivers/net/eexpress.c --- a/drivers/net/eexpress.c~git-netdev-all +++ a/drivers/net/eexpress.c @@ -1698,7 +1698,7 @@ MODULE_LICENSE("GPL"); * are specified, we verify and then use them. If no parameters are given, we * autoprobe for one card only. */ -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/epic100.c~git-netdev-all drivers/net/epic100.c --- a/drivers/net/epic100.c~git-netdev-all +++ a/drivers/net/epic100.c @@ -1604,7 +1604,7 @@ static int __init epic_init (void) version, version2, version3); #endif - return pci_module_init (&epic_driver); + return pci_register_driver(&epic_driver); } diff -puN drivers/net/es3210.c~git-netdev-all drivers/net/es3210.c --- a/drivers/net/es3210.c~git-netdev-all +++ a/drivers/net/es3210.c @@ -421,8 +421,7 @@ MODULE_PARM_DESC(mem, "memory base addre MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver"); MODULE_LICENSE("GPL"); -int -init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/eth16i.c~git-netdev-all drivers/net/eth16i.c --- a/drivers/net/eth16i.c~git-netdev-all +++ a/drivers/net/eth16i.c @@ -1434,7 +1434,7 @@ MODULE_PARM_DESC(mediatype, "eth16i medi module_param(debug, int, 0); MODULE_PARM_DESC(debug, "eth16i debug level (0-6)"); -int init_module(void) +int __init init_module(void) { int this_dev, found = 0; struct net_device *dev; diff -puN drivers/net/fealnx.c~git-netdev-all drivers/net/fealnx.c --- a/drivers/net/fealnx.c~git-netdev-all +++ a/drivers/net/fealnx.c @@ -92,7 +92,7 @@ static int full_duplex[MAX_UNITS] = { -1 #include /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n"; @@ -1984,7 +1984,7 @@ static int __init fealnx_init(void) printk(version); #endif - return pci_module_init(&fealnx_driver); + return pci_register_driver(&fealnx_driver); } static void __exit fealnx_exit(void) diff -puN drivers/net/forcedeth.c~git-netdev-all drivers/net/forcedeth.c --- a/drivers/net/forcedeth.c~git-netdev-all +++ a/drivers/net/forcedeth.c @@ -109,6 +109,7 @@ * 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup. * 0.55: 22 Mar 2006: Add flow control (pause frame). * 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support. + * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -120,7 +121,12 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.56" +#ifdef CONFIG_FORCEDETH_NAPI +#define DRIVERNAPI "-NAPI" +#else +#define DRIVERNAPI +#endif +#define FORCEDETH_VERSION "0.57" #define DRV_NAME "forcedeth" #include @@ -262,7 +268,8 @@ enum { NvRegRingSizes = 0x108, #define NVREG_RINGSZ_TXSHIFT 0 #define NVREG_RINGSZ_RXSHIFT 16 - NvRegUnknownTransmitterReg = 0x10c, + NvRegTransmitPoll = 0x10c, +#define NVREG_TRANSMITPOLL_MAC_ADDR_REV 0x00008000 NvRegLinkSpeed = 0x110, #define NVREG_LINKSPEED_FORCE 0x10000 #define NVREG_LINKSPEED_10 1000 @@ -381,21 +388,21 @@ enum { /* Big endian: should work, but is untested */ struct ring_desc { - u32 PacketBuffer; - u32 FlagLen; + __le32 buf; + __le32 flaglen; }; struct ring_desc_ex { - u32 PacketBufferHigh; - u32 PacketBufferLow; - u32 TxVlan; - u32 FlagLen; + __le32 bufhigh; + __le32 buflow; + __le32 txvlan; + __le32 flaglen; }; -typedef union _ring_type { +union ring_type { struct ring_desc* orig; struct ring_desc_ex* ex; -} ring_type; +}; #define FLAG_MASK_V1 0xffff0000 #define FLAG_MASK_V2 0xffffc000 @@ -653,8 +660,8 @@ static const struct nv_ethtool_str nv_et }; struct register_test { - u32 reg; - u32 mask; + __le32 reg; + __le32 mask; }; static const struct register_test nv_registers_test[] = { @@ -713,7 +720,7 @@ struct fe_priv { /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ - ring_type rx_ring; + union ring_type rx_ring; unsigned int cur_rx, refill_rx; struct sk_buff **rx_skbuff; dma_addr_t *rx_dma; @@ -733,7 +740,7 @@ struct fe_priv { /* * tx specific fields. */ - ring_type tx_ring; + union ring_type tx_ring; unsigned int next_tx, nic_tx; struct sk_buff **tx_skbuff; dma_addr_t *tx_dma; @@ -826,13 +833,13 @@ static inline void pci_push(u8 __iomem * static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v) { - return le32_to_cpu(prd->FlagLen) + return le32_to_cpu(prd->flaglen) & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); } static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v) { - return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2; + return le32_to_cpu(prd->flaglen) & LEN_MASK_V2; } static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, @@ -885,7 +892,7 @@ static void free_rings(struct net_device struct fe_priv *np = get_nvpriv(dev); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - if(np->rx_ring.orig) + if (np->rx_ring.orig) pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size), np->rx_ring.orig, np->ring_addr); } else { @@ -1178,7 +1185,7 @@ static void nv_stop_tx(struct net_device KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); udelay(NV_TXSTOP_DELAY2); - writel(0, base + NvRegUnknownTransmitterReg); + writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); } static void nv_txrx_reset(struct net_device *dev) @@ -1258,14 +1265,14 @@ static int nv_alloc_rx(struct net_device np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->end-skb->data, PCI_DMA_FROMDEVICE); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]); wmb(); - np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); } else { - np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32; - np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; + np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32; + np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; wmb(); - np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); } dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); @@ -1277,6 +1284,16 @@ static int nv_alloc_rx(struct net_device return 0; } +/* If rx bufs are exhausted called after 50ms to attempt to refresh */ +#ifdef CONFIG_FORCEDETH_NAPI +static void nv_do_rx_refill(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + + /* Just reschedule NAPI rx processing */ + netif_rx_schedule(dev); +} +#else static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; @@ -1305,6 +1322,7 @@ static void nv_do_rx_refill(unsigned lon enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } } +#endif static void nv_init_rx(struct net_device *dev) { @@ -1315,9 +1333,9 @@ static void nv_init_rx(struct net_device np->refill_rx = 0; for (i = 0; i < np->rx_ring_size; i++) if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->rx_ring.orig[i].FlagLen = 0; + np->rx_ring.orig[i].flaglen = 0; else - np->rx_ring.ex[i].FlagLen = 0; + np->rx_ring.ex[i].flaglen = 0; } static void nv_init_tx(struct net_device *dev) @@ -1328,9 +1346,9 @@ static void nv_init_tx(struct net_device np->next_tx = np->nic_tx = 0; for (i = 0; i < np->tx_ring_size; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[i].FlagLen = 0; + np->tx_ring.orig[i].flaglen = 0; else - np->tx_ring.ex[i].FlagLen = 0; + np->tx_ring.ex[i].flaglen = 0; np->tx_skbuff[i] = NULL; np->tx_dma[i] = 0; } @@ -1373,9 +1391,9 @@ static void nv_drain_tx(struct net_devic for (i = 0; i < np->tx_ring_size; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->tx_ring.orig[i].FlagLen = 0; + np->tx_ring.orig[i].flaglen = 0; else - np->tx_ring.ex[i].FlagLen = 0; + np->tx_ring.ex[i].flaglen = 0; if (nv_release_txskb(dev, i)) np->stats.tx_dropped++; } @@ -1387,9 +1405,9 @@ static void nv_drain_rx(struct net_devic int i; for (i = 0; i < np->rx_ring_size; i++) { if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - np->rx_ring.orig[i].FlagLen = 0; + np->rx_ring.orig[i].flaglen = 0; else - np->rx_ring.ex[i].FlagLen = 0; + np->rx_ring.ex[i].flaglen = 0; wmb(); if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], @@ -1450,17 +1468,17 @@ static int nv_start_xmit(struct sk_buff np->tx_dma_len[nr] = bcnt; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); } else { - np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); } tx_flags = np->tx_flags; offset += bcnt; size -= bcnt; - } while(size); + } while (size); /* setup the fragments */ for (i = 0; i < fragments; i++) { @@ -1477,12 +1495,12 @@ static int nv_start_xmit(struct sk_buff np->tx_dma_len[nr] = bcnt; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); } else { - np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); } offset += bcnt; size -= bcnt; @@ -1491,9 +1509,9 @@ static int nv_start_xmit(struct sk_buff /* set last fragment flag */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra); } else { - np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra); } np->tx_skbuff[nr] = skb; @@ -1512,10 +1530,10 @@ static int nv_start_xmit(struct sk_buff /* set tx flags */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); } else { - np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan); - np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan); + np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); } dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", @@ -1547,7 +1565,7 @@ static int nv_start_xmit(struct sk_buff static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - u32 Flags; + u32 flags; unsigned int i; struct sk_buff *skb; @@ -1555,22 +1573,22 @@ static void nv_tx_done(struct net_device i = np->nic_tx % np->tx_ring_size; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen); + flags = le32_to_cpu(np->tx_ring.orig[i].flaglen); else - Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen); + flags = le32_to_cpu(np->tx_ring.ex[i].flaglen); - dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", - dev->name, np->nic_tx, Flags); - if (Flags & NV_TX_VALID) + dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n", + dev->name, np->nic_tx, flags); + if (flags & NV_TX_VALID) break; if (np->desc_ver == DESC_VER_1) { - if (Flags & NV_TX_LASTPACKET) { + if (flags & NV_TX_LASTPACKET) { skb = np->tx_skbuff[i]; - if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (Flags & NV_TX_UNDERFLOW) + if (flags & NV_TX_UNDERFLOW) np->stats.tx_fifo_errors++; - if (Flags & NV_TX_CARRIERLOST) + if (flags & NV_TX_CARRIERLOST) np->stats.tx_carrier_errors++; np->stats.tx_errors++; } else { @@ -1579,13 +1597,13 @@ static void nv_tx_done(struct net_device } } } else { - if (Flags & NV_TX2_LASTPACKET) { + if (flags & NV_TX2_LASTPACKET) { skb = np->tx_skbuff[i]; - if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (Flags & NV_TX2_UNDERFLOW) + if (flags & NV_TX2_UNDERFLOW) np->stats.tx_fifo_errors++; - if (Flags & NV_TX2_CARRIERLOST) + if (flags & NV_TX2_CARRIERLOST) np->stats.tx_carrier_errors++; np->stats.tx_errors++; } else { @@ -1638,29 +1656,29 @@ static void nv_tx_timeout(struct net_dev if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n", i, - le32_to_cpu(np->tx_ring.orig[i].PacketBuffer), - le32_to_cpu(np->tx_ring.orig[i].FlagLen), - le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer), - le32_to_cpu(np->tx_ring.orig[i+1].FlagLen), - le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer), - le32_to_cpu(np->tx_ring.orig[i+2].FlagLen), - le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer), - le32_to_cpu(np->tx_ring.orig[i+3].FlagLen)); + le32_to_cpu(np->tx_ring.orig[i].buf), + le32_to_cpu(np->tx_ring.orig[i].flaglen), + le32_to_cpu(np->tx_ring.orig[i+1].buf), + le32_to_cpu(np->tx_ring.orig[i+1].flaglen), + le32_to_cpu(np->tx_ring.orig[i+2].buf), + le32_to_cpu(np->tx_ring.orig[i+2].flaglen), + le32_to_cpu(np->tx_ring.orig[i+3].buf), + le32_to_cpu(np->tx_ring.orig[i+3].flaglen)); } else { printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n", i, - le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh), - le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow), - le32_to_cpu(np->tx_ring.ex[i].FlagLen), - le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh), - le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow), - le32_to_cpu(np->tx_ring.ex[i+1].FlagLen), - le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh), - le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow), - le32_to_cpu(np->tx_ring.ex[i+2].FlagLen), - le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh), - le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow), - le32_to_cpu(np->tx_ring.ex[i+3].FlagLen)); + le32_to_cpu(np->tx_ring.ex[i].bufhigh), + le32_to_cpu(np->tx_ring.ex[i].buflow), + le32_to_cpu(np->tx_ring.ex[i].flaglen), + le32_to_cpu(np->tx_ring.ex[i+1].bufhigh), + le32_to_cpu(np->tx_ring.ex[i+1].buflow), + le32_to_cpu(np->tx_ring.ex[i+1].flaglen), + le32_to_cpu(np->tx_ring.ex[i+2].bufhigh), + le32_to_cpu(np->tx_ring.ex[i+2].buflow), + le32_to_cpu(np->tx_ring.ex[i+2].flaglen), + le32_to_cpu(np->tx_ring.ex[i+3].bufhigh), + le32_to_cpu(np->tx_ring.ex[i+3].buflow), + le32_to_cpu(np->tx_ring.ex[i+3].flaglen)); } } } @@ -1697,7 +1715,7 @@ static int nv_getlen(struct net_device * int protolen; /* length as stored in the proto field */ /* 1) calculate len according to header */ - if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) { + if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) { protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto ); hdrlen = VLAN_HLEN; } else { @@ -1740,13 +1758,14 @@ static int nv_getlen(struct net_device * } } -static void nv_rx_process(struct net_device *dev) +static int nv_rx_process(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); - u32 Flags; + u32 flags; u32 vlanflags = 0; + int count; - for (;;) { + for (count = 0; count < limit; ++count) { struct sk_buff *skb; int len; int i; @@ -1755,18 +1774,18 @@ static void nv_rx_process(struct net_dev i = np->cur_rx % np->rx_ring_size; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen); + flags = le32_to_cpu(np->rx_ring.orig[i].flaglen); len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); } else { - Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); + flags = le32_to_cpu(np->rx_ring.ex[i].flaglen); len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); - vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow); + vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow); } - dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", - dev->name, np->cur_rx, Flags); + dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n", + dev->name, np->cur_rx, flags); - if (Flags & NV_RX_AVAIL) + if (flags & NV_RX_AVAIL) break; /* still owned by hardware, */ /* @@ -1780,7 +1799,7 @@ static void nv_rx_process(struct net_dev { int j; - dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags); + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags); for (j=0; j<64; j++) { if ((j%16) == 0) dprintk("\n%03x:", j); @@ -1790,30 +1809,30 @@ static void nv_rx_process(struct net_dev } /* look at what we actually got: */ if (np->desc_ver == DESC_VER_1) { - if (!(Flags & NV_RX_DESCRIPTORVALID)) + if (!(flags & NV_RX_DESCRIPTORVALID)) goto next_pkt; - if (Flags & NV_RX_ERROR) { - if (Flags & NV_RX_MISSEDFRAME) { + if (flags & NV_RX_ERROR) { + if (flags & NV_RX_MISSEDFRAME) { np->stats.rx_missed_errors++; np->stats.rx_errors++; goto next_pkt; } - if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { + if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX_CRCERR) { + if (flags & NV_RX_CRCERR) { np->stats.rx_crc_errors++; np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX_OVERFLOW) { + if (flags & NV_RX_OVERFLOW) { np->stats.rx_over_errors++; np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX_ERROR4) { + if (flags & NV_RX_ERROR4) { len = nv_getlen(dev, np->rx_skbuff[i]->data, len); if (len < 0) { np->stats.rx_errors++; @@ -1821,32 +1840,32 @@ static void nv_rx_process(struct net_dev } } /* framing errors are soft errors. */ - if (Flags & NV_RX_FRAMINGERR) { - if (Flags & NV_RX_SUBSTRACT1) { + if (flags & NV_RX_FRAMINGERR) { + if (flags & NV_RX_SUBSTRACT1) { len--; } } } } else { - if (!(Flags & NV_RX2_DESCRIPTORVALID)) + if (!(flags & NV_RX2_DESCRIPTORVALID)) goto next_pkt; - if (Flags & NV_RX2_ERROR) { - if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { + if (flags & NV_RX2_ERROR) { + if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX2_CRCERR) { + if (flags & NV_RX2_CRCERR) { np->stats.rx_crc_errors++; np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX2_OVERFLOW) { + if (flags & NV_RX2_OVERFLOW) { np->stats.rx_over_errors++; np->stats.rx_errors++; goto next_pkt; } - if (Flags & NV_RX2_ERROR4) { + if (flags & NV_RX2_ERROR4) { len = nv_getlen(dev, np->rx_skbuff[i]->data, len); if (len < 0) { np->stats.rx_errors++; @@ -1854,17 +1873,17 @@ static void nv_rx_process(struct net_dev } } /* framing errors are soft errors */ - if (Flags & NV_RX2_FRAMINGERR) { - if (Flags & NV_RX2_SUBSTRACT1) { + if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { len--; } } } if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) { - Flags &= NV_RX2_CHECKSUMMASK; - if (Flags == NV_RX2_CHECKSUMOK1 || - Flags == NV_RX2_CHECKSUMOK2 || - Flags == NV_RX2_CHECKSUMOK3) { + flags &= NV_RX2_CHECKSUMMASK; + if (flags == NV_RX2_CHECKSUMOK1 || + flags == NV_RX2_CHECKSUMOK2 || + flags == NV_RX2_CHECKSUMOK3) { dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name); np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY; } else { @@ -1880,17 +1899,27 @@ static void nv_rx_process(struct net_dev skb->protocol = eth_type_trans(skb, dev); dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", dev->name, np->cur_rx, len, skb->protocol); - if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) { - vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK); - } else { +#ifdef CONFIG_FORCEDETH_NAPI + if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) + vlan_hwaccel_receive_skb(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); + else + netif_receive_skb(skb); +#else + if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) + vlan_hwaccel_rx(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); + else netif_rx(skb); - } +#endif dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; next_pkt: np->cur_rx++; } + + return count; } static void set_bufsize(struct net_device *dev) @@ -1990,7 +2019,7 @@ static int nv_set_mac_address(struct net struct fe_priv *np = netdev_priv(dev); struct sockaddr *macaddr = (struct sockaddr*)addr; - if(!is_valid_ether_addr(macaddr->sa_data)) + if (!is_valid_ether_addr(macaddr->sa_data)) return -EADDRNOTAVAIL; /* synchronized against open : rtnl_lock() held by caller */ @@ -2283,20 +2312,20 @@ set_speed: lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM); switch (adv_pause) { - case (ADVERTISE_PAUSE_CAP): + case ADVERTISE_PAUSE_CAP: if (lpa_pause & LPA_PAUSE_CAP) { pause_flags |= NV_PAUSEFRAME_RX_ENABLE; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; - case (ADVERTISE_PAUSE_ASYM): + case ADVERTISE_PAUSE_ASYM: if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM)) { pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } break; - case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM): + case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM: if (lpa_pause & LPA_PAUSE_CAP) { pause_flags |= NV_PAUSEFRAME_RX_ENABLE; @@ -2376,14 +2405,6 @@ static irqreturn_t nv_nic_irq(int foo, v nv_tx_done(dev); spin_unlock(&np->lock); - nv_rx_process(dev); - if (nv_alloc_rx(dev)) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); - } - if (events & NVREG_IRQ_LINK) { spin_lock(&np->lock); nv_link_irq(dev); @@ -2403,6 +2424,29 @@ static irqreturn_t nv_nic_irq(int foo, v printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } +#ifdef CONFIG_FORCEDETH_NAPI + if (events & NVREG_IRQ_RX_ALL) { + netif_rx_schedule(dev); + + /* Disable furthur receive irq's */ + spin_lock(&np->lock); + np->irqmask &= ~NVREG_IRQ_RX_ALL; + + if (np->msi_flags & NV_MSI_X_ENABLED) + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + spin_unlock(&np->lock); + } +#else + nv_rx_process(dev, dev->weight); + if (nv_alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } +#endif if (i > max_interrupt_work) { spin_lock(&np->lock); /* disable interrupts on the nic */ @@ -2474,6 +2518,63 @@ static irqreturn_t nv_nic_irq_tx(int foo return IRQ_RETVAL(i); } +#ifdef CONFIG_FORCEDETH_NAPI +static int nv_napi_poll(struct net_device *dev, int *budget) +{ + int pkts, limit = min(*budget, dev->quota); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + pkts = nv_rx_process(dev, limit); + + if (nv_alloc_rx(dev)) { + spin_lock_irq(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock_irq(&np->lock); + } + + if (pkts < limit) { + /* all done, no more packets present */ + netif_rx_complete(dev); + + /* re-enable receive interrupts */ + spin_lock_irq(&np->lock); + np->irqmask |= NVREG_IRQ_RX_ALL; + if (np->msi_flags & NV_MSI_X_ENABLED) + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + spin_unlock_irq(&np->lock); + return 0; + } else { + /* used up our quantum, so reschedule */ + dev->quota -= pkts; + *budget -= pkts; + return 1; + } +} +#endif + +#ifdef CONFIG_FORCEDETH_NAPI +static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + u8 __iomem *base = get_hwbase(dev); + u32 events; + + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; + writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + + if (events) { + netif_rx_schedule(dev); + /* disable receive interrupts on the nic */ + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + pci_push(base); + } + return IRQ_HANDLED; +} +#else static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; @@ -2492,7 +2593,7 @@ static irqreturn_t nv_nic_irq_rx(int foo if (!(events & np->irqmask)) break; - nv_rx_process(dev); + nv_rx_process(dev, dev->weight); if (nv_alloc_rx(dev)) { spin_lock_irq(&np->lock); if (!np->in_shutdown) @@ -2514,12 +2615,12 @@ static irqreturn_t nv_nic_irq_rx(int foo spin_unlock_irq(&np->lock); break; } - } dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name); return IRQ_RETVAL(i); } +#endif static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) { @@ -3245,7 +3346,7 @@ static int nv_set_ringparam(struct net_d if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) { /* fall back to old rings */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - if(rxtx_ring) + if (rxtx_ring) pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending), rxtx_ring, ring_addr); } else { @@ -3481,7 +3582,7 @@ static int nv_get_stats_count(struct net struct fe_priv *np = netdev_priv(dev); if (np->driver_data & DEV_HAS_STATISTICS) - return (sizeof(struct nv_ethtool_stats)/sizeof(u64)); + return sizeof(struct nv_ethtool_stats)/sizeof(u64); else return 0; } @@ -3619,7 +3720,7 @@ static int nv_loopback_test(struct net_d struct sk_buff *tx_skb, *rx_skb; dma_addr_t test_dma_addr; u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); - u32 Flags; + u32 flags; int len, i, pkt_len; u8 *pkt_data; u32 filter_flags = 0; @@ -3663,12 +3764,12 @@ static int nv_loopback_test(struct net_d tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE); if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr); - np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr); + np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); } else { - np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32; - np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF; - np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); + np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32; + np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF; + np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); } writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); @@ -3677,21 +3778,21 @@ static int nv_loopback_test(struct net_d /* check for rx of the packet */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen); + flags = le32_to_cpu(np->rx_ring.orig[0].flaglen); len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver); } else { - Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen); + flags = le32_to_cpu(np->rx_ring.ex[0].flaglen); len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver); } - if (Flags & NV_RX_AVAIL) { + if (flags & NV_RX_AVAIL) { ret = 0; } else if (np->desc_ver == DESC_VER_1) { - if (Flags & NV_RX_ERROR) + if (flags & NV_RX_ERROR) ret = 0; } else { - if (Flags & NV_RX2_ERROR) { + if (flags & NV_RX2_ERROR) { ret = 0; } } @@ -3753,6 +3854,7 @@ static void nv_self_test(struct net_devi if (test->flags & ETH_TEST_FL_OFFLINE) { if (netif_running(dev)) { netif_stop_queue(dev); + netif_poll_disable(dev); netif_tx_lock_bh(dev); spin_lock_irq(&np->lock); nv_disable_hw_interrupts(dev, np->irqmask); @@ -3811,6 +3913,7 @@ static void nv_self_test(struct net_devi nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); + netif_poll_enable(dev); nv_enable_hw_interrupts(dev, np->irqmask); } } @@ -3895,10 +3998,9 @@ static int nv_open(struct net_device *de dprintk(KERN_DEBUG "nv_open: begin\n"); - /* 1) erase previous misconfiguration */ + /* erase previous misconfiguration */ if (np->driver_data & DEV_HAS_POWER_CNTRL) nv_mac_reset(dev); - /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); writel(0, base + NvRegMulticastAddrB); writel(0, base + NvRegMulticastMaskA); @@ -3913,26 +4015,22 @@ static int nv_open(struct net_device *de if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame); - /* 2) initialize descriptor rings */ + /* initialize descriptor rings */ set_bufsize(dev); oom = nv_init_ring(dev); writel(0, base + NvRegLinkSpeed); - writel(0, base + NvRegUnknownTransmitterReg); + writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); nv_txrx_reset(dev); writel(0, base + NvRegUnknownSetupReg6); np->in_shutdown = 0; - /* 3) set mac address */ - nv_copy_mac_to_hw(dev); - - /* 4) give hw rings */ + /* give hw rings */ setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING); writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); - /* 5) continue setup */ writel(np->linkspeed, base + NvRegLinkSpeed); if (np->desc_ver == DESC_VER_1) writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark); @@ -3950,7 +4048,6 @@ static int nv_open(struct net_device *de writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); - /* 6) continue setup */ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); @@ -4020,6 +4117,8 @@ static int nv_open(struct net_device *de nv_start_rx(dev); nv_start_tx(dev); netif_start_queue(dev); + netif_poll_enable(dev); + if (ret) { netif_carrier_on(dev); } else { @@ -4049,6 +4148,7 @@ static int nv_close(struct net_device *d spin_lock_irq(&np->lock); np->in_shutdown = 1; spin_unlock_irq(&np->lock); + netif_poll_disable(dev); synchronize_irq(dev->irq); del_timer_sync(&np->oom_kick); @@ -4076,12 +4176,6 @@ static int nv_close(struct net_device *d if (np->wolenabled) nv_start_rx(dev); - /* special op: write back the misordered MAC address - otherwise - * the next nv_probe would see a wrong address. - */ - writel(np->orig_mac[0], base + NvRegMacAddrA); - writel(np->orig_mac[1], base + NvRegMacAddrB); - /* FIXME: power down nic */ return 0; @@ -4094,7 +4188,7 @@ static int __devinit nv_probe(struct pci unsigned long addr; u8 __iomem *base; int err, i; - u32 powerstate; + u32 powerstate, txreg; dev = alloc_etherdev(sizeof(struct fe_priv)); err = -ENOMEM; @@ -4270,6 +4364,10 @@ static int __devinit nv_probe(struct pci #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif + dev->weight = 64; +#ifdef CONFIG_FORCEDETH_NAPI + dev->poll = nv_napi_poll; +#endif SET_ETHTOOL_OPS(dev, &ops); dev->tx_timeout = nv_tx_timeout; dev->watchdog_timeo = NV_WATCHDOG_TIMEO; @@ -4281,12 +4379,30 @@ static int __devinit nv_probe(struct pci np->orig_mac[0] = readl(base + NvRegMacAddrA); np->orig_mac[1] = readl(base + NvRegMacAddrB); - dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; - dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; - dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; - dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; - dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; - dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + /* check the workaround bit for correct mac address order */ + txreg = readl(base + NvRegTransmitPoll); + if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) { + /* mac address is already in correct order */ + dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff; + dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff; + dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff; + dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff; + dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff; + dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff; + } else { + /* need to reverse mac address to correct order */ + dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; + dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; + dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; + dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; + dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; + dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + /* set permanent address to be correct aswell */ + np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); + } memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (!is_valid_ether_addr(dev->perm_addr)) { @@ -4309,6 +4425,9 @@ static int __devinit nv_probe(struct pci dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + /* set mac address */ + nv_copy_mac_to_hw(dev); + /* disable WOL */ writel(0, base + NvRegWakeUpFlags); np->wolenabled = 0; @@ -4421,9 +4540,17 @@ out: static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); unregister_netdev(dev); + /* special op: write back the misordered MAC address - otherwise + * the next nv_probe would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + /* free all structures */ free_rings(dev); iounmap(get_hwbase(dev)); @@ -4540,7 +4667,7 @@ static struct pci_driver driver = { static int __init init_nic(void) { printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION); - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit exit_nic(void) diff -puN drivers/net/fs_enet/Makefile~git-netdev-all drivers/net/fs_enet/Makefile --- a/drivers/net/fs_enet/Makefile~git-netdev-all +++ a/drivers/net/fs_enet/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_FS_ENET) += fs_enet.o -obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o -obj-$(CONFIG_8260) += mac-fcc.o +obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o +obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o -fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o +fs_enet-objs := fs_enet-main.o diff -puN /dev/null drivers/net/fs_enet/fec.h --- /dev/null +++ a/drivers/net/fs_enet/fec.h @@ -0,0 +1,42 @@ +#ifndef FS_ENET_FEC_H +#define FS_ENET_FEC_H + +/* CRC polynomium used by the FEC for the multicast group filtering */ +#define FEC_CRC_POLY 0x04C11DB7 + +#define FEC_MAX_MULTICAST_ADDRS 64 + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ +#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ +#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ +#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ +#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ +#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ +#define FEC_ENET_RXF 0x02000000U /* Full frame received */ +#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ +#define FEC_ENET_MII 0x00800000U /* MII interrupt */ +#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ + +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + + + +/* + * Delay to wait for FEC reset command to complete (in us) + */ +#define FEC_RESET_DELAY 50 +#endif diff -puN drivers/net/fs_enet/fs_enet-main.c~git-netdev-all drivers/net/fs_enet/fs_enet-main.c --- a/drivers/net/fs_enet/fs_enet-main.c~git-netdev-all +++ a/drivers/net/fs_enet/fs_enet-main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -682,35 +683,6 @@ static void fs_free_irq(struct net_devic (*fep->ops->post_free_irq)(dev, irq); } -/**********************************************************************************/ - -/* This interrupt occurs when the PHY detects a link change. */ -static irqreturn_t -fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct fs_enet_private *fep; - const struct fs_platform_info *fpi; - - fep = netdev_priv(dev); - fpi = fep->fpi; - - /* - * Acknowledge the interrupt if possible. If we have not - * found the PHY yet we can't process or acknowledge the - * interrupt now. Instead we ignore this interrupt for now, - * which we can do since it is edge triggered. It will be - * acknowledged later by fs_enet_open(). - */ - if (!fep->phy) - return IRQ_NONE; - - fs_mii_ack_int(dev); - fs_mii_link_status_change_check(dev, 0); - - return IRQ_HANDLED; -} - static void fs_timeout(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); @@ -722,10 +694,13 @@ static void fs_timeout(struct net_device spin_lock_irqsave(&fep->lock, flags); if (dev->flags & IFF_UP) { + phy_stop(fep->phydev); (*fep->ops->stop)(dev); (*fep->ops->restart)(dev); + phy_start(fep->phydev); } + phy_start(fep->phydev); wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); spin_unlock_irqrestore(&fep->lock, flags); @@ -733,35 +708,112 @@ static void fs_timeout(struct net_device netif_wake_queue(dev); } +/*----------------------------------------------------------------------------- + * generic link-change handler - should be sufficient for most cases + *-----------------------------------------------------------------------------*/ +static void generic_adjust_link(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev = fep->phydev; + int new_state = 0; + + if (phydev->link) { + + /* adjust to duplex mode */ + if (phydev->duplex != fep->oldduplex){ + new_state = 1; + fep->oldduplex = phydev->duplex; + } + + if (phydev->speed != fep->oldspeed) { + new_state = 1; + fep->oldspeed = phydev->speed; + } + + if (!fep->oldlink) { + new_state = 1; + fep->oldlink = 1; + netif_schedule(dev); + netif_carrier_on(dev); + netif_start_queue(dev); + } + + if (new_state) + fep->ops->restart(dev); + + } else if (fep->oldlink) { + new_state = 1; + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + netif_carrier_off(dev); + netif_stop_queue(dev); + } + + if (new_state && netif_msg_link(fep)) + phy_print_status(phydev); +} + + +static void fs_adjust_link(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&fep->lock, flags); + + if(fep->ops->adjust_link) + fep->ops->adjust_link(dev); + else + generic_adjust_link(dev); + + spin_unlock_irqrestore(&fep->lock, flags); +} + +static int fs_init_phy(struct net_device *dev) +{ + struct fs_enet_private *fep = netdev_priv(dev); + struct phy_device *phydev; + + fep->oldlink = 0; + fep->oldspeed = 0; + fep->oldduplex = -1; + if(fep->fpi->bus_id) + phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0); + else { + printk("No phy bus ID specified in BSP code\n"); + return -EINVAL; + } + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + fep->phydev = phydev; + + return 0; +} + + static int fs_enet_open(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; int r; + int err; /* Install our interrupt handler. */ r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); if (r != 0) { printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate FEC IRQ!", dev->name); + ": %s Could not allocate FS_ENET IRQ!", dev->name); return -EINVAL; } - /* Install our phy interrupt handler */ - if (fpi->phy_irq != -1) { + err = fs_init_phy(dev); + if(err) + return err; - r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); - if (r != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s Could not allocate PHY IRQ!", dev->name); - fs_free_irq(dev, fep->interrupt); - return -EINVAL; - } - } - - fs_mii_startup(dev); - netif_carrier_off(dev); - fs_mii_link_status_change_check(dev, 1); + phy_start(fep->phydev); return 0; } @@ -769,20 +821,19 @@ static int fs_enet_open(struct net_devic static int fs_enet_close(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; unsigned long flags; netif_stop_queue(dev); netif_carrier_off(dev); - fs_mii_shutdown(dev); + phy_stop(fep->phydev); spin_lock_irqsave(&fep->lock, flags); (*fep->ops->stop)(dev); spin_unlock_irqrestore(&fep->lock, flags); /* release any irqs */ - if (fpi->phy_irq != -1) - fs_free_irq(dev, fpi->phy_irq); + phy_disconnect(fep->phydev); + fep->phydev = NULL; fs_free_irq(dev, fep->interrupt); return 0; @@ -830,33 +881,19 @@ static void fs_get_regs(struct net_devic static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_gset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; + return phy_ethtool_gset(fep->phydev, cmd); } static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct fs_enet_private *fep = netdev_priv(dev); - unsigned long flags; - int rc; - - spin_lock_irqsave(&fep->lock, flags); - rc = mii_ethtool_sset(&fep->mii_if, cmd); - spin_unlock_irqrestore(&fep->lock, flags); - - return rc; + phy_ethtool_sset(fep->phydev, cmd); + return 0; } static int fs_nway_reset(struct net_device *dev) { - struct fs_enet_private *fep = netdev_priv(dev); - return mii_nway_restart(&fep->mii_if); + return 0; } static u32 fs_get_msglevel(struct net_device *dev) @@ -898,7 +935,7 @@ static int fs_ioctl(struct net_device *d return -EINVAL; spin_lock_irqsave(&fep->lock, flags); - rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); + rc = phy_mii_ioctl(fep->phydev, mii, cmd); spin_unlock_irqrestore(&fep->lock, flags); return rc; } @@ -1030,12 +1067,6 @@ static struct net_device *fs_init_instan } registered = 1; - err = fs_mii_connect(ndev); - if (err != 0) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s fs_mii_connect failed.\n", ndev->name); - goto err; - } return ndev; @@ -1073,8 +1104,6 @@ static int fs_cleanup_instance(struct ne fpi = fep->fpi; - fs_mii_disconnect(ndev); - unregister_netdev(ndev); dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), @@ -1196,17 +1225,39 @@ static int __init fs_init(void) r = setup_immap(); if (r != 0) return r; - r = driver_register(&fs_enet_fec_driver); + +#ifdef CONFIG_FS_ENET_HAS_FCC + /* let's insert mii stuff */ + r = fs_enet_mdio_bb_init(); + + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "BB PHY init failed.\n"); + return r; + } + r = driver_register(&fs_enet_fcc_driver); if (r != 0) goto err; +#endif - r = driver_register(&fs_enet_fcc_driver); +#ifdef CONFIG_FS_ENET_HAS_FEC + r = fs_enet_mdio_fec_init(); + if (r != 0) { + printk(KERN_ERR DRV_MODULE_NAME + "FEC PHY init failed.\n"); + return r; + } + + r = driver_register(&fs_enet_fec_driver); if (r != 0) goto err; +#endif +#ifdef CONFIG_FS_ENET_HAS_SCC r = driver_register(&fs_enet_scc_driver); if (r != 0) goto err; +#endif return 0; err: diff -puN drivers/net/fs_enet/fs_enet-mii.c~git-netdev-all /dev/null --- a/drivers/net/fs_enet/fs_enet-mii.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * Heavily based on original FEC driver by Dan Malek - * and modifications by Joakim Tjernlund - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -/*************************************************/ - -/* - * Generic PHY support. - * Should work for all PHYs, but link change is detected by polling - */ - -static void generic_timer_callback(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct fs_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; - - add_timer(&fep->phy_timer_list); - - fs_mii_link_status_change_check(dev, 0); -} - -static void generic_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ - fep->phy_timer_list.data = (unsigned long)dev; - fep->phy_timer_list.function = generic_timer_callback; - add_timer(&fep->phy_timer_list); -} - -static void generic_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - del_timer_sync(&fep->phy_timer_list); -} - -/* ------------------------------------------------------------------------- */ -/* The Davicom DM9161 is used on the NETTA board */ - -/* register definitions */ - -#define MII_DM9161_ANAR 4 /* Aux. Config Register */ -#define MII_DM9161_ACR 16 /* Aux. Config Register */ -#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ -#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ -#define MII_DM9161_INTR 21 /* Interrupt Register */ -#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ -#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ - -static void dm9161_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); - /* Start autonegotiation */ - fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ*8); -} - -static void dm9161_ack_int(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); -} - -static void dm9161_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); -} - -/**********************************************************************************/ - -static const struct phy_info phy_info[] = { - { - .id = 0x00181b88, - .name = "DM9161", - .startup = dm9161_startup, - .ack_int = dm9161_ack_int, - .shutdown = dm9161_shutdown, - }, { - .id = 0, - .name = "GENERIC", - .startup = generic_startup, - .shutdown = generic_shutdown, - }, -}; - -/**********************************************************************************/ - -static int phy_id_detect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - struct fs_enet_mii_bus *bus = fep->mii_bus; - int i, r, start, end, phytype, physubtype; - const struct phy_info *phy; - int phy_hwid, phy_id; - - phy_hwid = -1; - fep->phy = NULL; - - /* auto-detect? */ - if (fpi->phy_addr == -1) { - start = 1; - end = 32; - } else { /* direct */ - start = fpi->phy_addr; - end = start + 1; - } - - for (phy_id = start; phy_id < end; phy_id++) { - /* skip already used phy addresses on this bus */ - if (bus->usage_map & (1 << phy_id)) - continue; - r = fs_mii_read(dev, phy_id, MII_PHYSID1); - if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) - continue; - r = fs_mii_read(dev, phy_id, MII_PHYSID2); - if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) - continue; - phy_hwid = (phytype << 16) | physubtype; - if (phy_hwid != -1) - break; - } - - if (phy_hwid == -1) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s No PHY detected! range=0x%02x-0x%02x\n", - dev->name, start, end); - return -1; - } - - for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) - if (phy->id == (phy_hwid >> 4) || phy->id == 0) - break; - - if (i >= ARRAY_SIZE(phy_info)) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s PHY id 0x%08x is not supported!\n", - dev->name, phy_hwid); - return -1; - } - - fep->phy = phy; - - /* mark this address as used */ - bus->usage_map |= (1 << phy_id); - - printk(KERN_INFO DRV_MODULE_NAME - ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", - dev->name, phy_id, fep->phy->name, phy_hwid, - fpi->phy_addr == -1 ? " (auto-detected)" : ""); - - return phy_id; -} - -void fs_mii_startup(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->startup) - (*fep->phy->startup) (dev); -} - -void fs_mii_shutdown(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->shutdown) - (*fep->phy->shutdown) (dev); -} - -void fs_mii_ack_int(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - - if (fep->phy->ack_int) - (*fep->phy->ack_int) (dev); -} - -#define MII_LINK 0x0001 -#define MII_HALF 0x0002 -#define MII_FULL 0x0004 -#define MII_BASE4 0x0008 -#define MII_10M 0x0010 -#define MII_100M 0x0020 -#define MII_1G 0x0040 -#define MII_10G 0x0080 - -/* return full mii info at one gulp, with a usable form */ -static unsigned int mii_full_status(struct mii_if_info *mii) -{ - unsigned int status; - int bmsr, adv, lpa, neg; - struct fs_enet_private* fep = netdev_priv(mii->dev); - - /* first, a dummy read, needed to latch some MII phys */ - (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); - bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); - - /* no link */ - if ((bmsr & BMSR_LSTATUS) == 0) - return 0; - - status = MII_LINK; - - /* Lets look what ANEG says if it's supported - otherwize we shall - take the right values from the platform info*/ - if(!mii->force_media) { - /* autoneg not completed; don't bother */ - if ((bmsr & BMSR_ANEGCOMPLETE) == 0) - return 0; - - adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); - lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); - - neg = lpa & adv; - } else { - neg = fep->fpi->bus_info->lpa; - } - - if (neg & LPA_100FULL) - status |= MII_FULL | MII_100M; - else if (neg & LPA_100BASE4) - status |= MII_FULL | MII_BASE4 | MII_100M; - else if (neg & LPA_100HALF) - status |= MII_HALF | MII_100M; - else if (neg & LPA_10FULL) - status |= MII_FULL | MII_10M; - else - status |= MII_HALF | MII_10M; - - return status; -} - -void fs_mii_link_status_change_check(struct net_device *dev, int init_media) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct mii_if_info *mii = &fep->mii_if; - unsigned int mii_status; - int ok_to_print, link, duplex, speed; - unsigned long flags; - - ok_to_print = netif_msg_link(fep); - - mii_status = mii_full_status(mii); - - if (!init_media && mii_status == fep->last_mii_status) - return; - - fep->last_mii_status = mii_status; - - link = !!(mii_status & MII_LINK); - duplex = !!(mii_status & MII_FULL); - speed = (mii_status & MII_100M) ? 100 : 10; - - if (link == 0) { - netif_carrier_off(mii->dev); - netif_stop_queue(dev); - if (!init_media) { - spin_lock_irqsave(&fep->lock, flags); - (*fep->ops->stop)(dev); - spin_unlock_irqrestore(&fep->lock, flags); - } - - if (ok_to_print) - printk(KERN_INFO "%s: link down\n", mii->dev->name); - - } else { - - mii->full_duplex = duplex; - - netif_carrier_on(mii->dev); - - spin_lock_irqsave(&fep->lock, flags); - fep->duplex = duplex; - fep->speed = speed; - (*fep->ops->restart)(dev); - spin_unlock_irqrestore(&fep->lock, flags); - - netif_start_queue(dev); - - if (ok_to_print) - printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", - dev->name, speed, duplex ? "full" : "half"); - } -} - -/**********************************************************************************/ - -int fs_mii_read(struct net_device *dev, int phy_id, int location) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = fep->mii_bus; - - unsigned long flags; - int ret; - - spin_lock_irqsave(&bus->mii_lock, flags); - ret = (*bus->mii_read)(bus, phy_id, location); - spin_unlock_irqrestore(&bus->mii_lock, flags); - - return ret; -} - -void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = fep->mii_bus; - unsigned long flags; - - spin_lock_irqsave(&bus->mii_lock, flags); - (*bus->mii_write)(bus, phy_id, location, value); - spin_unlock_irqrestore(&bus->mii_lock, flags); -} - -/*****************************************************************************/ - -/* list of all registered mii buses */ -static LIST_HEAD(fs_mii_bus_list); - -static struct fs_enet_mii_bus *lookup_bus(int method, int id) -{ - struct list_head *ptr; - struct fs_enet_mii_bus *bus; - - list_for_each(ptr, &fs_mii_bus_list) { - bus = list_entry(ptr, struct fs_enet_mii_bus, list); - if (bus->bus_info->method == method && - bus->bus_info->id == id) - return bus; - } - return NULL; -} - -static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) -{ - struct fs_enet_mii_bus *bus; - int ret = 0; - - bus = kmalloc(sizeof(*bus), GFP_KERNEL); - if (bus == NULL) { - ret = -ENOMEM; - goto err; - } - memset(bus, 0, sizeof(*bus)); - spin_lock_init(&bus->mii_lock); - bus->bus_info = bi; - bus->refs = 0; - bus->usage_map = 0; - - /* perform initialization */ - switch (bi->method) { - - case fsmii_fixed: - ret = fs_mii_fixed_init(bus); - if (ret != 0) - goto err; - break; - - case fsmii_bitbang: - ret = fs_mii_bitbang_init(bus); - if (ret != 0) - goto err; - break; -#ifdef CONFIG_FS_ENET_HAS_FEC - case fsmii_fec: - ret = fs_mii_fec_init(bus); - if (ret != 0) - goto err; - break; -#endif - default: - ret = -EINVAL; - goto err; - } - - list_add(&bus->list, &fs_mii_bus_list); - - return bus; - -err: - kfree(bus); - return ERR_PTR(ret); -} - -static void destroy_bus(struct fs_enet_mii_bus *bus) -{ - /* remove from bus list */ - list_del(&bus->list); - - /* nothing more needed */ - kfree(bus); -} - -int fs_mii_connect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - const struct fs_platform_info *fpi = fep->fpi; - struct fs_enet_mii_bus *bus = NULL; - - /* check method validity */ - switch (fpi->bus_info->method) { - case fsmii_fixed: - case fsmii_bitbang: - break; -#ifdef CONFIG_FS_ENET_HAS_FEC - case fsmii_fec: - break; -#endif - default: - printk(KERN_ERR DRV_MODULE_NAME - ": %s Unknown MII bus method (%d)!\n", - dev->name, fpi->bus_info->method); - return -EINVAL; - } - - bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); - - /* if not found create new bus */ - if (bus == NULL) { - bus = create_bus(fpi->bus_info); - if (IS_ERR(bus)) { - printk(KERN_ERR DRV_MODULE_NAME - ": %s MII bus creation failure!\n", dev->name); - return PTR_ERR(bus); - } - } - - bus->refs++; - - fep->mii_bus = bus; - - fep->mii_if.dev = dev; - fep->mii_if.phy_id_mask = 0x1f; - fep->mii_if.reg_num_mask = 0x1f; - fep->mii_if.mdio_read = fs_mii_read; - fep->mii_if.mdio_write = fs_mii_write; - fep->mii_if.force_media = fpi->bus_info->disable_aneg; - fep->mii_if.phy_id = phy_id_detect(dev); - - return 0; -} - -void fs_mii_disconnect(struct net_device *dev) -{ - struct fs_enet_private *fep = netdev_priv(dev); - struct fs_enet_mii_bus *bus = NULL; - - bus = fep->mii_bus; - fep->mii_bus = NULL; - - if (--bus->refs <= 0) - destroy_bus(bus); -} diff -puN drivers/net/fs_enet/fs_enet.h~git-netdev-all drivers/net/fs_enet/fs_enet.h --- a/drivers/net/fs_enet/fs_enet.h~git-netdev-all +++ a/drivers/net/fs_enet/fs_enet.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -12,12 +13,30 @@ #ifdef CONFIG_CPM1 #include + +struct fec_info { + fec_t* fecp; + u32 mii_speed; +}; #endif #ifdef CONFIG_CPM2 #include #endif +/* This is used to operate with pins. + Note that the actual port size may + be different; cpm(s) handle it OK */ +struct bb_info { + u8 mdio_dat_msk; + u8 mdio_dir_msk; + u8 *mdio_dir; + u8 *mdio_dat; + u8 mdc_msk; + u8 *mdc_dat; + int delay; +}; + /* hw driver ops */ struct fs_ops { int (*setup_data)(struct net_device *dev); @@ -25,6 +44,7 @@ struct fs_ops { void (*free_bd)(struct net_device *dev); void (*cleanup_data)(struct net_device *dev); void (*set_multicast_list)(struct net_device *dev); + void (*adjust_link)(struct net_device *dev); void (*restart)(struct net_device *dev); void (*stop)(struct net_device *dev); void (*pre_request_irq)(struct net_device *dev, int irq); @@ -100,10 +120,6 @@ struct fs_enet_mii_bus { }; }; -int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); -int fs_mii_fec_init(struct fs_enet_mii_bus *bus); - struct fs_enet_private { struct device *dev; /* pointer back to the device (must be initialized first) */ spinlock_t lock; /* during all ops except TX pckt processing */ @@ -130,7 +146,8 @@ struct fs_enet_private { struct fs_enet_mii_bus *mii_bus; int interrupt; - int duplex, speed; /* current settings */ + struct phy_device *phydev; + int oldduplex, oldspeed, oldlink; /* current settings */ /* event masks */ u32 ev_napi_rx; /* mask of NAPI rx events */ @@ -168,15 +185,9 @@ struct fs_enet_private { }; /***************************************************************************/ - -int fs_mii_read(struct net_device *dev, int phy_id, int location); -void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); - -void fs_mii_startup(struct net_device *dev); -void fs_mii_shutdown(struct net_device *dev); -void fs_mii_ack_int(struct net_device *dev); - -void fs_mii_link_status_change_check(struct net_device *dev, int init_media); +int fs_enet_mdio_bb_init(void); +int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); +int fs_enet_mdio_fec_init(void); void fs_init_bds(struct net_device *dev); void fs_cleanup_bds(struct net_device *dev); @@ -194,7 +205,6 @@ int fs_enet_platform_init(void); void fs_enet_platform_cleanup(void); /***************************************************************************/ - /* buffer descriptor access macros */ /* access macros */ diff -puN drivers/net/fs_enet/mac-fcc.c~git-netdev-all drivers/net/fs_enet/mac-fcc.c --- a/drivers/net/fs_enet/mac-fcc.c~git-netdev-all +++ a/drivers/net/fs_enet/mac-fcc.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -122,22 +123,32 @@ static int do_pd_setup(struct fs_enet_pr /* Attach the memory for the FCC Parameter RAM */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); - fep->fcc.ep = (void *)r->start; - + fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1); if (fep->fcc.ep == NULL) return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); - fep->fcc.fccp = (void *)r->start; - + fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1); if (fep->fcc.fccp == NULL) return -EINVAL; - fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + if (fep->fpi->fcc_regs_c) { + + fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; + } else { + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "fcc_regs_c"); + fep->fcc.fcccp = (void *)ioremap(r->start, + r->end - r->start + 1); + } if (fep->fcc.fcccp == NULL) return -EINVAL; + fep->fcc.mem = (void *)fep->fpi->mem_offset; + if (fep->fcc.mem == NULL) + return -EINVAL; + return 0; } @@ -155,8 +166,6 @@ static int setup_data(struct net_device if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ return -EINVAL; - fep->fcc.mem = (void *)fpi->mem_offset; - if (do_pd_setup(fep) != 0) return -EINVAL; @@ -394,7 +403,7 @@ static void restart(struct net_device *d /* adjust to speed (for RMII mode) */ if (fpi->use_rmii) { - if (fep->speed == 100) + if (fep->phydev->speed == 100) C8(fcccp, fcc_gfemr, 0x20); else S8(fcccp, fcc_gfemr, 0x20); @@ -420,7 +429,7 @@ static void restart(struct net_device *d S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); /* adjust to duplex mode */ - if (fep->duplex) + if (fep->phydev->duplex) S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); else C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); @@ -486,7 +495,10 @@ static void rx_bd_done(struct net_device static void tx_kickstart(struct net_device *dev) { - /* nothing */ + struct fs_enet_private *fep = netdev_priv(dev); + fcc_t *fccp = fep->fcc.fccp; + + S32(fccp, fcc_ftodr, 0x80); } static u32 get_int_events(struct net_device *dev) diff -puN drivers/net/fs_enet/mac-fec.c~git-netdev-all drivers/net/fs_enet/mac-fec.c --- a/drivers/net/fs_enet/mac-fec.c~git-netdev-all +++ a/drivers/net/fs_enet/mac-fec.c @@ -46,6 +46,7 @@ #endif #include "fs_enet.h" +#include "fec.h" /*************************************************/ @@ -75,50 +76,8 @@ /* clear bits */ #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) - -/* CRC polynomium used by the FEC for the multicast group filtering */ -#define FEC_CRC_POLY 0x04C11DB7 - -#define FEC_MAX_MULTICAST_ADDRS 64 - -/* Interrupt events/masks. -*/ -#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ -#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ -#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ -#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ -#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ -#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ -#define FEC_ENET_RXF 0x02000000U /* Full frame received */ -#define FEC_ENET_RXB 0x01000000U /* A buffer was received */ -#define FEC_ENET_MII 0x00800000U /* MII interrupt */ -#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ - -#define FEC_ECNTRL_PINMUX 0x00000004 -#define FEC_ECNTRL_ETHER_EN 0x00000002 -#define FEC_ECNTRL_RESET 0x00000001 - -#define FEC_RCNTRL_BC_REJ 0x00000010 -#define FEC_RCNTRL_PROM 0x00000008 -#define FEC_RCNTRL_MII_MODE 0x00000004 -#define FEC_RCNTRL_DRT 0x00000002 -#define FEC_RCNTRL_LOOP 0x00000001 - -#define FEC_TCNTRL_FDEN 0x00000004 -#define FEC_TCNTRL_HBC 0x00000002 -#define FEC_TCNTRL_GTS 0x00000001 - - -/* Make MII read/write commands for the FEC. -*/ -#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) -#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) -#define mk_mii_end 0 - -#define FEC_MII_LOOPS 10000 - /* - * Delay to wait for FEC reset command to complete (in us) + * Delay to wait for FEC reset command to complete (in us) */ #define FEC_RESET_DELAY 50 @@ -303,13 +262,15 @@ static void restart(struct net_device *d int r; u32 addrhi, addrlo; + struct mii_bus* mii = fep->phydev->bus; + struct fec_info* fec_inf = mii->priv; + r = whack_reset(fep->fec.fecp); if (r != 0) printk(KERN_ERR DRV_MODULE_NAME ": %s FEC Reset FAILED!\n", dev->name); - /* - * Set station address. + * Set station address. */ addrhi = ((u32) dev->dev_addr[0] << 24) | ((u32) dev->dev_addr[1] << 16) | @@ -350,12 +311,12 @@ static void restart(struct net_device *d FW(fecp, fun_code, 0x78000000); /* - * Set MII speed. + * Set MII speed. */ - FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); + FW(fecp, mii_speed, fec_inf->mii_speed); /* - * Clear any outstanding interrupt. + * Clear any outstanding interrupt. */ FW(fecp, ievent, 0xffc0); FW(fecp, ivec, (fep->interrupt / 2) << 29); @@ -390,11 +351,12 @@ static void restart(struct net_device *d } #endif + FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ /* - * adjust to duplex mode + * adjust to duplex mode */ - if (fep->duplex) { + if (fep->phydev->duplex) { FC(fecp, r_cntrl, FEC_RCNTRL_DRT); FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ } else { @@ -418,9 +380,11 @@ static void restart(struct net_device *d static void stop(struct net_device *dev) { struct fs_enet_private *fep = netdev_priv(dev); + const struct fs_platform_info *fpi = fep->fpi; fec_t *fecp = fep->fec.fecp; - struct fs_enet_mii_bus *bus = fep->mii_bus; - const struct fs_mii_bus_info *bi = bus->bus_info; + + struct fec_info* feci= fep->phydev->bus->priv; + int i; if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) @@ -444,11 +408,11 @@ static void stop(struct net_device *dev) fs_cleanup_bds(dev); /* shut down FEC1? that's where the mii bus is */ - if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { + if (fpi->has_phy) { FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); FW(fecp, ievent, FEC_ENET_MII); - FW(fecp, mii_speed, bus->fec.mii_speed); + FW(fecp, mii_speed, feci->mii_speed); } } @@ -583,73 +547,3 @@ const struct fs_ops fs_fec_ops = { .free_bd = free_bd, }; -/***********************************************************************/ - -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) -{ - fec_t *fecp = bus->fec.fecp; - int i, ret = -1; - - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); - - /* Add PHY address to register command. */ - FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) { - FW(fecp, ievent, FEC_ENET_MII); - ret = FR(fecp, mii_data) & 0xffff; - } - - return ret; -} - -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) -{ - fec_t *fecp = bus->fec.fecp; - int i; - - /* this must never happen */ - if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) - BUG(); - - /* Add PHY address to register command. */ - FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); - - for (i = 0; i < FEC_MII_LOOPS; i++) - if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) - break; - - if (i < FEC_MII_LOOPS) - FW(fecp, ievent, FEC_ENET_MII); -} - -int fs_mii_fec_init(struct fs_enet_mii_bus *bus) -{ - bd_t *bd = (bd_t *)__res; - const struct fs_mii_bus_info *bi = bus->bus_info; - fec_t *fecp; - - if (bi->id != 0) - return -1; - - bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; - bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) - & 0x3F) << 1; - - fecp = bus->fec.fecp; - - FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ - FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); - FW(fecp, ievent, FEC_ENET_MII); - FW(fecp, mii_speed, bus->fec.mii_speed); - - bus->mii_read = mii_read; - bus->mii_write = mii_write; - - return 0; -} diff -puN drivers/net/fs_enet/mac-scc.c~git-netdev-all drivers/net/fs_enet/mac-scc.c --- a/drivers/net/fs_enet/mac-scc.c~git-netdev-all +++ a/drivers/net/fs_enet/mac-scc.c @@ -369,7 +369,7 @@ static void restart(struct net_device *d W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* Set full duplex mode if needed */ - if (fep->duplex) + if (fep->phydev->duplex) S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); @@ -500,6 +500,8 @@ static void tx_restart(struct net_device scc_cr_cmd(fep, CPM_CR_RESTART_TX); } + + /*************************************************************************/ const struct fs_ops fs_scc_ops = { diff -puN drivers/net/fs_enet/mii-bitbang.c~git-netdev-all drivers/net/fs_enet/mii-bitbang.c --- a/drivers/net/fs_enet/mii-bitbang.c~git-netdev-all +++ a/drivers/net/fs_enet/mii-bitbang.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -40,129 +41,25 @@ #include "fs_enet.h" -#ifdef CONFIG_8xx -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) +static int bitbang_prep_bit(u8 **datp, u8 *mskp, + struct fs_mii_bit *mii_bit) { - immap_t *im = (immap_t *)fs_enet_immap; - void *dir, *dat, *ppar; + void *dat; int adv; u8 msk; - switch (port) { - case fsiop_porta: - dir = &im->im_ioport.iop_padir; - dat = &im->im_ioport.iop_padat; - ppar = &im->im_ioport.iop_papar; - break; - - case fsiop_portb: - dir = &im->im_cpm.cp_pbdir; - dat = &im->im_cpm.cp_pbdat; - ppar = &im->im_cpm.cp_pbpar; - break; - - case fsiop_portc: - dir = &im->im_ioport.iop_pcdir; - dat = &im->im_ioport.iop_pcdat; - ppar = &im->im_ioport.iop_pcpar; - break; - - case fsiop_portd: - dir = &im->im_ioport.iop_pddir; - dat = &im->im_ioport.iop_pddat; - ppar = &im->im_ioport.iop_pdpar; - break; - - case fsiop_porte: - dir = &im->im_cpm.cp_pedir; - dat = &im->im_cpm.cp_pedat; - ppar = &im->im_cpm.cp_pepar; - break; - - default: - printk(KERN_ERR DRV_MODULE_NAME - "Illegal port value %d!\n", port); - return -EINVAL; - } - - adv = bit >> 3; - dir = (char *)dir + adv; - dat = (char *)dat + adv; - ppar = (char *)ppar + adv; - - msk = 1 << (7 - (bit & 7)); - if ((in_8(ppar) & msk) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - "pin %d on port %d is not general purpose!\n", bit, port); - return -EINVAL; - } - - *dirp = dir; - *datp = dat; - *mskp = msk; - - return 0; -} -#endif - -#ifdef CONFIG_8260 -static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) -{ - iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; - void *dir, *dat, *ppar; - int adv; - u8 msk; - - switch (port) { - case fsiop_porta: - dir = &io->iop_pdira; - dat = &io->iop_pdata; - ppar = &io->iop_ppara; - break; - - case fsiop_portb: - dir = &io->iop_pdirb; - dat = &io->iop_pdatb; - ppar = &io->iop_pparb; - break; - - case fsiop_portc: - dir = &io->iop_pdirc; - dat = &io->iop_pdatc; - ppar = &io->iop_pparc; - break; - - case fsiop_portd: - dir = &io->iop_pdird; - dat = &io->iop_pdatd; - ppar = &io->iop_ppard; - break; - - default: - printk(KERN_ERR DRV_MODULE_NAME - "Illegal port value %d!\n", port); - return -EINVAL; - } + dat = (void*) mii_bit->offset; - adv = bit >> 3; - dir = (char *)dir + adv; + adv = mii_bit->bit >> 3; dat = (char *)dat + adv; - ppar = (char *)ppar + adv; - msk = 1 << (7 - (bit & 7)); - if ((in_8(ppar) & msk) != 0) { - printk(KERN_ERR DRV_MODULE_NAME - "pin %d on port %d is not general purpose!\n", bit, port); - return -EINVAL; - } + msk = 1 << (7 - (mii_bit->bit & 7)); - *dirp = dir; *datp = dat; *mskp = msk; return 0; } -#endif static inline void bb_set(u8 *p, u8 m) { @@ -179,44 +76,44 @@ static inline int bb_read(u8 *p, u8 m) return (in_8(p) & m) != 0; } -static inline void mdio_active(struct fs_enet_mii_bus *bus) +static inline void mdio_active(struct bb_info *bitbang) { - bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); + bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk); } -static inline void mdio_tristate(struct fs_enet_mii_bus *bus) +static inline void mdio_tristate(struct bb_info *bitbang ) { - bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); + bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk); } -static inline int mdio_read(struct fs_enet_mii_bus *bus) +static inline int mdio_read(struct bb_info *bitbang ) { - return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk); } -static inline void mdio(struct fs_enet_mii_bus *bus, int what) +static inline void mdio(struct bb_info *bitbang , int what) { if (what) - bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk); else - bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); + bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk); } -static inline void mdc(struct fs_enet_mii_bus *bus, int what) +static inline void mdc(struct bb_info *bitbang , int what) { if (what) - bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + bb_set(bitbang->mdc_dat, bitbang->mdc_msk); else - bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); + bb_clr(bitbang->mdc_dat, bitbang->mdc_msk); } -static inline void mii_delay(struct fs_enet_mii_bus *bus) +static inline void mii_delay(struct bb_info *bitbang ) { - udelay(bus->bus_info->i.bitbang.delay); + udelay(bitbang->delay); } /* Utility to send the preamble, address, and register (common to read and write). */ -static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) +static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg) { int j; @@ -228,177 +125,284 @@ static void bitbang_pre(struct fs_enet_m * but it is safer and will be much more robust. */ - mdio_active(bus); - mdio(bus, 1); + mdio_active(bitbang); + mdio(bitbang, 1); for (j = 0; j < 32; j++) { - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); } /* send the start bit (01) and the read opcode (10) or write (10) */ - mdc(bus, 0); - mdio(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, 1); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, read); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, !read); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, read); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, !read); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* send the PHY address */ for (j = 0; j < 5; j++) { - mdc(bus, 0); - mdio(bus, (addr & 0x10) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio(bitbang, (addr & 0x10) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); addr <<= 1; } /* send the register address */ for (j = 0; j < 5; j++) { - mdc(bus, 0); - mdio(bus, (reg & 0x10) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio(bitbang, (reg & 0x10) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); reg <<= 1; } } -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) +static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location) { u16 rdreg; int ret, j; u8 addr = phy_id & 0xff; u8 reg = location & 0xff; + struct bb_info* bitbang = bus->priv; - bitbang_pre(bus, 1, addr, reg); + bitbang_pre(bitbang, 1, addr, reg); /* tri-state our MDIO I/O pin so we can read */ - mdc(bus, 0); - mdio_tristate(bus); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio_tristate(bitbang); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* check the turnaround bit: the PHY should be driving it to zero */ - if (mdio_read(bus) != 0) { + if (mdio_read(bitbang) != 0) { /* PHY didn't drive TA low */ for (j = 0; j < 32; j++) { - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); } ret = -1; goto out; } - mdc(bus, 0); - mii_delay(bus); + mdc(bitbang, 0); + mii_delay(bitbang); /* read 16 bits of register data, MSB first */ rdreg = 0; for (j = 0; j < 16; j++) { - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 1); + mii_delay(bitbang); rdreg <<= 1; - rdreg |= mdio_read(bus); - mdc(bus, 0); - mii_delay(bus); + rdreg |= mdio_read(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); } - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); ret = rdreg; out: return ret; } -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) +static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val) { int j; + struct bb_info* bitbang = bus->priv; + u8 addr = phy_id & 0xff; u8 reg = location & 0xff; u16 value = val & 0xffff; - bitbang_pre(bus, 0, addr, reg); + bitbang_pre(bitbang, 0, addr, reg); /* send the turnaround (10) */ - mdc(bus, 0); - mdio(bus, 1); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); - mdc(bus, 0); - mdio(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + mdc(bitbang, 0); + mdio(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); /* write 16 bits of register data, MSB first */ for (j = 0; j < 16; j++) { - mdc(bus, 0); - mdio(bus, (value & 0x8000) != 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdc(bitbang, 0); + mdio(bitbang, (value & 0x8000) != 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); value <<= 1; } /* * Tri-state the MDIO line. */ - mdio_tristate(bus); - mdc(bus, 0); - mii_delay(bus); - mdc(bus, 1); - mii_delay(bus); + mdio_tristate(bitbang); + mdc(bitbang, 0); + mii_delay(bitbang); + mdc(bitbang, 1); + mii_delay(bitbang); + return 0; } -int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) +static int fs_enet_mii_bb_reset(struct mii_bus *bus) +{ + /*nothing here - dunno how to reset it*/ + return 0; +} + +static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi) { - const struct fs_mii_bus_info *bi = bus->bus_info; int r; - r = bitbang_prep_bit(&bus->bitbang.mdio_dir, - &bus->bitbang.mdio_dat, - &bus->bitbang.mdio_msk, - bi->i.bitbang.mdio_port, - bi->i.bitbang.mdio_bit); + bitbang->delay = fmpi->delay; + + r = bitbang_prep_bit(&bitbang->mdio_dir, + &bitbang->mdio_dir_msk, + &fmpi->mdio_dir); if (r != 0) return r; - r = bitbang_prep_bit(&bus->bitbang.mdc_dir, - &bus->bitbang.mdc_dat, - &bus->bitbang.mdc_msk, - bi->i.bitbang.mdc_port, - bi->i.bitbang.mdc_bit); + r = bitbang_prep_bit(&bitbang->mdio_dat, + &bitbang->mdio_dat_msk, + &fmpi->mdio_dat); if (r != 0) return r; - bus->mii_read = mii_read; - bus->mii_write = mii_write; + r = bitbang_prep_bit(&bitbang->mdc_dat, + &bitbang->mdc_msk, + &fmpi->mdc_dat); + if (r != 0) + return r; return 0; } + + +static int __devinit fs_enet_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fs_mii_bb_platform_info *pdata; + struct mii_bus *new_bus; + struct bb_info *bitbang; + int err = 0; + + if (NULL == dev) + return -EINVAL; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); + + if (NULL == bitbang) + return -ENOMEM; + + new_bus->name = "BB MII Bus", + new_bus->read = &fs_enet_mii_bb_read, + new_bus->write = &fs_enet_mii_bb_write, + new_bus->reset = &fs_enet_mii_bb_reset, + new_bus->id = pdev->id; + + new_bus->phy_mask = ~0x9; + pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /*set up workspace*/ + fs_mii_bitbang_init(bitbang, pdata); + + new_bus->priv = bitbang; + + new_bus->irq = pdata->irq; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + kfree(bitbang); + kfree(new_bus); + + return err; +} + + +static int fs_enet_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + + iounmap((void *) (&bus->priv)); + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver fs_enet_bb_mdio_driver = { + .name = "fsl-bb-mdio", + .bus = &platform_bus_type, + .probe = fs_enet_mdio_probe, + .remove = fs_enet_mdio_remove, +}; + +int fs_enet_mdio_bb_init(void) +{ + return driver_register(&fs_enet_bb_mdio_driver); +} + +void fs_enet_mdio_bb_exit(void) +{ + driver_unregister(&fs_enet_bb_mdio_driver); +} + diff -puN /dev/null drivers/net/fs_enet/mii-fec.c --- /dev/null +++ a/drivers/net/fs_enet/mii-fec.c @@ -0,0 +1,243 @@ +/* + * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fs_enet.h" +#include "fec.h" + +/* Make MII read/write commands for the FEC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) +#define mk_mii_end 0 + +#define FEC_MII_LOOPS 10000 + +static int match_has_phy (struct device *dev, void* data) +{ + struct platform_device* pdev = container_of(dev, struct platform_device, dev); + struct fs_platform_info* fpi; + if(strcmp(pdev->name, (char*)data)) + { + return 0; + } + + fpi = pdev->dev.platform_data; + if((fpi)&&(fpi->has_phy)) + return 1; + return 0; +} + +static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi) +{ + struct resource *r; + fec_t *fecp; + char* name = "fsl-cpm-fec"; + + /* we need fec in order to be useful */ + struct platform_device *fec_pdev = + container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy), + struct platform_device, dev); + + if(fec_pdev == NULL) { + printk(KERN_ERR"Unable to find PHY for %s", name); + return -ENODEV; + } + + r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs"); + + fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t)); + fec->mii_speed = fmpi->mii_speed; + + setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ + setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + out_be32(&fecp->fec_mii_speed, fec->mii_speed); + + return 0; +} + +static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) +{ + struct fec_info* fec = bus->priv; + fec_t *fecp = fec->fecp; + int i, ret = -1; + + if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) { + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + ret = in_be32(&fecp->fec_mii_data) & 0xffff; + } + + return ret; + +} + +static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +{ + struct fec_info* fec = bus->priv; + fec_t *fecp = fec->fecp; + int i; + + /* this must never happen */ + if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) + BUG(); + + /* Add PHY address to register command. */ + out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); + + for (i = 0; i < FEC_MII_LOOPS; i++) + if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) + break; + + if (i < FEC_MII_LOOPS) + out_be32(&fecp->fec_ievent, FEC_ENET_MII); + + return 0; + +} + +static int fs_enet_fec_mii_reset(struct mii_bus *bus) +{ + /* nothing here - for now */ + return 0; +} + +static int __devinit fs_enet_fec_mdio_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fs_mii_fec_platform_info *pdata; + struct mii_bus *new_bus; + struct fec_info *fec; + int err = 0; + if (NULL == dev) + return -EINVAL; + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) + return -ENOMEM; + + fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); + + if (NULL == fec) + return -ENOMEM; + + new_bus->name = "FEC MII Bus", + new_bus->read = &fs_enet_fec_mii_read, + new_bus->write = &fs_enet_fec_mii_write, + new_bus->reset = &fs_enet_fec_mii_reset, + new_bus->id = pdev->id; + + pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data; + + if (NULL == pdata) { + printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id); + return -ENODEV; + } + + /*set up workspace*/ + + fs_mii_fec_init(fec, pdata); + new_bus->priv = fec; + + new_bus->irq = pdata->irq; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + kfree(new_bus); + + return err; +} + + +static int fs_enet_fec_mdio_remove(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + + mdiobus_unregister(bus); + + dev_set_drvdata(dev, NULL); + kfree(bus->priv); + + bus->priv = NULL; + kfree(bus); + + return 0; +} + +static struct device_driver fs_enet_fec_mdio_driver = { + .name = "fsl-cpm-fec-mdio", + .bus = &platform_bus_type, + .probe = fs_enet_fec_mdio_probe, + .remove = fs_enet_fec_mdio_remove, +}; + +int fs_enet_mdio_fec_init(void) +{ + return driver_register(&fs_enet_fec_mdio_driver); +} + +void fs_enet_mdio_fec_exit(void) +{ + driver_unregister(&fs_enet_fec_mdio_driver); +} + diff -puN drivers/net/fs_enet/mii-fixed.c~git-netdev-all /dev/null --- a/drivers/net/fs_enet/mii-fixed.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_enet.h" - -static const u16 mii_regs[7] = { - 0x3100, - 0x786d, - 0x0fff, - 0x0fff, - 0x01e1, - 0x45e1, - 0x0003, -}; - -static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) -{ - int ret = 0; - - if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) - return -1; - - if (location != 5) - ret = mii_regs[location]; - else - ret = bus->fixed.lpa; - - return ret; -} - -static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) -{ - /* do nothing */ -} - -int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) -{ - const struct fs_mii_bus_info *bi = bus->bus_info; - - bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ - - /* if speed is fixed at 10Mb, remove 100Mb modes */ - if (bi->i.fixed.speed == 10) - bus->fixed.lpa &= ~LPA_100; - - /* if duplex is half, remove full duplex modes */ - if (bi->i.fixed.duplex == 0) - bus->fixed.lpa &= ~LPA_DUPLEX; - - bus->mii_read = mii_read; - bus->mii_write = mii_write; - - return 0; -} diff -puN drivers/net/hp100.c~git-netdev-all drivers/net/hp100.c --- a/drivers/net/hp100.c~git-netdev-all +++ a/drivers/net/hp100.c @@ -111,7 +111,6 @@ #include #include #include -#include /* for CONFIG_PCI */ #include #include #include diff -puN drivers/net/irda/mcs7780.c~git-netdev-all drivers/net/irda/mcs7780.c --- a/drivers/net/irda/mcs7780.c~git-netdev-all +++ a/drivers/net/irda/mcs7780.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include diff -puN drivers/net/irda/w83977af_ir.c~git-netdev-all drivers/net/irda/w83977af_ir.c --- a/drivers/net/irda/w83977af_ir.c~git-netdev-all +++ a/drivers/net/irda/w83977af_ir.c @@ -40,7 +40,6 @@ ********************************************************************/ #include -#include #include #include #include diff -puN drivers/net/ixgb/ixgb_hw.c~git-netdev-all drivers/net/ixgb/ixgb_hw.c --- a/drivers/net/ixgb/ixgb_hw.c~git-netdev-all +++ a/drivers/net/ixgb/ixgb_hw.c @@ -236,6 +236,17 @@ ixgb_identify_phy(struct ixgb_hw *hw) DEBUGOUT("Identified G6104 optics\n"); phy_type = ixgb_phy_type_g6104; break; + case IXGB_DEVICE_ID_82597EX_CX4: + DEBUGOUT("Identified CX4\n"); + xpak_vendor = ixgb_identify_xpak_vendor(hw); + if (xpak_vendor == ixgb_xpak_vendor_intel) { + DEBUGOUT("Identified TXN17201 optics\n"); + phy_type = ixgb_phy_type_txn17201; + } else { + DEBUGOUT("Identified G6005 optics\n"); + phy_type = ixgb_phy_type_g6005; + } + break; default: DEBUGOUT("Unknown physical layer module\n"); phy_type = ixgb_phy_type_unknown; diff -puN drivers/net/ixgb/ixgb_ids.h~git-netdev-all drivers/net/ixgb/ixgb_ids.h --- a/drivers/net/ixgb/ixgb_ids.h~git-netdev-all +++ a/drivers/net/ixgb/ixgb_ids.h @@ -45,6 +45,7 @@ #define IXGB_DEVICE_ID_82597EX_CX4 0x109E #define IXGB_SUBDEVICE_ID_A00C 0xA00C +#define IXGB_SUBDEVICE_ID_A01C 0xA01C #endif /* #ifndef _IXGB_IDS_H_ */ /* End of File */ diff -puN drivers/net/ixgb/ixgb_main.c~git-netdev-all drivers/net/ixgb/ixgb_main.c --- a/drivers/net/ixgb/ixgb_main.c~git-netdev-all +++ a/drivers/net/ixgb/ixgb_main.c @@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Inte #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "1.0.109-k2"DRIVERNAPI +#define DRV_VERSION "1.0.109-k4"DRIVERNAPI char ixgb_driver_version[] = DRV_VERSION; static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -140,12 +140,12 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); /* some defines for controlling descriptor fetches in h/w */ -#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */ -#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below - * this */ -#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail - * is pushed this many descriptors - * from head */ +#define RXDCTL_WTHRESH_DEFAULT 15 /* chip writes back at this many or RXT0 */ +#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below + * this */ +#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail + * is pushed this many descriptors + * from head */ /** * ixgb_init_module - Driver Registration Routine @@ -162,7 +162,7 @@ ixgb_init_module(void) printk(KERN_INFO "%s\n", ixgb_copyright); - return pci_module_init(&ixgb_driver); + return pci_register_driver(&ixgb_driver); } module_init(ixgb_init_module); diff -puN drivers/net/lance.c~git-netdev-all drivers/net/lance.c --- a/drivers/net/lance.c~git-netdev-all +++ a/drivers/net/lance.c @@ -326,7 +326,7 @@ MODULE_PARM_DESC(dma, "LANCE/PCnet ISA D MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)"); MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)"); -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/lne390.c~git-netdev-all drivers/net/lne390.c --- a/drivers/net/lne390.c~git-netdev-all +++ a/drivers/net/lne390.c @@ -406,7 +406,7 @@ MODULE_PARM_DESC(mem, "memory base addre MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver"); MODULE_LICENSE("GPL"); -int init_module(void) +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/myri10ge/myri10ge.c~git-netdev-all drivers/net/myri10ge/myri10ge.c --- a/drivers/net/myri10ge/myri10ge.c~git-netdev-all +++ a/drivers/net/myri10ge/myri10ge.c @@ -187,11 +187,14 @@ struct myri10ge_priv { u8 mac_addr[6]; /* eeprom mac address */ unsigned long serial_number; int vendor_specific_offset; + int fw_multicast_support; u32 devctl; u16 msi_flags; u32 read_dma; u32 write_dma; u32 read_write_dma; + u32 link_changes; + u32 msg_enable; }; static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; @@ -257,6 +260,12 @@ module_param(myri10ge_max_irq_loops, int MODULE_PARM_DESC(myri10ge_max_irq_loops, "Set stuck legacy IRQ detection threshold\n"); +#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK + +static int myri10ge_debug = -1; /* defaults above */ +module_param(myri10ge_debug, int, 0); +MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); + #define MYRI10GE_FW_OFFSET 1024*1024 #define MYRI10GE_HIGHPART_TO_U32(X) \ (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) @@ -271,7 +280,7 @@ myri10ge_send_cmd(struct myri10ge_priv * struct mcp_cmd *buf; char buf_bytes[sizeof(*buf) + 8]; struct mcp_cmd_response *response = mgp->cmd; - char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET; + char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD; u32 dma_low, dma_high, result, value; int sleep_total = 0; @@ -320,6 +329,8 @@ myri10ge_send_cmd(struct myri10ge_priv * if (result == 0) { data->data0 = value; return 0; + } else if (result == MXGEFW_CMD_UNKNOWN) { + return -ENOSYS; } else { dev_err(&mgp->pdev->dev, "command %d failed, result = %d\n", @@ -404,7 +415,7 @@ static void myri10ge_dummy_rdma(struct m buf[4] = htonl(dma_low); /* dummy addr LSW */ buf[5] = htonl(enable); /* enable? */ - submit = mgp->sram + 0xfc01c0; + submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA; myri10ge_pio_copy(submit, &buf, sizeof(buf)); for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++) @@ -600,7 +611,7 @@ static int myri10ge_load_firmware(struct buf[5] = htonl(8); /* where to copy to */ buf[6] = htonl(0); /* where to jump to */ - submit = mgp->sram + 0xfc0000; + submit = mgp->sram + MXGEFW_BOOT_HANDOFF; myri10ge_pio_copy(submit, &buf, sizeof(buf)); mb(); @@ -764,6 +775,7 @@ static int myri10ge_reset(struct myri10g mgp->rx_small.cnt = 0; mgp->rx_done.idx = 0; mgp->rx_done.cnt = 0; + mgp->link_changes = 0; status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); myri10ge_change_promisc(mgp, 0, 0); myri10ge_change_pause(mgp, mgp->pause); @@ -798,12 +810,13 @@ myri10ge_submit_8rx(struct mcp_kreq_ethe * pages directly and building a fraglist in the near future. */ -static inline struct sk_buff *myri10ge_alloc_big(int bytes) +static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev, + int bytes) { struct sk_buff *skb; unsigned long data, roundup; - skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD); + skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD); if (skb == NULL) return NULL; @@ -821,12 +834,13 @@ static inline struct sk_buff *myri10ge_a /* Allocate 2x as much space as required and use whichever portion * does not cross a 4KB boundary */ -static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes) +static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev, + unsigned int bytes) { struct sk_buff *skb; unsigned long data, boundary; - skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1); + skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1); if (unlikely(skb == NULL)) return NULL; @@ -847,12 +861,13 @@ static inline struct sk_buff *myri10ge_a /* Allocate just enough space, and verify that the allocated * space does not cross a 4KB boundary */ -static inline struct sk_buff *myri10ge_alloc_small(int bytes) +static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev, + int bytes) { struct sk_buff *skb; unsigned long roundup, data, end; - skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD); + skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD); if (unlikely(skb == NULL)) return NULL; @@ -868,15 +883,17 @@ static inline struct sk_buff *myri10ge_a "myri10ge_alloc_small: small skb crossed 4KB boundary\n"); myri10ge_skb_cross_4k = 1; dev_kfree_skb_any(skb); - skb = myri10ge_alloc_small_safe(bytes); + skb = myri10ge_alloc_small_safe(dev, bytes); } return skb; } static inline int -myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes, - int idx) +myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp, + int bytes, int idx) { + struct net_device *dev = mgp->dev; + struct pci_dev *pdev = mgp->pdev; struct sk_buff *skb; dma_addr_t bus; int len, retval = 0; @@ -884,11 +901,11 @@ myri10ge_getbuf(struct myri10ge_rx_buf * bytes += VLAN_HLEN; /* account for 802.1q vlan tag */ if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ ) - skb = myri10ge_alloc_big(bytes); + skb = myri10ge_alloc_big(dev, bytes); else if (myri10ge_skb_cross_4k) - skb = myri10ge_alloc_small_safe(bytes); + skb = myri10ge_alloc_small_safe(dev, bytes); else - skb = myri10ge_alloc_small(bytes); + skb = myri10ge_alloc_small(dev, bytes); if (unlikely(skb == NULL)) { rx->alloc_fail++; @@ -951,7 +968,7 @@ myri10ge_rx_done(struct myri10ge_priv *m unmap_len = pci_unmap_len(&rx->info[idx], len); /* try to replace the received skb */ - if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) { + if (myri10ge_getbuf(rx, mgp, bytes, idx)) { /* drop the frame -- the old skbuf is re-cycled */ mgp->stats.rx_dropped += 1; return 0; @@ -968,7 +985,6 @@ myri10ge_rx_done(struct myri10ge_priv *m skb_put(skb, len); skb->protocol = eth_type_trans(skb, mgp->dev); - skb->dev = mgp->dev; if (mgp->csum_flag) { if ((skb->protocol == ntohs(ETH_P_IP)) || (skb->protocol == ntohs(ETH_P_IPV6))) { @@ -1081,13 +1097,19 @@ static inline void myri10ge_check_statbl if (mgp->link_state != stats->link_up) { mgp->link_state = stats->link_up; if (mgp->link_state) { - printk(KERN_INFO "myri10ge: %s: link up\n", - mgp->dev->name); + if (netif_msg_link(mgp)) + printk(KERN_INFO + "myri10ge: %s: link up\n", + mgp->dev->name); netif_carrier_on(mgp->dev); + mgp->link_changes++; } else { - printk(KERN_INFO "myri10ge: %s: link down\n", - mgp->dev->name); + if (netif_msg_link(mgp)) + printk(KERN_INFO + "myri10ge: %s: link down\n", + mgp->dev->name); netif_carrier_off(mgp->dev); + mgp->link_changes++; } } if (mgp->rdma_tags_available != @@ -1289,7 +1311,8 @@ static const char myri10ge_gstrings_stat "serial_number", "tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt", "wake_queue", "stop_queue", "watchdog_resets", "tx_linearized", - "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered", + "link_changes", "link_up", "dropped_link_overflow", + "dropped_link_error_or_filtered", "dropped_multicast_filtered", "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", "dropped_no_big_buffer" }; @@ -1341,16 +1364,31 @@ myri10ge_get_ethtool_stats(struct net_de data[i++] = (unsigned int)mgp->stop_queue; data[i++] = (unsigned int)mgp->watchdog_resets; data[i++] = (unsigned int)mgp->tx_linearized; + data[i++] = (unsigned int)mgp->link_changes; data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered); + data[i++] = + (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer); } +static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + mgp->msg_enable = value; +} + +static u32 myri10ge_get_msglevel(struct net_device *netdev) +{ + struct myri10ge_priv *mgp = netdev_priv(netdev); + return mgp->msg_enable; +} + static struct ethtool_ops myri10ge_ethtool_ops = { .get_settings = myri10ge_get_settings, .get_drvinfo = myri10ge_get_drvinfo, @@ -1371,7 +1409,9 @@ static struct ethtool_ops myri10ge_ethto #endif .get_strings = myri10ge_get_strings, .get_stats_count = myri10ge_get_stats_count, - .get_ethtool_stats = myri10ge_get_ethtool_stats + .get_ethtool_stats = myri10ge_get_ethtool_stats, + .set_msglevel = myri10ge_set_msglevel, + .get_msglevel = myri10ge_get_msglevel }; static int myri10ge_allocate_rings(struct net_device *dev) @@ -1439,7 +1479,7 @@ static int myri10ge_allocate_rings(struc /* Fill the receive rings */ for (i = 0; i <= mgp->rx_small.mask; i++) { - status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev, + status = myri10ge_getbuf(&mgp->rx_small, mgp, mgp->small_bytes, i); if (status) { printk(KERN_ERR @@ -1451,8 +1491,7 @@ static int myri10ge_allocate_rings(struc for (i = 0; i <= mgp->rx_big.mask; i++) { status = - myri10ge_getbuf(&mgp->rx_big, mgp->pdev, - dev->mtu + ETH_HLEN, i); + myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i); if (status) { printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n", @@ -1648,9 +1687,11 @@ static int myri10ge_open(struct net_devi } if (mgp->mtrr >= 0) { - mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000; - mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000; - mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000; + mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4; + mgp->rx_small.wc_fifo = + (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL; + mgp->rx_big.wc_fifo = + (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG; } else { mgp->tx.wc_fifo = NULL; mgp->rx_small.wc_fifo = NULL; @@ -1686,7 +1727,21 @@ static int myri10ge_open(struct net_devi cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus); cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus); - status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0); + cmd.data2 = sizeof(struct mcp_irq_data); + status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); + if (status == -ENOSYS) { + dma_addr_t bus = mgp->fw_stats_bus; + bus += offsetof(struct mcp_irq_data, send_done_count); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); + status = myri10ge_send_cmd(mgp, + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, + &cmd, 0); + /* Firmware cannot support multicast without STATS_DMA_V2 */ + mgp->fw_multicast_support = 0; + } else { + mgp->fw_multicast_support = 1; + } if (status) { printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n", dev->name); @@ -1841,7 +1896,8 @@ myri10ge_submit_req_wc(struct myri10ge_t if (cnt > 0) { /* pad it to 64 bytes. The src is 64 bytes bigger than it * needs to be so that we don't overrun it */ - myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64); + myri10ge_pio_copy(tx->wc_fifo + MXGEFW_ETH_SEND_OFFSET(cnt), + src, 64); mb(); } } @@ -2140,9 +2196,81 @@ static struct net_device_stats *myri10ge static void myri10ge_set_multicast_list(struct net_device *dev) { + struct myri10ge_cmd cmd; + struct myri10ge_priv *mgp; + struct dev_mc_list *mc_list; + int err; + + mgp = netdev_priv(dev); /* can be called from atomic contexts, * pass 1 to force atomicity in myri10ge_send_cmd() */ - myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1); + myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1); + + /* This firmware is known to not support multicast */ + if (!mgp->fw_multicast_support) + return; + + /* Disable multicast filtering */ + + err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1); + if (err != 0) { + printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_ENABLE_ALLMULTI," + " error status: %d\n", dev->name, err); + goto abort; + } + + if (dev->flags & IFF_ALLMULTI) { + /* request to disable multicast filtering, so quit here */ + return; + } + + /* Flush the filters */ + + err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, + &cmd, 1); + if (err != 0) { + printk(KERN_ERR + "myri10ge: %s: Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS" + ", error status: %d\n", dev->name, err); + goto abort; + } + + /* Walk the multicast list, and add each address */ + for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) { + memcpy(&cmd.data0, &mc_list->dmi_addr, 4); + memcpy(&cmd.data1, ((char *)&mc_list->dmi_addr) + 4, 2); + cmd.data0 = htonl(cmd.data0); + cmd.data1 = htonl(cmd.data1); + err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP, + &cmd, 1); + + if (err != 0) { + printk(KERN_ERR "myri10ge: %s: Failed " + "MXGEFW_JOIN_MULTICAST_GROUP, error status:" + "%d\t", dev->name, err); + printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + ((unsigned char *)&mc_list->dmi_addr)[0], + ((unsigned char *)&mc_list->dmi_addr)[1], + ((unsigned char *)&mc_list->dmi_addr)[2], + ((unsigned char *)&mc_list->dmi_addr)[3], + ((unsigned char *)&mc_list->dmi_addr)[4], + ((unsigned char *)&mc_list->dmi_addr)[5] + ); + goto abort; + } + } + /* Enable multicast filtering */ + err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1); + if (err != 0) { + printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_DISABLE_ALLMULTI," + "error status: %d\n", dev->name, err); + goto abort; + } + + return; + +abort: + return; } static int myri10ge_set_mac_address(struct net_device *dev, void *addr) @@ -2581,6 +2709,7 @@ static int myri10ge_probe(struct pci_dev mgp->csum_flag = MXGEFW_FLAGS_CKSUM; mgp->pause = myri10ge_flow_control; mgp->intr_coal_delay = myri10ge_intr_coal_delay; + mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); init_waitqueue_head(&mgp->down_wq); if (pci_enable_device(pdev)) { diff -puN drivers/net/myri10ge/myri10ge_mcp.h~git-netdev-all drivers/net/myri10ge/myri10ge_mcp.h --- a/drivers/net/myri10ge/myri10ge_mcp.h~git-netdev-all +++ a/drivers/net/myri10ge/myri10ge_mcp.h @@ -91,7 +91,19 @@ struct mcp_kreq_ether_recv { /* Commands */ -#define MXGEFW_CMD_OFFSET 0xf80000 +#define MXGEFW_BOOT_HANDOFF 0xfc0000 +#define MXGEFW_BOOT_DUMMY_RDMA 0xfc01c0 + +#define MXGEFW_ETH_CMD 0xf80000 +#define MXGEFW_ETH_SEND_4 0x200000 +#define MXGEFW_ETH_SEND_1 0x240000 +#define MXGEFW_ETH_SEND_2 0x280000 +#define MXGEFW_ETH_SEND_3 0x2c0000 +#define MXGEFW_ETH_RECV_SMALL 0x300000 +#define MXGEFW_ETH_RECV_BIG 0x340000 + +#define MXGEFW_ETH_SEND(n) (0x200000 + (((n) & 0x03) * 0x40000)) +#define MXGEFW_ETH_SEND_OFFSET(n) (MXGEFW_ETH_SEND(n) - MXGEFW_ETH_SEND_4) enum myri10ge_mcp_cmd_type { MXGEFW_CMD_NONE = 0, @@ -154,7 +166,7 @@ enum myri10ge_mcp_cmd_type { MXGEFW_CMD_SET_MTU, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ - MXGEFW_CMD_SET_STATS_DMA, + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */ MXGEFW_ENABLE_PROMISC, MXGEFW_DISABLE_PROMISC, @@ -168,7 +180,26 @@ enum myri10ge_mcp_cmd_type { * data2 = RDMA length (MSH), WDMA length (LSH) * command return data = repetitions (MSH), 0.5-ms ticks (LSH) */ - MXGEFW_DMA_TEST + MXGEFW_DMA_TEST, + + MXGEFW_ENABLE_ALLMULTI, + MXGEFW_DISABLE_ALLMULTI, + + /* returns MXGEFW_CMD_ERROR_MULTICAST + * if there is no room in the cache + * data0,MSH(data1) = multicast group address */ + MXGEFW_JOIN_MULTICAST_GROUP, + /* returns MXGEFW_CMD_ERROR_MULTICAST + * if the address is not in the cache, + * or is equal to FF-FF-FF-FF-FF-FF + * data0,MSH(data1) = multicast group address */ + MXGEFW_LEAVE_MULTICAST_GROUP, + MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, + + MXGEFW_CMD_SET_STATS_DMA_V2, + /* data0, data1 = bus addr, + * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows + * adding new stuff to mcp_irq_data without changing the ABI */ }; enum myri10ge_mcp_cmd_status { @@ -180,11 +211,17 @@ enum myri10ge_mcp_cmd_status { MXGEFW_CMD_ERROR_CLOSED, MXGEFW_CMD_ERROR_HASH_ERROR, MXGEFW_CMD_ERROR_BAD_PORT, - MXGEFW_CMD_ERROR_RESOURCES + MXGEFW_CMD_ERROR_RESOURCES, + MXGEFW_CMD_ERROR_MULTICAST }; -/* 40 Bytes */ +#define MXGEFW_OLD_IRQ_DATA_LEN 40 + struct mcp_irq_data { + /* add new counters at the beginning */ + u32 future_use[5]; + u32 dropped_multicast_filtered; + /* 40 Bytes */ u32 send_done_count; u32 link_up; diff -puN drivers/net/natsemi.c~git-netdev-all drivers/net/natsemi.c --- a/drivers/net/natsemi.c~git-netdev-all +++ a/drivers/net/natsemi.c @@ -3246,7 +3246,7 @@ static int __init natsemi_init_mod (void printk(version); #endif - return pci_module_init (&natsemi_driver); + return pci_register_driver(&natsemi_driver); } static void __exit natsemi_exit_mod (void) diff -puN drivers/net/ne2k-pci.c~git-netdev-all drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c~git-netdev-all +++ a/drivers/net/ne2k-pci.c @@ -702,7 +702,7 @@ static int __init ne2k_pci_init(void) #ifdef MODULE printk(version); #endif - return pci_module_init (&ne2k_driver); + return pci_register_driver(&ne2k_driver); } diff -puN drivers/net/netx-eth.c~git-netdev-all drivers/net/netx-eth.c --- a/drivers/net/netx-eth.c~git-netdev-all +++ a/drivers/net/netx-eth.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff -puN drivers/net/ni52.c~git-netdev-all drivers/net/ni52.c --- a/drivers/net/ni52.c~git-netdev-all +++ a/drivers/net/ni52.c @@ -1323,7 +1323,7 @@ MODULE_PARM_DESC(irq, "NI5210 IRQ number MODULE_PARM_DESC(memstart, "NI5210 memory base address,required"); MODULE_PARM_DESC(memend, "NI5210 memory end address,required"); -int init_module(void) +int __init init_module(void) { if(io <= 0x0 || !memend || !memstart || irq < 2) { printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); diff -puN drivers/net/ni65.c~git-netdev-all drivers/net/ni65.c --- a/drivers/net/ni65.c~git-netdev-all +++ a/drivers/net/ni65.c @@ -1253,7 +1253,7 @@ MODULE_PARM_DESC(irq, "ni6510 IRQ number MODULE_PARM_DESC(io, "ni6510 I/O base address"); MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)"); -int init_module(void) +int __init init_module(void) { dev_ni65 = ni65_probe(-1); return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0; diff -puN drivers/net/ns83820.c~git-netdev-all drivers/net/ns83820.c --- a/drivers/net/ns83820.c~git-netdev-all +++ a/drivers/net/ns83820.c @@ -2178,7 +2178,7 @@ static struct pci_driver driver = { static int __init ns83820_init(void) { printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n"); - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void __exit ns83820_exit(void) diff -puN drivers/net/pci-skeleton.c~git-netdev-all drivers/net/pci-skeleton.c --- a/drivers/net/pci-skeleton.c~git-netdev-all +++ a/drivers/net/pci-skeleton.c @@ -1963,7 +1963,7 @@ static int __init netdrv_init_module (vo #ifdef MODULE printk(version); #endif - return pci_module_init (&netdrv_pci_driver); + return pci_register_driver(&netdrv_pci_driver); } diff -puN drivers/net/pcmcia/axnet_cs.c~git-netdev-all drivers/net/pcmcia/axnet_cs.c --- a/drivers/net/pcmcia/axnet_cs.c~git-netdev-all +++ a/drivers/net/pcmcia/axnet_cs.c @@ -771,6 +771,7 @@ static struct pcmcia_device_id axnet_ids PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309), PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106), PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), + PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc), PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef), PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef), @@ -786,8 +787,6 @@ static struct pcmcia_device_id axnet_ids PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116), PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058), PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef), - /* this is not specific enough */ - /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */ PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, axnet_ids); diff -puN drivers/net/pcmcia/pcnet_cs.c~git-netdev-all drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c~git-netdev-all +++ a/drivers/net/pcmcia/pcnet_cs.c @@ -654,11 +654,8 @@ static int pcnet_config(struct pcmcia_de SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); if (info->flags & (IS_DL10019|IS_DL10022)) { - u_char id = inb(dev->base_addr + 0x1a); dev->do_ioctl = &ei_ioctl; mii_phy_probe(dev); - if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4)) - info->eth_phy = 0; } link->dev_node = &info->node; @@ -821,15 +818,6 @@ static void mdio_write(kio_addr_t addr, } } -static void mdio_reset(kio_addr_t addr, int phy_id) -{ - outb_p(0x08, addr); - outb_p(0x0c, addr); - outb_p(0x08, addr); - outb_p(0x0c, addr); - outb_p(0x00, addr); -} - /*====================================================================== EEPROM access routines for DL10019 and DL10022 based cards @@ -942,7 +930,8 @@ static void set_misc_reg(struct net_devi } if (info->flags & IS_DL10022) { if (info->flags & HAS_MII) { - mdio_reset(nic_base + DLINK_GPIO, info->eth_phy); + /* Advertise 100F, 100H, 10F, 10H */ + mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1); /* Restart MII autonegotiation */ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000); mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200); diff -puN drivers/net/pcmcia/xirc2ps_cs.c~git-netdev-all drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c~git-netdev-all +++ a/drivers/net/pcmcia/xirc2ps_cs.c @@ -345,6 +345,7 @@ typedef struct local_info_t { void __iomem *dingo_ccr; /* only used for CEM56 cards */ unsigned last_ptr_value; /* last packets transmitted value */ const char *manf_str; + struct work_struct tx_timeout_task; } local_info_t; /**************** @@ -352,6 +353,7 @@ typedef struct local_info_t { */ static int do_start_xmit(struct sk_buff *skb, struct net_device *dev); static void do_tx_timeout(struct net_device *dev); +static void xirc2ps_tx_timeout_task(void *data); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -589,6 +591,7 @@ xirc2ps_probe(struct pcmcia_device *link #ifdef HAVE_TX_TIMEOUT dev->tx_timeout = do_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev); #endif return xirc2ps_config(link); @@ -1341,17 +1344,24 @@ xirc2ps_interrupt(int irq, void *dev_id, /*====================================================================*/ static void -do_tx_timeout(struct net_device *dev) +xirc2ps_tx_timeout_task(void *data) { - local_info_t *lp = netdev_priv(dev); - printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); - lp->stats.tx_errors++; + struct net_device *dev = data; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; netif_wake_queue(dev); } +static void +do_tx_timeout(struct net_device *dev) +{ + local_info_t *lp = netdev_priv(dev); + lp->stats.tx_errors++; + printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); + schedule_work(&lp->tx_timeout_task); +} + static int do_start_xmit(struct sk_buff *skb, struct net_device *dev) { diff -puN drivers/net/pcnet32.c~git-netdev-all drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c~git-netdev-all +++ a/drivers/net/pcnet32.c @@ -202,6 +202,8 @@ static int homepna[MAX_UNITS]; #define CSR15 15 #define PCNET32_MC_FILTER 8 +#define PCNET32_79C970A 0x2621 + /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { u32 base; @@ -289,6 +291,7 @@ struct pcnet32_private { /* each bit indicates an available PHY */ u32 phymask; + unsigned short chip_version; /* which variant this is */ }; static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); @@ -724,9 +727,11 @@ static u32 pcnet32_get_link(struct net_d spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { r = mii_link_ok(&lp->mii_if); - } else { + } else if (lp->chip_version >= PCNET32_79C970A) { ulong ioaddr = dev->base_addr; /* card base I/O address */ r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } else { /* can not detect link on really old chips */ + r = 1; } spin_unlock_irqrestore(&lp->lock, flags); @@ -1091,6 +1096,10 @@ static int pcnet32_suspend(struct net_de ulong ioaddr = dev->base_addr; int ticks; + /* really old chips have to be stopped. */ + if (lp->chip_version < PCNET32_79C970A) + return 0; + /* set SUSPEND (SPND) - CSR5 bit 0 */ csr5 = a->read_csr(ioaddr, CSR5); a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND); @@ -1529,6 +1538,7 @@ pcnet32_probe1(unsigned long ioaddr, int lp->mii_if.reg_num_mask = 0x1f; lp->dxsuflo = dxsuflo; lp->mii = mii; + lp->chip_version = chip_version; lp->msg_enable = pcnet32_debug; if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) @@ -1839,10 +1849,7 @@ static int pcnet32_open(struct net_devic val |= 2; } else if (lp->options & PCNET32_PORT_ASEL) { /* workaround of xSeries250, turn on for 79C975 only */ - i = ((lp->a.read_csr(ioaddr, 88) | - (lp->a. - read_csr(ioaddr, 89) << 16)) >> 12) & 0xffff; - if (i == 0x2627) + if (lp->chip_version == 0x2627) val |= 3; } lp->a.write_bcr(ioaddr, 9, val); @@ -1986,9 +1993,11 @@ static int pcnet32_open(struct net_devic netif_start_queue(dev); - /* Print the link status and start the watchdog */ - pcnet32_check_media(dev, 1); - mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + if (lp->chip_version >= PCNET32_79C970A) { + /* Print the link status and start the watchdog */ + pcnet32_check_media(dev, 1); + mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + } i = 0; while (i++ < 100) @@ -2969,7 +2978,7 @@ static int __init pcnet32_init_module(vo tx_start = tx_start_pt; /* find the PCI devices */ - if (!pci_module_init(&pcnet32_driver)) + if (!pci_register_driver(&pcnet32_driver)) pcnet32_have_pci = 1; /* should we find any remaining VLbus devices ? */ diff -puN drivers/net/phy/Kconfig~git-netdev-all drivers/net/phy/Kconfig --- a/drivers/net/phy/Kconfig~git-netdev-all +++ a/drivers/net/phy/Kconfig @@ -56,5 +56,22 @@ config SMSC_PHY ---help--- Currently supports the LAN83C185 PHY +config FIXED_PHY + tristate "Drivers for PHY emulation on fixed speed/link" + depends on PHYLIB + ---help--- + Adds the driver to PHY layer to cover the boards that do not have any PHY bound, + but with the ability to manipulate with speed/link in software. The relavant MII + speed/duplex parameters could be effectively handled in user-specified fuction. + Currently tested with mpc866ads. + +config FIXED_MII_10_FDX + bool "Emulation for 10M Fdx fixed PHY behavior" + depends on FIXED_PHY + +config FIXED_MII_100_FDX + bool "Emulation for 100M Fdx fixed PHY behavior" + depends on FIXED_PHY + endmenu diff -puN drivers/net/phy/Makefile~git-netdev-all drivers/net/phy/Makefile --- a/drivers/net/phy/Makefile~git-netdev-all +++ a/drivers/net/phy/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o +obj-$(CONFIG_FIXED_PHY) += fixed.o diff -puN /dev/null drivers/net/phy/fixed.c --- /dev/null +++ a/drivers/net/phy/fixed.c @@ -0,0 +1,358 @@ +/* + * drivers/net/phy/fixed.c + * + * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode. + * + * Author: Vitaly Bordug + * + * Copyright (c) 2006 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MII_REGS_NUM 7 + +/* + The idea is to emulate normal phy behavior by responding with + pre-defined values to mii BMCR read, so that read_status hook could + take all the needed info. +*/ + +struct fixed_phy_status { + u8 link; + u16 speed; + u8 duplex; +}; + +/*----------------------------------------------------------------------------- + * Private information hoder for mii_bus + *-----------------------------------------------------------------------------*/ +struct fixed_info { + u16 *regs; + u8 regs_num; + struct fixed_phy_status phy_status; + struct phy_device *phydev; /* pointer to the container */ + /* link & speed cb */ + int(*link_update)(struct net_device*, struct fixed_phy_status*); + +}; + +/*----------------------------------------------------------------------------- + * If something weird is required to be done with link/speed, + * network driver is able to assign a function to implement this. + * May be useful for PHY's that need to be software-driven. + *-----------------------------------------------------------------------------*/ +int fixed_mdio_set_link_update(struct phy_device* phydev, + int(*link_update)(struct net_device*, struct fixed_phy_status*)) +{ + struct fixed_info *fixed; + + if(link_update == NULL) + return -EINVAL; + + if(phydev) { + if(phydev->bus) { + fixed = phydev->bus->priv; + fixed->link_update = link_update; + return 0; + } + } + return -EINVAL; +} +EXPORT_SYMBOL(fixed_mdio_set_link_update); + +/*----------------------------------------------------------------------------- + * This is used for updating internal mii regs from the status + *-----------------------------------------------------------------------------*/ +static int fixed_mdio_update_regs(struct fixed_info *fixed) +{ + u16 *regs = fixed->regs; + u16 bmsr = 0; + u16 bmcr = 0; + + if(!regs) { + printk(KERN_ERR "%s: regs not set up", __FUNCTION__); + return -EINVAL; + } + + if(fixed->phy_status.link) + bmsr |= BMSR_LSTATUS; + + if(fixed->phy_status.duplex) { + bmcr |= BMCR_FULLDPLX; + + switch ( fixed->phy_status.speed ) { + case 100: + bmsr |= BMSR_100FULL; + bmcr |= BMCR_SPEED100; + break; + + case 10: + bmsr |= BMSR_10FULL; + break; + } + } else { + switch ( fixed->phy_status.speed ) { + case 100: + bmsr |= BMSR_100HALF; + bmcr |= BMCR_SPEED100; + break; + + case 10: + bmsr |= BMSR_100HALF; + break; + } + } + + regs[MII_BMCR] = bmcr; + regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/ + + return 0; +} + +static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) +{ + struct fixed_info *fixed = bus->priv; + + /* if user has registered link update callback, use it */ + if(fixed->phydev) + if(fixed->phydev->attached_dev) { + if(fixed->link_update) { + fixed->link_update(fixed->phydev->attached_dev, + &fixed->phy_status); + fixed_mdio_update_regs(fixed); + } + } + + if ((unsigned int)location >= fixed->regs_num) + return -1; + return fixed->regs[location]; +} + +static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) +{ + /* do nothing for now*/ + return 0; +} + +static int fixed_mii_reset(struct mii_bus *bus) +{ + /*nothing here - no way/need to reset it*/ + return 0; +} + +static int fixed_config_aneg(struct phy_device *phydev) +{ + /* :TODO:03/13/2006 09:45:37 PM:: + The full autoneg funcionality can be emulated, + but no need to have anything here for now + */ + return 0; +} + +/*----------------------------------------------------------------------------- + * the manual bind will do the magic - with phy_id_mask == 0 + * match will never return true... + *-----------------------------------------------------------------------------*/ +static struct phy_driver fixed_mdio_driver = { + .name = "Fixed PHY", + .features = PHY_BASIC_FEATURES, + .config_aneg = fixed_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +/*----------------------------------------------------------------------------- + * This func is used to create all the necessary stuff, bind + * the fixed phy driver and register all it on the mdio_bus_type. + * speed is either 10 or 100, duplex is boolean. + * number is used to create multiple fixed PHYs, so that several devices can + * utilize them simultaneously. + *-----------------------------------------------------------------------------*/ +static int fixed_mdio_register_device(int number, int speed, int duplex) +{ + struct mii_bus *new_bus; + struct fixed_info *fixed; + struct phy_device *phydev; + int err = 0; + + struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL); + + if (NULL == dev) + return -ENOMEM; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (NULL == new_bus) { + kfree(dev); + return -ENOMEM; + } + fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); + + if (NULL == fixed) { + kfree(dev); + kfree(new_bus); + return -ENOMEM; + } + + fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL); + fixed->regs_num = MII_REGS_NUM; + fixed->phy_status.speed = speed; + fixed->phy_status.duplex = duplex; + fixed->phy_status.link = 1; + + new_bus->name = "Fixed MII Bus", + new_bus->read = &fixed_mii_read, + new_bus->write = &fixed_mii_write, + new_bus->reset = &fixed_mii_reset, + + /*set up workspace*/ + fixed_mdio_update_regs(fixed); + new_bus->priv = fixed; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + /* create phy_device and register it on the mdio bus */ + phydev = phy_device_create(new_bus, 0, 0); + + /* + Put the phydev pointer into the fixed pack so that bus read/write code could + be able to access for instance attached netdev. Well it doesn't have to do + so, only in case of utilizing user-specified link-update... + */ + fixed->phydev = phydev; + + if(NULL == phydev) { + err = -ENOMEM; + goto device_create_fail; + } + + phydev->irq = -1; + phydev->dev.bus = &mdio_bus_type; + + if(number) + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + "fixed_%d@%d:%d", number, speed, duplex); + else + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, + "fixed@%d:%d", speed, duplex); + phydev->bus = new_bus; + + err = device_register(&phydev->dev); + if(err) { + printk(KERN_ERR "Phy %s failed to register\n", + phydev->dev.bus_id); + goto bus_register_fail; + } + + /* + the mdio bus has phy_id match... In order not to do it + artificially, we are binding the driver here by hand; + it will be the same for all the fixed phys anyway. + */ + down_write(&phydev->dev.bus->subsys.rwsem); + + phydev->dev.driver = &fixed_mdio_driver.driver; + + err = phydev->dev.driver->probe(&phydev->dev); + if(err < 0) { + printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); + up_write(&phydev->dev.bus->subsys.rwsem); + goto probe_fail; + } + + device_bind_driver(&phydev->dev); + up_write(&phydev->dev.bus->subsys.rwsem); + + return 0; + +probe_fail: + device_unregister(&phydev->dev); +bus_register_fail: + kfree(phydev); +device_create_fail: + kfree(dev); + kfree(new_bus); + kfree(fixed); + + return err; +} + + +MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); +MODULE_AUTHOR("Vitaly Bordug"); +MODULE_LICENSE("GPL"); + +static int __init fixed_init(void) +{ + int ret; + int duplex = 0; + + /* register on the bus... Not expected to be matched with anything there... */ + phy_driver_register(&fixed_mdio_driver); + + /* So let the fun begin... + We will create several mdio devices here, and will bound the upper + driver to them. + + Then the external software can lookup the phy bus by searching + fixed@speed:duplex, e.g. fixed@100:1, to be connected to the + virtual 100M Fdx phy. + + In case several virtual PHYs required, the bus_id will be in form + fixed_@:, which make it able even to define + driver-specific link control callback, if for instance PHY is completely + SW-driven. + + */ + +#ifdef CONFIG_FIXED_MII_DUPLEX + duplex = 1; +#endif + +#ifdef CONFIG_FIXED_MII_100_FDX + fixed_mdio_register_device(0, 100, 1); +#endif + +#ifdef CONFIX_FIXED_MII_10_FDX + fixed_mdio_register_device(0, 10, 1); +#endif + return 0; +} + +static void __exit fixed_exit(void) +{ + phy_driver_unregister(&fixed_mdio_driver); + /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */ +} + +module_init(fixed_init); +module_exit(fixed_exit); diff -puN drivers/net/phy/mdio_bus.c~git-netdev-all drivers/net/phy/mdio_bus.c --- a/drivers/net/phy/mdio_bus.c~git-netdev-all +++ a/drivers/net/phy/mdio_bus.c @@ -159,6 +159,7 @@ struct bus_type mdio_bus_type = { .suspend = mdio_bus_suspend, .resume = mdio_bus_resume, }; +EXPORT_SYMBOL(mdio_bus_type); int __init mdio_bus_init(void) { diff -puN drivers/net/phy/phy_device.c~git-netdev-all drivers/net/phy/phy_device.c --- a/drivers/net/phy/phy_device.c~git-netdev-all +++ a/drivers/net/phy/phy_device.c @@ -45,6 +45,35 @@ static struct phy_driver genphy_driver; extern int mdio_bus_init(void); extern void mdio_bus_exit(void); +struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) +{ + struct phy_device *dev; + /* We allocate the device, and initialize the + * default values */ + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + + if (NULL == dev) + return (struct phy_device*) PTR_ERR((void*)-ENOMEM); + + dev->speed = 0; + dev->duplex = -1; + dev->pause = dev->asym_pause = 0; + dev->link = 1; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->state = PHY_DOWN; + + spin_lock_init(&dev->lock); + + return dev; +} +EXPORT_SYMBOL(phy_device_create); + /* get_phy_device * * description: Reads the ID registers of the PHY at addr on the @@ -78,27 +107,7 @@ struct phy_device * get_phy_device(struc if (0xffffffff == phy_id) return NULL; - /* Otherwise, we allocate the device, and initialize the - * default values */ - dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); - - if (NULL == dev) - return ERR_PTR(-ENOMEM); - - dev->speed = 0; - dev->duplex = -1; - dev->pause = dev->asym_pause = 0; - dev->link = 1; - - dev->autoneg = AUTONEG_ENABLE; - - dev->addr = addr; - dev->phy_id = phy_id; - dev->bus = bus; - - dev->state = PHY_DOWN; - - spin_lock_init(&dev->lock); + dev = phy_device_create(bus, addr, phy_id); return dev; } diff -puN drivers/net/phy/smsc.c~git-netdev-all drivers/net/phy/smsc.c --- a/drivers/net/phy/smsc.c~git-netdev-all +++ a/drivers/net/phy/smsc.c @@ -14,7 +14,6 @@ * */ -#include #include #include #include diff -puN drivers/net/phy/vitesse.c~git-netdev-all drivers/net/phy/vitesse.c --- a/drivers/net/phy/vitesse.c~git-netdev-all +++ a/drivers/net/phy/vitesse.c @@ -12,7 +12,6 @@ * */ -#include #include #include #include diff -puN /dev/null drivers/net/qla3xxx.c --- /dev/null +++ a/drivers/net/qla3xxx.c @@ -0,0 +1,3537 @@ +/* + * QLogic QLA3xxx NIC HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla3xxx for copyright and licensing details. + */ + +#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 "qla3xxx.h" + +#define DRV_NAME "qla3xxx" +#define DRV_STRING "QLogic ISP3XXX Network Driver" +#define DRV_VERSION "v2.02.00-k36" +#define PFX DRV_NAME " " + +static const char ql3xxx_driver_name[] = DRV_NAME; +static const char ql3xxx_driver_version[] = DRV_VERSION; + +MODULE_AUTHOR("QLogic Corporation"); +MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +static const u32 default_msg + = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; + +static int debug = -1; /* defaults above */ +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +static int msi; +module_param(msi, int, 0); +MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts."); + +static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl); + +/* + * Caller must take hw_lock. + */ +static int ql_sem_spinlock(struct ql3_adapter *qdev, + u32 sem_mask, u32 sem_bits) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + u32 value; + unsigned int seconds = 3; + + do { + writel((sem_mask | sem_bits), + &port_regs->CommonRegs.semaphoreReg); + value = readl(&port_regs->CommonRegs.semaphoreReg); + if ((value & (sem_mask >> 16)) == sem_bits) + return 0; + ssleep(1); + } while(--seconds); + return -1; +} + +static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + writel(sem_mask, &port_regs->CommonRegs.semaphoreReg); + readl(&port_regs->CommonRegs.semaphoreReg); +} + +static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + u32 value; + + writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg); + value = readl(&port_regs->CommonRegs.semaphoreReg); + return ((value & (sem_mask >> 16)) == sem_bits); +} + +/* + * Caller holds hw_lock. + */ +static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev) +{ + int i = 0; + + while (1) { + if (!ql_sem_lock(qdev, + QL_DRVR_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) + * 2) << 1)) { + if (i < 10) { + ssleep(1); + i++; + } else { + printk(KERN_ERR PFX "%s: Timed out waiting for " + "driver lock...\n", + qdev->ndev->name); + return 0; + } + } else { + printk(KERN_DEBUG PFX + "%s: driver lock acquired.\n", + qdev->ndev->name); + return 1; + } + } +} + +static void ql_set_register_page(struct ql3_adapter *qdev, u32 page) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + + writel(((ISP_CONTROL_NP_MASK << 16) | page), + &port_regs->CommonRegs.ispControlStatus); + readl(&port_regs->CommonRegs.ispControlStatus); + qdev->current_page = page; +} + +static u32 ql_read_common_reg_l(struct ql3_adapter *qdev, + u32 __iomem * reg) +{ + u32 value; + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + value = readl(reg); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + + return value; +} + +static u32 ql_read_common_reg(struct ql3_adapter *qdev, + u32 __iomem * reg) +{ + return readl(reg); +} + +static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg) +{ + u32 value; + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + + if (qdev->current_page != 0) + ql_set_register_page(qdev,0); + value = readl(reg); + + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return value; +} + +static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg) +{ + if (qdev->current_page != 0) + ql_set_register_page(qdev,0); + return readl(reg); +} + +static void ql_write_common_reg_l(struct ql3_adapter *qdev, + u32 * reg, u32 value) +{ + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + writel(value, (u32 *) reg); + readl(reg); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return; +} + +static void ql_write_common_reg(struct ql3_adapter *qdev, + u32 * reg, u32 value) +{ + writel(value, (u32 *) reg); + readl(reg); + return; +} + +static void ql_write_page0_reg(struct ql3_adapter *qdev, + u32 * reg, u32 value) +{ + if (qdev->current_page != 0) + ql_set_register_page(qdev,0); + writel(value, (u32 *) reg); + readl(reg); + return; +} + +/* + * Caller holds hw_lock. Only called during init. + */ +static void ql_write_page1_reg(struct ql3_adapter *qdev, + u32 * reg, u32 value) +{ + if (qdev->current_page != 1) + ql_set_register_page(qdev,1); + writel(value, (u32 *) reg); + readl(reg); + return; +} + +/* + * Caller holds hw_lock. Only called during init. + */ +static void ql_write_page2_reg(struct ql3_adapter *qdev, + u32 * reg, u32 value) +{ + if (qdev->current_page != 2) + ql_set_register_page(qdev,2); + writel(value, (u32 *) reg); + readl(reg); + return; +} + +static void ql_disable_interrupts(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + + ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg, + (ISP_IMR_ENABLE_INT << 16)); + +} + +static void ql_enable_interrupts(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + + ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg, + ((0xff << 16) | ISP_IMR_ENABLE_INT)); + +} + +static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, + struct ql_rcv_buf_cb *lrg_buf_cb) +{ + u64 map; + lrg_buf_cb->next = NULL; + + if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */ + qdev->lrg_buf_free_head = qdev->lrg_buf_free_tail = lrg_buf_cb; + } else { + qdev->lrg_buf_free_tail->next = lrg_buf_cb; + qdev->lrg_buf_free_tail = lrg_buf_cb; + } + + if (!lrg_buf_cb->skb) { + lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len); + if (unlikely(!lrg_buf_cb->skb)) { + printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n", + qdev->ndev->name); + qdev->lrg_buf_skb_check++; + } else { + /* + * We save some space to copy the ethhdr from first + * buffer + */ + skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE); + map = pci_map_single(qdev->pdev, + lrg_buf_cb->skb->data, + qdev->lrg_buffer_len - + QL_HEADER_SPACE, + PCI_DMA_FROMDEVICE); + lrg_buf_cb->buf_phy_addr_low = + cpu_to_le32(LS_64BITS(map)); + lrg_buf_cb->buf_phy_addr_high = + cpu_to_le32(MS_64BITS(map)); + pci_unmap_addr_set(lrg_buf_cb, mapaddr, map); + pci_unmap_len_set(lrg_buf_cb, maplen, + qdev->lrg_buffer_len - + QL_HEADER_SPACE); + } + } + + qdev->lrg_buf_free_count++; +} + +static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter + *qdev) +{ + struct ql_rcv_buf_cb *lrg_buf_cb; + + if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) { + if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL) + qdev->lrg_buf_free_tail = NULL; + qdev->lrg_buf_free_count--; + } + + return lrg_buf_cb; +} + +static u32 addrBits = EEPROM_NO_ADDR_BITS; +static u32 dataBits = EEPROM_NO_DATA_BITS; + +static void fm93c56a_deselect(struct ql3_adapter *qdev); +static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr, + unsigned short *value); + +/* + * Caller holds hw_lock. + */ +static void fm93c56a_select(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1; + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev->eeprom_cmd_data); + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data)); +} + +/* + * Caller holds hw_lock. + */ +static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr) +{ + int i; + u32 mask; + u32 dataBit; + u32 previousBit; + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + /* Clock in a zero, then do the start bit */ + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev->eeprom_cmd_data | + AUBURN_EEPROM_DO_1); + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_RISE); + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | AUBURN_EEPROM_DO_1 | + AUBURN_EEPROM_CLK_FALL); + + mask = 1 << (FM93C56A_CMD_BITS - 1); + /* Force the previous data bit to be different */ + previousBit = 0xffff; + for (i = 0; i < FM93C56A_CMD_BITS; i++) { + dataBit = + (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0; + if (previousBit != dataBit) { + /* + * If the bit changed, then change the DO state to + * match + */ + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit); + previousBit = dataBit; + } + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE); + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL); + cmd = cmd << 1; + } + + mask = 1 << (addrBits - 1); + /* Force the previous data bit to be different */ + previousBit = 0xffff; + for (i = 0; i < addrBits; i++) { + dataBit = + (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 : + AUBURN_EEPROM_DO_0; + if (previousBit != dataBit) { + /* + * If the bit changed, then change the DO state to + * match + */ + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit); + previousBit = dataBit; + } + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_RISE); + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev-> + eeprom_cmd_data | dataBit | + AUBURN_EEPROM_CLK_FALL); + eepromAddr = eepromAddr << 1; + } +} + +/* + * Caller holds hw_lock. + */ +static void fm93c56a_deselect(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0; + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev->eeprom_cmd_data); +} + +/* + * Caller holds hw_lock. + */ +static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value) +{ + int i; + u32 data = 0; + u32 dataBit; + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + /* Read the data bits */ + /* The first bit is a dummy. Clock right over it. */ + for (i = 0; i < dataBits; i++) { + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev->eeprom_cmd_data | + AUBURN_EEPROM_CLK_RISE); + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg, + ISP_NVRAM_MASK | qdev->eeprom_cmd_data | + AUBURN_EEPROM_CLK_FALL); + dataBit = + (ql_read_common_reg + (qdev, + &port_regs->CommonRegs. + serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0; + data = (data << 1) | dataBit; + } + *value = (u16) data; +} + +/* + * Caller holds hw_lock. + */ +static void eeprom_readword(struct ql3_adapter *qdev, + u32 eepromAddr, unsigned short *value) +{ + fm93c56a_select(qdev); + fm93c56a_cmd(qdev, (int)FM93C56A_READ, eepromAddr); + fm93c56a_datain(qdev, value); + fm93c56a_deselect(qdev); +} + +static void ql_swap_mac_addr(u8 * macAddress) +{ +#ifdef __BIG_ENDIAN + u8 temp; + temp = macAddress[0]; + macAddress[0] = macAddress[1]; + macAddress[1] = temp; + temp = macAddress[2]; + macAddress[2] = macAddress[3]; + macAddress[3] = temp; + temp = macAddress[4]; + macAddress[4] = macAddress[5]; + macAddress[5] = temp; +#endif +} + +static int ql_get_nvram_params(struct ql3_adapter *qdev) +{ + u16 *pEEPROMData; + u16 checksum = 0; + u32 index; + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + + pEEPROMData = (u16 *) & qdev->nvram_data; + qdev->eeprom_cmd_data = 0; + if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 10)) { + printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n", + __func__); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return -1; + } + + for (index = 0; index < EEPROM_SIZE; index++) { + eeprom_readword(qdev, index, pEEPROMData); + checksum += *pEEPROMData; + pEEPROMData++; + } + ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK); + + if (checksum != 0) { + printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n", + qdev->ndev->name, checksum); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return -1; + } + + /* + * We have a problem with endianness for the MAC addresses + * and the two 8-bit values version, and numPorts. We + * have to swap them on big endian systems. + */ + ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress); + ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress); + ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress); + ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress); + pEEPROMData = (u16 *) & qdev->nvram_data.version; + *pEEPROMData = le16_to_cpu(*pEEPROMData); + + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return checksum; +} + +static const u32 PHYAddr[2] = { + PORT0_PHY_ADDRESS, PORT1_PHY_ADDRESS +}; + +static int ql_wait_for_mii_ready(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 temp; + int count = 1000; + + while (count) { + temp = ql_read_page0_reg(qdev, &port_regs->macMIIStatusReg); + if (!(temp & MAC_MII_STATUS_BSY)) + return 0; + udelay(10); + count--; + } + return -1; +} + +static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 scanControl; + + if (qdev->numPorts > 1) { + /* Auto scan will cycle through multiple ports */ + scanControl = MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC; + } else { + scanControl = MAC_MII_CONTROL_SC; + } + + /* + * Scan register 1 of PHY/PETBI, + * Set up to scan both devices + * The autoscan starts from the first register, completes + * the last one before rolling over to the first + */ + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + PHYAddr[0] | MII_SCAN_REGISTER); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + (scanControl) | + ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS) << 16)); +} + +static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev) +{ + u8 ret; + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + /* See if scan mode is enabled before we turn it off */ + if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) & + (MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC)) { + /* Scan is enabled */ + ret = 1; + } else { + /* Scan is disabled */ + ret = 0; + } + + /* + * When disabling scan mode you must first change the MII register + * address + */ + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + PHYAddr[0] | MII_SCAN_REGISTER); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS | + MAC_MII_CONTROL_RC) << 16)); + + return ret; +} + +static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, + u16 regAddr, u16 value, u32 mac_index) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u8 scanWasEnabled; + + scanWasEnabled = ql_mii_disable_scan_mode(qdev); + + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + PHYAddr[mac_index] | regAddr); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value); + + /* Wait for write to complete 9/10/04 SJP */ + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to" + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + if (scanWasEnabled) + ql_mii_enable_scan_mode(qdev); + + return 0; +} + +static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, + u16 * value, u32 mac_index) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u8 scanWasEnabled; + u32 temp; + + scanWasEnabled = ql_mii_disable_scan_mode(qdev); + + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + PHYAddr[mac_index] | regAddr); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + (MAC_MII_CONTROL_RC << 16)); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC); + + /* Wait for the read to complete */ + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free after issuing command.\n", + qdev->ndev->name); + return -1; + } + + temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg); + *value = (u16) temp; + + if (scanWasEnabled) + ql_mii_enable_scan_mode(qdev); + + return 0; +} + +static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + ql_mii_disable_scan_mode(qdev); + + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + qdev->PHYAddr | regAddr); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value); + + /* Wait for write to complete. */ + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + ql_mii_enable_scan_mode(qdev); + + return 0; +} + +static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value) +{ + u32 temp; + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + ql_mii_disable_scan_mode(qdev); + + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, + qdev->PHYAddr | regAddr); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + (MAC_MII_CONTROL_RC << 16)); + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC); + + /* Wait for the read to complete */ + if (ql_wait_for_mii_ready(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Timed out waiting for management port to " + "get free before issuing command.\n", + qdev->ndev->name); + return -1; + } + + temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg); + *value = (u16) temp; + + ql_mii_enable_scan_mode(qdev); + + return 0; +} + +static void ql_petbi_reset(struct ql3_adapter *qdev) +{ + ql_mii_write_reg(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET); +} + +static void ql_petbi_start_neg(struct ql3_adapter *qdev) +{ + u16 reg; + + /* Enable Auto-negotiation sense */ + ql_mii_read_reg(qdev, PETBI_TBI_CTRL, ®); + reg |= PETBI_TBI_AUTO_SENSE; + ql_mii_write_reg(qdev, PETBI_TBI_CTRL, reg); + + ql_mii_write_reg(qdev, PETBI_NEG_ADVER, + PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX); + + ql_mii_write_reg(qdev, PETBI_CONTROL_REG, + PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG | + PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000); + +} + +static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET, + mac_index); +} + +static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + u16 reg; + + /* Enable Auto-negotiation sense */ + ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, mac_index); + reg |= PETBI_TBI_AUTO_SENSE; + ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index); + + ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, + PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index); + + ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, + PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG | + PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000, + mac_index); +} + +static void ql_petbi_init(struct ql3_adapter *qdev) +{ + ql_petbi_reset(qdev); + ql_petbi_start_neg(qdev); +} + +static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + ql_petbi_reset_ex(qdev, mac_index); + ql_petbi_start_neg_ex(qdev, mac_index); +} + +static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) +{ + u16 reg; + + if (ql_mii_read_reg(qdev, PETBI_NEG_PARTNER, ®) < 0) + return 0; + + return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE; +} + +static int ql_phy_get_speed(struct ql3_adapter *qdev) +{ + u16 reg; + + if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) + return 0; + + reg = (((reg & 0x18) >> 3) & 3); + + if (reg == 2) + return SPEED_1000; + else if (reg == 1) + return SPEED_100; + else if (reg == 0) + return SPEED_10; + else + return -1; +} + +static int ql_is_full_dup(struct ql3_adapter *qdev) +{ + u16 reg; + + if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) + return 0; + + return (reg & PHY_AUX_DUPLEX_STAT) != 0; +} + +static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) +{ + u16 reg; + + if (ql_mii_read_reg(qdev, PHY_NEG_PARTNER, ®) < 0) + return 0; + + return (reg & PHY_NEG_PAUSE) != 0; +} + +/* + * Caller holds hw_lock. + */ +static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 value; + + if (enable) + value = (MAC_CONFIG_REG_PE | (MAC_CONFIG_REG_PE << 16)); + else + value = (MAC_CONFIG_REG_PE << 16); + + if (qdev->mac_index) + ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value); + else + ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value); +} + +/* + * Caller holds hw_lock. + */ +static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 value; + + if (enable) + value = (MAC_CONFIG_REG_SR | (MAC_CONFIG_REG_SR << 16)); + else + value = (MAC_CONFIG_REG_SR << 16); + + if (qdev->mac_index) + ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value); + else + ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value); +} + +/* + * Caller holds hw_lock. + */ +static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 value; + + if (enable) + value = (MAC_CONFIG_REG_GM | (MAC_CONFIG_REG_GM << 16)); + else + value = (MAC_CONFIG_REG_GM << 16); + + if (qdev->mac_index) + ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value); + else + ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value); +} + +/* + * Caller holds hw_lock. + */ +static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 value; + + if (enable) + value = (MAC_CONFIG_REG_FD | (MAC_CONFIG_REG_FD << 16)); + else + value = (MAC_CONFIG_REG_FD << 16); + + if (qdev->mac_index) + ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value); + else + ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value); +} + +/* + * Caller holds hw_lock. + */ +static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 value; + + if (enable) + value = + ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) | + ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16)); + else + value = ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16); + + if (qdev->mac_index) + ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value); + else + ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value); +} + +/* + * Caller holds hw_lock. + */ +static int ql_is_fiber(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp; + + switch (qdev->mac_index) { + case 0: + bitToCheck = PORT_STATUS_SM0; + break; + case 1: + bitToCheck = PORT_STATUS_SM1; + break; + } + + temp = ql_read_page0_reg(qdev, &port_regs->portStatus); + return (temp & bitToCheck) != 0; +} + +static int ql_is_auto_cfg(struct ql3_adapter *qdev) +{ + u16 reg; + ql_mii_read_reg(qdev, 0x00, ®); + return (reg & 0x1000) != 0; +} + +/* + * Caller holds hw_lock. + */ +static int ql_is_auto_neg_complete(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp; + + switch (qdev->mac_index) { + case 0: + bitToCheck = PORT_STATUS_AC0; + break; + case 1: + bitToCheck = PORT_STATUS_AC1; + break; + } + + temp = ql_read_page0_reg(qdev, &port_regs->portStatus); + if (temp & bitToCheck) { + if (netif_msg_link(qdev)) + printk(KERN_INFO PFX + "%s: Auto-Negotiate complete.\n", + qdev->ndev->name); + return 1; + } else { + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Auto-Negotiate incomplete.\n", + qdev->ndev->name); + return 0; + } +} + +/* + * ql_is_neg_pause() returns 1 if pause was negotiated to be on + */ +static int ql_is_neg_pause(struct ql3_adapter *qdev) +{ + if (ql_is_fiber(qdev)) + return ql_is_petbi_neg_pause(qdev); + else + return ql_is_phy_neg_pause(qdev); +} + +static int ql_auto_neg_error(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp; + + switch (qdev->mac_index) { + case 0: + bitToCheck = PORT_STATUS_AE0; + break; + case 1: + bitToCheck = PORT_STATUS_AE1; + break; + } + temp = ql_read_page0_reg(qdev, &port_regs->portStatus); + return (temp & bitToCheck) != 0; +} + +static u32 ql_get_link_speed(struct ql3_adapter *qdev) +{ + if (ql_is_fiber(qdev)) + return SPEED_1000; + else + return ql_phy_get_speed(qdev); +} + +static int ql_is_link_full_dup(struct ql3_adapter *qdev) +{ + if (ql_is_fiber(qdev)) + return 1; + else + return ql_is_full_dup(qdev); +} + +/* + * Caller holds hw_lock. + */ +static int ql_link_down_detect(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp; + + switch (qdev->mac_index) { + case 0: + bitToCheck = ISP_CONTROL_LINK_DN_0; + break; + case 1: + bitToCheck = ISP_CONTROL_LINK_DN_1; + break; + } + + temp = + ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus); + return (temp & bitToCheck) != 0; +} + +/* + * Caller holds hw_lock. + */ +static int ql_link_down_detect_clear(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + switch (qdev->mac_index) { + case 0: + ql_write_common_reg(qdev, + &port_regs->CommonRegs.ispControlStatus, + (ISP_CONTROL_LINK_DN_0) | + (ISP_CONTROL_LINK_DN_0 << 16)); + break; + + case 1: + ql_write_common_reg(qdev, + &port_regs->CommonRegs.ispControlStatus, + (ISP_CONTROL_LINK_DN_1) | + (ISP_CONTROL_LINK_DN_1 << 16)); + break; + + default: + return 1; + } + + return 0; +} + +/* + * Caller holds hw_lock. + */ +static int ql_this_adapter_controls_port(struct ql3_adapter *qdev, + u32 mac_index) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp; + + switch (mac_index) { + case 0: + bitToCheck = PORT_STATUS_F1_ENABLED; + break; + case 1: + bitToCheck = PORT_STATUS_F3_ENABLED; + break; + default: + break; + } + + temp = ql_read_page0_reg(qdev, &port_regs->portStatus); + if (temp & bitToCheck) { + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: is not link master.\n", qdev->ndev->name); + return 0; + } else { + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: is link master.\n", qdev->ndev->name); + return 1; + } +} + +static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index); +} + +static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + u16 reg; + + ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, + PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index); + + ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, mac_index); + ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG, + mac_index); +} + +static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index) +{ + ql_phy_reset_ex(qdev, mac_index); + ql_phy_start_neg_ex(qdev, mac_index); +} + +/* + * Caller holds hw_lock. + */ +static u32 ql_get_link_state(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + u32 bitToCheck = 0; + u32 temp, linkState; + + switch (qdev->mac_index) { + case 0: + bitToCheck = PORT_STATUS_UP0; + break; + case 1: + bitToCheck = PORT_STATUS_UP1; + break; + } + temp = ql_read_page0_reg(qdev, &port_regs->portStatus); + if (temp & bitToCheck) { + linkState = LS_UP; + } else { + linkState = LS_DOWN; + if (netif_msg_link(qdev)) + printk(KERN_WARNING PFX + "%s: Link is down.\n", qdev->ndev->name); + } + return linkState; +} + +static int ql_port_start(struct ql3_adapter *qdev) +{ + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return -1; + + if (ql_is_fiber(qdev)) { + ql_petbi_init(qdev); + } else { + /* Copper port */ + ql_phy_init_ex(qdev, qdev->mac_index); + } + + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + return 0; +} + +static int ql_finish_auto_neg(struct ql3_adapter *qdev) +{ + + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return -1; + + if (!ql_auto_neg_error(qdev)) { + if (test_bit(QL_LINK_MASTER,&qdev->flags)) { + /* configure the MAC */ + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: Configuring link.\n", + qdev->ndev-> + name); + ql_mac_cfg_soft_reset(qdev, 1); + ql_mac_cfg_gig(qdev, + (ql_get_link_speed + (qdev) == + SPEED_1000)); + ql_mac_cfg_full_dup(qdev, + ql_is_link_full_dup + (qdev)); + ql_mac_cfg_pause(qdev, + ql_is_neg_pause + (qdev)); + ql_mac_cfg_soft_reset(qdev, 0); + + /* enable the MAC */ + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: Enabling mac.\n", + qdev->ndev-> + name); + ql_mac_enable(qdev, 1); + } + + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: Change port_link_state LS_DOWN to LS_UP.\n", + qdev->ndev->name); + qdev->port_link_state = LS_UP; + netif_start_queue(qdev->ndev); + netif_carrier_on(qdev->ndev); + if (netif_msg_link(qdev)) + printk(KERN_INFO PFX + "%s: Link is up at %d Mbps, %s duplex.\n", + qdev->ndev->name, + ql_get_link_speed(qdev), + ql_is_link_full_dup(qdev) + ? "full" : "half"); + + } else { /* Remote error detected */ + + if (test_bit(QL_LINK_MASTER,&qdev->flags)) { + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: Remote error detected. " + "Calling ql_port_start().\n", + qdev->ndev-> + name); + /* + * ql_port_start() is shared code and needs + * to lock the PHY on it's own. + */ + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + if(ql_port_start(qdev)) {/* Restart port */ + return -1; + } else + return 0; + } + } + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + return 0; +} + +static void ql_link_state_machine(struct ql3_adapter *qdev) +{ + u32 curr_link_state; + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + + curr_link_state = ql_get_link_state(qdev); + + if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) { + if (netif_msg_link(qdev)) + printk(KERN_INFO PFX + "%s: Reset in progress, skip processing link " + "state.\n", qdev->ndev->name); + return; + } + + switch (qdev->port_link_state) { + default: + if (test_bit(QL_LINK_MASTER,&qdev->flags)) { + ql_port_start(qdev); + } + qdev->port_link_state = LS_DOWN; + /* Fall Through */ + + case LS_DOWN: + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: port_link_state = LS_DOWN.\n", + qdev->ndev->name); + if (curr_link_state == LS_UP) { + if (netif_msg_link(qdev)) + printk(KERN_DEBUG PFX + "%s: curr_link_state = LS_UP.\n", + qdev->ndev->name); + if (ql_is_auto_neg_complete(qdev)) + ql_finish_auto_neg(qdev); + + if (qdev->port_link_state == LS_UP) + ql_link_down_detect_clear(qdev); + + } + break; + + case LS_UP: + /* + * See if the link is currently down or went down and came + * back up + */ + if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) { + if (netif_msg_link(qdev)) + printk(KERN_INFO PFX "%s: Link is down.\n", + qdev->ndev->name); + qdev->port_link_state = LS_DOWN; + } + break; + } + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); +} + +/* + * Caller must take hw_lock and QL_PHY_GIO_SEM. + */ +static void ql_get_phy_owner(struct ql3_adapter *qdev) +{ + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) + set_bit(QL_LINK_MASTER,&qdev->flags); + else + clear_bit(QL_LINK_MASTER,&qdev->flags); +} + +/* + * Caller must take hw_lock and QL_PHY_GIO_SEM. + */ +static void ql_init_scan_mode(struct ql3_adapter *qdev) +{ + ql_mii_enable_scan_mode(qdev); + + if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) + ql_petbi_init_ex(qdev, qdev->mac_index); + } else { + if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) + ql_phy_init_ex(qdev, qdev->mac_index); + } +} + +/* + * MII_Setup needs to be called before taking the PHY out of reset so that the + * management interface clock speed can be set properly. It would be better if + * we had a way to disable MDC until after the PHY is out of reset, but we + * don't have that capability. + */ +static int ql_mii_setup(struct ql3_adapter *qdev) +{ + u32 reg; + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return -1; + + /* Divide 125MHz clock by 28 to meet PHY timing requirements */ + reg = MAC_MII_CONTROL_CLK_SEL_DIV28; + + ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, + reg | ((MAC_MII_CONTROL_CLK_SEL_MASK) << 16)); + + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + return 0; +} + +static u32 ql_supported_modes(struct ql3_adapter *qdev) +{ + u32 supported; + + if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { + supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE + | SUPPORTED_Autoneg; + } else { + supported = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP; + } + + return supported; +} + +static int ql_get_auto_cfg_status(struct ql3_adapter *qdev) +{ + int status; + unsigned long hw_flags; + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return 0; + status = ql_is_auto_cfg(qdev); + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return status; +} + +static u32 ql_get_speed(struct ql3_adapter *qdev) +{ + u32 status; + unsigned long hw_flags; + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return 0; + status = ql_get_link_speed(qdev); + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return status; +} + +static int ql_get_full_dup(struct ql3_adapter *qdev) +{ + int status; + unsigned long hw_flags; + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) + return 0; + status = ql_is_link_full_dup(qdev); + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + return status; +} + + +static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + + ecmd->transceiver = XCVR_INTERNAL; + ecmd->supported = ql_supported_modes(qdev); + + if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { + ecmd->port = PORT_FIBRE; + } else { + ecmd->port = PORT_TP; + ecmd->phy_address = qdev->PHYAddr; + } + ecmd->advertising = ql_supported_modes(qdev); + ecmd->autoneg = ql_get_auto_cfg_status(qdev); + ecmd->speed = ql_get_speed(qdev); + ecmd->duplex = ql_get_full_dup(qdev); + return 0; +} + +static void ql_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *drvinfo) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + strncpy(drvinfo->driver, ql3xxx_driver_name, 32); + strncpy(drvinfo->version, ql3xxx_driver_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); + strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +static u32 ql_get_msglevel(struct net_device *ndev) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + return qdev->msg_enable; +} + +static void ql_set_msglevel(struct net_device *ndev, u32 value) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + qdev->msg_enable = value; +} + +static struct ethtool_ops ql3xxx_ethtool_ops = { + .get_settings = ql_get_settings, + .get_drvinfo = ql_get_drvinfo, + .get_perm_addr = ethtool_op_get_perm_addr, + .get_link = ethtool_op_get_link, + .get_msglevel = ql_get_msglevel, + .set_msglevel = ql_set_msglevel, +}; + +static int ql_populate_free_queue(struct ql3_adapter *qdev) +{ + struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head; + u64 map; + + while (lrg_buf_cb) { + if (!lrg_buf_cb->skb) { + lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len); + if (unlikely(!lrg_buf_cb->skb)) { + printk(KERN_DEBUG PFX + "%s: Failed dev_alloc_skb().\n", + qdev->ndev->name); + break; + } else { + /* + * We save some space to copy the ethhdr from + * first buffer + */ + skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE); + map = pci_map_single(qdev->pdev, + lrg_buf_cb->skb->data, + qdev->lrg_buffer_len - + QL_HEADER_SPACE, + PCI_DMA_FROMDEVICE); + lrg_buf_cb->buf_phy_addr_low = + cpu_to_le32(LS_64BITS(map)); + lrg_buf_cb->buf_phy_addr_high = + cpu_to_le32(MS_64BITS(map)); + pci_unmap_addr_set(lrg_buf_cb, mapaddr, map); + pci_unmap_len_set(lrg_buf_cb, maplen, + qdev->lrg_buffer_len - + QL_HEADER_SPACE); + --qdev->lrg_buf_skb_check; + if (!qdev->lrg_buf_skb_check) + return 1; + } + } + lrg_buf_cb = lrg_buf_cb->next; + } + return 0; +} + +/* + * Caller holds hw_lock. + */ +static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev) +{ + struct bufq_addr_element *lrg_buf_q_ele; + int i; + struct ql_rcv_buf_cb *lrg_buf_cb; + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + + if ((qdev->lrg_buf_free_count >= 8) + && (qdev->lrg_buf_release_cnt >= 16)) { + + if (qdev->lrg_buf_skb_check) + if (!ql_populate_free_queue(qdev)) + return; + + lrg_buf_q_ele = qdev->lrg_buf_next_free; + + while ((qdev->lrg_buf_release_cnt >= 16) + && (qdev->lrg_buf_free_count >= 8)) { + + for (i = 0; i < 8; i++) { + lrg_buf_cb = + ql_get_from_lrg_buf_free_list(qdev); + lrg_buf_q_ele->addr_high = + lrg_buf_cb->buf_phy_addr_high; + lrg_buf_q_ele->addr_low = + lrg_buf_cb->buf_phy_addr_low; + lrg_buf_q_ele++; + + qdev->lrg_buf_release_cnt--; + } + + qdev->lrg_buf_q_producer_index++; + + if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES) + qdev->lrg_buf_q_producer_index = 0; + + if (qdev->lrg_buf_q_producer_index == + (NUM_LBUFQ_ENTRIES - 1)) { + lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr; + } + } + + qdev->lrg_buf_next_free = lrg_buf_q_ele; + + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + rxLargeQProducerIndex, + qdev->lrg_buf_q_producer_index); + } +} + +static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, + struct ob_mac_iocb_rsp *mac_rsp) +{ + struct ql_tx_buf_cb *tx_cb; + + tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; + pci_unmap_single(qdev->pdev, + pci_unmap_addr(tx_cb, mapaddr), + pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); + dev_kfree_skb_irq(tx_cb->skb); + qdev->stats.tx_packets++; + qdev->stats.tx_bytes += tx_cb->skb->len; + tx_cb->skb = NULL; + atomic_inc(&qdev->tx_count); +} + +static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, + struct ib_mac_iocb_rsp *ib_mac_rsp_ptr) +{ + long int offset; + u32 lrg_buf_phy_addr_low = 0; + struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; + struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; + u32 *curr_ial_ptr; + struct sk_buff *skb; + u16 length = le16_to_cpu(ib_mac_rsp_ptr->length); + + /* + * Get the inbound address list (small buffer). + */ + offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE; + if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) + qdev->small_buf_index = 0; + + curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset); + qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; + qdev->small_buf_release_cnt++; + + /* start of first buffer */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + + /* start of second buffer */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index]; + + /* + * Second buffer gets sent up the stack. + */ + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + skb = lrg_buf_cb2->skb; + + qdev->stats.rx_packets++; + qdev->stats.rx_bytes += length; + + skb_put(skb, length); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(lrg_buf_cb2, mapaddr), + pci_unmap_len(lrg_buf_cb2, maplen), + PCI_DMA_FROMDEVICE); + prefetch(skb->data); + skb->dev = qdev->ndev; + skb->ip_summed = CHECKSUM_NONE; + skb->protocol = eth_type_trans(skb, qdev->ndev); + + netif_receive_skb(skb); + qdev->ndev->last_rx = jiffies; + lrg_buf_cb2->skb = NULL; + + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); +} + +static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, + struct ib_ip_iocb_rsp *ib_ip_rsp_ptr) +{ + long int offset; + u32 lrg_buf_phy_addr_low = 0; + struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; + struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; + u32 *curr_ial_ptr; + struct sk_buff *skb1, *skb2; + struct net_device *ndev = qdev->ndev; + u16 length = le16_to_cpu(ib_ip_rsp_ptr->length); + u16 size = 0; + + /* + * Get the inbound address list (small buffer). + */ + + offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE; + if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) + qdev->small_buf_index = 0; + curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset); + qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; + qdev->small_buf_release_cnt++; + + /* start of first buffer */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + skb1 = lrg_buf_cb1->skb; + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + + /* start of second buffer */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index]; + skb2 = lrg_buf_cb2->skb; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + + qdev->stats.rx_packets++; + qdev->stats.rx_bytes += length; + + /* + * Copy the ethhdr from first buffer to second. This + * is necessary for IP completions. + */ + if (*((u16 *) skb1->data) != 0xFFFF) + size = VLAN_ETH_HLEN; + else + size = ETH_HLEN; + + skb_put(skb2, length); /* Just the second buffer length here. */ + pci_unmap_single(qdev->pdev, + pci_unmap_addr(lrg_buf_cb2, mapaddr), + pci_unmap_len(lrg_buf_cb2, maplen), + PCI_DMA_FROMDEVICE); + prefetch(skb2->data); + + memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); + skb2->dev = qdev->ndev; + skb2->ip_summed = CHECKSUM_NONE; + skb2->protocol = eth_type_trans(skb2, qdev->ndev); + + netif_receive_skb(skb2); + ndev->last_rx = jiffies; + lrg_buf_cb2->skb = NULL; + + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); +} + +static int ql_tx_rx_clean(struct ql3_adapter *qdev, + int *tx_cleaned, int *rx_cleaned, int work_to_do) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + struct net_rsp_iocb *net_rsp; + struct net_device *ndev = qdev->ndev; + unsigned long hw_flags; + + /* While there are entries in the completion queue. */ + while ((cpu_to_le32(*(qdev->prsp_producer_index)) != + qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) { + + net_rsp = qdev->rsp_current; + switch (net_rsp->opcode) { + + case OPCODE_OB_MAC_IOCB_FN0: + case OPCODE_OB_MAC_IOCB_FN2: + ql_process_mac_tx_intr(qdev, (struct ob_mac_iocb_rsp *) + net_rsp); + (*tx_cleaned)++; + break; + + case OPCODE_IB_MAC_IOCB: + ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *) + net_rsp); + (*rx_cleaned)++; + break; + + case OPCODE_IB_IP_IOCB: + ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *) + net_rsp); + (*rx_cleaned)++; + break; + default: + { + u32 *tmp = (u32 *) net_rsp; + printk(KERN_ERR PFX + "%s: Hit default case, not " + "handled!\n" + " dropping the packet, opcode = " + "%x.\n", + ndev->name, net_rsp->opcode); + printk(KERN_ERR PFX + "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n", + (unsigned long int)tmp[0], + (unsigned long int)tmp[1], + (unsigned long int)tmp[2], + (unsigned long int)tmp[3]); + } + } + + qdev->rsp_consumer_index++; + + if (qdev->rsp_consumer_index == NUM_RSP_Q_ENTRIES) { + qdev->rsp_consumer_index = 0; + qdev->rsp_current = qdev->rsp_q_virt_addr; + } else { + qdev->rsp_current++; + } + } + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + + ql_update_lrg_bufq_prod_index(qdev); + + if (qdev->small_buf_release_cnt >= 16) { + while (qdev->small_buf_release_cnt >= 16) { + qdev->small_buf_q_producer_index++; + + if (qdev->small_buf_q_producer_index == + NUM_SBUFQ_ENTRIES) + qdev->small_buf_q_producer_index = 0; + qdev->small_buf_release_cnt -= 8; + } + + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + rxSmallQProducerIndex, + qdev->small_buf_q_producer_index); + } + + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs.rspQConsumerIndex, + qdev->rsp_consumer_index); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + + if (unlikely(netif_queue_stopped(qdev->ndev))) { + if (netif_queue_stopped(qdev->ndev) && + (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4))) + netif_wake_queue(qdev->ndev); + } + + return *tx_cleaned + *rx_cleaned; +} + +static int ql_poll(struct net_device *ndev, int *budget) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + int work_to_do = min(*budget, ndev->quota); + int rx_cleaned = 0, tx_cleaned = 0; + + if (!netif_carrier_ok(ndev)) + goto quit_polling; + + ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do); + *budget -= rx_cleaned; + ndev->quota -= rx_cleaned; + + if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) { +quit_polling: + netif_rx_complete(ndev); + ql_enable_interrupts(qdev); + return 0; + } + return 1; +} + +static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + + struct net_device *ndev = dev_id; + struct ql3_adapter *qdev = netdev_priv(ndev); + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + u32 value; + int handled = 1; + u32 var; + + port_regs = qdev->mem_map_registers; + + value = + ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus); + + if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) { + spin_lock(&qdev->adapter_lock); + netif_stop_queue(qdev->ndev); + netif_carrier_off(qdev->ndev); + ql_disable_interrupts(qdev); + qdev->port_link_state = LS_DOWN; + set_bit(QL_RESET_ACTIVE,&qdev->flags) ; + + if (value & ISP_CONTROL_FE) { + /* + * Chip Fatal Error. + */ + var = + ql_read_page0_reg_l(qdev, + &port_regs->PortFatalErrStatus); + printk(KERN_WARNING PFX + "%s: Resetting chip. PortFatalErrStatus " + "register = 0x%x\n", ndev->name, var); + set_bit(QL_RESET_START,&qdev->flags) ; + } else { + /* + * Soft Reset Requested. + */ + set_bit(QL_RESET_PER_SCSI,&qdev->flags) ; + printk(KERN_ERR PFX + "%s: Another function issued a reset to the " + "chip. ISR value = %x.\n", ndev->name, value); + } + queue_work(qdev->workqueue, &qdev->reset_work); + spin_unlock(&qdev->adapter_lock); + } else if (value & ISP_IMR_DISABLE_CMPL_INT) { + ql_disable_interrupts(qdev); + if (likely(netif_rx_schedule_prep(ndev))) + __netif_rx_schedule(ndev); + else + ql_enable_interrupts(qdev); + } else { + return IRQ_NONE; + } + + return IRQ_RETVAL(handled); +} + +static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + struct ql_tx_buf_cb *tx_cb; + struct ob_mac_iocb_req *mac_iocb_ptr; + u64 map; + + if (unlikely(atomic_read(&qdev->tx_count) < 2)) { + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; + mac_iocb_ptr = tx_cb->queue_entry; + memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); + mac_iocb_ptr->opcode = qdev->mac_ob_opcode; + mac_iocb_ptr->flags |= qdev->mb_bit_mask; + mac_iocb_ptr->transaction_id = qdev->req_producer_index; + mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len); + tx_cb->skb = skb; + map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map)); + mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map)); + mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E); + pci_unmap_addr_set(tx_cb, mapaddr, map); + pci_unmap_len_set(tx_cb, maplen, skb->len); + atomic_dec(&qdev->tx_count); + + qdev->req_producer_index++; + if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) + qdev->req_producer_index = 0; + wmb(); + ql_write_common_reg_l(qdev, + (u32 *) & port_regs->CommonRegs.reqQProducerIndex, + qdev->req_producer_index); + + ndev->trans_start = jiffies; + if (netif_msg_tx_queued(qdev)) + printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", + ndev->name, qdev->req_producer_index, skb->len); + + return NETDEV_TX_OK; +} +static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev) +{ + qdev->req_q_size = + (u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req)); + + qdev->req_q_virt_addr = + pci_alloc_consistent(qdev->pdev, + (size_t) qdev->req_q_size, + &qdev->req_q_phy_addr); + + if ((qdev->req_q_virt_addr == NULL) || + LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) { + printk(KERN_ERR PFX "%s: reqQ failed.\n", + qdev->ndev->name); + return -ENOMEM; + } + + qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb); + + qdev->rsp_q_virt_addr = + pci_alloc_consistent(qdev->pdev, + (size_t) qdev->rsp_q_size, + &qdev->rsp_q_phy_addr); + + if ((qdev->rsp_q_virt_addr == NULL) || + LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) { + printk(KERN_ERR PFX + "%s: rspQ allocation failed\n", + qdev->ndev->name); + pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size, + qdev->req_q_virt_addr, + qdev->req_q_phy_addr); + return -ENOMEM; + } + + set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags); + + return 0; +} + +static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev) +{ + if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) { + printk(KERN_INFO PFX + "%s: Already done.\n", qdev->ndev->name); + return; + } + + pci_free_consistent(qdev->pdev, + qdev->req_q_size, + qdev->req_q_virt_addr, qdev->req_q_phy_addr); + + qdev->req_q_virt_addr = NULL; + + pci_free_consistent(qdev->pdev, + qdev->rsp_q_size, + qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr); + + qdev->rsp_q_virt_addr = NULL; + + clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags); +} + +static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) +{ + /* Create Large Buffer Queue */ + qdev->lrg_buf_q_size = + NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry); + if (qdev->lrg_buf_q_size < PAGE_SIZE) + qdev->lrg_buf_q_alloc_size = PAGE_SIZE; + else + qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2; + + qdev->lrg_buf_q_alloc_virt_addr = + pci_alloc_consistent(qdev->pdev, + qdev->lrg_buf_q_alloc_size, + &qdev->lrg_buf_q_alloc_phy_addr); + + if (qdev->lrg_buf_q_alloc_virt_addr == NULL) { + printk(KERN_ERR PFX + "%s: lBufQ failed\n", qdev->ndev->name); + return -ENOMEM; + } + qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr; + qdev->lrg_buf_q_phy_addr = qdev->lrg_buf_q_alloc_phy_addr; + + /* Create Small Buffer Queue */ + qdev->small_buf_q_size = + NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry); + if (qdev->small_buf_q_size < PAGE_SIZE) + qdev->small_buf_q_alloc_size = PAGE_SIZE; + else + qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2; + + qdev->small_buf_q_alloc_virt_addr = + pci_alloc_consistent(qdev->pdev, + qdev->small_buf_q_alloc_size, + &qdev->small_buf_q_alloc_phy_addr); + + if (qdev->small_buf_q_alloc_virt_addr == NULL) { + printk(KERN_ERR PFX + "%s: Small Buffer Queue allocation failed.\n", + qdev->ndev->name); + pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, + qdev->lrg_buf_q_alloc_virt_addr, + qdev->lrg_buf_q_alloc_phy_addr); + return -ENOMEM; + } + + qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr; + qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr; + set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags); + return 0; +} + +static void ql_free_buffer_queues(struct ql3_adapter *qdev) +{ + if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) { + printk(KERN_INFO PFX + "%s: Already done.\n", qdev->ndev->name); + return; + } + + pci_free_consistent(qdev->pdev, + qdev->lrg_buf_q_alloc_size, + qdev->lrg_buf_q_alloc_virt_addr, + qdev->lrg_buf_q_alloc_phy_addr); + + qdev->lrg_buf_q_virt_addr = NULL; + + pci_free_consistent(qdev->pdev, + qdev->small_buf_q_alloc_size, + qdev->small_buf_q_alloc_virt_addr, + qdev->small_buf_q_alloc_phy_addr); + + qdev->small_buf_q_virt_addr = NULL; + + clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags); +} + +static int ql_alloc_small_buffers(struct ql3_adapter *qdev) +{ + int i; + struct bufq_addr_element *small_buf_q_entry; + + /* Currently we allocate on one of memory and use it for smallbuffers */ + qdev->small_buf_total_size = + (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES * + QL_SMALL_BUFFER_SIZE); + + qdev->small_buf_virt_addr = + pci_alloc_consistent(qdev->pdev, + qdev->small_buf_total_size, + &qdev->small_buf_phy_addr); + + if (qdev->small_buf_virt_addr == NULL) { + printk(KERN_ERR PFX + "%s: Failed to get small buffer memory.\n", + qdev->ndev->name); + return -ENOMEM; + } + + qdev->small_buf_phy_addr_low = LS_64BITS(qdev->small_buf_phy_addr); + qdev->small_buf_phy_addr_high = MS_64BITS(qdev->small_buf_phy_addr); + + small_buf_q_entry = qdev->small_buf_q_virt_addr; + + qdev->last_rsp_offset = qdev->small_buf_phy_addr_low; + + /* Initialize the small buffer queue. */ + for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) { + small_buf_q_entry->addr_high = + cpu_to_le32(qdev->small_buf_phy_addr_high); + small_buf_q_entry->addr_low = + cpu_to_le32(qdev->small_buf_phy_addr_low + + (i * QL_SMALL_BUFFER_SIZE)); + small_buf_q_entry++; + } + qdev->small_buf_index = 0; + set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags); + return 0; +} + +static void ql_free_small_buffers(struct ql3_adapter *qdev) +{ + if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) { + printk(KERN_INFO PFX + "%s: Already done.\n", qdev->ndev->name); + return; + } + if (qdev->small_buf_virt_addr != NULL) { + pci_free_consistent(qdev->pdev, + qdev->small_buf_total_size, + qdev->small_buf_virt_addr, + qdev->small_buf_phy_addr); + + qdev->small_buf_virt_addr = NULL; + } +} + +static void ql_free_large_buffers(struct ql3_adapter *qdev) +{ + int i = 0; + struct ql_rcv_buf_cb *lrg_buf_cb; + + for (i = 0; i < NUM_LARGE_BUFFERS; i++) { + lrg_buf_cb = &qdev->lrg_buf[i]; + if (lrg_buf_cb->skb) { + dev_kfree_skb(lrg_buf_cb->skb); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(lrg_buf_cb, mapaddr), + pci_unmap_len(lrg_buf_cb, maplen), + PCI_DMA_FROMDEVICE); + memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb)); + } else { + break; + } + } +} + +static void ql_init_large_buffers(struct ql3_adapter *qdev) +{ + int i; + struct ql_rcv_buf_cb *lrg_buf_cb; + struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr; + + for (i = 0; i < NUM_LARGE_BUFFERS; i++) { + lrg_buf_cb = &qdev->lrg_buf[i]; + buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high; + buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low; + buf_addr_ele++; + } + qdev->lrg_buf_index = 0; + qdev->lrg_buf_skb_check = 0; +} + +static int ql_alloc_large_buffers(struct ql3_adapter *qdev) +{ + int i; + struct ql_rcv_buf_cb *lrg_buf_cb; + struct sk_buff *skb; + u64 map; + + for (i = 0; i < NUM_LARGE_BUFFERS; i++) { + skb = dev_alloc_skb(qdev->lrg_buffer_len); + if (unlikely(!skb)) { + /* Better luck next round */ + printk(KERN_ERR PFX + "%s: large buff alloc failed, " + "for %d bytes at index %d.\n", + qdev->ndev->name, + qdev->lrg_buffer_len * 2, i); + ql_free_large_buffers(qdev); + return -ENOMEM; + } else { + + lrg_buf_cb = &qdev->lrg_buf[i]; + memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb)); + lrg_buf_cb->index = i; + lrg_buf_cb->skb = skb; + /* + * We save some space to copy the ethhdr from first + * buffer + */ + skb_reserve(skb, QL_HEADER_SPACE); + map = pci_map_single(qdev->pdev, + skb->data, + qdev->lrg_buffer_len - + QL_HEADER_SPACE, + PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(lrg_buf_cb, mapaddr, map); + pci_unmap_len_set(lrg_buf_cb, maplen, + qdev->lrg_buffer_len - + QL_HEADER_SPACE); + lrg_buf_cb->buf_phy_addr_low = + cpu_to_le32(LS_64BITS(map)); + lrg_buf_cb->buf_phy_addr_high = + cpu_to_le32(MS_64BITS(map)); + } + } + return 0; +} + +static void ql_create_send_free_list(struct ql3_adapter *qdev) +{ + struct ql_tx_buf_cb *tx_cb; + int i; + struct ob_mac_iocb_req *req_q_curr = + qdev->req_q_virt_addr; + + /* Create free list of transmit buffers */ + for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + tx_cb = &qdev->tx_buf[i]; + tx_cb->skb = NULL; + tx_cb->queue_entry = req_q_curr; + req_q_curr++; + } +} + +static int ql_alloc_mem_resources(struct ql3_adapter *qdev) +{ + if (qdev->ndev->mtu == NORMAL_MTU_SIZE) + qdev->lrg_buffer_len = NORMAL_MTU_SIZE; + else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) { + qdev->lrg_buffer_len = JUMBO_MTU_SIZE; + } else { + printk(KERN_ERR PFX + "%s: Invalid mtu size. Only 1500 and 9000 are accepted.\n", + qdev->ndev->name); + return -ENOMEM; + } + qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE; + qdev->max_frame_size = + (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE; + + /* + * First allocate a page of shared memory and use it for shadow + * locations of Network Request Queue Consumer Address Register and + * Network Completion Queue Producer Index Register + */ + qdev->shadow_reg_virt_addr = + pci_alloc_consistent(qdev->pdev, + PAGE_SIZE, &qdev->shadow_reg_phy_addr); + + if (qdev->shadow_reg_virt_addr != NULL) { + qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr; + qdev->req_consumer_index_phy_addr_high = + MS_64BITS(qdev->shadow_reg_phy_addr); + qdev->req_consumer_index_phy_addr_low = + LS_64BITS(qdev->shadow_reg_phy_addr); + + qdev->prsp_producer_index = + (u32 *) (((u8 *) qdev->preq_consumer_index) + 8); + qdev->rsp_producer_index_phy_addr_high = + qdev->req_consumer_index_phy_addr_high; + qdev->rsp_producer_index_phy_addr_low = + qdev->req_consumer_index_phy_addr_low + 8; + } else { + printk(KERN_ERR PFX + "%s: shadowReg Alloc failed.\n", qdev->ndev->name); + return -ENOMEM; + } + + if (ql_alloc_net_req_rsp_queues(qdev) != 0) { + printk(KERN_ERR PFX + "%s: ql_alloc_net_req_rsp_queues failed.\n", + qdev->ndev->name); + goto err_req_rsp; + } + + if (ql_alloc_buffer_queues(qdev) != 0) { + printk(KERN_ERR PFX + "%s: ql_alloc_buffer_queues failed.\n", + qdev->ndev->name); + goto err_buffer_queues; + } + + if (ql_alloc_small_buffers(qdev) != 0) { + printk(KERN_ERR PFX + "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name); + goto err_small_buffers; + } + + if (ql_alloc_large_buffers(qdev) != 0) { + printk(KERN_ERR PFX + "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name); + goto err_small_buffers; + } + + /* Initialize the large buffer queue. */ + ql_init_large_buffers(qdev); + ql_create_send_free_list(qdev); + + qdev->rsp_current = qdev->rsp_q_virt_addr; + + return 0; + +err_small_buffers: + ql_free_buffer_queues(qdev); +err_buffer_queues: + ql_free_net_req_rsp_queues(qdev); +err_req_rsp: + pci_free_consistent(qdev->pdev, + PAGE_SIZE, + qdev->shadow_reg_virt_addr, + qdev->shadow_reg_phy_addr); + + return -ENOMEM; +} + +static void ql_free_mem_resources(struct ql3_adapter *qdev) +{ + ql_free_large_buffers(qdev); + ql_free_small_buffers(qdev); + ql_free_buffer_queues(qdev); + ql_free_net_req_rsp_queues(qdev); + if (qdev->shadow_reg_virt_addr != NULL) { + pci_free_consistent(qdev->pdev, + PAGE_SIZE, + qdev->shadow_reg_virt_addr, + qdev->shadow_reg_phy_addr); + qdev->shadow_reg_virt_addr = NULL; + } +} + +static int ql_init_misc_registers(struct ql3_adapter *qdev) +{ + struct ql3xxx_local_ram_registers *local_ram = + (struct ql3xxx_local_ram_registers *)qdev->mem_map_registers; + + if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 4)) + return -1; + + ql_write_page2_reg(qdev, + &local_ram->bufletSize, qdev->nvram_data.bufletSize); + + ql_write_page2_reg(qdev, + &local_ram->maxBufletCount, + qdev->nvram_data.bufletCount); + + ql_write_page2_reg(qdev, + &local_ram->freeBufletThresholdLow, + (qdev->nvram_data.tcpWindowThreshold25 << 16) | + (qdev->nvram_data.tcpWindowThreshold0)); + + ql_write_page2_reg(qdev, + &local_ram->freeBufletThresholdHigh, + qdev->nvram_data.tcpWindowThreshold50); + + ql_write_page2_reg(qdev, + &local_ram->ipHashTableBase, + (qdev->nvram_data.ipHashTableBaseHi << 16) | + qdev->nvram_data.ipHashTableBaseLo); + ql_write_page2_reg(qdev, + &local_ram->ipHashTableCount, + qdev->nvram_data.ipHashTableSize); + ql_write_page2_reg(qdev, + &local_ram->tcpHashTableBase, + (qdev->nvram_data.tcpHashTableBaseHi << 16) | + qdev->nvram_data.tcpHashTableBaseLo); + ql_write_page2_reg(qdev, + &local_ram->tcpHashTableCount, + qdev->nvram_data.tcpHashTableSize); + ql_write_page2_reg(qdev, + &local_ram->ncbBase, + (qdev->nvram_data.ncbTableBaseHi << 16) | + qdev->nvram_data.ncbTableBaseLo); + ql_write_page2_reg(qdev, + &local_ram->maxNcbCount, + qdev->nvram_data.ncbTableSize); + ql_write_page2_reg(qdev, + &local_ram->drbBase, + (qdev->nvram_data.drbTableBaseHi << 16) | + qdev->nvram_data.drbTableBaseLo); + ql_write_page2_reg(qdev, + &local_ram->maxDrbCount, + qdev->nvram_data.drbTableSize); + ql_sem_unlock(qdev, QL_DDR_RAM_SEM_MASK); + return 0; +} + +static int ql_adapter_initialize(struct ql3_adapter *qdev) +{ + u32 value; + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + struct ql3xxx_host_memory_registers __iomem *hmem_regs = + (struct ql3xxx_host_memory_registers *)port_regs; + u32 delay = 10; + int status = 0; + + if(ql_mii_setup(qdev)) + return -1; + + /* Bring out PHY out of reset */ + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + (ISP_SERIAL_PORT_IF_WE | + (ISP_SERIAL_PORT_IF_WE << 16))); + + qdev->port_link_state = LS_DOWN; + netif_carrier_off(qdev->ndev); + + /* V2 chip fix for ARS-39168. */ + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg, + (ISP_SERIAL_PORT_IF_SDE | + (ISP_SERIAL_PORT_IF_SDE << 16))); + + /* Request Queue Registers */ + *((u32 *) (qdev->preq_consumer_index)) = 0; + atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES); + qdev->req_producer_index = 0; + + ql_write_page1_reg(qdev, + &hmem_regs->reqConsumerIndexAddrHigh, + qdev->req_consumer_index_phy_addr_high); + ql_write_page1_reg(qdev, + &hmem_regs->reqConsumerIndexAddrLow, + qdev->req_consumer_index_phy_addr_low); + + ql_write_page1_reg(qdev, + &hmem_regs->reqBaseAddrHigh, + MS_64BITS(qdev->req_q_phy_addr)); + ql_write_page1_reg(qdev, + &hmem_regs->reqBaseAddrLow, + LS_64BITS(qdev->req_q_phy_addr)); + ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES); + + /* Response Queue Registers */ + *((u16 *) (qdev->prsp_producer_index)) = 0; + qdev->rsp_consumer_index = 0; + qdev->rsp_current = qdev->rsp_q_virt_addr; + + ql_write_page1_reg(qdev, + &hmem_regs->rspProducerIndexAddrHigh, + qdev->rsp_producer_index_phy_addr_high); + + ql_write_page1_reg(qdev, + &hmem_regs->rspProducerIndexAddrLow, + qdev->rsp_producer_index_phy_addr_low); + + ql_write_page1_reg(qdev, + &hmem_regs->rspBaseAddrHigh, + MS_64BITS(qdev->rsp_q_phy_addr)); + + ql_write_page1_reg(qdev, + &hmem_regs->rspBaseAddrLow, + LS_64BITS(qdev->rsp_q_phy_addr)); + + ql_write_page1_reg(qdev, &hmem_regs->rspLength, NUM_RSP_Q_ENTRIES); + + /* Large Buffer Queue */ + ql_write_page1_reg(qdev, + &hmem_regs->rxLargeQBaseAddrHigh, + MS_64BITS(qdev->lrg_buf_q_phy_addr)); + + ql_write_page1_reg(qdev, + &hmem_regs->rxLargeQBaseAddrLow, + LS_64BITS(qdev->lrg_buf_q_phy_addr)); + + ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES); + + ql_write_page1_reg(qdev, + &hmem_regs->rxLargeBufferLength, + qdev->lrg_buffer_len); + + /* Small Buffer Queue */ + ql_write_page1_reg(qdev, + &hmem_regs->rxSmallQBaseAddrHigh, + MS_64BITS(qdev->small_buf_q_phy_addr)); + + ql_write_page1_reg(qdev, + &hmem_regs->rxSmallQBaseAddrLow, + LS_64BITS(qdev->small_buf_q_phy_addr)); + + ql_write_page1_reg(qdev, &hmem_regs->rxSmallQLength, NUM_SBUFQ_ENTRIES); + ql_write_page1_reg(qdev, + &hmem_regs->rxSmallBufferLength, + QL_SMALL_BUFFER_SIZE); + + qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1; + qdev->small_buf_release_cnt = 8; + qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1; + qdev->lrg_buf_release_cnt = 8; + qdev->lrg_buf_next_free = + (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr; + qdev->small_buf_index = 0; + qdev->lrg_buf_index = 0; + qdev->lrg_buf_free_count = 0; + qdev->lrg_buf_free_head = NULL; + qdev->lrg_buf_free_tail = NULL; + + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + rxSmallQProducerIndex, + qdev->small_buf_q_producer_index); + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + rxLargeQProducerIndex, + qdev->lrg_buf_q_producer_index); + + /* + * Find out if the chip has already been initialized. If it has, then + * we skip some of the initialization. + */ + clear_bit(QL_LINK_MASTER, &qdev->flags); + value = ql_read_page0_reg(qdev, &port_regs->portStatus); + if ((value & PORT_STATUS_IC) == 0) { + + /* Chip has not been configured yet, so let it rip. */ + if(ql_init_misc_registers(qdev)) { + status = -1; + goto out; + } + + if (qdev->mac_index) + ql_write_page0_reg(qdev, + &port_regs->mac1MaxFrameLengthReg, + qdev->max_frame_size); + else + ql_write_page0_reg(qdev, + &port_regs->mac0MaxFrameLengthReg, + qdev->max_frame_size); + + value = qdev->nvram_data.tcpMaxWindowSize; + ql_write_page0_reg(qdev, &port_regs->tcpMaxWindow, value); + + value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig; + + if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) + * 2) << 13)) { + status = -1; + goto out; + } + ql_write_page0_reg(qdev, &port_regs->ExternalHWConfig, value); + ql_write_page0_reg(qdev, &port_regs->InternalChipConfig, + (((INTERNAL_CHIP_SD | INTERNAL_CHIP_WE) << + 16) | (INTERNAL_CHIP_SD | + INTERNAL_CHIP_WE))); + ql_sem_unlock(qdev, QL_FLASH_SEM_MASK); + } + + + if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, + (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * + 2) << 7)) { + status = -1; + goto out; + } + + ql_init_scan_mode(qdev); + ql_get_phy_owner(qdev); + + /* Load the MAC Configuration */ + + /* Program lower 32 bits of the MAC address */ + ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg, + (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16)); + ql_write_page0_reg(qdev, &port_regs->macAddrDataReg, + ((qdev->ndev->dev_addr[2] << 24) + | (qdev->ndev->dev_addr[3] << 16) + | (qdev->ndev->dev_addr[4] << 8) + | qdev->ndev->dev_addr[5])); + + /* Program top 16 bits of the MAC address */ + ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg, + ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1)); + ql_write_page0_reg(qdev, &port_regs->macAddrDataReg, + ((qdev->ndev->dev_addr[0] << 8) + | qdev->ndev->dev_addr[1])); + + /* Enable Primary MAC */ + ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg, + ((MAC_ADDR_INDIRECT_PTR_REG_PE << 16) | + MAC_ADDR_INDIRECT_PTR_REG_PE)); + + /* Clear Primary and Secondary IP addresses */ + ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg, + ((IP_ADDR_INDEX_REG_MASK << 16) | + (qdev->mac_index << 2))); + ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0); + + ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg, + ((IP_ADDR_INDEX_REG_MASK << 16) | + ((qdev->mac_index << 2) + 1))); + ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0); + + ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); + + /* Indicate Configuration Complete */ + ql_write_page0_reg(qdev, + &port_regs->portControl, + ((PORT_CONTROL_CC << 16) | PORT_CONTROL_CC)); + + do { + value = ql_read_page0_reg(qdev, &port_regs->portStatus); + if (value & PORT_STATUS_IC) + break; + msleep(500); + } while (--delay); + + if (delay == 0) { + printk(KERN_ERR PFX + "%s: Hw Initialization timeout.\n", qdev->ndev->name); + status = -1; + goto out; + } + + /* Enable Ethernet Function */ + value = + (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI | + PORT_CONTROL_HH); + ql_write_page0_reg(qdev, &port_regs->portControl, + ((value << 16) | value)); + +out: + return status; +} + +/* + * Caller holds hw_lock. + */ +static int ql_adapter_reset(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + int status = 0; + u16 value; + int max_wait_time; + + set_bit(QL_RESET_ACTIVE, &qdev->flags); + clear_bit(QL_RESET_DONE, &qdev->flags); + + /* + * Issue soft reset to chip. + */ + printk(KERN_DEBUG PFX + "%s: Issue soft reset to chip.\n", + qdev->ndev->name); + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs.ispControlStatus, + ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR)); + + /* Wait 3 seconds for reset to complete. */ + printk(KERN_DEBUG PFX + "%s: Wait 10 milliseconds for reset to complete.\n", + qdev->ndev->name); + + /* Wait until the firmware tells us the Soft Reset is done */ + max_wait_time = 5; + do { + value = + ql_read_common_reg(qdev, + &port_regs->CommonRegs.ispControlStatus); + if ((value & ISP_CONTROL_SR) == 0) + break; + + ssleep(1); + } while ((--max_wait_time)); + + /* + * Also, make sure that the Network Reset Interrupt bit has been + * cleared after the soft reset has taken place. + */ + value = + ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus); + if (value & ISP_CONTROL_RI) { + printk(KERN_DEBUG PFX + "ql_adapter_reset: clearing RI after reset.\n"); + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + ispControlStatus, + ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI)); + } + + if (max_wait_time == 0) { + /* Issue Force Soft Reset */ + ql_write_common_reg(qdev, + (u32 *) & port_regs->CommonRegs. + ispControlStatus, + ((ISP_CONTROL_FSR << 16) | + ISP_CONTROL_FSR)); + /* + * Wait until the firmware tells us the Force Soft Reset is + * done + */ + max_wait_time = 5; + do { + value = + ql_read_common_reg(qdev, + &port_regs->CommonRegs. + ispControlStatus); + if ((value & ISP_CONTROL_FSR) == 0) { + break; + } + ssleep(1); + } while ((--max_wait_time)); + } + if (max_wait_time == 0) + status = 1; + + clear_bit(QL_RESET_ACTIVE, &qdev->flags); + set_bit(QL_RESET_DONE, &qdev->flags); + return status; +} + +static void ql_set_mac_info(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + u32 value, port_status; + u8 func_number; + + /* Get the function number */ + value = + ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus); + func_number = (u8) ((value >> 4) & OPCODE_FUNC_ID_MASK); + port_status = ql_read_page0_reg(qdev, &port_regs->portStatus); + switch (value & ISP_CONTROL_FN_MASK) { + case ISP_CONTROL_FN0_NET: + qdev->mac_index = 0; + qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number; + qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number; + qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number; + qdev->mb_bit_mask = FN0_MA_BITS_MASK; + qdev->PHYAddr = PORT0_PHY_ADDRESS; + if (port_status & PORT_STATUS_SM0) + set_bit(QL_LINK_OPTICAL,&qdev->flags); + else + clear_bit(QL_LINK_OPTICAL,&qdev->flags); + break; + + case ISP_CONTROL_FN1_NET: + qdev->mac_index = 1; + qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number; + qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number; + qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number; + qdev->mb_bit_mask = FN1_MA_BITS_MASK; + qdev->PHYAddr = PORT1_PHY_ADDRESS; + if (port_status & PORT_STATUS_SM1) + set_bit(QL_LINK_OPTICAL,&qdev->flags); + else + clear_bit(QL_LINK_OPTICAL,&qdev->flags); + break; + + case ISP_CONTROL_FN0_SCSI: + case ISP_CONTROL_FN1_SCSI: + default: + printk(KERN_DEBUG PFX + "%s: Invalid function number, ispControlStatus = 0x%x\n", + qdev->ndev->name,value); + break; + } + qdev->numPorts = qdev->nvram_data.numPorts; +} + +static void ql_display_dev_info(struct net_device *ndev) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); + struct pci_dev *pdev = qdev->pdev; + + printk(KERN_INFO PFX + "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n", + DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot); + printk(KERN_INFO PFX + "%s Interface.\n", + test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER"); + + /* + * Print PCI bus width/type. + */ + printk(KERN_INFO PFX + "Bus interface is %s %s.\n", + ((qdev->pci_width == 64) ? "64-bit" : "32-bit"), + ((qdev->pci_x) ? "PCI-X" : "PCI")); + + printk(KERN_INFO PFX + "mem IO base address adjusted = 0x%p\n", + qdev->mem_map_registers); + printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq); + + if (netif_msg_probe(qdev)) + printk(KERN_INFO PFX + "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", + ndev->name, ndev->dev_addr[0], ndev->dev_addr[1], + ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], + ndev->dev_addr[5]); +} + +static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) +{ + struct net_device *ndev = qdev->ndev; + int retval = 0; + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + clear_bit(QL_ADAPTER_UP,&qdev->flags); + clear_bit(QL_LINK_MASTER,&qdev->flags); + + ql_disable_interrupts(qdev); + + free_irq(qdev->pdev->irq, ndev); + + if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) { + printk(KERN_INFO PFX + "%s: calling pci_disable_msi().\n", qdev->ndev->name); + clear_bit(QL_MSI_ENABLED,&qdev->flags); + pci_disable_msi(qdev->pdev); + } + + del_timer_sync(&qdev->adapter_timer); + + netif_poll_disable(ndev); + + if (do_reset) { + int soft_reset; + unsigned long hw_flags; + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if (ql_wait_for_drvr_lock(qdev)) { + if ((soft_reset = ql_adapter_reset(qdev))) { + printk(KERN_ERR PFX + "%s: ql_adapter_reset(%d) FAILED!\n", + ndev->name, qdev->index); + } + printk(KERN_ERR PFX + "%s: Releaseing driver lock via chip reset.\n",ndev->name); + } else { + printk(KERN_ERR PFX + "%s: Could not acquire driver lock to do " + "reset!\n", ndev->name); + retval = -1; + } + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + } + ql_free_mem_resources(qdev); + return retval; +} + +static int ql_adapter_up(struct ql3_adapter *qdev) +{ + struct net_device *ndev = qdev->ndev; + int err; + unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ; + unsigned long hw_flags; + + if (ql_alloc_mem_resources(qdev)) { + printk(KERN_ERR PFX + "%s Unable to allocate buffers.\n", ndev->name); + return -ENOMEM; + } + + if (qdev->msi) { + if (pci_enable_msi(qdev->pdev)) { + printk(KERN_ERR PFX + "%s: User requested MSI, but MSI failed to " + "initialize. Continuing without MSI.\n", + qdev->ndev->name); + qdev->msi = 0; + } else { + printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name); + set_bit(QL_MSI_ENABLED,&qdev->flags); + irq_flags &= ~SA_SHIRQ; + } + } + + if ((err = request_irq(qdev->pdev->irq, + ql3xxx_isr, + irq_flags, ndev->name, ndev))) { + printk(KERN_ERR PFX + "%s: Failed to reserve interrupt %d already in use.\n", + ndev->name, qdev->pdev->irq); + goto err_irq; + } + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + + if ((err = ql_wait_for_drvr_lock(qdev))) { + if ((err = ql_adapter_initialize(qdev))) { + printk(KERN_ERR PFX + "%s: Unable to initialize adapter.\n", + ndev->name); + goto err_init; + } + printk(KERN_ERR PFX + "%s: Releaseing driver lock.\n",ndev->name); + ql_sem_unlock(qdev, QL_DRVR_SEM_MASK); + } else { + printk(KERN_ERR PFX + "%s: Could not aquire driver lock.\n", + ndev->name); + goto err_lock; + } + + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + + set_bit(QL_ADAPTER_UP,&qdev->flags); + + mod_timer(&qdev->adapter_timer, jiffies + HZ * 1); + + netif_poll_enable(ndev); + ql_enable_interrupts(qdev); + return 0; + +err_init: + ql_sem_unlock(qdev, QL_DRVR_SEM_MASK); +err_lock: + free_irq(qdev->pdev->irq, ndev); +err_irq: + if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) { + printk(KERN_INFO PFX + "%s: calling pci_disable_msi().\n", + qdev->ndev->name); + clear_bit(QL_MSI_ENABLED,&qdev->flags); + pci_disable_msi(qdev->pdev); + } + return err; +} + +static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset) +{ + if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) { + printk(KERN_ERR PFX + "%s: Driver up/down cycle failed, " + "closing device\n",qdev->ndev->name); + dev_close(qdev->ndev); + return -1; + } + return 0; +} + +static int ql3xxx_close(struct net_device *ndev) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + + /* + * Wait for device to recover from a reset. + * (Rarely happens, but possible.) + */ + while (!test_bit(QL_ADAPTER_UP,&qdev->flags)) + msleep(50); + + ql_adapter_down(qdev,QL_DO_RESET); + return 0; +} + +static int ql3xxx_open(struct net_device *ndev) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + return (ql_adapter_up(qdev)); +} + +static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv; + return &qdev->stats; +} + +static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu) +{ + struct ql3_adapter *qdev = netdev_priv(ndev); + printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu); + if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) { + printk(KERN_ERR PFX + "%s: mtu size of %d is not valid. Use exactly %d or " + "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE, + JUMBO_MTU_SIZE); + return -EINVAL; + } + + if (!netif_running(ndev)) { + ndev->mtu = new_mtu; + return 0; + } + + ndev->mtu = new_mtu; + return ql_cycle_adapter(qdev,QL_DO_RESET); +} + +static void ql3xxx_set_multicast_list(struct net_device *ndev) +{ + /* + * We are manually parsing the list in the net_device structure. + */ + return; +} + +static int ql3xxx_set_mac_address(struct net_device *ndev, void *p) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); + struct ql3xxx_port_registers __iomem *port_regs = + qdev->mem_map_registers; + struct sockaddr *addr = p; + unsigned long hw_flags; + + if (netif_running(ndev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + /* Program lower 32 bits of the MAC address */ + ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg, + (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16)); + ql_write_page0_reg(qdev, &port_regs->macAddrDataReg, + ((ndev->dev_addr[2] << 24) | (ndev-> + dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | ndev->dev_addr[5])); + + /* Program top 16 bits of the MAC address */ + ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg, + ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1)); + ql_write_page0_reg(qdev, &port_regs->macAddrDataReg, + ((ndev->dev_addr[0] << 8) | ndev->dev_addr[1])); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + + return 0; +} + +static void ql3xxx_tx_timeout(struct net_device *ndev) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); + + printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name); + /* + * Stop the queues, we've got a problem. + */ + netif_stop_queue(ndev); + + /* + * Wake up the worker to process this event. + */ + queue_work(qdev->workqueue, &qdev->tx_timeout_work); +} + +static void ql_reset_work(struct ql3_adapter *qdev) +{ + struct net_device *ndev = qdev->ndev; + u32 value; + struct ql_tx_buf_cb *tx_cb; + int max_wait_time, i; + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + unsigned long hw_flags; + + if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) { + clear_bit(QL_LINK_MASTER,&qdev->flags); + + /* + * Loop through the active list and return the skb. + */ + for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + tx_cb = &qdev->tx_buf[i]; + if (tx_cb->skb) { + + printk(KERN_DEBUG PFX + "%s: Freeing lost SKB.\n", + qdev->ndev->name); + pci_unmap_single(qdev->pdev, + pci_unmap_addr(tx_cb, mapaddr), + pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); + dev_kfree_skb(tx_cb->skb); + tx_cb->skb = NULL; + } + } + + printk(KERN_ERR PFX + "%s: Clearing NRI after reset.\n", qdev->ndev->name); + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + ispControlStatus, + ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI)); + /* + * Wait the for Soft Reset to Complete. + */ + max_wait_time = 10; + do { + value = ql_read_common_reg(qdev, + &port_regs->CommonRegs. + + ispControlStatus); + if ((value & ISP_CONTROL_SR) == 0) { + printk(KERN_DEBUG PFX + "%s: reset completed.\n", + qdev->ndev->name); + break; + } + + if (value & ISP_CONTROL_RI) { + printk(KERN_DEBUG PFX + "%s: clearing NRI after reset.\n", + qdev->ndev->name); + ql_write_common_reg(qdev, + (u32 *) & + port_regs-> + CommonRegs. + ispControlStatus, + ((ISP_CONTROL_RI << + 16) | ISP_CONTROL_RI)); + } + + ssleep(1); + } while (--max_wait_time); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + + if (value & ISP_CONTROL_SR) { + + /* + * Set the reset flags and clear the board again. + * Nothing else to do... + */ + printk(KERN_ERR PFX + "%s: Timed out waiting for reset to " + "complete.\n", ndev->name); + printk(KERN_ERR PFX + "%s: Do a reset.\n", ndev->name); + clear_bit(QL_RESET_PER_SCSI,&qdev->flags); + clear_bit(QL_RESET_START,&qdev->flags); + ql_cycle_adapter(qdev,QL_DO_RESET); + return; + } + + clear_bit(QL_RESET_ACTIVE,&qdev->flags); + clear_bit(QL_RESET_PER_SCSI,&qdev->flags); + clear_bit(QL_RESET_START,&qdev->flags); + ql_cycle_adapter(qdev,QL_NO_RESET); + } +} + +static void ql_tx_timeout_work(struct ql3_adapter *qdev) +{ + ql_cycle_adapter(qdev,QL_DO_RESET); +} + +static void ql_get_board_info(struct ql3_adapter *qdev) +{ + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + u32 value; + + value = ql_read_page0_reg_l(qdev, &port_regs->portStatus); + + qdev->chip_rev_id = ((value & PORT_STATUS_REV_ID_MASK) >> 12); + if (value & PORT_STATUS_64) + qdev->pci_width = 64; + else + qdev->pci_width = 32; + if (value & PORT_STATUS_X) + qdev->pci_x = 1; + else + qdev->pci_x = 0; + qdev->pci_slot = (u8) PCI_SLOT(qdev->pdev->devfn); +} + +static void ql3xxx_timer(unsigned long ptr) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)ptr; + + if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) { + printk(KERN_DEBUG PFX + "%s: Reset in progress.\n", + qdev->ndev->name); + goto end; + } + + ql_link_state_machine(qdev); + + /* Restart timer on 2 second interval. */ +end: + mod_timer(&qdev->adapter_timer, jiffies + HZ * 1); +} + +static int __devinit ql3xxx_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_entry) +{ + struct net_device *ndev = NULL; + struct ql3_adapter *qdev = NULL; + static int cards_found = 0; + int pci_using_dac, err; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "%s cannot enable PCI device\n", + pci_name(pdev)); + goto err_out; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", + pci_name(pdev)); + goto err_out_disable_pdev; + } + + pci_set_master(pdev); + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + pci_using_dac = 0; + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + } + + if (err) { + printk(KERN_ERR PFX "%s no usable DMA configuration\n", + pci_name(pdev)); + goto err_out_free_regions; + } + + ndev = alloc_etherdev(sizeof(struct ql3_adapter)); + if (!ndev) + goto err_out_free_regions; + + SET_MODULE_OWNER(ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + + ndev->features = NETIF_F_LLTX; + if (pci_using_dac) + ndev->features |= NETIF_F_HIGHDMA; + + pci_set_drvdata(pdev, ndev); + + qdev = netdev_priv(ndev); + qdev->index = cards_found; + qdev->ndev = ndev; + qdev->pdev = pdev; + qdev->port_link_state = LS_DOWN; + if (msi) + qdev->msi = 1; + + qdev->msg_enable = netif_msg_init(debug, default_msg); + + qdev->mem_map_registers = + ioremap_nocache(pci_resource_start(pdev, 1), + pci_resource_len(qdev->pdev, 1)); + if (!qdev->mem_map_registers) { + printk(KERN_ERR PFX "%s: cannot map device registers\n", + pci_name(pdev)); + goto err_out_free_ndev; + } + + spin_lock_init(&qdev->adapter_lock); + spin_lock_init(&qdev->hw_lock); + + /* Set driver entry points */ + ndev->open = ql3xxx_open; + ndev->hard_start_xmit = ql3xxx_send; + ndev->stop = ql3xxx_close; + ndev->get_stats = ql3xxx_get_stats; + ndev->change_mtu = ql3xxx_change_mtu; + ndev->set_multicast_list = ql3xxx_set_multicast_list; + SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); + ndev->set_mac_address = ql3xxx_set_mac_address; + ndev->tx_timeout = ql3xxx_tx_timeout; + ndev->watchdog_timeo = 5 * HZ; + + ndev->poll = &ql_poll; + ndev->weight = 64; + + ndev->irq = pdev->irq; + + /* make sure the EEPROM is good */ + if (ql_get_nvram_params(qdev)) { + printk(KERN_ALERT PFX + "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n", + qdev->index); + goto err_out_iounmap; + } + + ql_set_mac_info(qdev); + + /* Validate and set parameters */ + if (qdev->mac_index) { + memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress, + ETH_ALEN); + } else { + memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress, + ETH_ALEN); + } + memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); + + ndev->tx_queue_len = NUM_REQ_Q_ENTRIES; + + /* Turn off support for multicasting */ + ndev->flags &= ~IFF_MULTICAST; + + /* Record PCI bus information. */ + ql_get_board_info(qdev); + + /* + * Set the Maximum Memory Read Byte Count value. We do this to handle + * jumbo frames. + */ + if (qdev->pci_x) { + pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036); + } + + err = register_netdev(ndev); + if (err) { + printk(KERN_ERR PFX "%s: cannot register net device\n", + pci_name(pdev)); + goto err_out_iounmap; + } + + /* we're going to reset, so assume we have no link for now */ + + netif_carrier_off(ndev); + netif_stop_queue(ndev); + + qdev->workqueue = create_singlethread_workqueue(ndev->name); + INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev); + INIT_WORK(&qdev->tx_timeout_work, + (void (*)(void *))ql_tx_timeout_work, qdev); + + init_timer(&qdev->adapter_timer); + qdev->adapter_timer.function = ql3xxx_timer; + qdev->adapter_timer.expires = jiffies + HZ * 2; /* two second delay */ + qdev->adapter_timer.data = (unsigned long)qdev; + + if(!cards_found) { + printk(KERN_ALERT PFX "%s\n", DRV_STRING); + printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n", + DRV_NAME, DRV_VERSION); + } + ql_display_dev_info(ndev); + + cards_found++; + return 0; + +err_out_iounmap: + iounmap(qdev->mem_map_registers); +err_out_free_ndev: + free_netdev(ndev); +err_out_free_regions: + pci_release_regions(pdev); +err_out_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +err_out: + return err; +} + +static void __devexit ql3xxx_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ql3_adapter *qdev = netdev_priv(ndev); + + unregister_netdev(ndev); + qdev = netdev_priv(ndev); + + ql_disable_interrupts(qdev); + + if (qdev->workqueue) { + cancel_delayed_work(&qdev->reset_work); + cancel_delayed_work(&qdev->tx_timeout_work); + destroy_workqueue(qdev->workqueue); + qdev->workqueue = NULL; + } + + iounmap((void *)qdev->mmap_virt_base); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(ndev); +} + +static struct pci_driver ql3xxx_driver = { + + .name = DRV_NAME, + .id_table = ql3xxx_pci_tbl, + .probe = ql3xxx_probe, + .remove = __devexit_p(ql3xxx_remove), +}; + +static int __init ql3xxx_init_module(void) +{ + return pci_register_driver(&ql3xxx_driver); +} + +static void __exit ql3xxx_exit(void) +{ + pci_unregister_driver(&ql3xxx_driver); +} + +module_init(ql3xxx_init_module); +module_exit(ql3xxx_exit); diff -puN /dev/null drivers/net/qla3xxx.h --- /dev/null +++ a/drivers/net/qla3xxx.h @@ -0,0 +1,1194 @@ +/* + * QLogic QLA3xxx NIC HBA Driver + * Copyright (c) 2003-2006 QLogic Corporation + * + * See LICENSE.qla3xxx for copyright and licensing details. + */ +#ifndef _QLA3XXX_H_ +#define _QLA3XXX_H_ + +/* + * IOCB Definitions... + */ +#pragma pack(1) + +#define OPCODE_OB_MAC_IOCB_FN0 0x01 +#define OPCODE_OB_MAC_IOCB_FN2 0x21 +#define OPCODE_OB_TCP_IOCB_FN0 0x03 +#define OPCODE_OB_TCP_IOCB_FN2 0x23 +#define OPCODE_UPDATE_NCB_IOCB_FN0 0x00 +#define OPCODE_UPDATE_NCB_IOCB_FN2 0x20 + +#define OPCODE_UPDATE_NCB_IOCB 0xF0 +#define OPCODE_IB_MAC_IOCB 0xF9 +#define OPCODE_IB_IP_IOCB 0xFA +#define OPCODE_IB_TCP_IOCB 0xFB +#define OPCODE_DUMP_PROTO_IOCB 0xFE +#define OPCODE_BUFFER_ALERT_IOCB 0xFB + +#define OPCODE_FUNC_ID_MASK 0x30 +#define OUTBOUND_MAC_IOCB 0x01 /* plus function bits */ +#define OUTBOUND_TCP_IOCB 0x03 /* plus function bits */ +#define UPDATE_NCB_IOCB 0x00 /* plus function bits */ + +#define FN0_MA_BITS_MASK 0x00 +#define FN1_MA_BITS_MASK 0x80 + +struct ob_mac_iocb_req { + u8 opcode; + u8 flags; +#define OB_MAC_IOCB_REQ_MA 0xC0 +#define OB_MAC_IOCB_REQ_F 0x20 +#define OB_MAC_IOCB_REQ_X 0x10 +#define OB_MAC_IOCB_REQ_D 0x02 +#define OB_MAC_IOCB_REQ_I 0x01 + __le16 reserved0; + + __le32 transaction_id; + __le16 data_len; + __le16 reserved1; + __le32 reserved2; + __le32 reserved3; + __le32 buf_addr0_low; + __le32 buf_addr0_high; + __le32 buf_0_len; + __le32 buf_addr1_low; + __le32 buf_addr1_high; + __le32 buf_1_len; + __le32 buf_addr2_low; + __le32 buf_addr2_high; + __le32 buf_2_len; + __le32 reserved4; + __le32 reserved5; +}; +/* + * The following constants define control bits for buffer + * length fields for all IOCB's. + */ +#define OB_MAC_IOCB_REQ_E 0x80000000 /* Last valid buffer in list. */ +#define OB_MAC_IOCB_REQ_C 0x40000000 /* points to an OAL. (continuation) */ +#define OB_MAC_IOCB_REQ_L 0x20000000 /* Auburn local address pointer. */ +#define OB_MAC_IOCB_REQ_R 0x10000000 /* 32-bit address pointer. */ + +struct ob_mac_iocb_rsp { + u8 opcode; + u8 flags; +#define OB_MAC_IOCB_RSP_P 0x08 +#define OB_MAC_IOCB_RSP_S 0x02 +#define OB_MAC_IOCB_RSP_I 0x01 + + __le16 reserved0; + __le32 transaction_id; + __le32 reserved1; + __le32 reserved2; +}; + +struct ib_mac_iocb_rsp { + u8 opcode; + u8 flags; +#define IB_MAC_IOCB_RSP_S 0x80 +#define IB_MAC_IOCB_RSP_H1 0x40 +#define IB_MAC_IOCB_RSP_H0 0x20 +#define IB_MAC_IOCB_RSP_B 0x10 +#define IB_MAC_IOCB_RSP_M 0x08 +#define IB_MAC_IOCB_RSP_MA 0x07 + + __le16 length; + __le32 reserved; + __le32 ial_low; + __le32 ial_high; + +}; + +struct ob_ip_iocb_req { + u8 opcode; + __le16 flags; +#define OB_IP_IOCB_REQ_O 0x100 +#define OB_IP_IOCB_REQ_H 0x008 +#define OB_IP_IOCB_REQ_U 0x004 +#define OB_IP_IOCB_REQ_D 0x002 +#define OB_IP_IOCB_REQ_I 0x001 + + u8 reserved0; + + __le32 transaction_id; + __le16 data_len; + __le16 reserved1; + __le32 hncb_ptr_low; + __le32 hncb_ptr_high; + __le32 buf_addr0_low; + __le32 buf_addr0_high; + __le32 buf_0_len; + __le32 buf_addr1_low; + __le32 buf_addr1_high; + __le32 buf_1_len; + __le32 buf_addr2_low; + __le32 buf_addr2_high; + __le32 buf_2_len; + __le32 reserved2; + __le32 reserved3; +}; + +/* defines for BufferLength fields above */ +#define OB_IP_IOCB_REQ_E 0x80000000 +#define OB_IP_IOCB_REQ_C 0x40000000 +#define OB_IP_IOCB_REQ_L 0x20000000 +#define OB_IP_IOCB_REQ_R 0x10000000 + +struct ob_ip_iocb_rsp { + u8 opcode; + u8 flags; +#define OB_MAC_IOCB_RSP_E 0x08 +#define OB_MAC_IOCB_RSP_L 0x04 +#define OB_MAC_IOCB_RSP_S 0x02 +#define OB_MAC_IOCB_RSP_I 0x01 + + __le16 reserved0; + __le32 transaction_id; + __le32 reserved1; + __le32 reserved2; +}; + +struct ob_tcp_iocb_req { + u8 opcode; + + u8 flags0; +#define OB_TCP_IOCB_REQ_P 0x80 +#define OB_TCP_IOCB_REQ_CI 0x20 +#define OB_TCP_IOCB_REQ_H 0x10 +#define OB_TCP_IOCB_REQ_LN 0x08 +#define OB_TCP_IOCB_REQ_K 0x04 +#define OB_TCP_IOCB_REQ_D 0x02 +#define OB_TCP_IOCB_REQ_I 0x01 + + u8 flags1; +#define OB_TCP_IOCB_REQ_OSM 0x40 +#define OB_TCP_IOCB_REQ_URG 0x20 +#define OB_TCP_IOCB_REQ_ACK 0x10 +#define OB_TCP_IOCB_REQ_PSH 0x08 +#define OB_TCP_IOCB_REQ_RST 0x04 +#define OB_TCP_IOCB_REQ_SYN 0x02 +#define OB_TCP_IOCB_REQ_FIN 0x01 + + u8 options_len; +#define OB_TCP_IOCB_REQ_OMASK 0xF0 +#define OB_TCP_IOCB_REQ_SHIFT 4 + + __le32 transaction_id; + __le32 data_len; + __le32 hncb_ptr_low; + __le32 hncb_ptr_high; + __le32 buf_addr0_low; + __le32 buf_addr0_high; + __le32 buf_0_len; + __le32 buf_addr1_low; + __le32 buf_addr1_high; + __le32 buf_1_len; + __le32 buf_addr2_low; + __le32 buf_addr2_high; + __le32 buf_2_len; + __le32 time_stamp; + __le32 reserved1; +}; + +struct ob_tcp_iocb_rsp { + u8 opcode; + + u8 flags0; +#define OB_TCP_IOCB_RSP_C 0x20 +#define OB_TCP_IOCB_RSP_H 0x10 +#define OB_TCP_IOCB_RSP_LN 0x08 +#define OB_TCP_IOCB_RSP_K 0x04 +#define OB_TCP_IOCB_RSP_D 0x02 +#define OB_TCP_IOCB_RSP_I 0x01 + + u8 flags1; +#define OB_TCP_IOCB_RSP_E 0x10 +#define OB_TCP_IOCB_RSP_W 0x08 +#define OB_TCP_IOCB_RSP_P 0x04 +#define OB_TCP_IOCB_RSP_T 0x02 +#define OB_TCP_IOCB_RSP_F 0x01 + + u8 state; +#define OB_TCP_IOCB_RSP_SMASK 0xF0 +#define OB_TCP_IOCB_RSP_SHIFT 4 + + __le32 transaction_id; + __le32 local_ncb_ptr; + __le32 reserved0; +}; + +struct ib_ip_iocb_rsp { + u8 opcode; + u8 flags; +#define IB_IP_IOCB_RSP_S 0x80 +#define IB_IP_IOCB_RSP_H1 0x40 +#define IB_IP_IOCB_RSP_H0 0x20 +#define IB_IP_IOCB_RSP_B 0x10 +#define IB_IP_IOCB_RSP_M 0x08 +#define IB_IP_IOCB_RSP_MA 0x07 + + __le16 length; + __le16 checksum; + __le16 reserved; +#define IB_IP_IOCB_RSP_R 0x01 + __le32 ial_low; + __le32 ial_high; +}; + +struct ib_tcp_iocb_rsp { + u8 opcode; + u8 flags; +#define IB_TCP_IOCB_RSP_P 0x80 +#define IB_TCP_IOCB_RSP_T 0x40 +#define IB_TCP_IOCB_RSP_D 0x20 +#define IB_TCP_IOCB_RSP_N 0x10 +#define IB_TCP_IOCB_RSP_IP 0x03 +#define IB_TCP_FLAG_MASK 0xf0 +#define IB_TCP_FLAG_IOCB_SYN 0x00 + +#define TCP_IB_RSP_FLAGS(x) (x->flags & ~IB_TCP_FLAG_MASK) + + __le16 length; + __le32 hncb_ref_num; + __le32 ial_low; + __le32 ial_high; +}; + +struct net_rsp_iocb { + u8 opcode; + u8 flags; + __le16 reserved0; + __le32 reserved[3]; +}; +#pragma pack() + +/* + * Register Definitions... + */ +#define PORT0_PHY_ADDRESS 0x1e00 +#define PORT1_PHY_ADDRESS 0x1f00 + +#define ETHERNET_CRC_SIZE 4 + +#define MII_SCAN_REGISTER 0x00000001 + +/* 32-bit ispControlStatus */ +enum { + ISP_CONTROL_NP_MASK = 0x0003, + ISP_CONTROL_NP_PCSR = 0x0000, + ISP_CONTROL_NP_HMCR = 0x0001, + ISP_CONTROL_NP_LRAMCR = 0x0002, + ISP_CONTROL_NP_PSR = 0x0003, + ISP_CONTROL_RI = 0x0008, + ISP_CONTROL_CI = 0x0010, + ISP_CONTROL_PI = 0x0020, + ISP_CONTROL_IN = 0x0040, + ISP_CONTROL_BE = 0x0080, + ISP_CONTROL_FN_MASK = 0x0700, + ISP_CONTROL_FN0_NET = 0x0400, + ISP_CONTROL_FN0_SCSI = 0x0500, + ISP_CONTROL_FN1_NET = 0x0600, + ISP_CONTROL_FN1_SCSI = 0x0700, + ISP_CONTROL_LINK_DN_0 = 0x0800, + ISP_CONTROL_LINK_DN_1 = 0x1000, + ISP_CONTROL_FSR = 0x2000, + ISP_CONTROL_FE = 0x4000, + ISP_CONTROL_SR = 0x8000, +}; + +/* 32-bit ispInterruptMaskReg */ +enum { + ISP_IMR_ENABLE_INT = 0x0004, + ISP_IMR_DISABLE_RESET_INT = 0x0008, + ISP_IMR_DISABLE_CMPL_INT = 0x0010, + ISP_IMR_DISABLE_PROC_INT = 0x0020, +}; + +/* 32-bit serialPortInterfaceReg */ +enum { + ISP_SERIAL_PORT_IF_CLK = 0x0001, + ISP_SERIAL_PORT_IF_CS = 0x0002, + ISP_SERIAL_PORT_IF_D0 = 0x0004, + ISP_SERIAL_PORT_IF_DI = 0x0008, + ISP_NVRAM_MASK = (0x000F << 16), + ISP_SERIAL_PORT_IF_WE = 0x0010, + ISP_SERIAL_PORT_IF_NVR_MASK = 0x001F, + ISP_SERIAL_PORT_IF_SCI = 0x0400, + ISP_SERIAL_PORT_IF_SC0 = 0x0800, + ISP_SERIAL_PORT_IF_SCE = 0x1000, + ISP_SERIAL_PORT_IF_SDI = 0x2000, + ISP_SERIAL_PORT_IF_SDO = 0x4000, + ISP_SERIAL_PORT_IF_SDE = 0x8000, + ISP_SERIAL_PORT_IF_I2C_MASK = 0xFC00, +}; + +/* semaphoreReg */ +enum { + QL_RESOURCE_MASK_BASE_CODE = 0x7, + QL_RESOURCE_BITS_BASE_CODE = 0x4, + QL_DRVR_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 1), + QL_DDR_RAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 4), + QL_PHY_GIO_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 7), + QL_NVRAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 10), + QL_FLASH_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 13), + QL_DRVR_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (1 + 16)), + QL_DDR_RAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (4 + 16)), + QL_PHY_GIO_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (7 + 16)), + QL_NVRAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (10 + 16)), + QL_FLASH_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (13 + 16)), +}; + + /* + * QL3XXX memory-mapped registers + * QL3XXX has 4 "pages" of registers, each page occupying + * 256 bytes. Each page has a "common" area at the start and then + * page-specific registers after that. + */ +struct ql3xxx_common_registers { + u32 MB0; /* Offset 0x00 */ + u32 MB1; /* Offset 0x04 */ + u32 MB2; /* Offset 0x08 */ + u32 MB3; /* Offset 0x0c */ + u32 MB4; /* Offset 0x10 */ + u32 MB5; /* Offset 0x14 */ + u32 MB6; /* Offset 0x18 */ + u32 MB7; /* Offset 0x1c */ + u32 flashBiosAddr; + u32 flashBiosData; + u32 ispControlStatus; + u32 ispInterruptMaskReg; + u32 serialPortInterfaceReg; + u32 semaphoreReg; + u32 reqQProducerIndex; + u32 rspQConsumerIndex; + + u32 rxLargeQProducerIndex; + u32 rxSmallQProducerIndex; + u32 arcMadiCommand; + u32 arcMadiData; +}; + +enum { + EXT_HW_CONFIG_SP_MASK = 0x0006, + EXT_HW_CONFIG_SP_NONE = 0x0000, + EXT_HW_CONFIG_SP_BYTE_PARITY = 0x0002, + EXT_HW_CONFIG_SP_ECC = 0x0004, + EXT_HW_CONFIG_SP_ECCx = 0x0006, + EXT_HW_CONFIG_SIZE_MASK = 0x0060, + EXT_HW_CONFIG_SIZE_128M = 0x0000, + EXT_HW_CONFIG_SIZE_256M = 0x0020, + EXT_HW_CONFIG_SIZE_512M = 0x0040, + EXT_HW_CONFIG_SIZE_INVALID = 0x0060, + EXT_HW_CONFIG_PD = 0x0080, + EXT_HW_CONFIG_FW = 0x0200, + EXT_HW_CONFIG_US = 0x0400, + EXT_HW_CONFIG_DCS_MASK = 0x1800, + EXT_HW_CONFIG_DCS_9MA = 0x0000, + EXT_HW_CONFIG_DCS_15MA = 0x0800, + EXT_HW_CONFIG_DCS_18MA = 0x1000, + EXT_HW_CONFIG_DCS_24MA = 0x1800, + EXT_HW_CONFIG_DDS_MASK = 0x6000, + EXT_HW_CONFIG_DDS_9MA = 0x0000, + EXT_HW_CONFIG_DDS_15MA = 0x2000, + EXT_HW_CONFIG_DDS_18MA = 0x4000, + EXT_HW_CONFIG_DDS_24MA = 0x6000, +}; + +/* InternalChipConfig */ +enum { + INTERNAL_CHIP_DM = 0x0001, + INTERNAL_CHIP_SD = 0x0002, + INTERNAL_CHIP_RAP_MASK = 0x000C, + INTERNAL_CHIP_RAP_RR = 0x0000, + INTERNAL_CHIP_RAP_NRM = 0x0004, + INTERNAL_CHIP_RAP_ERM = 0x0008, + INTERNAL_CHIP_RAP_ERMx = 0x000C, + INTERNAL_CHIP_WE = 0x0010, + INTERNAL_CHIP_EF = 0x0020, + INTERNAL_CHIP_FR = 0x0040, + INTERNAL_CHIP_FW = 0x0080, + INTERNAL_CHIP_FI = 0x0100, + INTERNAL_CHIP_FT = 0x0200, +}; + +/* portControl */ +enum { + PORT_CONTROL_DS = 0x0001, + PORT_CONTROL_HH = 0x0002, + PORT_CONTROL_EI = 0x0004, + PORT_CONTROL_ET = 0x0008, + PORT_CONTROL_EF = 0x0010, + PORT_CONTROL_DRM = 0x0020, + PORT_CONTROL_RLB = 0x0040, + PORT_CONTROL_RCB = 0x0080, + PORT_CONTROL_MAC = 0x0100, + PORT_CONTROL_IPV = 0x0200, + PORT_CONTROL_IFP = 0x0400, + PORT_CONTROL_ITP = 0x0800, + PORT_CONTROL_FI = 0x1000, + PORT_CONTROL_DFP = 0x2000, + PORT_CONTROL_OI = 0x4000, + PORT_CONTROL_CC = 0x8000, +}; + +/* portStatus */ +enum { + PORT_STATUS_SM0 = 0x0001, + PORT_STATUS_SM1 = 0x0002, + PORT_STATUS_X = 0x0008, + PORT_STATUS_DL = 0x0080, + PORT_STATUS_IC = 0x0200, + PORT_STATUS_MRC = 0x0400, + PORT_STATUS_NL = 0x0800, + PORT_STATUS_REV_ID_MASK = 0x7000, + PORT_STATUS_REV_ID_1 = 0x1000, + PORT_STATUS_REV_ID_2 = 0x2000, + PORT_STATUS_REV_ID_3 = 0x3000, + PORT_STATUS_64 = 0x8000, + PORT_STATUS_UP0 = 0x10000, + PORT_STATUS_AC0 = 0x20000, + PORT_STATUS_AE0 = 0x40000, + PORT_STATUS_UP1 = 0x100000, + PORT_STATUS_AC1 = 0x200000, + PORT_STATUS_AE1 = 0x400000, + PORT_STATUS_F0_ENABLED = 0x1000000, + PORT_STATUS_F1_ENABLED = 0x2000000, + PORT_STATUS_F2_ENABLED = 0x4000000, + PORT_STATUS_F3_ENABLED = 0x8000000, +}; + +/* macMIIMgmtControlReg */ +enum { + MAC_ADDR_INDIRECT_PTR_REG_RP_MASK = 0x0003, + MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_LWR = 0x0000, + MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_UPR = 0x0001, + MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_LWR = 0x0002, + MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_UPR = 0x0003, + MAC_ADDR_INDIRECT_PTR_REG_PR = 0x0008, + MAC_ADDR_INDIRECT_PTR_REG_SS = 0x0010, + MAC_ADDR_INDIRECT_PTR_REG_SE = 0x0020, + MAC_ADDR_INDIRECT_PTR_REG_SP = 0x0040, + MAC_ADDR_INDIRECT_PTR_REG_PE = 0x0080, +}; + +/* macMIIMgmtControlReg */ +enum { + MAC_MII_CONTROL_RC = 0x0001, + MAC_MII_CONTROL_SC = 0x0002, + MAC_MII_CONTROL_AS = 0x0004, + MAC_MII_CONTROL_NP = 0x0008, + MAC_MII_CONTROL_CLK_SEL_MASK = 0x0070, + MAC_MII_CONTROL_CLK_SEL_DIV2 = 0x0000, + MAC_MII_CONTROL_CLK_SEL_DIV4 = 0x0010, + MAC_MII_CONTROL_CLK_SEL_DIV6 = 0x0020, + MAC_MII_CONTROL_CLK_SEL_DIV8 = 0x0030, + MAC_MII_CONTROL_CLK_SEL_DIV10 = 0x0040, + MAC_MII_CONTROL_CLK_SEL_DIV14 = 0x0050, + MAC_MII_CONTROL_CLK_SEL_DIV20 = 0x0060, + MAC_MII_CONTROL_CLK_SEL_DIV28 = 0x0070, + MAC_MII_CONTROL_RM = 0x8000, +}; + +/* macMIIStatusReg */ +enum { + MAC_MII_STATUS_BSY = 0x0001, + MAC_MII_STATUS_SC = 0x0002, + MAC_MII_STATUS_NV = 0x0004, +}; + +enum { + MAC_CONFIG_REG_PE = 0x0001, + MAC_CONFIG_REG_TF = 0x0002, + MAC_CONFIG_REG_RF = 0x0004, + MAC_CONFIG_REG_FD = 0x0008, + MAC_CONFIG_REG_GM = 0x0010, + MAC_CONFIG_REG_LB = 0x0020, + MAC_CONFIG_REG_SR = 0x8000, +}; + +enum { + MAC_HALF_DUPLEX_REG_ED = 0x10000, + MAC_HALF_DUPLEX_REG_NB = 0x20000, + MAC_HALF_DUPLEX_REG_BNB = 0x40000, + MAC_HALF_DUPLEX_REG_ALT = 0x80000, +}; + +enum { + IP_ADDR_INDEX_REG_MASK = 0x000f, + IP_ADDR_INDEX_REG_FUNC_0_PRI = 0x0000, + IP_ADDR_INDEX_REG_FUNC_0_SEC = 0x0001, + IP_ADDR_INDEX_REG_FUNC_1_PRI = 0x0002, + IP_ADDR_INDEX_REG_FUNC_1_SEC = 0x0003, + IP_ADDR_INDEX_REG_FUNC_2_PRI = 0x0004, + IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005, + IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006, + IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007, +}; + +enum { + PROBE_MUX_ADDR_REG_MUX_SEL_MASK = 0x003f, + PROBE_MUX_ADDR_REG_SYSCLK = 0x0000, + PROBE_MUX_ADDR_REG_PCICLK = 0x0040, + PROBE_MUX_ADDR_REG_NRXCLK = 0x0080, + PROBE_MUX_ADDR_REG_CPUCLK = 0x00C0, + PROBE_MUX_ADDR_REG_MODULE_SEL_MASK = 0x3f00, + PROBE_MUX_ADDR_REG_UP = 0x4000, + PROBE_MUX_ADDR_REG_RE = 0x8000, +}; + +enum { + STATISTICS_INDEX_REG_MASK = 0x01ff, + STATISTICS_INDEX_REG_MAC0_TX_FRAME = 0x0000, + STATISTICS_INDEX_REG_MAC0_TX_BYTES = 0x0001, + STATISTICS_INDEX_REG_MAC0_TX_STAT1 = 0x0002, + STATISTICS_INDEX_REG_MAC0_TX_STAT2 = 0x0003, + STATISTICS_INDEX_REG_MAC0_TX_STAT3 = 0x0004, + STATISTICS_INDEX_REG_MAC0_TX_STAT4 = 0x0005, + STATISTICS_INDEX_REG_MAC0_TX_STAT5 = 0x0006, + STATISTICS_INDEX_REG_MAC0_RX_FRAME = 0x0007, + STATISTICS_INDEX_REG_MAC0_RX_BYTES = 0x0008, + STATISTICS_INDEX_REG_MAC0_RX_STAT1 = 0x0009, + STATISTICS_INDEX_REG_MAC0_RX_STAT2 = 0x000a, + STATISTICS_INDEX_REG_MAC0_RX_STAT3 = 0x000b, + STATISTICS_INDEX_REG_MAC0_RX_ERR_CRC = 0x000c, + STATISTICS_INDEX_REG_MAC0_RX_ERR_ENC = 0x000d, + STATISTICS_INDEX_REG_MAC0_RX_ERR_LEN = 0x000e, + STATISTICS_INDEX_REG_MAC0_RX_STAT4 = 0x000f, + STATISTICS_INDEX_REG_MAC1_TX_FRAME = 0x0010, + STATISTICS_INDEX_REG_MAC1_TX_BYTES = 0x0011, + STATISTICS_INDEX_REG_MAC1_TX_STAT1 = 0x0012, + STATISTICS_INDEX_REG_MAC1_TX_STAT2 = 0x0013, + STATISTICS_INDEX_REG_MAC1_TX_STAT3 = 0x0014, + STATISTICS_INDEX_REG_MAC1_TX_STAT4 = 0x0015, + STATISTICS_INDEX_REG_MAC1_TX_STAT5 = 0x0016, + STATISTICS_INDEX_REG_MAC1_RX_FRAME = 0x0017, + STATISTICS_INDEX_REG_MAC1_RX_BYTES = 0x0018, + STATISTICS_INDEX_REG_MAC1_RX_STAT1 = 0x0019, + STATISTICS_INDEX_REG_MAC1_RX_STAT2 = 0x001a, + STATISTICS_INDEX_REG_MAC1_RX_STAT3 = 0x001b, + STATISTICS_INDEX_REG_MAC1_RX_ERR_CRC = 0x001c, + STATISTICS_INDEX_REG_MAC1_RX_ERR_ENC = 0x001d, + STATISTICS_INDEX_REG_MAC1_RX_ERR_LEN = 0x001e, + STATISTICS_INDEX_REG_MAC1_RX_STAT4 = 0x001f, + STATISTICS_INDEX_REG_IP_TX_PKTS = 0x0020, + STATISTICS_INDEX_REG_IP_TX_BYTES = 0x0021, + STATISTICS_INDEX_REG_IP_TX_FRAG = 0x0022, + STATISTICS_INDEX_REG_IP_RX_PKTS = 0x0023, + STATISTICS_INDEX_REG_IP_RX_BYTES = 0x0024, + STATISTICS_INDEX_REG_IP_RX_FRAG = 0x0025, + STATISTICS_INDEX_REG_IP_DGRM_REASSEMBLY = 0x0026, + STATISTICS_INDEX_REG_IP_V6_RX_PKTS = 0x0027, + STATISTICS_INDEX_REG_IP_RX_PKTERR = 0x0028, + STATISTICS_INDEX_REG_IP_REASSEMBLY_ERR = 0x0029, + STATISTICS_INDEX_REG_TCP_TX_SEG = 0x0030, + STATISTICS_INDEX_REG_TCP_TX_BYTES = 0x0031, + STATISTICS_INDEX_REG_TCP_RX_SEG = 0x0032, + STATISTICS_INDEX_REG_TCP_RX_BYTES = 0x0033, + STATISTICS_INDEX_REG_TCP_TIMER_EXP = 0x0034, + STATISTICS_INDEX_REG_TCP_RX_ACK = 0x0035, + STATISTICS_INDEX_REG_TCP_TX_ACK = 0x0036, + STATISTICS_INDEX_REG_TCP_RX_ERR = 0x0037, + STATISTICS_INDEX_REG_TCP_RX_WIN_PROBE = 0x0038, + STATISTICS_INDEX_REG_TCP_ECC_ERR_CORR = 0x003f, +}; + +enum { + PORT_FATAL_ERROR_STATUS_OFB_RE_MAC0 = 0x00000001, + PORT_FATAL_ERROR_STATUS_OFB_RE_MAC1 = 0x00000002, + PORT_FATAL_ERROR_STATUS_OFB_WE = 0x00000004, + PORT_FATAL_ERROR_STATUS_IFB_RE = 0x00000008, + PORT_FATAL_ERROR_STATUS_IFB_WE_MAC0 = 0x00000010, + PORT_FATAL_ERROR_STATUS_IFB_WE_MAC1 = 0x00000020, + PORT_FATAL_ERROR_STATUS_ODE_RE = 0x00000040, + PORT_FATAL_ERROR_STATUS_ODE_WE = 0x00000080, + PORT_FATAL_ERROR_STATUS_IDE_RE = 0x00000100, + PORT_FATAL_ERROR_STATUS_IDE_WE = 0x00000200, + PORT_FATAL_ERROR_STATUS_SDE_RE = 0x00000400, + PORT_FATAL_ERROR_STATUS_SDE_WE = 0x00000800, + PORT_FATAL_ERROR_STATUS_BLE = 0x00001000, + PORT_FATAL_ERROR_STATUS_SPE = 0x00002000, + PORT_FATAL_ERROR_STATUS_EP0 = 0x00004000, + PORT_FATAL_ERROR_STATUS_EP1 = 0x00008000, + PORT_FATAL_ERROR_STATUS_ICE = 0x00010000, + PORT_FATAL_ERROR_STATUS_ILE = 0x00020000, + PORT_FATAL_ERROR_STATUS_OPE = 0x00040000, + PORT_FATAL_ERROR_STATUS_TA = 0x00080000, + PORT_FATAL_ERROR_STATUS_MA = 0x00100000, + PORT_FATAL_ERROR_STATUS_SCE = 0x00200000, + PORT_FATAL_ERROR_STATUS_RPE = 0x00400000, + PORT_FATAL_ERROR_STATUS_MPE = 0x00800000, + PORT_FATAL_ERROR_STATUS_OCE = 0x01000000, +}; + +/* + * port control and status page - page 0 + */ + +struct ql3xxx_port_registers { + struct ql3xxx_common_registers CommonRegs; + + u32 ExternalHWConfig; + u32 InternalChipConfig; + u32 portControl; + u32 portStatus; + u32 macAddrIndirectPtrReg; + u32 macAddrDataReg; + u32 macMIIMgmtControlReg; + u32 macMIIMgmtAddrReg; + u32 macMIIMgmtDataReg; + u32 macMIIStatusReg; + u32 mac0ConfigReg; + u32 mac0IpgIfgReg; + u32 mac0HalfDuplexReg; + u32 mac0MaxFrameLengthReg; + u32 mac0PauseThresholdReg; + u32 mac1ConfigReg; + u32 mac1IpgIfgReg; + u32 mac1HalfDuplexReg; + u32 mac1MaxFrameLengthReg; + u32 mac1PauseThresholdReg; + u32 ipAddrIndexReg; + u32 ipAddrDataReg; + u32 ipReassemblyTimeout; + u32 tcpMaxWindow; + u32 currentTcpTimestamp[2]; + u32 internalRamRWAddrReg; + u32 internalRamWDataReg; + u32 reclaimedBufferAddrRegLow; + u32 reclaimedBufferAddrRegHigh; + u32 reserved[2]; + u32 fpgaRevID; + u32 localRamAddr; + u32 localRamDataAutoIncr; + u32 localRamDataNonIncr; + u32 gpOutput; + u32 gpInput; + u32 probeMuxAddr; + u32 probeMuxData; + u32 statisticsIndexReg; + u32 statisticsReadDataRegAutoIncr; + u32 statisticsReadDataRegNoIncr; + u32 PortFatalErrStatus; +}; + +/* + * port host memory config page - page 1 + */ +struct ql3xxx_host_memory_registers { + struct ql3xxx_common_registers CommonRegs; + + u32 reserved[12]; + + /* Network Request Queue */ + u32 reqConsumerIndex; + u32 reqConsumerIndexAddrLow; + u32 reqConsumerIndexAddrHigh; + u32 reqBaseAddrLow; + u32 reqBaseAddrHigh; + u32 reqLength; + + /* Network Completion Queue */ + u32 rspProducerIndex; + u32 rspProducerIndexAddrLow; + u32 rspProducerIndexAddrHigh; + u32 rspBaseAddrLow; + u32 rspBaseAddrHigh; + u32 rspLength; + + /* RX Large Buffer Queue */ + u32 rxLargeQConsumerIndex; + u32 rxLargeQBaseAddrLow; + u32 rxLargeQBaseAddrHigh; + u32 rxLargeQLength; + u32 rxLargeBufferLength; + + /* RX Small Buffer Queue */ + u32 rxSmallQConsumerIndex; + u32 rxSmallQBaseAddrLow; + u32 rxSmallQBaseAddrHigh; + u32 rxSmallQLength; + u32 rxSmallBufferLength; + +}; + +/* + * port local RAM page - page 2 + */ +struct ql3xxx_local_ram_registers { + struct ql3xxx_common_registers CommonRegs; + u32 bufletSize; + u32 maxBufletCount; + u32 currentBufletCount; + u32 reserved; + u32 freeBufletThresholdLow; + u32 freeBufletThresholdHigh; + u32 ipHashTableBase; + u32 ipHashTableCount; + u32 tcpHashTableBase; + u32 tcpHashTableCount; + u32 ncbBase; + u32 maxNcbCount; + u32 currentNcbCount; + u32 drbBase; + u32 maxDrbCount; + u32 currentDrbCount; +}; + +/* + * definitions for Semaphore bits in Semaphore/Serial NVRAM interface register + */ + +#define LS_64BITS(x) (u32)(0xffffffff & ((u64)x)) +#define MS_64BITS(x) (u32)(0xffffffff & (((u64)x)>>16>>16) ) + +/* + * I/O register + */ + +enum { + CONTROL_REG = 0, + STATUS_REG = 1, + PHY_STAT_LINK_UP = 0x0004, + PHY_CTRL_LOOPBACK = 0x4000, + + PETBI_CONTROL_REG = 0x00, + PETBI_CTRL_SOFT_RESET = 0x8000, + PETBI_CTRL_AUTO_NEG = 0x1000, + PETBI_CTRL_RESTART_NEG = 0x0200, + PETBI_CTRL_FULL_DUPLEX = 0x0100, + PETBI_CTRL_SPEED_1000 = 0x0040, + + PETBI_STATUS_REG = 0x01, + PETBI_STAT_NEG_DONE = 0x0020, + PETBI_STAT_LINK_UP = 0x0004, + + PETBI_NEG_ADVER = 0x04, + PETBI_NEG_PAUSE = 0x0080, + PETBI_NEG_PAUSE_MASK = 0x0180, + PETBI_NEG_DUPLEX = 0x0020, + PETBI_NEG_DUPLEX_MASK = 0x0060, + + PETBI_NEG_PARTNER = 0x05, + PETBI_NEG_ERROR_MASK = 0x3000, + + PETBI_EXPANSION_REG = 0x06, + PETBI_EXP_PAGE_RX = 0x0002, + + PETBI_TBI_CTRL = 0x11, + PETBI_TBI_RESET = 0x8000, + PETBI_TBI_AUTO_SENSE = 0x0100, + PETBI_TBI_SERDES_MODE = 0x0010, + PETBI_TBI_SERDES_WRAP = 0x0002, + + AUX_CONTROL_STATUS = 0x1c, + PHY_AUX_NEG_DONE = 0x8000, + PHY_NEG_PARTNER = 5, + PHY_AUX_DUPLEX_STAT = 0x0020, + PHY_AUX_SPEED_STAT = 0x0018, + PHY_AUX_NO_HW_STRAP = 0x0004, + PHY_AUX_RESET_STICK = 0x0002, + PHY_NEG_PAUSE = 0x0400, + PHY_CTRL_SOFT_RESET = 0x8000, + PHY_NEG_ADVER = 4, + PHY_NEG_ADV_SPEED = 0x01e0, + PHY_CTRL_RESTART_NEG = 0x0200, +}; +enum { +/* AM29LV Flash definitions */ + FM93C56A_START = 0x1, +/* Commands */ + FM93C56A_READ = 0x2, + FM93C56A_WEN = 0x0, + FM93C56A_WRITE = 0x1, + FM93C56A_WRITE_ALL = 0x0, + FM93C56A_WDS = 0x0, + FM93C56A_ERASE = 0x3, + FM93C56A_ERASE_ALL = 0x0, +/* Command Extentions */ + FM93C56A_WEN_EXT = 0x3, + FM93C56A_WRITE_ALL_EXT = 0x1, + FM93C56A_WDS_EXT = 0x0, + FM93C56A_ERASE_ALL_EXT = 0x2, +/* Special Bits */ + FM93C56A_READ_DUMMY_BITS = 1, + FM93C56A_READY = 0, + FM93C56A_BUSY = 1, + FM93C56A_CMD_BITS = 2, +/* AM29LV Flash definitions */ + FM93C56A_SIZE_8 = 0x100, + FM93C56A_SIZE_16 = 0x80, + FM93C66A_SIZE_8 = 0x200, + FM93C66A_SIZE_16 = 0x100, + FM93C86A_SIZE_16 = 0x400, +/* Address Bits */ + FM93C56A_NO_ADDR_BITS_16 = 8, + FM93C56A_NO_ADDR_BITS_8 = 9, + FM93C86A_NO_ADDR_BITS_16 = 10, +/* Data Bits */ + FM93C56A_DATA_BITS_16 = 16, + FM93C56A_DATA_BITS_8 = 8, +}; +enum { +/* Auburn Bits */ + AUBURN_EEPROM_DI = 0x8, + AUBURN_EEPROM_DI_0 = 0x0, + AUBURN_EEPROM_DI_1 = 0x8, + AUBURN_EEPROM_DO = 0x4, + AUBURN_EEPROM_DO_0 = 0x0, + AUBURN_EEPROM_DO_1 = 0x4, + AUBURN_EEPROM_CS = 0x2, + AUBURN_EEPROM_CS_0 = 0x0, + AUBURN_EEPROM_CS_1 = 0x2, + AUBURN_EEPROM_CLK_RISE = 0x1, + AUBURN_EEPROM_CLK_FALL = 0x0, +}; +enum {EEPROM_SIZE = FM93C86A_SIZE_16, + EEPROM_NO_ADDR_BITS = FM93C86A_NO_ADDR_BITS_16, + EEPROM_NO_DATA_BITS = FM93C56A_DATA_BITS_16, +}; + +/* + * MAC Config data structure + */ + struct eeprom_port_cfg { + u16 etherMtu_mac; + u16 pauseThreshold_mac; + u16 resumeThreshold_mac; + u16 portConfiguration; +#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000 +#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000 +#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000 +#define PORT_CONFIG_HALF_DUPLEX_ENABLED 0x1000 +#define PORT_CONFIG_1000MB_SPEED 0x0400 +#define PORT_CONFIG_100MB_SPEED 0x0200 +#define PORT_CONFIG_10MB_SPEED 0x0100 +#define PORT_CONFIG_LINK_SPEED_MASK 0x0F00 + u16 reserved[12]; + +}; + +/* + * BIOS data structure + */ +struct eeprom_bios_cfg { + u16 SpinDlyEn:1, disBios:1, EnMemMap:1, EnSelectBoot:1, Reserved:12; + + u8 bootID0:7, boodID0Valid:1; + u8 bootLun0[8]; + + u8 bootID1:7, boodID1Valid:1; + u8 bootLun1[8]; + + u16 MaxLunsTrgt; + u8 reserved[10]; +}; + +/* + * Function Specific Data structure + */ +struct eeprom_function_cfg { + u8 reserved[30]; + u8 macAddress[6]; + u8 macAddressSecondary[6]; + + u16 subsysVendorId; + u16 subsysDeviceId; +}; + +/* + * EEPROM format + */ +struct eeprom_data { + u8 asicId[4]; + u8 version; + u8 numPorts; + u16 boardId; + +#define EEPROM_BOARDID_STR_SIZE 16 +#define EEPROM_SERIAL_NUM_SIZE 16 + + u8 boardIdStr[16]; + u8 serialNumber[16]; + u16 extHwConfig; + struct eeprom_port_cfg macCfg_port0; + struct eeprom_port_cfg macCfg_port1; + u16 bufletSize; + u16 bufletCount; + u16 tcpWindowThreshold50; + u16 tcpWindowThreshold25; + u16 tcpWindowThreshold0; + u16 ipHashTableBaseHi; + u16 ipHashTableBaseLo; + u16 ipHashTableSize; + u16 tcpHashTableBaseHi; + u16 tcpHashTableBaseLo; + u16 tcpHashTableSize; + u16 ncbTableBaseHi; + u16 ncbTableBaseLo; + u16 ncbTableSize; + u16 drbTableBaseHi; + u16 drbTableBaseLo; + u16 drbTableSize; + u16 reserved_142[4]; + u16 ipReassemblyTimeout; + u16 tcpMaxWindowSize; + u16 ipSecurity; +#define IPSEC_CONFIG_PRESENT 0x0001 + u8 reserved_156[294]; + u16 qDebug[8]; + struct eeprom_function_cfg funcCfg_fn0; + u16 reserved_510; + u8 oemSpace[432]; + struct eeprom_bios_cfg biosCfg_fn1; + struct eeprom_function_cfg funcCfg_fn1; + u16 reserved_1022; + u8 reserved_1024[464]; + struct eeprom_function_cfg funcCfg_fn2; + u16 reserved_1534; + u8 reserved_1536[432]; + struct eeprom_bios_cfg biosCfg_fn3; + struct eeprom_function_cfg funcCfg_fn3; + u16 checksum; +}; + +/* + * General definitions... + */ + +/* + * Below are a number compiler switches for controlling driver behavior. + * Some are not supported under certain conditions and are notated as such. + */ + +#define QL3XXX_VENDOR_ID 0x1077 +#define QL3022_DEVICE_ID 0x3022 + +/* MTU & Frame Size stuff */ +#define NORMAL_MTU_SIZE ETH_DATA_LEN +#define JUMBO_MTU_SIZE 9000 +#define VLAN_ID_LEN 2 + +/* Request Queue Related Definitions */ +#define NUM_REQ_Q_ENTRIES 256 /* so that 64 * 64 = 4096 (1 page) */ + +/* Response Queue Related Definitions */ +#define NUM_RSP_Q_ENTRIES 256 /* so that 256 * 16 = 4096 (1 page) */ + +/* Transmit and Receive Buffers */ +#define NUM_LBUFQ_ENTRIES 128 +#define NUM_SBUFQ_ENTRIES 64 +#define QL_SMALL_BUFFER_SIZE 32 +#define QL_ADDR_ELE_PER_BUFQ_ENTRY \ +(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element)) + /* Each send has at least control block. This is how many we keep. */ +#define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY +#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY +#define QL_HEADER_SPACE 32 /* make header space at top of skb. */ +/* + * Large & Small Buffers for Receives + */ +struct lrg_buf_q_entry { + + u32 addr0_lower; +#define IAL_LAST_ENTRY 0x00000001 +#define IAL_CONT_ENTRY 0x00000002 +#define IAL_FLAG_MASK 0x00000003 + u32 addr0_upper; + u32 addr1_lower; + u32 addr1_upper; + u32 addr2_lower; + u32 addr2_upper; + u32 addr3_lower; + u32 addr3_upper; + u32 addr4_lower; + u32 addr4_upper; + u32 addr5_lower; + u32 addr5_upper; + u32 addr6_lower; + u32 addr6_upper; + u32 addr7_lower; + u32 addr7_upper; + +}; + +struct bufq_addr_element { + u32 addr_low; + u32 addr_high; +}; + +#define QL_NO_RESET 0 +#define QL_DO_RESET 1 + +enum link_state_t { + LS_UNKNOWN = 0, + LS_DOWN, + LS_DEGRADE, + LS_RECOVER, + LS_UP, +}; + +struct ql_rcv_buf_cb { + struct ql_rcv_buf_cb *next; + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); + __le32 buf_phy_addr_low; + __le32 buf_phy_addr_high; + int index; +}; + +struct ql_tx_buf_cb { + struct sk_buff *skb; + struct ob_mac_iocb_req *queue_entry ; + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); +}; + +/* definitions for type field */ +#define QL_BUF_TYPE_MACIOCB 0x01 +#define QL_BUF_TYPE_IPIOCB 0x02 +#define QL_BUF_TYPE_TCPIOCB 0x03 + +/* qdev->flags definitions. */ +enum { QL_RESET_DONE = 1, /* Reset finished. */ + QL_RESET_ACTIVE = 2, /* Waiting for reset to finish. */ + QL_RESET_START = 3, /* Please reset the chip. */ + QL_RESET_PER_SCSI = 4, /* SCSI driver requests reset. */ + QL_TX_TIMEOUT = 5, /* Timeout in progress. */ + QL_LINK_MASTER = 6, /* This driver controls the link. */ + QL_ADAPTER_UP = 7, /* Adapter has been brought up. */ + QL_THREAD_UP = 8, /* This flag is available. */ + QL_LINK_UP = 9, /* Link Status. */ + QL_ALLOC_REQ_RSP_Q_DONE = 10, + QL_ALLOC_BUFQS_DONE = 11, + QL_ALLOC_SMALL_BUF_DONE = 12, + QL_LINK_OPTICAL = 13, + QL_MSI_ENABLED = 14, +}; + +/* + * ql3_adapter - The main Adapter structure definition. + * This structure has all fields relevant to the hardware. + */ + +struct ql3_adapter { + u32 reserved_00; + unsigned long flags; + + /* PCI Configuration information for this device */ + struct pci_dev *pdev; + struct net_device *ndev; /* Parent NET device */ + + /* Hardware information */ + u8 chip_rev_id; + u8 pci_slot; + u8 pci_width; + u8 pci_x; + u32 msi; + int index; + struct timer_list adapter_timer; /* timer used for various functions */ + + spinlock_t adapter_lock; + spinlock_t hw_lock; + + /* PCI Bus Relative Register Addresses */ + u8 *mmap_virt_base; /* stores return value from ioremap() */ + struct ql3xxx_port_registers __iomem *mem_map_registers; + u32 current_page; /* tracks current register page */ + + u32 msg_enable; + u8 reserved_01[2]; + u8 reserved_02[2]; + + /* Page for Shadow Registers */ + void *shadow_reg_virt_addr; + dma_addr_t shadow_reg_phy_addr; + + /* Net Request Queue */ + u32 req_q_size; + u32 reserved_03; + struct ob_mac_iocb_req *req_q_virt_addr; + dma_addr_t req_q_phy_addr; + u16 req_producer_index; + u16 reserved_04; + u16 *preq_consumer_index; + u32 req_consumer_index_phy_addr_high; + u32 req_consumer_index_phy_addr_low; + atomic_t tx_count; + struct ql_tx_buf_cb tx_buf[NUM_REQ_Q_ENTRIES]; + + /* Net Response Queue */ + u32 rsp_q_size; + u32 eeprom_cmd_data; + struct net_rsp_iocb *rsp_q_virt_addr; + dma_addr_t rsp_q_phy_addr; + struct net_rsp_iocb *rsp_current; + u16 rsp_consumer_index; + u16 reserved_06; + u32 *prsp_producer_index; + u32 rsp_producer_index_phy_addr_high; + u32 rsp_producer_index_phy_addr_low; + + /* Large Buffer Queue */ + u32 lrg_buf_q_alloc_size; + u32 lrg_buf_q_size; + void *lrg_buf_q_alloc_virt_addr; + void *lrg_buf_q_virt_addr; + dma_addr_t lrg_buf_q_alloc_phy_addr; + dma_addr_t lrg_buf_q_phy_addr; + u32 lrg_buf_q_producer_index; + u32 lrg_buf_release_cnt; + struct bufq_addr_element *lrg_buf_next_free; + + /* Large (Receive) Buffers */ + struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS]; + struct ql_rcv_buf_cb *lrg_buf_free_head; + struct ql_rcv_buf_cb *lrg_buf_free_tail; + u32 lrg_buf_free_count; + u32 lrg_buffer_len; + u32 lrg_buf_index; + u32 lrg_buf_skb_check; + + /* Small Buffer Queue */ + u32 small_buf_q_alloc_size; + u32 small_buf_q_size; + u32 small_buf_q_producer_index; + void *small_buf_q_alloc_virt_addr; + void *small_buf_q_virt_addr; + dma_addr_t small_buf_q_alloc_phy_addr; + dma_addr_t small_buf_q_phy_addr; + u32 small_buf_index; + + /* Small (Receive) Buffers */ + void *small_buf_virt_addr; + dma_addr_t small_buf_phy_addr; + u32 small_buf_phy_addr_low; + u32 small_buf_phy_addr_high; + u32 small_buf_release_cnt; + u32 small_buf_total_size; + + /* ISR related, saves status for DPC. */ + u32 control_status; + + struct eeprom_data nvram_data; + struct timer_list ioctl_timer; + u32 port_link_state; + u32 last_rsp_offset; + + /* 4022 specific */ + u32 mac_index; /* Driver's MAC number can be 0 or 1 for first and second networking functions respectively */ + u32 PHYAddr; /* Address of PHY 0x1e00 Port 0 and 0x1f00 Port 1 */ + u32 mac_ob_opcode; /* Opcode to use on mac transmission */ + u32 tcp_ob_opcode; /* Opcode to use on tcp transmission */ + u32 update_ob_opcode; /* Opcode to use for updating NCB */ + u32 mb_bit_mask; /* MA Bits mask to use on transmission */ + u32 numPorts; + struct net_device_stats stats; + struct workqueue_struct *workqueue; + struct work_struct reset_work; + struct work_struct tx_timeout_work; + u32 max_frame_size; +}; + +#endif /* _QLA3XXX_H_ */ diff -puN drivers/net/r8169.c~git-netdev-all drivers/net/r8169.c --- a/drivers/net/r8169.c~git-netdev-all +++ a/drivers/net/r8169.c @@ -2809,7 +2809,7 @@ static struct pci_driver rtl8169_pci_dri static int __init rtl8169_init_module(void) { - return pci_module_init(&rtl8169_pci_driver); + return pci_register_driver(&rtl8169_pci_driver); } static void __exit diff -puN drivers/net/rrunner.c~git-netdev-all drivers/net/rrunner.c --- a/drivers/net/rrunner.c~git-netdev-all +++ a/drivers/net/rrunner.c @@ -1736,7 +1736,7 @@ static struct pci_driver rr_driver = { static int __init rr_init_module(void) { - return pci_module_init(&rr_driver); + return pci_register_driver(&rr_driver); } static void __exit rr_cleanup_module(void) diff -puN drivers/net/s2io.c~git-netdev-all drivers/net/s2io.c --- a/drivers/net/s2io.c~git-netdev-all +++ a/drivers/net/s2io.c @@ -71,6 +71,7 @@ #include #include #include +#include /* local include */ #include "s2io.h" @@ -7232,7 +7233,7 @@ static void __devexit s2io_rem_nic(struc int __init s2io_starter(void) { - return pci_module_init(&s2io_driver); + return pci_register_driver(&s2io_driver); } /** diff -puN drivers/net/saa9730.c~git-netdev-all drivers/net/saa9730.c --- a/drivers/net/saa9730.c~git-netdev-all +++ a/drivers/net/saa9730.c @@ -1131,7 +1131,7 @@ static struct pci_driver saa9730_driver static int __init saa9730_init(void) { - return pci_module_init(&saa9730_driver); + return pci_register_driver(&saa9730_driver); } static void __exit saa9730_cleanup(void) diff -puN drivers/net/seeq8005.c~git-netdev-all drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c~git-netdev-all +++ a/drivers/net/seeq8005.c @@ -742,7 +742,7 @@ module_param(irq, int, 0); MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address"); MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number"); -int init_module(void) +int __init init_module(void) { dev_seeq = seeq8005_probe(-1); if (IS_ERR(dev_seeq)) diff -puN drivers/net/sis190.c~git-netdev-all drivers/net/sis190.c --- a/drivers/net/sis190.c~git-netdev-all +++ a/drivers/net/sis190.c @@ -1871,7 +1871,7 @@ static struct pci_driver sis190_pci_driv static int __init sis190_init_module(void) { - return pci_module_init(&sis190_pci_driver); + return pci_register_driver(&sis190_pci_driver); } static void __exit sis190_cleanup_module(void) diff -puN drivers/net/sis900.c~git-netdev-all drivers/net/sis900.c --- a/drivers/net/sis900.c~git-netdev-all +++ a/drivers/net/sis900.c @@ -134,6 +134,7 @@ static const struct mii_chip_info { { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, { "ICS LAN PHY", 0x0015, 0xF440, LAN }, + { "ICS LAN PHY", 0x0143, 0xBC70, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, { "NS 83847 PHY", 0x2000, 0x5C30, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, @@ -2495,7 +2496,7 @@ static int __init sis900_init_module(voi printk(version); #endif - return pci_module_init(&sis900_pci_driver); + return pci_register_driver(&sis900_pci_driver); } static void __exit sis900_cleanup_module(void) diff -puN drivers/net/sk98lin/skge.c~git-netdev-all drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c~git-netdev-all +++ a/drivers/net/sk98lin/skge.c @@ -5133,7 +5133,7 @@ static struct pci_driver skge_driver = { static int __init skge_init(void) { - return pci_module_init(&skge_driver); + return pci_register_driver(&skge_driver); } static void __exit skge_exit(void) diff -puN drivers/net/skfp/skfddi.c~git-netdev-all drivers/net/skfp/skfddi.c --- a/drivers/net/skfp/skfddi.c~git-netdev-all +++ a/drivers/net/skfp/skfddi.c @@ -2280,7 +2280,7 @@ static struct pci_driver skfddi_pci_driv static int __init skfd_init(void) { - return pci_module_init(&skfddi_pci_driver); + return pci_register_driver(&skfddi_pci_driver); } static void __exit skfd_exit(void) diff -puN drivers/net/skge.c~git-netdev-all drivers/net/skge.c --- a/drivers/net/skge.c~git-netdev-all +++ a/drivers/net/skge.c @@ -2211,6 +2211,7 @@ static int skge_up(struct net_device *de skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); skge_led(skge, LED_MODE_ON); + netif_poll_enable(dev); return 0; free_rx_ring: @@ -2279,6 +2280,7 @@ static int skge_down(struct net_device * skge_led(skge, LED_MODE_OFF); + netif_poll_disable(dev); skge_tx_clean(skge); skge_rx_clean(skge); @@ -3508,7 +3510,7 @@ static struct pci_driver skge_driver = { static int __init skge_init_module(void) { - return pci_module_init(&skge_driver); + return pci_register_driver(&skge_driver); } static void __exit skge_cleanup_module(void) diff -puN drivers/net/sky2.c~git-netdev-all drivers/net/sky2.c --- a/drivers/net/sky2.c~git-netdev-all +++ a/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.5" +#define DRV_VERSION "1.6" #define PFX DRV_NAME " " /* @@ -121,6 +121,11 @@ static const struct pci_device_id sky2_i { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, { 0 } }; @@ -233,6 +238,8 @@ static void sky2_set_power_state(struct if (hw->ports > 1) reg1 |= PCI_Y2_PHY2_COMA; } + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + udelay(100); if (hw->chip_id == CHIP_ID_YUKON_EC_U) { sky2_pci_write32(hw, PCI_DEV_REG3, 0); @@ -242,9 +249,6 @@ static void sky2_set_power_state(struct sky2_pci_write32(hw, PCI_DEV_REG5, 0); } - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - udelay(100); - break; case PCI_D3hot: @@ -1927,12 +1931,6 @@ static inline void sky2_tx_done(struct n } } -/* Is status ring empty or is there more to do? */ -static inline int sky2_more_work(const struct sky2_hw *hw) -{ - return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)); -} - /* Process status response ring */ static int sky2_status_intr(struct sky2_hw *hw, int to_do) { @@ -2023,6 +2021,9 @@ static int sky2_status_intr(struct sky2_ } } + /* Fully processed status ring so clear irq */ + sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); + exit_loop: if (buf_write[0]) { sky2 = netdev_priv(hw->dev[0]); @@ -2232,19 +2233,16 @@ static int sky2_poll(struct net_device * sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); work_done = sky2_status_intr(hw, work_limit); - *budget -= work_done; - dev0->quota -= work_done; - - if (status & Y2_IS_STAT_BMU) - sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); + if (work_done < work_limit) { + netif_rx_complete(dev0); - if (sky2_more_work(hw)) + sky2_read32(hw, B0_Y2_SP_LISR); + return 0; + } else { + *budget -= work_done; + dev0->quota -= work_done; return 1; - - netif_rx_complete(dev0); - - sky2_read32(hw, B0_Y2_SP_LISR); - return 0; + } } static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) diff -puN drivers/net/slhc.c~git-netdev-all drivers/net/slhc.c --- a/drivers/net/slhc.c~git-netdev-all +++ a/drivers/net/slhc.c @@ -94,27 +94,23 @@ slhc_init(int rslots, int tslots) register struct cstate *ts; struct slcompress *comp; - comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), - GFP_KERNEL); + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) goto out_fail; - memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); + comp->rstate = kzalloc(rsize, GFP_KERNEL); if (! comp->rstate) goto out_free; - memset(comp->rstate, 0, rsize); comp->rslot_limit = rslots - 1; } if ( tslots > 0 && tslots < 256 ) { size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); + comp->tstate = kzalloc(tsize, GFP_KERNEL); if (! comp->tstate) goto out_free2; - memset(comp->tstate, 0, tsize); comp->tslot_limit = tslots - 1; } @@ -141,9 +137,9 @@ slhc_init(int rslots, int tslots) return comp; out_free2: - kfree((unsigned char *)comp->rstate); + kfree(comp->rstate); out_free: - kfree((unsigned char *)comp); + kfree(comp); out_fail: return NULL; } @@ -700,20 +696,6 @@ EXPORT_SYMBOL(slhc_compress); EXPORT_SYMBOL(slhc_uncompress); EXPORT_SYMBOL(slhc_toss); -#ifdef MODULE - -int init_module(void) -{ - printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n"); - return 0; -} - -void cleanup_module(void) -{ - return; -} - -#endif /* MODULE */ #else /* CONFIG_INET */ diff -puN drivers/net/smc911x.c~git-netdev-all drivers/net/smc911x.c --- a/drivers/net/smc911x.c~git-netdev-all +++ a/drivers/net/smc911x.c @@ -55,8 +55,6 @@ static const char version[] = ) #endif - -#include #include #include #include @@ -1092,6 +1090,7 @@ static irqreturn_t smc911x_interrupt(int /* Spurious interrupt check */ if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) { + spin_unlock_irqrestore(&lp->lock, flags); return IRQ_NONE; } diff -puN drivers/net/smc91x.c~git-netdev-all drivers/net/smc91x.c --- a/drivers/net/smc91x.c~git-netdev-all +++ a/drivers/net/smc91x.c @@ -321,12 +321,12 @@ static void smc_reset(struct net_device DBG(2, "%s: %s\n", dev->name, __FUNCTION__); /* Disable all interrupts, block TX tasklet */ - spin_lock(&lp->lock); + spin_lock_irq(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); pending_skb = lp->pending_tx_skb; lp->pending_tx_skb = NULL; - spin_unlock(&lp->lock); + spin_unlock_irq(&lp->lock); /* free any pending tx skb */ if (pending_skb) { @@ -448,12 +448,12 @@ static void smc_shutdown(struct net_devi DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); /* no more interrupts for me */ - spin_lock(&lp->lock); + spin_lock_irq(&lp->lock); SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); pending_skb = lp->pending_tx_skb; lp->pending_tx_skb = NULL; - spin_unlock(&lp->lock); + spin_unlock_irq(&lp->lock); if (pending_skb) dev_kfree_skb(pending_skb); diff -puN drivers/net/smc91x.h~git-netdev-all drivers/net/smc91x.h --- a/drivers/net/smc91x.h~git-netdev-all +++ a/drivers/net/smc91x.h @@ -136,14 +136,9 @@ #define SMC_CAN_USE_32BIT 0 #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 -#define SMC_USE_PXA_DMA 1 -#define SMC_inb(a, r) readb((a) + (r)) #define SMC_inw(a, r) readw((a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) @@ -189,16 +184,10 @@ SMC_outw(u16 val, void __iomem *ioaddr, #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 -#define SMC_inb(a, r) readb((a) + (r)) -#define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_inw(a, r) readw((a) + (r)) #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) -#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) #include #include @@ -372,6 +361,24 @@ static inline void LPD7_SMC_outsw (unsig #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 diff -puN drivers/net/spider_net.c~git-netdev-all drivers/net/spider_net.c --- a/drivers/net/spider_net.c~git-netdev-all +++ a/drivers/net/spider_net.c @@ -1611,13 +1611,12 @@ spider_net_open(struct net_device *netde int result; result = -ENOMEM; - if (spider_net_init_chain(card, &card->tx_chain, - card->descr, - PCI_DMA_TODEVICE, tx_descriptors)) + if (spider_net_init_chain(card, &card->tx_chain, card->descr, + PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; if (spider_net_init_chain(card, &card->rx_chain, - card->descr + tx_descriptors, - PCI_DMA_FROMDEVICE, rx_descriptors)) + card->descr + card->rx_desc, + PCI_DMA_FROMDEVICE, card->rx_desc)) goto alloc_rx_failed; /* allocate rx skbs */ @@ -2005,6 +2004,9 @@ spider_net_setup_netdev(struct spider_ne card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; + card->tx_desc = tx_descriptors; + card->rx_desc = rx_descriptors; + spider_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; diff -puN drivers/net/spider_net.h~git-netdev-all drivers/net/spider_net.h --- a/drivers/net/spider_net.h~git-netdev-all +++ a/drivers/net/spider_net.h @@ -440,6 +440,9 @@ struct spider_net_card { /* for ethtool */ int msg_enable; + int rx_desc; + int tx_desc; + struct spider_net_descr descr[0]; }; diff -puN drivers/net/spider_net_ethtool.c~git-netdev-all drivers/net/spider_net_ethtool.c --- a/drivers/net/spider_net_ethtool.c~git-netdev-all +++ a/drivers/net/spider_net_ethtool.c @@ -130,6 +130,18 @@ spider_net_ethtool_set_tx_csum(struct ne return 0; } +static void +spider_net_ethtool_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + struct spider_net_card *card = netdev->priv; + + ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; + ering->tx_pending = card->tx_desc; + ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; + ering->rx_pending = card->rx_desc; +} + struct ethtool_ops spider_net_ethtool_ops = { .get_settings = spider_net_ethtool_get_settings, .get_drvinfo = spider_net_ethtool_get_drvinfo, @@ -141,5 +153,6 @@ struct ethtool_ops spider_net_ethtool_op .set_rx_csum = spider_net_ethtool_set_rx_csum, .get_tx_csum = spider_net_ethtool_get_tx_csum, .set_tx_csum = spider_net_ethtool_set_tx_csum, + .get_ringparam = spider_net_ethtool_get_ringparam, }; diff -puN drivers/net/starfire.c~git-netdev-all drivers/net/starfire.c --- a/drivers/net/starfire.c~git-netdev-all +++ a/drivers/net/starfire.c @@ -2053,7 +2053,7 @@ static int __init starfire_init (void) return -ENODEV; } - return pci_module_init (&starfire_driver); + return pci_register_driver(&starfire_driver); } diff -puN drivers/net/sundance.c~git-netdev-all drivers/net/sundance.c --- a/drivers/net/sundance.c~git-netdev-all +++ a/drivers/net/sundance.c @@ -17,6 +17,8 @@ Support and updates available at http://www.scyld.com/network/sundance.html [link no longer provides useful info -jgarzik] + Archives of the mailing list are still available at + http://www.beowulf.org/pipermail/netdrivers/ */ @@ -107,7 +109,7 @@ static char *media[MAX_UNITS]; #endif /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/sundance.html\n"; @@ -646,7 +648,7 @@ static int __devinit sundance_probe1 (st /* Reset the chip to erase previous misconfiguration. */ if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - iowrite16(0x00ff, ioaddr + ASICCtrl + 2); + sundance_reset(dev, 0x00ff << 16); if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); @@ -1075,13 +1077,8 @@ reset_tx (struct net_device *dev) /* Reset tx logic, TxListPtr will be cleaned */ iowrite16 (TxDisable, ioaddr + MACCtrl1); - iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset, - ioaddr + ASICCtrl + 2); - for (i=50; i > 0; i--) { - if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0) - break; - mdelay(1); - } + sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16); + /* free all tx skbuff */ for (i = 0; i < TX_RING_SIZE; i++) { skb = np->tx_skbuff[i]; @@ -1736,7 +1733,7 @@ static int __init sundance_init(void) #ifdef MODULE printk(version); #endif - return pci_module_init(&sundance_driver); + return pci_register_driver(&sundance_driver); } static void __exit sundance_exit(void) diff -puN drivers/net/sungem.c~git-netdev-all drivers/net/sungem.c --- a/drivers/net/sungem.c~git-netdev-all +++ a/drivers/net/sungem.c @@ -3194,7 +3194,7 @@ static struct pci_driver gem_driver = { static int __init gem_init(void) { - return pci_module_init(&gem_driver); + return pci_register_driver(&gem_driver); } static void __exit gem_cleanup(void) diff -puN drivers/net/tc35815.c~git-netdev-all drivers/net/tc35815.c --- a/drivers/net/tc35815.c~git-netdev-all +++ a/drivers/net/tc35815.c @@ -1725,7 +1725,7 @@ static struct pci_driver tc35815_driver static int __init tc35815_init_module(void) { - return pci_module_init(&tc35815_driver); + return pci_register_driver(&tc35815_driver); } static void __exit tc35815_cleanup_module(void) diff -puN drivers/net/tg3.c~git-netdev-all drivers/net/tg3.c --- a/drivers/net/tg3.c~git-netdev-all +++ a/drivers/net/tg3.c @@ -11819,7 +11819,7 @@ static struct pci_driver tg3_driver = { static int __init tg3_init(void) { - return pci_module_init(&tg3_driver); + return pci_register_driver(&tg3_driver); } static void __exit tg3_cleanup(void) diff -puN drivers/net/tokenring/3c359.c~git-netdev-all drivers/net/tokenring/3c359.c --- a/drivers/net/tokenring/3c359.c~git-netdev-all +++ a/drivers/net/tokenring/3c359.c @@ -1815,7 +1815,7 @@ static struct pci_driver xl_3c359_driver static int __init xl_pci_init (void) { - return pci_module_init (&xl_3c359_driver); + return pci_register_driver(&xl_3c359_driver); } diff -puN drivers/net/tokenring/ibmtr.c~git-netdev-all drivers/net/tokenring/ibmtr.c --- a/drivers/net/tokenring/ibmtr.c~git-netdev-all +++ a/drivers/net/tokenring/ibmtr.c @@ -140,7 +140,7 @@ in the event that chatty debug messages /* version and credits */ #ifndef PCMCIA -static char version[] __initdata = +static char version[] __devinitdata = "\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" " v2.1.125 10/20/98 Paul Norton \n" " v2.2.0 12/30/98 Joel Sloan \n" @@ -216,7 +216,7 @@ static int __devinitdata turbo_irq[IBMTR static int __devinitdata turbo_searched = 0; #ifndef PCMCIA -static __u32 ibmtr_mem_base __initdata = 0xd0000; +static __u32 ibmtr_mem_base __devinitdata = 0xd0000; #endif static void __devinit PrtChanID(char *pcid, short stride) diff -puN drivers/net/tokenring/lanstreamer.c~git-netdev-all drivers/net/tokenring/lanstreamer.c --- a/drivers/net/tokenring/lanstreamer.c~git-netdev-all +++ a/drivers/net/tokenring/lanstreamer.c @@ -1998,7 +1998,7 @@ static struct pci_driver streamer_pci_dr }; static int __init streamer_init_module(void) { - return pci_module_init(&streamer_pci_driver); + return pci_register_driver(&streamer_pci_driver); } static void __exit streamer_cleanup_module(void) { diff -puN drivers/net/tokenring/smctr.c~git-netdev-all drivers/net/tokenring/smctr.c --- a/drivers/net/tokenring/smctr.c~git-netdev-all +++ a/drivers/net/tokenring/smctr.c @@ -5666,7 +5666,7 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param(ringspeed, int, 0); -static struct net_device *setup_card(int n) +static struct net_device * __init setup_card(int n) { struct net_device *dev = alloc_trdev(sizeof(struct net_local)); int err; @@ -5696,9 +5696,8 @@ out: free_netdev(dev); return ERR_PTR(err); } - -int init_module(void) +int __init init_module(void) { int i, found = 0; struct net_device *dev; diff -puN drivers/net/tulip/de2104x.c~git-netdev-all drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c~git-netdev-all +++ a/drivers/net/tulip/de2104x.c @@ -2172,7 +2172,7 @@ static int __init de_init (void) #ifdef MODULE printk("%s", version); #endif - return pci_module_init (&de_driver); + return pci_register_driver(&de_driver); } static void __exit de_exit (void) diff -puN drivers/net/tulip/de4x5.c~git-netdev-all drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c~git-netdev-all +++ a/drivers/net/tulip/de4x5.c @@ -5754,7 +5754,7 @@ static int __init de4x5_module_init (voi int err = 0; #ifdef CONFIG_PCI - err = pci_module_init (&de4x5_pci_driver); + err = pci_register_driver(&de4x5_pci_driver); #endif #ifdef CONFIG_EISA err |= eisa_driver_register (&de4x5_eisa_driver); diff -puN drivers/net/tulip/dmfe.c~git-netdev-all drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c~git-netdev-all +++ a/drivers/net/tulip/dmfe.c @@ -2039,7 +2039,7 @@ static int __init dmfe_init_module(void) if (HPNA_NoiseFloor > 15) HPNA_NoiseFloor = 0; - rc = pci_module_init(&dmfe_driver); + rc = pci_register_driver(&dmfe_driver); if (rc < 0) return rc; diff -puN drivers/net/tulip/tulip_core.c~git-netdev-all drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c~git-netdev-all +++ a/drivers/net/tulip/tulip_core.c @@ -1849,7 +1849,7 @@ static int __init tulip_init (void) tulip_max_interrupt_work = max_interrupt_work; /* probe for and init boards */ - return pci_module_init (&tulip_driver); + return pci_register_driver(&tulip_driver); } diff -puN drivers/net/tulip/uli526x.c~git-netdev-all drivers/net/tulip/uli526x.c --- a/drivers/net/tulip/uli526x.c~git-netdev-all +++ a/drivers/net/tulip/uli526x.c @@ -1702,7 +1702,6 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: static int __init uli526x_init_module(void) { - int rc; printk(version); printed_version = 1; @@ -1714,22 +1713,19 @@ static int __init uli526x_init_module(vo if (cr6set) uli526x_cr6_user_set = cr6set; - switch(mode) { + switch (mode) { case ULI526X_10MHF: case ULI526X_100MHF: case ULI526X_10MFD: case ULI526X_100MFD: uli526x_media_mode = mode; break; - default:uli526x_media_mode = ULI526X_AUTO; + default: + uli526x_media_mode = ULI526X_AUTO; break; } - rc = pci_module_init(&uli526x_driver); - if (rc < 0) - return rc; - - return 0; + return pci_register_driver(&uli526x_driver); } diff -puN drivers/net/tulip/winbond-840.c~git-netdev-all drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c~git-netdev-all +++ a/drivers/net/tulip/winbond-840.c @@ -138,7 +138,7 @@ static int full_duplex[MAX_UNITS] = {-1, #include /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static char version[] = KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker \n" KERN_INFO " http://www.scyld.com/network/drivers.html\n"; @@ -1689,7 +1689,7 @@ static struct pci_driver w840_driver = { static int __init w840_init(void) { printk(version); - return pci_module_init(&w840_driver); + return pci_register_driver(&w840_driver); } static void __exit w840_exit(void) diff -puN drivers/net/tulip/xircom_cb.c~git-netdev-all drivers/net/tulip/xircom_cb.c --- a/drivers/net/tulip/xircom_cb.c~git-netdev-all +++ a/drivers/net/tulip/xircom_cb.c @@ -1264,8 +1264,7 @@ static void investigate_write_descriptor static int __init xircom_init(void) { - pci_register_driver(&xircom_ops); - return 0; + return pci_register_driver(&xircom_ops); } static void __exit xircom_exit(void) diff -puN drivers/net/tulip/xircom_tulip_cb.c~git-netdev-all drivers/net/tulip/xircom_tulip_cb.c --- a/drivers/net/tulip/xircom_tulip_cb.c~git-netdev-all +++ a/drivers/net/tulip/xircom_tulip_cb.c @@ -1707,7 +1707,7 @@ static int __init xircom_init(void) #ifdef MODULE printk(version); #endif - return pci_module_init(&xircom_driver); + return pci_register_driver(&xircom_driver); } diff -puN drivers/net/typhoon.c~git-netdev-all drivers/net/typhoon.c --- a/drivers/net/typhoon.c~git-netdev-all +++ a/drivers/net/typhoon.c @@ -2660,7 +2660,7 @@ static struct pci_driver typhoon_driver static int __init typhoon_init(void) { - return pci_module_init(&typhoon_driver); + return pci_register_driver(&typhoon_driver); } static void __exit diff -puN /dev/null drivers/net/ucc_geth.c --- /dev/null +++ a/drivers/net/ucc_geth.c @@ -0,0 +1,4278 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * QE UCC Gigabit Ethernet Driver + * + * Changelog: + * Jul 6, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" + +#undef DEBUG + +#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:June 20, 2006" +#define DRV_NAME "ucc_geth" + +#define ugeth_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugeth_dbg(format, arg...) \ + ugeth_printk(KERN_DEBUG , format , ## arg) +#define ugeth_err(format, arg...) \ + ugeth_printk(KERN_ERR , format , ## arg) +#define ugeth_info(format, arg...) \ + ugeth_printk(KERN_INFO , format , ## arg) +#define ugeth_warn(format, arg...) \ + ugeth_printk(KERN_WARNING , format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugeth_vdbg ugeth_dbg +#else +#define ugeth_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static DEFINE_SPINLOCK(ugeth_lock); + +static ucc_geth_info_t ugeth_primary_info = { + .uf_info = { + .bd_mem_part = MEM_PART_SYSTEM, + .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, + .max_rx_buf_length = 1536, +/* FIXME: should be changed in run time for 1G and 100M */ +#ifdef CONFIG_UGETH_HAS_GIGA + .urfs = UCC_GETH_URFS_GIGA_INIT, + .urfet = UCC_GETH_URFET_GIGA_INIT, + .urfset = UCC_GETH_URFSET_GIGA_INIT, + .utfs = UCC_GETH_UTFS_GIGA_INIT, + .utfet = UCC_GETH_UTFET_GIGA_INIT, + .utftt = UCC_GETH_UTFTT_GIGA_INIT, +#else + .urfs = UCC_GETH_URFS_INIT, + .urfet = UCC_GETH_URFET_INIT, + .urfset = UCC_GETH_URFSET_INIT, + .utfs = UCC_GETH_UTFS_INIT, + .utfet = UCC_GETH_UTFET_INIT, + .utftt = UCC_GETH_UTFTT_INIT, +#endif + .ufpt = 256, + .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, + .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, + .tenc = UCC_FAST_TX_ENCODING_NRZ, + .renc = UCC_FAST_RX_ENCODING_NRZ, + .tcrc = UCC_FAST_16_BIT_CRC, + .synl = UCC_FAST_SYNC_LEN_NOT_USED, + }, + .numQueuesTx = 1, + .numQueuesRx = 1, + .extendedFilteringChainPointer = ((uint32_t) NULL), + .typeorlen = 3072 /*1536 */ , + .nonBackToBackIfgPart1 = 0x40, + .nonBackToBackIfgPart2 = 0x60, + .miminumInterFrameGapEnforcement = 0x50, + .backToBackInterFrameGap = 0x60, + .mblinterval = 128, + .nortsrbytetime = 5, + .fracsiz = 1, + .strictpriorityq = 0xff, + .altBebTruncation = 0xa, + .excessDefer = 1, + .maxRetransmission = 0xf, + .collisionWindow = 0x37, + .receiveFlowControl = 1, + .maxGroupAddrInHash = 4, + .maxIndAddrInHash = 4, + .prel = 7, + .maxFrameLength = 1518, + .minFrameLength = 64, + .maxD1Length = 1520, + .maxD2Length = 1520, + .vlantype = 0x8100, + .ecamptr = ((uint32_t) NULL), + .eventRegMask = UCCE_OTHER, + .pausePeriod = 0xf000, + .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1}, + .bdRingLenTx = { + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN, + TX_BD_RING_LEN}, + + .bdRingLenRx = { + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN, + RX_BD_RING_LEN}, + + .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1, + .largestexternallookupkeysize = + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE, + .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE, + .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP, + .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP, + .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT, + .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE, + .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC, + .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4, + .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4, + .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, + .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, +}; + +static ucc_geth_info_t ugeth_info[8]; + +#ifdef DEBUG +static void mem_disp(u8 *addr, int size) +{ + u8 *i; + int size16Aling = (size >> 4) << 4; + int size4Aling = (size >> 2) << 2; + int notAlign = 0; + if (size % 16) + notAlign = 1; + + for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16) + printk("0x%08x: %08x %08x %08x %08x\r\n", + (u32) i, + *((u32 *) (i)), + *((u32 *) (i + 4)), + *((u32 *) (i + 8)), *((u32 *) (i + 12))); + if (notAlign == 1) + printk("0x%08x: ", (u32) i); + for (; (u32) i < (u32) addr + size4Aling; i += 4) + printk("%08x ", *((u32 *) (i))); + for (; (u32) i < (u32) addr + size; i++) + printk("%02x", *((u8 *) (i))); + if (notAlign == 1) + printk("\r\n"); +} +#endif /* DEBUG */ + +#ifdef CONFIG_UGETH_FILTERING +static void enqueue(struct list_head *node, struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + list_add_tail(node, lh); + spin_unlock_irqrestore(ugeth_lock, flags); +} +#endif /* CONFIG_UGETH_FILTERING */ + +static struct list_head *dequeue(struct list_head *lh) +{ + unsigned long flags; + + spin_lock_irqsave(ugeth_lock, flags); + if (!list_empty(lh)) { + struct list_head *node = lh->next; + list_del(node); + spin_unlock_irqrestore(ugeth_lock, flags); + return node; + } else { + spin_unlock_irqrestore(ugeth_lock, flags); + return NULL; + } +} + +static int get_interface_details(enet_interface_e enet_interface, + enet_speed_e *speed, + int *r10m, + int *rmm, + int *rpm, + int *tbi, int *limited_to_full_duplex) +{ + /* Analyze enet_interface according to Interface Mode + Configuration table */ + switch (enet_interface) { + case ENET_10_MII: + *speed = ENET_SPEED_10BT; + break; + case ENET_10_RMII: + *speed = ENET_SPEED_10BT; + *r10m = 1; + *rmm = 1; + break; + case ENET_10_RGMII: + *speed = ENET_SPEED_10BT; + *rpm = 1; + *r10m = 1; + *limited_to_full_duplex = 1; + break; + case ENET_100_MII: + *speed = ENET_SPEED_100BT; + break; + case ENET_100_RMII: + *speed = ENET_SPEED_100BT; + *rmm = 1; + break; + case ENET_100_RGMII: + *speed = ENET_SPEED_100BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_GMII: + *speed = ENET_SPEED_1000BT; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RGMII: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_TBI: + *speed = ENET_SPEED_1000BT; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + case ENET_1000_RTBI: + *speed = ENET_SPEED_1000BT; + *rpm = 1; + *tbi = 1; + *limited_to_full_duplex = 1; + break; + default: + return -EINVAL; + break; + } + + return 0; +} + +static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd) +{ + struct sk_buff *skb = NULL; + + skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT); + + if (skb == NULL) + return NULL; + + /* We need the data buffer to be aligned properly. We will reserve + * as many bytes as needed to align the data properly + */ + skb_reserve(skb, + UCC_GETH_RX_DATA_BUF_ALIGNMENT - + (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - + 1))); + + skb->dev = ugeth->dev; + + BD_BUFFER_SET(bd, + dma_map_single(NULL, + skb->data, + ugeth->ug_info->uf_info.max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT, + DMA_FROM_DEVICE)); + + BD_STATUS_AND_LENGTH_SET(bd, + (R_E | R_I | + (BD_STATUS_AND_LENGTH(bd) & R_W))); + + return skb; +} + +static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ) +{ + u8 *bd; + u32 bd_status; + struct sk_buff *skb; + int i; + + bd = ugeth->p_rx_bd_ring[rxQ]; + i = 0; + + do { + bd_status = BD_STATUS_AND_LENGTH(bd); + skb = get_new_skb(ugeth, bd); + + if (!skb) /* If can not allocate data buffer, + abort. Cleanup will be elsewhere */ + return -ENOMEM; + + ugeth->rx_skbuff[rxQ][i] = skb; + + /* advance the BD pointer */ + bd += UCC_GETH_SIZE_OF_BD; + i++; + } while (!(bd_status & R_W)); + + return 0; +} + +static int fill_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + u32 thread_alignment, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + if ((snum = qe_get_snum()) < 0) { + ugeth_err("fill_init_enet_entries: Can not get SNUM."); + return snum; + } + if ((i == 0) && skip_page_for_first_entry) + /* First entry of Rx does not have page */ + init_enet_offset = 0; + else { + init_enet_offset = + qe_muram_alloc(thread_size, thread_alignment); + if (IS_MURAM_ERR(init_enet_offset)) { + ugeth_err + ("fill_init_enet_entries: Can not allocate DPRAM memory."); + qe_put_snum((u8) snum); + return -ENOMEM; + } + } + *(p_start++) = + ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset + | risc; + } + + return 0; +} + +static int return_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + qe_muram_free(init_enet_offset); + } + *(p_start++) = 0; /* Just for cosmetics */ + } + } + + return 0; +} + +#ifdef DEBUG +static int dump_init_enet_entries(ucc_geth_private_t *ugeth, + volatile u32 *p_start, + u8 num_entries, + u32 thread_size, + qe_risc_allocation_e risc, + int skip_page_for_first_entry) +{ + u32 init_enet_offset; + u8 i; + int snum; + + for (i = 0; i < num_entries; i++) { + /* Check that this entry was actually valid -- + needed in case failed in allocations */ + if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) { + snum = + (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >> + ENET_INIT_PARAM_SNUM_SHIFT; + qe_put_snum((u8) snum); + if (!((i == 0) && skip_page_for_first_entry)) { + /* First entry of Rx does not have page */ + init_enet_offset = + (in_be32(p_start) & + ENET_INIT_PARAM_PTR_MASK); + ugeth_info("Init enet entry %d:", i); + ugeth_info("Base address: 0x%08x", + (u32) + qe_muram_addr(init_enet_offset)); + mem_disp(qe_muram_addr(init_enet_offset), + thread_size); + } + p_start++; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_UGETH_FILTERING +static enet_addr_container_t *get_enet_addr_container(void) +{ + enet_addr_container_t *enet_addr_cont; + + /* allocate memory */ + enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL); + if (!enet_addr_cont) { + ugeth_err("%s: No memory for enet_addr_container_t object.", + __FUNCTION__); + return NULL; + } + + return enet_addr_cont; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont) +{ + kfree(enet_addr_cont); +} + +#ifdef CONFIG_UGETH_FILTERING +static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Ethernet frames are defined in Little Endian mode, */ + /* therefore to insert the address we reverse the bytes. */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + return 0; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + + if (!(paddr_num < NUM_OF_PADDRS)) { + ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__); + return -EINVAL; + } + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + /* Writing address ff.ff.ff.ff.ff.ff disables address + recognition for this register */ + out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff); + out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff); + + return 0; +} + +static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + u32 cecr_subblock; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + + /* Ethernet frames are defined in Little Endian mode, + therefor to insert */ + /* the address to the hash (Big Endian mode), we reverse the bytes.*/ + out_be16(&p_82xx_addr_filt->taddr.h, + (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) | + (u16) (*p_enet_addr)[4])); + out_be16(&p_82xx_addr_filt->taddr.m, + (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) | + (u16) (*p_enet_addr)[2])); + out_be16(&p_82xx_addr_filt->taddr.l, + (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) | + (u16) (*p_enet_addr)[0])); + + qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); +} + +#ifdef CONFIG_UGETH_MAGIC_PACKET +static void magic_packet_detection_enable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Enable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm |= UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Enable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 |= MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} + +static void magic_packet_detection_disable(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + ucc_geth_t *ug_regs; + u32 maccfg2, uccm; + + uccf = ugeth->uccf; + ug_regs = ugeth->ug_regs; + + /* Disable interrupts for magic packet detection */ + uccm = in_be32(uccf->p_uccm); + uccm &= ~UCCE_MPD; + out_be32(uccf->p_uccm, uccm); + + /* Disable magic packet detection */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 &= ~MACCFG2_MPE; + out_be32(&ug_regs->maccfg2, maccfg2); +} +#endif /* MAGIC_PACKET */ + +static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2) +{ + return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS); +} + +#ifdef DEBUG +static void get_statistics(ucc_geth_private_t *ugeth, + ucc_geth_tx_firmware_statistics_t * + tx_firmware_statistics, + ucc_geth_rx_firmware_statistics_t * + rx_firmware_statistics, + ucc_geth_hardware_statistics_t *hardware_statistics) +{ + ucc_fast_t *uf_regs; + ucc_geth_t *ug_regs; + ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + + ug_regs = ugeth->ug_regs; + uf_regs = (ucc_fast_t *) ug_regs; + p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram; + p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram; + + /* Tx firmware only if user handed pointer and driver actually + gathers Tx firmware statistics */ + if (tx_firmware_statistics && p_tx_fw_statistics_pram) { + tx_firmware_statistics->sicoltx = + in_be32(&p_tx_fw_statistics_pram->sicoltx); + tx_firmware_statistics->mulcoltx = + in_be32(&p_tx_fw_statistics_pram->mulcoltx); + tx_firmware_statistics->latecoltxfr = + in_be32(&p_tx_fw_statistics_pram->latecoltxfr); + tx_firmware_statistics->frabortduecol = + in_be32(&p_tx_fw_statistics_pram->frabortduecol); + tx_firmware_statistics->frlostinmactxer = + in_be32(&p_tx_fw_statistics_pram->frlostinmactxer); + tx_firmware_statistics->carriersenseertx = + in_be32(&p_tx_fw_statistics_pram->carriersenseertx); + tx_firmware_statistics->frtxok = + in_be32(&p_tx_fw_statistics_pram->frtxok); + tx_firmware_statistics->txfrexcessivedefer = + in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer); + tx_firmware_statistics->txpkts256 = + in_be32(&p_tx_fw_statistics_pram->txpkts256); + tx_firmware_statistics->txpkts512 = + in_be32(&p_tx_fw_statistics_pram->txpkts512); + tx_firmware_statistics->txpkts1024 = + in_be32(&p_tx_fw_statistics_pram->txpkts1024); + tx_firmware_statistics->txpktsjumbo = + in_be32(&p_tx_fw_statistics_pram->txpktsjumbo); + } + + /* Rx firmware only if user handed pointer and driver actually + * gathers Rx firmware statistics */ + if (rx_firmware_statistics && p_rx_fw_statistics_pram) { + int i; + rx_firmware_statistics->frrxfcser = + in_be32(&p_rx_fw_statistics_pram->frrxfcser); + rx_firmware_statistics->fraligner = + in_be32(&p_rx_fw_statistics_pram->fraligner); + rx_firmware_statistics->inrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->inrangelenrxer); + rx_firmware_statistics->outrangelenrxer = + in_be32(&p_rx_fw_statistics_pram->outrangelenrxer); + rx_firmware_statistics->frtoolong = + in_be32(&p_rx_fw_statistics_pram->frtoolong); + rx_firmware_statistics->runt = + in_be32(&p_rx_fw_statistics_pram->runt); + rx_firmware_statistics->verylongevent = + in_be32(&p_rx_fw_statistics_pram->verylongevent); + rx_firmware_statistics->symbolerror = + in_be32(&p_rx_fw_statistics_pram->symbolerror); + rx_firmware_statistics->dropbsy = + in_be32(&p_rx_fw_statistics_pram->dropbsy); + for (i = 0; i < 0x8; i++) + rx_firmware_statistics->res0[i] = + p_rx_fw_statistics_pram->res0[i]; + rx_firmware_statistics->mismatchdrop = + in_be32(&p_rx_fw_statistics_pram->mismatchdrop); + rx_firmware_statistics->underpkts = + in_be32(&p_rx_fw_statistics_pram->underpkts); + rx_firmware_statistics->pkts256 = + in_be32(&p_rx_fw_statistics_pram->pkts256); + rx_firmware_statistics->pkts512 = + in_be32(&p_rx_fw_statistics_pram->pkts512); + rx_firmware_statistics->pkts1024 = + in_be32(&p_rx_fw_statistics_pram->pkts1024); + rx_firmware_statistics->pktsjumbo = + in_be32(&p_rx_fw_statistics_pram->pktsjumbo); + rx_firmware_statistics->frlossinmacer = + in_be32(&p_rx_fw_statistics_pram->frlossinmacer); + rx_firmware_statistics->pausefr = + in_be32(&p_rx_fw_statistics_pram->pausefr); + for (i = 0; i < 0x4; i++) + rx_firmware_statistics->res1[i] = + p_rx_fw_statistics_pram->res1[i]; + rx_firmware_statistics->removevlan = + in_be32(&p_rx_fw_statistics_pram->removevlan); + rx_firmware_statistics->replacevlan = + in_be32(&p_rx_fw_statistics_pram->replacevlan); + rx_firmware_statistics->insertvlan = + in_be32(&p_rx_fw_statistics_pram->insertvlan); + } + + /* Hardware only if user handed pointer and driver actually + gathers hardware statistics */ + if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) { + hardware_statistics->tx64 = in_be32(&ug_regs->tx64); + hardware_statistics->tx127 = in_be32(&ug_regs->tx127); + hardware_statistics->tx255 = in_be32(&ug_regs->tx255); + hardware_statistics->rx64 = in_be32(&ug_regs->rx64); + hardware_statistics->rx127 = in_be32(&ug_regs->rx127); + hardware_statistics->rx255 = in_be32(&ug_regs->rx255); + hardware_statistics->txok = in_be32(&ug_regs->txok); + hardware_statistics->txcf = in_be16(&ug_regs->txcf); + hardware_statistics->tmca = in_be32(&ug_regs->tmca); + hardware_statistics->tbca = in_be32(&ug_regs->tbca); + hardware_statistics->rxfok = in_be32(&ug_regs->rxfok); + hardware_statistics->rxbok = in_be32(&ug_regs->rxbok); + hardware_statistics->rbyt = in_be32(&ug_regs->rbyt); + hardware_statistics->rmca = in_be32(&ug_regs->rmca); + hardware_statistics->rbca = in_be32(&ug_regs->rbca); + } +} + +static void dump_bds(ucc_geth_private_t *ugeth) +{ + int i; + int length; + + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + if (ugeth->p_tx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenTx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("TX BDs[%d]", i); + mem_disp(ugeth->p_tx_bd_ring[i], length); + } + } + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + if (ugeth->p_rx_bd_ring[i]) { + length = + (ugeth->ug_info->bdRingLenRx[i] * + UCC_GETH_SIZE_OF_BD); + ugeth_info("RX BDs[%d]", i); + mem_disp(ugeth->p_rx_bd_ring[i], length); + } + } +} + +static void dump_regs(ucc_geth_private_t *ugeth) +{ + int i; + + ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num); + ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs); + + ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg1, + in_be32(&ugeth->ug_regs->maccfg1)); + ugeth_info("maccfg2 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->maccfg2, + in_be32(&ugeth->ug_regs->maccfg2)); + ugeth_info("ipgifg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ipgifg, + in_be32(&ugeth->ug_regs->ipgifg)); + ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->hafdup, + in_be32(&ugeth->ug_regs->hafdup)); + ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcfg, + in_be32(&ugeth->ug_regs->miimng.miimcfg)); + ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcom, + in_be32(&ugeth->ug_regs->miimng.miimcom)); + ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimadd, + in_be32(&ugeth->ug_regs->miimng.miimadd)); + ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimcon, + in_be32(&ugeth->ug_regs->miimng.miimcon)); + ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimstat, + in_be32(&ugeth->ug_regs->miimng.miimstat)); + ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->miimng.miimind, + in_be32(&ugeth->ug_regs->miimng.miimind)); + ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifctl, + in_be32(&ugeth->ug_regs->ifctl)); + ugeth_info("ifstat : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->ifstat, + in_be32(&ugeth->ug_regs->ifstat)); + ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr1, + in_be32(&ugeth->ug_regs->macstnaddr1)); + ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->macstnaddr2, + in_be32(&ugeth->ug_regs->macstnaddr2)); + ugeth_info("uempr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->uempr, + in_be32(&ugeth->ug_regs->uempr)); + ugeth_info("utbipar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->utbipar, + in_be32(&ugeth->ug_regs->utbipar)); + ugeth_info("uescr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->uescr, + in_be16(&ugeth->ug_regs->uescr)); + ugeth_info("tx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx64, + in_be32(&ugeth->ug_regs->tx64)); + ugeth_info("tx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx127, + in_be32(&ugeth->ug_regs->tx127)); + ugeth_info("tx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tx255, + in_be32(&ugeth->ug_regs->tx255)); + ugeth_info("rx64 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx64, + in_be32(&ugeth->ug_regs->rx64)); + ugeth_info("rx127 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx127, + in_be32(&ugeth->ug_regs->rx127)); + ugeth_info("rx255 : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rx255, + in_be32(&ugeth->ug_regs->rx255)); + ugeth_info("txok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->txok, + in_be32(&ugeth->ug_regs->txok)); + ugeth_info("txcf : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->ug_regs->txcf, + in_be16(&ugeth->ug_regs->txcf)); + ugeth_info("tmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tmca, + in_be32(&ugeth->ug_regs->tmca)); + ugeth_info("tbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->tbca, + in_be32(&ugeth->ug_regs->tbca)); + ugeth_info("rxfok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxfok, + in_be32(&ugeth->ug_regs->rxfok)); + ugeth_info("rxbok : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rxbok, + in_be32(&ugeth->ug_regs->rxbok)); + ugeth_info("rbyt : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbyt, + in_be32(&ugeth->ug_regs->rbyt)); + ugeth_info("rmca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rmca, + in_be32(&ugeth->ug_regs->rmca)); + ugeth_info("rbca : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->rbca, + in_be32(&ugeth->ug_regs->rbca)); + ugeth_info("scar : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scar, + in_be32(&ugeth->ug_regs->scar)); + ugeth_info("scam : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->ug_regs->scam, + in_be32(&ugeth->ug_regs->scam)); + + if (ugeth->p_thread_data_tx) { + int numThreadsTxNumerical; + switch (ugeth->ug_info->numThreadsTx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsTxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsTxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsTxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsTxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsTxNumerical = 8; + break; + default: + numThreadsTxNumerical = 0; + break; + } + + ugeth_info("Thread data TXs:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_tx); + for (i = 0; i < numThreadsTxNumerical; i++) { + ugeth_info("Thread data TX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_tx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_tx[i], + sizeof(ucc_geth_thread_data_tx_t)); + } + } + if (ugeth->p_thread_data_rx) { + int numThreadsRxNumerical; + switch (ugeth->ug_info->numThreadsRx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsRxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsRxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsRxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsRxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsRxNumerical = 8; + break; + default: + numThreadsRxNumerical = 0; + break; + } + + ugeth_info("Thread data RX:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_thread_data_rx); + for (i = 0; i < numThreadsRxNumerical; i++) { + ugeth_info("Thread data RX[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_thread_data_rx[i]); + mem_disp((u8 *) & ugeth->p_thread_data_rx[i], + sizeof(ucc_geth_thread_data_rx_t)); + } + } + if (ugeth->p_exf_glbl_param) { + ugeth_info("EXF global param:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_exf_glbl_param); + mem_disp((u8 *) ugeth->p_exf_glbl_param, + sizeof(*ugeth->p_exf_glbl_param)); + } + if (ugeth->p_tx_glbl_pram) { + ugeth_info("TX global param:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram); + ugeth_info("temoder : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_tx_glbl_pram->temoder, + in_be16(&ugeth->p_tx_glbl_pram->temoder)); + ugeth_info("sqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->sqptr, + in_be32(&ugeth->p_tx_glbl_pram->sqptr)); + ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer, + in_be32(&ugeth->p_tx_glbl_pram-> + schedulerbasepointer)); + ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr, + in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr)); + ugeth_info("tstate : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->tstate, + in_be32(&ugeth->p_tx_glbl_pram->tstate)); + ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[0], + ugeth->p_tx_glbl_pram->iphoffset[0]); + ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[1], + ugeth->p_tx_glbl_pram->iphoffset[1]); + ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[2], + ugeth->p_tx_glbl_pram->iphoffset[2]); + ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[3], + ugeth->p_tx_glbl_pram->iphoffset[3]); + ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[4], + ugeth->p_tx_glbl_pram->iphoffset[4]); + ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[5], + ugeth->p_tx_glbl_pram->iphoffset[5]); + ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[6], + ugeth->p_tx_glbl_pram->iphoffset[6]); + ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_tx_glbl_pram->iphoffset[7], + ugeth->p_tx_glbl_pram->iphoffset[7]); + ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[0], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0])); + ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[1], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1])); + ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[2], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2])); + ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[3], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3])); + ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[4], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4])); + ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[5], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5])); + ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[6], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6])); + ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->vtagtable[7], + in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7])); + ugeth_info("tqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_tx_glbl_pram->tqptr, + in_be32(&ugeth->p_tx_glbl_pram->tqptr)); + } + if (ugeth->p_rx_glbl_pram) { + ugeth_info("RX global param:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_glbl_pram); + ugeth_info("remoder : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->remoder, + in_be32(&ugeth->p_rx_glbl_pram->remoder)); + ugeth_info("rqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rqptr, + in_be32(&ugeth->p_rx_glbl_pram->rqptr)); + ugeth_info("typeorlen : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->typeorlen, + in_be16(&ugeth->p_rx_glbl_pram->typeorlen)); + ugeth_info("rxgstpack : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_rx_glbl_pram->rxgstpack, + ugeth->p_rx_glbl_pram->rxgstpack); + ugeth_info("rxrmonbaseptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr, + in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr)); + ugeth_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->intcoalescingptr, + in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr)); + ugeth_info("rstate : addr - 0x%08x, val - 0x%02x", + (u32) & ugeth->p_rx_glbl_pram->rstate, + ugeth->p_rx_glbl_pram->rstate); + ugeth_info("mrblr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->mrblr, + in_be16(&ugeth->p_rx_glbl_pram->mrblr)); + ugeth_info("rbdqptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->rbdqptr, + in_be32(&ugeth->p_rx_glbl_pram->rbdqptr)); + ugeth_info("mflr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->mflr, + in_be16(&ugeth->p_rx_glbl_pram->mflr)); + ugeth_info("minflr : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->minflr, + in_be16(&ugeth->p_rx_glbl_pram->minflr)); + ugeth_info("maxd1 : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->maxd1, + in_be16(&ugeth->p_rx_glbl_pram->maxd1)); + ugeth_info("maxd2 : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->maxd2, + in_be16(&ugeth->p_rx_glbl_pram->maxd2)); + ugeth_info("ecamptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->ecamptr, + in_be32(&ugeth->p_rx_glbl_pram->ecamptr)); + ugeth_info("l2qt : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l2qt, + in_be32(&ugeth->p_rx_glbl_pram->l2qt)); + ugeth_info("l3qt[0] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[0], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[0])); + ugeth_info("l3qt[1] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[1], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[1])); + ugeth_info("l3qt[2] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[2], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[2])); + ugeth_info("l3qt[3] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[3], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[3])); + ugeth_info("l3qt[4] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[4], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[4])); + ugeth_info("l3qt[5] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[5], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[5])); + ugeth_info("l3qt[6] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[6], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[6])); + ugeth_info("l3qt[7] : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->l3qt[7], + in_be32(&ugeth->p_rx_glbl_pram->l3qt[7])); + ugeth_info("vlantype : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->vlantype, + in_be16(&ugeth->p_rx_glbl_pram->vlantype)); + ugeth_info("vlantci : addr - 0x%08x, val - 0x%04x", + (u32) & ugeth->p_rx_glbl_pram->vlantci, + in_be16(&ugeth->p_rx_glbl_pram->vlantci)); + for (i = 0; i < 64; i++) + ugeth_info + ("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x", + i, + (u32) & ugeth->p_rx_glbl_pram->addressfiltering[i], + ugeth->p_rx_glbl_pram->addressfiltering[i]); + ugeth_info("exfGlobalParam : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_glbl_pram->exfGlobalParam, + in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam)); + } + if (ugeth->p_send_q_mem_reg) { + ugeth_info("Send Q memory registers:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_send_q_mem_reg); + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + ugeth_info("SQQD[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_send_q_mem_reg->sqqd[i]); + mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i], + sizeof(ucc_geth_send_queue_qd_t)); + } + } + if (ugeth->p_scheduler) { + ugeth_info("Scheduler:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_scheduler); + mem_disp((u8 *) ugeth->p_scheduler, + sizeof(*ugeth->p_scheduler)); + } + if (ugeth->p_tx_fw_statistics_pram) { + ugeth_info("TX FW statistics pram:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_tx_fw_statistics_pram); + mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram, + sizeof(*ugeth->p_tx_fw_statistics_pram)); + } + if (ugeth->p_rx_fw_statistics_pram) { + ugeth_info("RX FW statistics pram:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_rx_fw_statistics_pram); + mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram, + sizeof(*ugeth->p_rx_fw_statistics_pram)); + } + if (ugeth->p_rx_irq_coalescing_tbl) { + ugeth_info("RX IRQ coalescing tables:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_rx_irq_coalescing_tbl); + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + ugeth_info("RX IRQ coalescing table entry[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]); + ugeth_info + ("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i].interruptcoalescingmaxvalue, + in_be32(&ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]. + interruptcoalescingmaxvalue)); + ugeth_info + ("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i].interruptcoalescingcounter, + in_be32(&ugeth->p_rx_irq_coalescing_tbl-> + coalescingentry[i]. + interruptcoalescingcounter)); + } + } + if (ugeth->p_rx_bd_qs_tbl) { + ugeth_info("RX BD QS tables:"); + ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_bd_qs_tbl); + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + ugeth_info("RX BD QS table[%d]:", i); + ugeth_info("Base address: 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i]); + ugeth_info + ("bdbaseptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr)); + ugeth_info + ("bdptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr)); + ugeth_info + ("externalbdbaseptr: addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i]. + externalbdbaseptr)); + ugeth_info + ("externalbdptr : addr - 0x%08x, val - 0x%08x", + (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdptr, + in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr)); + ugeth_info("ucode RX Prefetched BDs:"); + ugeth_info("Base address: 0x%08x", + (u32) + qe_muram_addr(in_be32 + (&ugeth->p_rx_bd_qs_tbl[i]. + bdbaseptr))); + mem_disp((u8 *) + qe_muram_addr(in_be32 + (&ugeth->p_rx_bd_qs_tbl[i]. + bdbaseptr)), + sizeof(ucc_geth_rx_prefetched_bds_t)); + } + } + if (ugeth->p_init_enet_param_shadow) { + int size; + ugeth_info("Init enet param shadow:"); + ugeth_info("Base address: 0x%08x", + (u32) ugeth->p_init_enet_param_shadow); + mem_disp((u8 *) ugeth->p_init_enet_param_shadow, + sizeof(*ugeth->p_init_enet_param_shadow)); + + size = sizeof(ucc_geth_thread_rx_pram_t); + if (ugeth->ug_info->rxExtendedFiltering) { + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; + if (ugeth->ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; + if (ugeth->ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; + } + + dump_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_TX, + sizeof(ucc_geth_thread_tx_pram_t), + ugeth->ug_info->riscTx, 0); + dump_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + rxthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_RX, size, + ugeth->ug_info->riscRx, 1); + } +} +#endif /* DEBUG */ + +static void init_default_reg_vals(volatile u32 *upsmr_register, + volatile u32 *maccfg1_register, + volatile u32 *maccfg2_register) +{ + out_be32(upsmr_register, UCC_GETH_UPSMR_INIT); + out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT); + out_be32(maccfg2_register, UCC_GETH_MACCFG2_INIT); +} + +static int init_half_duplex_params(int alt_beb, + int back_pressure_no_backoff, + int no_backoff, + int excess_defer, + u8 alt_beb_truncation, + u8 max_retransmissions, + u8 collision_window, + volatile u32 *hafdup_register) +{ + u32 value = 0; + + if ((alt_beb_truncation > HALFDUP_ALT_BEB_TRUNCATION_MAX) || + (max_retransmissions > HALFDUP_MAX_RETRANSMISSION_MAX) || + (collision_window > HALFDUP_COLLISION_WINDOW_MAX)) + return -EINVAL; + + value = (u32) (alt_beb_truncation << HALFDUP_ALT_BEB_TRUNCATION_SHIFT); + + if (alt_beb) + value |= HALFDUP_ALT_BEB; + if (back_pressure_no_backoff) + value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF; + if (no_backoff) + value |= HALFDUP_NO_BACKOFF; + if (excess_defer) + value |= HALFDUP_EXCESSIVE_DEFER; + + value |= (max_retransmissions << HALFDUP_MAX_RETRANSMISSION_SHIFT); + + value |= collision_window; + + out_be32(hafdup_register, value); + return 0; +} + +static int init_inter_frame_gap_params(u8 non_btb_cs_ipg, + u8 non_btb_ipg, + u8 min_ifg, + u8 btb_ipg, + volatile u32 *ipgifg_register) +{ + u32 value = 0; + + /* Non-Back-to-back IPG part 1 should be <= Non-Back-to-back + IPG part 2 */ + if (non_btb_cs_ipg > non_btb_ipg) + return -EINVAL; + + if ((non_btb_cs_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX) || + (non_btb_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX) || + /*(min_ifg > IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX) || */ + (btb_ipg > IPGIFG_BACK_TO_BACK_IFG_MAX)) + return -EINVAL; + + value |= + ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT) & + IPGIFG_NBTB_CS_IPG_MASK); + value |= + ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) & + IPGIFG_NBTB_IPG_MASK); + value |= + ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) & + IPGIFG_MIN_IFG_MASK); + value |= (btb_ipg & IPGIFG_BTB_IPG_MASK); + + out_be32(ipgifg_register, value); + return 0; +} + +static int init_flow_control_params(u32 automatic_flow_control_mode, + int rx_flow_control_enable, + int tx_flow_control_enable, + u16 pause_period, + u16 extension_field, + volatile u32 *upsmr_register, + volatile u32 *uempr_register, + volatile u32 *maccfg1_register) +{ + u32 value = 0; + + /* Set UEMPR register */ + value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT; + value |= (u32) extension_field << UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT; + out_be32(uempr_register, value); + + /* Set UPSMR register */ + value = in_be32(upsmr_register); + value |= automatic_flow_control_mode; + out_be32(upsmr_register, value); + + value = in_be32(maccfg1_register); + if (rx_flow_control_enable) + value |= MACCFG1_FLOW_RX; + if (tx_flow_control_enable) + value |= MACCFG1_FLOW_TX; + out_be32(maccfg1_register, value); + + return 0; +} + +static int init_hw_statistics_gathering_mode(int enable_hardware_statistics, + int auto_zero_hardware_statistics, + volatile u32 *upsmr_register, + volatile u16 *uescr_register) +{ + u32 upsmr_value = 0; + u16 uescr_value = 0; + /* Enable hardware statistics gathering if requested */ + if (enable_hardware_statistics) { + upsmr_value = in_be32(upsmr_register); + upsmr_value |= UPSMR_HSE; + out_be32(upsmr_register, upsmr_value); + } + + /* Clear hardware statistics counters */ + uescr_value = in_be16(uescr_register); + uescr_value |= UESCR_CLRCNT; + /* Automatically zero hardware statistics counters on read, + if requested */ + if (auto_zero_hardware_statistics) + uescr_value |= UESCR_AUTOZ; + out_be16(uescr_register, uescr_value); + + return 0; +} + +static int init_firmware_statistics_gathering_mode(int + enable_tx_firmware_statistics, + int enable_rx_firmware_statistics, + volatile u32 *tx_rmon_base_ptr, + u32 tx_firmware_statistics_structure_address, + volatile u32 *rx_rmon_base_ptr, + u32 rx_firmware_statistics_structure_address, + volatile u16 *temoder_register, + volatile u32 *remoder_register) +{ + /* Note: this function does not check if */ + /* the parameters it receives are NULL */ + u16 temoder_value; + u32 remoder_value; + + if (enable_tx_firmware_statistics) { + out_be32(tx_rmon_base_ptr, + tx_firmware_statistics_structure_address); + temoder_value = in_be16(temoder_register); + temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE; + out_be16(temoder_register, temoder_value); + } + + if (enable_rx_firmware_statistics) { + out_be32(rx_rmon_base_ptr, + rx_firmware_statistics_structure_address); + remoder_value = in_be32(remoder_register); + remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE; + out_be32(remoder_register, remoder_value); + } + + return 0; +} + +static int init_mac_station_addr_regs(u8 address_byte_0, + u8 address_byte_1, + u8 address_byte_2, + u8 address_byte_3, + u8 address_byte_4, + u8 address_byte_5, + volatile u32 *macstnaddr1_register, + volatile u32 *macstnaddr2_register) +{ + u32 value = 0; + + /* Example: for a station address of 0x12345678ABCD, */ + /* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5 */ + + /* MACSTNADDR1 Register: */ + + /* 0 7 8 15 */ + /* station address byte 5 station address byte 4 */ + /* 16 23 24 31 */ + /* station address byte 3 station address byte 2 */ + value |= (u32) ((address_byte_2 << 0) & 0x000000FF); + value |= (u32) ((address_byte_3 << 8) & 0x0000FF00); + value |= (u32) ((address_byte_4 << 16) & 0x00FF0000); + value |= (u32) ((address_byte_5 << 24) & 0xFF000000); + + out_be32(macstnaddr1_register, value); + + /* MACSTNADDR2 Register: */ + + /* 0 7 8 15 */ + /* station address byte 1 station address byte 0 */ + /* 16 23 24 31 */ + /* reserved reserved */ + value = 0; + value |= (u32) ((address_byte_0 << 16) & 0x00FF0000); + value |= (u32) ((address_byte_1 << 24) & 0xFF000000); + + out_be32(macstnaddr2_register, value); + + return 0; +} + +static int init_mac_duplex_mode(int full_duplex, + int limited_to_full_duplex, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + /* some interfaces must work in full duplex mode */ + if ((full_duplex == 0) && (limited_to_full_duplex == 1)) + return -EINVAL; + + value = in_be32(maccfg2_register); + + if (full_duplex) + value |= MACCFG2_FDX; + else + value &= ~MACCFG2_FDX; + + out_be32(maccfg2_register, value); + return 0; +} + +static int init_check_frame_length_mode(int length_check, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + value = in_be32(maccfg2_register); + + if (length_check) + value |= MACCFG2_LC; + else + value &= ~MACCFG2_LC; + + out_be32(maccfg2_register, value); + return 0; +} + +static int init_preamble_length(u8 preamble_length, + volatile u32 *maccfg2_register) +{ + u32 value = 0; + + if ((preamble_length < 3) || (preamble_length > 7)) + return -EINVAL; + + value = in_be32(maccfg2_register); + value &= ~MACCFG2_PREL_MASK; + value |= (preamble_length << MACCFG2_PREL_SHIFT); + out_be32(maccfg2_register, value); + return 0; +} + +static int init_mii_management_configuration(int reset_mgmt, + int preamble_supress, + volatile u32 *miimcfg_register, + volatile u32 *miimind_register) +{ + unsigned int timeout = PHY_INIT_TIMEOUT; + u32 value = 0; + + value = in_be32(miimcfg_register); + if (reset_mgmt) { + value |= MIIMCFG_RESET_MANAGEMENT; + out_be32(miimcfg_register, value); + } + + value = 0; + + if (preamble_supress) + value |= MIIMCFG_NO_PREAMBLE; + + value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; + out_be32(miimcfg_register, value); + + /* Wait until the bus is free */ + while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) + cpu_relax(); + + if (timeout <= 0) { + ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); + return -ETIMEDOUT; + } + + return 0; +} + +static int init_rx_parameters(int reject_broadcast, + int receive_short_frames, + int promiscuous, volatile u32 *upsmr_register) +{ + u32 value = 0; + + value = in_be32(upsmr_register); + + if (reject_broadcast) + value |= UPSMR_BRO; + else + value &= ~UPSMR_BRO; + + if (receive_short_frames) + value |= UPSMR_RSH; + else + value &= ~UPSMR_RSH; + + if (promiscuous) + value |= UPSMR_PRO; + else + value &= ~UPSMR_PRO; + + out_be32(upsmr_register, value); + + return 0; +} + +static int init_max_rx_buff_len(u16 max_rx_buf_len, + volatile u16 *mrblr_register) +{ + /* max_rx_buf_len value must be a multiple of 128 */ + if ((max_rx_buf_len == 0) + || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) + return -EINVAL; + + out_be16(mrblr_register, max_rx_buf_len); + return 0; +} + +static int init_min_frame_len(u16 min_frame_length, + volatile u16 *minflr_register, + volatile u16 *mrblr_register) +{ + u16 mrblr_value = 0; + + mrblr_value = in_be16(mrblr_register); + if (min_frame_length >= (mrblr_value - 4)) + return -EINVAL; + + out_be16(minflr_register, min_frame_length); + return 0; +} + +static int adjust_enet_interface(ucc_geth_private_t *ugeth) +{ + ucc_geth_info_t *ug_info; + ucc_geth_t *ug_regs; + ucc_fast_t *uf_regs; + enet_speed_e speed; + int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = + 0, limited_to_full_duplex = 0; + u32 upsmr, maccfg2, utbipar, tbiBaseAddress; + u16 value; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_info = ugeth->ug_info; + ug_regs = ugeth->ug_regs; + uf_regs = ugeth->uccf->uf_regs; + + /* Analyze enet_interface according to Interface Mode Configuration + table */ + ret_val = + get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, + &rpm, &tbi, &limited_to_full_duplex); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; + } + + /* Set MACCFG2 */ + maccfg2 = in_be32(&ug_regs->maccfg2); + maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; + if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) + maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; + else if (speed == ENET_SPEED_1000BT) + maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; + maccfg2 |= ug_info->padAndCrc; + out_be32(&ug_regs->maccfg2, maccfg2); + + /* Set UPSMR */ + upsmr = in_be32(&uf_regs->upsmr); + upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); + if (rpm) + upsmr |= UPSMR_RPM; + if (r10m) + upsmr |= UPSMR_R10M; + if (tbi) + upsmr |= UPSMR_TBIM; + if (rmm) + upsmr |= UPSMR_RMM; + out_be32(&uf_regs->upsmr, upsmr); + + /* Set UTBIPAR */ + utbipar = in_be32(&ug_regs->utbipar); + utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; + if (tbi) + utbipar |= + (ug_info->phy_address + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + else + utbipar |= + (0x10 + + ugeth->ug_info->uf_info. + ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; + out_be32(&ug_regs->utbipar, utbipar); + + /* Disable autonegotiation in tbi mode, because by default it + comes up in autonegotiation mode. */ + /* Note that this depends on proper setting in utbipar register. */ + if (tbi) { + tbiBaseAddress = in_be32(&ug_regs->utbipar); + tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; + tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; + value = + ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR); + value &= ~0x1000; /* Turn off autonegotiation */ + ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, + ENET_TBI_MII_CR, value); + } + + ret_val = init_mac_duplex_mode(1, + limited_to_full_duplex, + &ug_regs->maccfg2); + if (ret_val != 0) { + ugeth_err + ("%s: half duplex not supported in requested configuration.", + __FUNCTION__); + return ret_val; + } + + init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); + + ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2); + if (ret_val != 0) { + ugeth_err + ("%s: Preamble length must be between 3 and 7 inclusive.", + __FUNCTION__); + return ret_val; + } + + return 0; +} + +/* Called every time the controller might need to be made + * aware of new link state. The PHY code conveys this + * information through variables in the ugeth structure, and this + * function converts those variables into the appropriate + * register values, and can bring down the device if needed. + */ +static void adjust_link(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_geth_t *ug_regs; + u32 tempval; + struct ugeth_mii_info *mii_info = ugeth->mii_info; + + ug_regs = ugeth->ug_regs; + + if (mii_info->link) { + /* Now we make sure that we can be in full duplex mode. + * If not, we operate in half-duplex mode. */ + if (mii_info->duplex != ugeth->oldduplex) { + if (!(mii_info->duplex)) { + tempval = in_be32(&ug_regs->maccfg2); + tempval &= ~(MACCFG2_FDX); + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Half Duplex", dev->name); + } else { + tempval = in_be32(&ug_regs->maccfg2); + tempval |= MACCFG2_FDX; + out_be32(&ug_regs->maccfg2, tempval); + + ugeth_info("%s: Full Duplex", dev->name); + } + + ugeth->oldduplex = mii_info->duplex; + } + + if (mii_info->speed != ugeth->oldspeed) { + switch (mii_info->speed) { + case 1000: +#ifdef CONFIG_MPC836x +/* FIXME: This code is for 100Mbs BUG fixing, +remove this when it is fixed!!! */ + if (ugeth->ug_info->enet_interface == + ENET_1000_GMII) + /* Run the commands which initialize the PHY */ + { + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, 0x1b); + tempval |= 0x000f; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | BMCR_RESET)); + } else if (ugeth->ug_info->enet_interface == + ENET_1000_RGMII) + /* Run the commands which initialize the PHY */ + { + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, 0x1b); + tempval = (tempval & ~0x000f) | 0x000b; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth-> + dev, mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | BMCR_RESET)); + } + msleep(4000); +#endif /* CONFIG_MPC8360 */ + adjust_enet_interface(ugeth); + break; + case 100: + case 10: +#ifdef CONFIG_MPC836x +/* FIXME: This code is for 100Mbs BUG fixing, +remove this lines when it will be fixed!!! */ + ugeth->ug_info->enet_interface = ENET_100_RGMII; + tempval = + (u32) mii_info->mdio_read(ugeth->dev, + mii_info->mii_id, + 0x1b); + tempval = (tempval & ~0x000f) | 0x000b; + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, 0x1b, + (u16) tempval); + tempval = + (u32) mii_info->mdio_read(ugeth->dev, + mii_info->mii_id, + MII_BMCR); + mii_info->mdio_write(ugeth->dev, + mii_info->mii_id, MII_BMCR, + (u16) (tempval | + BMCR_RESET)); + msleep(4000); +#endif /* CONFIG_MPC8360 */ + adjust_enet_interface(ugeth); + break; + default: + ugeth_warn + ("%s: Ack! Speed (%d) is not 10/100/1000!", + dev->name, mii_info->speed); + break; + } + + ugeth_info("%s: Speed %dBT", dev->name, + mii_info->speed); + + ugeth->oldspeed = mii_info->speed; + } + + if (!ugeth->oldlink) { + ugeth_info("%s: Link is up", dev->name); + ugeth->oldlink = 1; + netif_carrier_on(dev); + netif_schedule(dev); + } + } else { + if (ugeth->oldlink) { + ugeth_info("%s: Link is down", dev->name); + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + netif_carrier_off(dev); + } + } +} + +/* Configure the PHY for dev. + * returns 0 if success. -1 if failure + */ +static int init_phy(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + struct phy_info *curphy; + ucc_mii_mng_t *mii_regs; + struct ugeth_mii_info *mii_info; + int err; + + mii_regs = &ugeth->ug_regs->miimng; + + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + + mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); + + if (NULL == mii_info) { + ugeth_err("%s: Could not allocate mii_info", dev->name); + return -ENOMEM; + } + + mii_info->mii_regs = mii_regs; + mii_info->speed = SPEED_1000; + mii_info->duplex = DUPLEX_FULL; + mii_info->pause = 0; + mii_info->link = 0; + + mii_info->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + mii_info->autoneg = 1; + + mii_info->mii_id = ugeth->ug_info->phy_address; + + mii_info->dev = dev; + + mii_info->mdio_read = &read_phy_reg; + mii_info->mdio_write = &write_phy_reg; + + ugeth->mii_info = mii_info; + + spin_lock_irq(&ugeth->lock); + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + if (init_mii_management_configuration(1, + ugeth->ug_info-> + miiPreambleSupress, + &mii_regs->miimcfg, + &mii_regs->miimind)) { + ugeth_err("%s: The MII Bus is stuck!", dev->name); + err = -1; + goto bus_fail; + } + + spin_unlock_irq(&ugeth->lock); + + /* get info for this PHY */ + curphy = get_phy_info(ugeth->mii_info); + + if (curphy == NULL) { + ugeth_err("%s: No PHY found", dev->name); + err = -1; + goto no_phy; + } + + mii_info->phyinfo = curphy; + + /* Run the commands which initialize the PHY */ + if (curphy->init) { + err = curphy->init(ugeth->mii_info); + if (err) + goto phy_init_fail; + } + + return 0; + + phy_init_fail: + no_phy: + bus_fail: + kfree(mii_info); + + return err; +} + +#ifdef CONFIG_UGETH_TX_ON_DEMOND +static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth) +{ + ucc_fast_transmit_on_demand(ugeth->uccf); + + return 0; +} +#endif + +static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + u32 temp; + + uccf = ugeth->uccf; + + /* Mask GRACEFUL STOP TX interrupt bit and clear it */ + temp = in_be32(uccf->p_uccm); + temp &= ~UCCE_GRA; + out_be32(uccf->p_uccm, temp); + out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */ + + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); + + /* Wait for command to complete */ + do { + temp = in_be32(uccf->p_ucce); + } while (!(temp & UCCE_GRA)); + + uccf->stopped_tx = 1; + + return 0; +} + +static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + u8 temp; + + uccf = ugeth->uccf; + + /* Clear acknowledge bit */ + temp = ugeth->p_rx_glbl_pram->rxgstpack; + temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; + ugeth->p_rx_glbl_pram->rxgstpack = temp; + + /* Keep issuing command and checking acknowledge bit until + it is asserted, according to spec */ + do { + /* Issue host command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info. + ucc_num); + qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, + (u8) QE_CR_PROTOCOL_ETHERNET, 0); + + temp = ugeth->p_rx_glbl_pram->rxgstpack; + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX)); + + uccf->stopped_rx = 1; + + return 0; +} + +static int ugeth_restart_tx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_TX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_tx = 0; + + return 0; +} + +static int ugeth_restart_rx(ucc_geth_private_t *ugeth) +{ + ucc_fast_private_t *uccf; + u32 cecr_subblock; + + uccf = ugeth->uccf; + + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(QE_RESTART_RX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + 0); + uccf->stopped_rx = 0; + + return 0; +} + +static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode) +{ + ucc_fast_private_t *uccf; + int enabled_tx, enabled_rx; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + return -EINVAL; + } + + enabled_tx = uccf->enabled_tx; + enabled_rx = uccf->enabled_rx; + + /* Get Tx and Rx going again, in case this channel was actively + disabled. */ + if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx) + ugeth_restart_tx(ugeth); + if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx) + ugeth_restart_rx(ugeth); + + ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */ + + return 0; + +} + +static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode) +{ + ucc_fast_private_t *uccf; + + uccf = ugeth->uccf; + + /* check if the UCC number is in range. */ + if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) { + ugeth_err("%s: ucc_num out of range.", __FUNCTION__); + return -EINVAL; + } + + /* Stop any transmissions */ + if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx) + ugeth_graceful_stop_tx(ugeth); + + /* Stop any receptions */ + if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx) + ugeth_graceful_stop_rx(ugeth); + + ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */ + + return 0; +} + +static void ugeth_dump_regs(ucc_geth_private_t *ugeth) +{ +#ifdef DEBUG + ucc_fast_dump_regs(ugeth->uccf); + dump_regs(ugeth); + dump_bds(ugeth); +#endif +} + +#ifdef CONFIG_UGETH_FILTERING +static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t * + p_UccGethTadParams, + qe_fltr_tad_t *qe_fltr_tad) +{ + u16 temp; + + /* Zero serialized TAD */ + memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE); + + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */ + if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode || + (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) + || (p_UccGethTadParams->vnontag_op != + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP) + ) + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF; + if (p_UccGethTadParams->reject_frame) + qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ; + temp = + (u16) (((u16) p_UccGethTadParams-> + vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT); + qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */ + + qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */ + if (p_UccGethTadParams->vnontag_op == + UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT) + qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP; + qe_fltr_tad->serialized[1] |= + p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT; + + qe_fltr_tad->serialized[2] |= + p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT; + /* upper bits */ + qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8); + /* lower bits */ + qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff); + + return 0; +} + +static enet_addr_container_t + *ugeth_82xx_filtering_get_match_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + enet_addr_container_t *enet_addr_cont; + struct list_head *p_lh; + u16 i, num; + int32_t j; + u8 *p_counter; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } + + if (!p_lh) + return NULL; + + num = *p_counter; + + for (i = 0; i < num; i++) { + enet_addr_cont = + (enet_addr_container_t *) + ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); + for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) { + if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j]) + break; + if (j == 0) + return enet_addr_cont; /* Found */ + } + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + } + return NULL; +} + +static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_enet_address_recognition_location_e location; + enet_addr_container_t *enet_addr_cont; + struct list_head *p_lh; + u8 i; + u32 limit; + u8 *p_counter; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + p_lh = &ugeth->group_hash_q; + limit = ugeth->ug_info->maxGroupAddrInHash; + location = + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + p_lh = &ugeth->ind_hash_q; + limit = ugeth->ug_info->maxIndAddrInHash; + location = + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH; + p_counter = &(ugeth->numIndAddrInHash); + } + + if ((enet_addr_cont = + ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) { + list_add(p_lh, &enet_addr_cont->node); /* Put it back */ + return 0; + } + if ((!p_lh) || (!(*p_counter < limit))) + return -EBUSY; + if (!(enet_addr_cont = get_enet_addr_container())) + return -ENOMEM; + for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) + (enet_addr_cont->address)[i] = (*p_enet_addr)[i]; + enet_addr_cont->location = location; + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + ++(*p_counter); + + hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); + + return 0; +} + +static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + enet_addr_container_t *enet_addr_cont; + ucc_fast_private_t *uccf; + comm_dir_e comm_dir; + u16 i, num; + struct list_head *p_lh; + u32 *addr_h, *addr_l; + u8 *p_counter; + + uccf = ugeth->uccf; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + if (! + (enet_addr_cont = + ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) + return -ENOENT; + + /* It's been found and removed from the CQ. */ + /* Now destroy its container */ + put_enet_addr_container(enet_addr_cont); + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { + addr_h = &(p_82xx_addr_filt->gaddr_h); + addr_l = &(p_82xx_addr_filt->gaddr_l); + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else { + addr_h = &(p_82xx_addr_filt->iaddr_h); + addr_l = &(p_82xx_addr_filt->iaddr_l); + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } + + comm_dir = 0; + if (uccf->enabled_tx) + comm_dir |= COMM_DIR_TX; + if (uccf->enabled_rx) + comm_dir |= COMM_DIR_RX; + if (comm_dir) + ugeth_disable(ugeth, comm_dir); + + /* Clear the hash table. */ + out_be32(addr_h, 0x00000000); + out_be32(addr_l, 0x00000000); + + /* Add all remaining CQ elements back into hash */ + num = --(*p_counter); + for (i = 0; i < num; i++) { + enet_addr_cont = + (enet_addr_container_t *) + ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); + hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address)); + enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ + } + + if (comm_dir) + ugeth_enable(ugeth, comm_dir); + + return 0; +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t * + ugeth, + enet_addr_type_e + enet_addr_type) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + ucc_fast_private_t *uccf; + comm_dir_e comm_dir; + struct list_head *p_lh; + u16 i, num; + u32 *addr_h, *addr_l; + u8 *p_counter; + + uccf = ugeth->uccf; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram-> + addressfiltering; + + if (enet_addr_type == ENET_ADDR_TYPE_GROUP) { + addr_h = &(p_82xx_addr_filt->gaddr_h); + addr_l = &(p_82xx_addr_filt->gaddr_l); + p_lh = &ugeth->group_hash_q; + p_counter = &(ugeth->numGroupAddrInHash); + } else if (enet_addr_type == ENET_ADDR_TYPE_INDIVIDUAL) { + addr_h = &(p_82xx_addr_filt->iaddr_h); + addr_l = &(p_82xx_addr_filt->iaddr_l); + p_lh = &ugeth->ind_hash_q; + p_counter = &(ugeth->numIndAddrInHash); + } else + return -EINVAL; + + comm_dir = 0; + if (uccf->enabled_tx) + comm_dir |= COMM_DIR_TX; + if (uccf->enabled_rx) + comm_dir |= COMM_DIR_RX; + if (comm_dir) + ugeth_disable(ugeth, comm_dir); + + /* Clear the hash table. */ + out_be32(addr_h, 0x00000000); + out_be32(addr_l, 0x00000000); + + if (!p_lh) + return 0; + + num = *p_counter; + + /* Delete all remaining CQ elements */ + for (i = 0; i < num; i++) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh))); + + *p_counter = 0; + + if (comm_dir) + ugeth_enable(ugeth, comm_dir); + + return 0; +} + +#ifdef CONFIG_UGETH_FILTERING +static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth, + enet_addr_t *p_enet_addr, + u8 paddr_num) +{ + int i; + + if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) + ugeth_warn + ("%s: multicast address added to paddr will have no " + "effect - is this what you wanted?", + __FUNCTION__); + + ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */ + /* store address in our database */ + for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) + ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i]; + /* put in hardware */ + return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num); +} +#endif /* CONFIG_UGETH_FILTERING */ + +static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t *ugeth, + u8 paddr_num) +{ + ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */ + return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */ +} + +static void ucc_geth_memclean(ucc_geth_private_t *ugeth) +{ + u16 i, j; + u8 *bd; + + if (!ugeth) + return; + + if (ugeth->uccf) + ucc_fast_free(ugeth->uccf); + + if (ugeth->p_thread_data_tx) { + qe_muram_free(ugeth->thread_dat_tx_offset); + ugeth->p_thread_data_tx = NULL; + } + if (ugeth->p_thread_data_rx) { + qe_muram_free(ugeth->thread_dat_rx_offset); + ugeth->p_thread_data_rx = NULL; + } + if (ugeth->p_exf_glbl_param) { + qe_muram_free(ugeth->exf_glbl_param_offset); + ugeth->p_exf_glbl_param = NULL; + } + if (ugeth->p_rx_glbl_pram) { + qe_muram_free(ugeth->rx_glbl_pram_offset); + ugeth->p_rx_glbl_pram = NULL; + } + if (ugeth->p_tx_glbl_pram) { + qe_muram_free(ugeth->tx_glbl_pram_offset); + ugeth->p_tx_glbl_pram = NULL; + } + if (ugeth->p_send_q_mem_reg) { + qe_muram_free(ugeth->send_q_mem_reg_offset); + ugeth->p_send_q_mem_reg = NULL; + } + if (ugeth->p_scheduler) { + qe_muram_free(ugeth->scheduler_offset); + ugeth->p_scheduler = NULL; + } + if (ugeth->p_tx_fw_statistics_pram) { + qe_muram_free(ugeth->tx_fw_statistics_pram_offset); + ugeth->p_tx_fw_statistics_pram = NULL; + } + if (ugeth->p_rx_fw_statistics_pram) { + qe_muram_free(ugeth->rx_fw_statistics_pram_offset); + ugeth->p_rx_fw_statistics_pram = NULL; + } + if (ugeth->p_rx_irq_coalescing_tbl) { + qe_muram_free(ugeth->rx_irq_coalescing_tbl_offset); + ugeth->p_rx_irq_coalescing_tbl = NULL; + } + if (ugeth->p_rx_bd_qs_tbl) { + qe_muram_free(ugeth->rx_bd_qs_tbl_offset); + ugeth->p_rx_bd_qs_tbl = NULL; + } + if (ugeth->p_init_enet_param_shadow) { + return_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + rxthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_RX, + ugeth->ug_info->riscRx, 1); + return_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), + ENET_INIT_PARAM_MAX_ENTRIES_TX, + ugeth->ug_info->riscTx, 0); + kfree(ugeth->p_init_enet_param_shadow); + ugeth->p_init_enet_param_shadow = NULL; + } + for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { + bd = ugeth->p_tx_bd_ring[i]; + for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { + if (ugeth->tx_skbuff[i][j]) { + dma_unmap_single(NULL, + BD_BUFFER_ARG(bd), + (BD_STATUS_AND_LENGTH(bd) & + BD_LENGTH_MASK), + DMA_TO_DEVICE); + dev_kfree_skb_any(ugeth->tx_skbuff[i][j]); + ugeth->tx_skbuff[i][j] = NULL; + } + } + + kfree(ugeth->tx_skbuff[i]); + + if (ugeth->p_tx_bd_ring[i]) { + if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_SYSTEM) + kfree((void *)ugeth->tx_bd_ring_offset[i]); + else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) + qe_muram_free(ugeth->tx_bd_ring_offset[i]); + ugeth->p_tx_bd_ring[i] = NULL; + } + } + for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) { + if (ugeth->p_rx_bd_ring[i]) { + /* Return existing data buffers in ring */ + bd = ugeth->p_rx_bd_ring[i]; + for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { + if (ugeth->rx_skbuff[i][j]) { + dma_unmap_single(NULL, BD_BUFFER(bd), + ugeth->ug_info-> + uf_info. + max_rx_buf_length + + UCC_GETH_RX_DATA_BUF_ALIGNMENT, + DMA_FROM_DEVICE); + + dev_kfree_skb_any(ugeth-> + rx_skbuff[i][j]); + ugeth->rx_skbuff[i][j] = NULL; + } + bd += UCC_GETH_SIZE_OF_BD; + } + + kfree(ugeth->rx_skbuff[i]); + + if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_SYSTEM) + kfree((void *)ugeth->rx_bd_ring_offset[i]); + else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) + qe_muram_free(ugeth->rx_bd_ring_offset[i]); + ugeth->p_rx_bd_ring[i] = NULL; + } + } + while (!list_empty(&ugeth->group_hash_q)) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY + (dequeue(&ugeth->group_hash_q))); + while (!list_empty(&ugeth->ind_hash_q)) + put_enet_addr_container(ENET_ADDR_CONT_ENTRY + (dequeue(&ugeth->ind_hash_q))); + +} + +static void ucc_geth_set_multi(struct net_device *dev) +{ + ucc_geth_private_t *ugeth; + struct dev_mc_list *dmi; + ucc_fast_t *uf_regs; + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + enet_addr_t tempaddr; + u8 *mcptr, *tdptr; + int i, j; + + ugeth = netdev_priv(dev); + + uf_regs = ugeth->uccf->uf_regs; + + if (dev->flags & IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + uf_regs->upsmr |= UPSMR_PRO; + + } else { + + uf_regs->upsmr &= ~UPSMR_PRO; + + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + p_rx_glbl_pram->addressfiltering; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + out_be32(&p_82xx_addr_filt->gaddr_h, 0xffffffff); + out_be32(&p_82xx_addr_filt->gaddr_l, 0xffffffff); + } else { + /* Clear filter and add the addresses in the list. + */ + out_be32(&p_82xx_addr_filt->gaddr_h, 0x0); + out_be32(&p_82xx_addr_filt->gaddr_l, 0x0); + + dmi = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u8 *) dmi->dmi_addr + 5; + tdptr = (u8 *) & tempaddr; + for (j = 0; j < 6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + hw_add_addr_in_hash(ugeth, &tempaddr); + + } + } + } +} + +static void ucc_geth_stop(ucc_geth_private_t *ugeth) +{ + ucc_geth_t *ug_regs = ugeth->ug_regs; + u32 tempval; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Disable the controller */ + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + /* Tell the kernel the link is down */ + ugeth->mii_info->link = 0; + adjust_link(ugeth->dev); + + /* Mask all interrupts */ + out_be32(ugeth->uccf->p_ucce, 0x00000000); + + /* Clear all interrupts */ + out_be32(ugeth->uccf->p_ucce, 0xffffffff); + + /* Disable Rx and Tx */ + tempval = in_be32(&ug_regs->maccfg1); + tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); + out_be32(&ug_regs->maccfg1, tempval); + + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + /* Clear any pending interrupts */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY Interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_DISABLED); + } + + free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); + } else { + del_timer_sync(&ugeth->phy_info_timer); + } + + ucc_geth_memclean(ugeth); +} + +static int ucc_geth_startup(ucc_geth_private_t *ugeth) +{ + ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt; + ucc_geth_init_pram_t *p_init_enet_pram; + ucc_fast_private_t *uccf; + ucc_geth_info_t *ug_info; + ucc_fast_info_t *uf_info; + ucc_fast_t *uf_regs; + ucc_geth_t *ug_regs; + int ret_val = -EINVAL; + u32 remoder = UCC_GETH_REMODER_INIT; + u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; + u32 ifstat, i, j, size, l2qt, l3qt, length; + u16 temoder = UCC_GETH_TEMODER_INIT; + u16 test; + u8 function_code = 0; + u8 *bd, *endOfRing; + u8 numThreadsRxNumerical, numThreadsTxNumerical; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_info = ugeth->ug_info; + uf_info = &ug_info->uf_info; + + if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || + (uf_info->bd_mem_part == MEM_PART_MURAM))) { + ugeth_err("%s: Bad memory partition value.", __FUNCTION__); + return -EINVAL; + } + + /* Rx BD lengths */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) || + (ug_info->bdRingLenRx[i] % + UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) { + ugeth_err + ("%s: Rx BD ring length must be multiple of 4," + " no smaller than 8.", __FUNCTION__); + return -EINVAL; + } + } + + /* Tx BD lengths */ + for (i = 0; i < ug_info->numQueuesTx; i++) { + if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) { + ugeth_err + ("%s: Tx BD ring length must be no smaller than 2.", + __FUNCTION__); + return -EINVAL; + } + } + + /* mrblr */ + if ((uf_info->max_rx_buf_length == 0) || + (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) { + ugeth_err + ("%s: max_rx_buf_length must be non-zero multiple of 128.", + __FUNCTION__); + return -EINVAL; + } + + /* num Tx queues */ + if (ug_info->numQueuesTx > NUM_TX_QUEUES) { + ugeth_err("%s: number of tx queues too large.", __FUNCTION__); + return -EINVAL; + } + + /* num Rx queues */ + if (ug_info->numQueuesRx > NUM_RX_QUEUES) { + ugeth_err("%s: number of rx queues too large.", __FUNCTION__); + return -EINVAL; + } + + /* l2qt */ + for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) { + if (ug_info->l2qt[i] >= ug_info->numQueuesRx) { + ugeth_err + ("%s: VLAN priority table entry must not be" + " larger than number of Rx queues.", + __FUNCTION__); + return -EINVAL; + } + } + + /* l3qt */ + for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) { + if (ug_info->l3qt[i] >= ug_info->numQueuesRx) { + ugeth_err + ("%s: IP priority table entry must not be" + " larger than number of Rx queues.", + __FUNCTION__); + return -EINVAL; + } + } + + if (ug_info->cam && !ug_info->ecamptr) { + ugeth_err("%s: If cam mode is chosen, must supply cam ptr.", + __FUNCTION__); + return -EINVAL; + } + + if ((ug_info->numStationAddresses != + UCC_GETH_NUM_OF_STATION_ADDRESSES_1) + && ug_info->rxExtendedFiltering) { + ugeth_err("%s: Number of station addresses greater than 1 " + "not allowed in extended parsing mode.", + __FUNCTION__); + return -EINVAL; + } + + /* Generate uccm_mask for receive */ + uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */ + for (i = 0; i < ug_info->numQueuesRx; i++) + uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i); + + for (i = 0; i < ug_info->numQueuesTx; i++) + uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); + /* Initialize the general fast UCC block. */ + if (ucc_fast_init(uf_info, &uccf)) { + ugeth_err("%s: Failed to init uccf.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->uccf = uccf; + + switch (ug_info->numThreadsRx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsRxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsRxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsRxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsRxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsRxNumerical = 8; + break; + default: + ugeth_err("%s: Bad number of Rx threads value.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + break; + } + + switch (ug_info->numThreadsTx) { + case UCC_GETH_NUM_OF_THREADS_1: + numThreadsTxNumerical = 1; + break; + case UCC_GETH_NUM_OF_THREADS_2: + numThreadsTxNumerical = 2; + break; + case UCC_GETH_NUM_OF_THREADS_4: + numThreadsTxNumerical = 4; + break; + case UCC_GETH_NUM_OF_THREADS_6: + numThreadsTxNumerical = 6; + break; + case UCC_GETH_NUM_OF_THREADS_8: + numThreadsTxNumerical = 8; + break; + default: + ugeth_err("%s: Bad number of Tx threads value.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + break; + } + + /* Calculate rx_extended_features */ + ugeth->rx_non_dynamic_extended_features = ug_info->ipCheckSumCheck || + ug_info->ipAddressAlignment || + (ug_info->numStationAddresses != + UCC_GETH_NUM_OF_STATION_ADDRESSES_1); + + ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features || + (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) + || (ug_info->vlanOperationNonTagged != + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); + + uf_regs = uccf->uf_regs; + ug_regs = (ucc_geth_t *) (uccf->uf_regs); + ugeth->ug_regs = ug_regs; + + init_default_reg_vals(&uf_regs->upsmr, + &ug_regs->maccfg1, &ug_regs->maccfg2); + + /* Set UPSMR */ + /* For more details see the hardware spec. */ + init_rx_parameters(ug_info->bro, + ug_info->rsh, ug_info->pro, &uf_regs->upsmr); + + /* We're going to ignore other registers for now, */ + /* except as needed to get up and running */ + + /* Set MACCFG1 */ + /* For more details see the hardware spec. */ + init_flow_control_params(ug_info->aufc, + ug_info->receiveFlowControl, + 1, + ug_info->pausePeriod, + ug_info->extensionField, + &uf_regs->upsmr, + &ug_regs->uempr, &ug_regs->maccfg1); + + maccfg1 = in_be32(&ug_regs->maccfg1); + maccfg1 |= MACCFG1_ENABLE_RX; + maccfg1 |= MACCFG1_ENABLE_TX; + out_be32(&ug_regs->maccfg1, maccfg1); + + /* Set IPGIFG */ + /* For more details see the hardware spec. */ + ret_val = init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1, + ug_info->nonBackToBackIfgPart2, + ug_info-> + miminumInterFrameGapEnforcement, + ug_info->backToBackInterFrameGap, + &ug_regs->ipgifg); + if (ret_val != 0) { + ugeth_err("%s: IPGIFG initialization parameter too large.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Set HAFDUP */ + /* For more details see the hardware spec. */ + ret_val = init_half_duplex_params(ug_info->altBeb, + ug_info->backPressureNoBackoff, + ug_info->noBackoff, + ug_info->excessDefer, + ug_info->altBebTruncation, + ug_info->maxRetransmission, + ug_info->collisionWindow, + &ug_regs->hafdup); + if (ret_val != 0) { + ugeth_err("%s: Half Duplex initialization parameter too large.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Set IFSTAT */ + /* For more details see the hardware spec. */ + /* Read only - resets upon read */ + ifstat = in_be32(&ug_regs->ifstat); + + /* Clear UEMPR */ + /* For more details see the hardware spec. */ + out_be32(&ug_regs->uempr, 0); + + /* Set UESCR */ + /* For more details see the hardware spec. */ + init_hw_statistics_gathering_mode((ug_info->statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE), + 0, &uf_regs->upsmr, &ug_regs->uescr); + + /* Allocate Tx bds */ + for (j = 0; j < ug_info->numQueuesTx; j++) { + /* Allocate in multiple of + UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT, + according to spec */ + length = ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) + / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) + * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + if ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) % + UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) + length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; + if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { + u32 align = 4; + if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4) + align = UCC_GETH_TX_BD_RING_ALIGNMENT; + ugeth->tx_bd_ring_offset[j] = + (u32) (kmalloc((u32) (length + align), + GFP_KERNEL)); + if (ugeth->tx_bd_ring_offset[j] != 0) + ugeth->p_tx_bd_ring[j] = + (void*)((ugeth->tx_bd_ring_offset[j] + + align) & ~(align - 1)); + } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { + ugeth->tx_bd_ring_offset[j] = + qe_muram_alloc(length, + UCC_GETH_TX_BD_RING_ALIGNMENT); + if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j])) + ugeth->p_tx_bd_ring[j] = + (u8 *) qe_muram_addr(ugeth-> + tx_bd_ring_offset[j]); + } + if (!ugeth->p_tx_bd_ring[j]) { + ugeth_err + ("%s: Can not allocate memory for Tx bd rings.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + /* Zero unused end of bd ring, according to spec */ + memset(ugeth->p_tx_bd_ring[j] + + ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD, 0, + length - ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD); + } + + /* Allocate Rx bds */ + for (j = 0; j < ug_info->numQueuesRx; j++) { + length = ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD; + if (uf_info->bd_mem_part == MEM_PART_SYSTEM) { + u32 align = 4; + if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) + align = UCC_GETH_RX_BD_RING_ALIGNMENT; + ugeth->rx_bd_ring_offset[j] = + (u32) (kmalloc((u32) (length + align), GFP_KERNEL)); + if (ugeth->rx_bd_ring_offset[j] != 0) + ugeth->p_rx_bd_ring[j] = + (void*)((ugeth->rx_bd_ring_offset[j] + + align) & ~(align - 1)); + } else if (uf_info->bd_mem_part == MEM_PART_MURAM) { + ugeth->rx_bd_ring_offset[j] = + qe_muram_alloc(length, + UCC_GETH_RX_BD_RING_ALIGNMENT); + if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j])) + ugeth->p_rx_bd_ring[j] = + (u8 *) qe_muram_addr(ugeth-> + rx_bd_ring_offset[j]); + } + if (!ugeth->p_rx_bd_ring[j]) { + ugeth_err + ("%s: Can not allocate memory for Rx bd rings.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + } + + /* Init Tx bds */ + for (j = 0; j < ug_info->numQueuesTx; j++) { + /* Setup the skbuff rings */ + ugeth->tx_skbuff[j] = + (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenTx[j], + GFP_KERNEL); + + if (ugeth->tx_skbuff[j] == NULL) { + ugeth_err("%s: Could not allocate tx_skbuff", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++) + ugeth->tx_skbuff[j][i] = NULL; + + ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0; + bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j]; + for (i = 0; i < ug_info->bdRingLenTx[j]; i++) { + BD_BUFFER_CLEAR(bd); + BD_STATUS_AND_LENGTH_SET(bd, 0); + bd += UCC_GETH_SIZE_OF_BD; + } + bd -= UCC_GETH_SIZE_OF_BD; + BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set Wrap bit */ + } + + /* Init Rx bds */ + for (j = 0; j < ug_info->numQueuesRx; j++) { + /* Setup the skbuff rings */ + ugeth->rx_skbuff[j] = + (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenRx[j], + GFP_KERNEL); + + if (ugeth->rx_skbuff[j] == NULL) { + ugeth_err("%s: Could not allocate rx_skbuff", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++) + ugeth->rx_skbuff[j][i] = NULL; + + ugeth->skb_currx[j] = 0; + bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j]; + for (i = 0; i < ug_info->bdRingLenRx[j]; i++) { + BD_STATUS_AND_LENGTH_SET(bd, R_I); + BD_BUFFER_CLEAR(bd); + bd += UCC_GETH_SIZE_OF_BD; + } + bd -= UCC_GETH_SIZE_OF_BD; + BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set Wrap bit */ + } + + /* + * Global PRAM + */ + /* Tx global PRAM */ + /* Allocate global tx parameter RAM page */ + ugeth->tx_glbl_pram_offset = + qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t), + UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_tx_glbl_pram = + (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth-> + tx_glbl_pram_offset); + /* Zero out p_tx_glbl_pram */ + memset(ugeth->p_tx_glbl_pram, 0, sizeof(ucc_geth_tx_global_pram_t)); + + /* Fill global PRAM */ + + /* TQPTR */ + /* Size varies with number of Tx threads */ + ugeth->thread_dat_tx_offset = + qe_muram_alloc(numThreadsTxNumerical * + sizeof(ucc_geth_thread_data_tx_t) + + 32 * (numThreadsTxNumerical == 1), + UCC_GETH_THREAD_DATA_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_thread_data_tx = + (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth-> + thread_dat_tx_offset); + out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset); + + /* vtagtable */ + for (i = 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++) + out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i], + ug_info->vtagtable[i]); + + /* iphoffset */ + for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++) + ugeth->p_tx_glbl_pram->iphoffset[i] = ug_info->iphoffset[i]; + + /* SQPTR */ + /* Size varies with number of Tx queues */ + ugeth->send_q_mem_reg_offset = + qe_muram_alloc(ug_info->numQueuesTx * + sizeof(ucc_geth_send_queue_qd_t), + UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_send_q_mem_reg = + (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth-> + send_q_mem_reg_offset); + out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset); + + /* Setup the table */ + /* Assume BD rings are already established */ + for (i = 0; i < ug_info->numQueuesTx; i++) { + endOfRing = + ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] - + 1) * UCC_GETH_SIZE_OF_BD; + if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, + (u32) virt_to_phys(ugeth->p_tx_bd_ring[i])); + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. + last_bd_completed_address, + (u32) virt_to_phys(endOfRing)); + } else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) { + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, + (u32) immrbar_virt_to_phys(ugeth-> + p_tx_bd_ring[i])); + out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. + last_bd_completed_address, + (u32) immrbar_virt_to_phys(endOfRing)); + } + } + + /* schedulerbasepointer */ + + if (ug_info->numQueuesTx > 1) { + /* scheduler exists only if more than 1 tx queue */ + ugeth->scheduler_offset = + qe_muram_alloc(sizeof(ucc_geth_scheduler_t), + UCC_GETH_SCHEDULER_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->scheduler_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_scheduler.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_scheduler = + (ucc_geth_scheduler_t *) qe_muram_addr(ugeth-> + scheduler_offset); + out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer, + ugeth->scheduler_offset); + /* Zero out p_scheduler */ + memset(ugeth->p_scheduler, 0, sizeof(ucc_geth_scheduler_t)); + + /* Set values in scheduler */ + out_be32(&ugeth->p_scheduler->mblinterval, + ug_info->mblinterval); + out_be16(&ugeth->p_scheduler->nortsrbytetime, + ug_info->nortsrbytetime); + ugeth->p_scheduler->fracsiz = ug_info->fracsiz; + ugeth->p_scheduler->strictpriorityq = ug_info->strictpriorityq; + ugeth->p_scheduler->txasap = ug_info->txasap; + ugeth->p_scheduler->extrabw = ug_info->extrabw; + for (i = 0; i < NUM_TX_QUEUES; i++) + ugeth->p_scheduler->weightfactor[i] = + ug_info->weightfactor[i]; + + /* Set pointers to cpucount registers in scheduler */ + ugeth->p_cpucount[0] = &(ugeth->p_scheduler->cpucount0); + ugeth->p_cpucount[1] = &(ugeth->p_scheduler->cpucount1); + ugeth->p_cpucount[2] = &(ugeth->p_scheduler->cpucount2); + ugeth->p_cpucount[3] = &(ugeth->p_scheduler->cpucount3); + ugeth->p_cpucount[4] = &(ugeth->p_scheduler->cpucount4); + ugeth->p_cpucount[5] = &(ugeth->p_scheduler->cpucount5); + ugeth->p_cpucount[6] = &(ugeth->p_scheduler->cpucount6); + ugeth->p_cpucount[7] = &(ugeth->p_scheduler->cpucount7); + } + + /* schedulerbasepointer */ + /* TxRMON_PTR (statistics) */ + if (ug_info-> + statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { + ugeth->tx_fw_statistics_pram_offset = + qe_muram_alloc(sizeof + (ucc_geth_tx_firmware_statistics_pram_t), + UCC_GETH_TX_STATISTICS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_tx_fw_statistics_pram.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_tx_fw_statistics_pram = + (ucc_geth_tx_firmware_statistics_pram_t *) + qe_muram_addr(ugeth->tx_fw_statistics_pram_offset); + /* Zero out p_tx_fw_statistics_pram */ + memset(ugeth->p_tx_fw_statistics_pram, + 0, sizeof(ucc_geth_tx_firmware_statistics_pram_t)); + } + + /* temoder */ + /* Already has speed set */ + + if (ug_info->numQueuesTx > 1) + temoder |= TEMODER_SCHEDULER_ENABLE; + if (ug_info->ipCheckSumGenerate) + temoder |= TEMODER_IP_CHECKSUM_GENERATE; + temoder |= ((ug_info->numQueuesTx - 1) << TEMODER_NUM_OF_QUEUES_SHIFT); + out_be16(&ugeth->p_tx_glbl_pram->temoder, temoder); + + test = in_be16(&ugeth->p_tx_glbl_pram->temoder); + + /* Function code register value to be used later */ + function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL; + /* Required for QE */ + + /* function code register */ + out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code) << 24); + + /* Rx global PRAM */ + /* Allocate global rx parameter RAM page */ + ugeth->rx_glbl_pram_offset = + qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t), + UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_rx_glbl_pram = + (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth-> + rx_glbl_pram_offset); + /* Zero out p_rx_glbl_pram */ + memset(ugeth->p_rx_glbl_pram, 0, sizeof(ucc_geth_rx_global_pram_t)); + + /* Fill global PRAM */ + + /* RQPTR */ + /* Size varies with number of Rx threads */ + ugeth->thread_dat_rx_offset = + qe_muram_alloc(numThreadsRxNumerical * + sizeof(ucc_geth_thread_data_rx_t), + UCC_GETH_THREAD_DATA_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_thread_data_rx = + (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth-> + thread_dat_rx_offset); + out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset); + + /* typeorlen */ + out_be16(&ugeth->p_rx_glbl_pram->typeorlen, ug_info->typeorlen); + + /* rxrmonbaseptr (statistics) */ + if (ug_info-> + statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) { + ugeth->rx_fw_statistics_pram_offset = + qe_muram_alloc(sizeof + (ucc_geth_rx_firmware_statistics_pram_t), + UCC_GETH_RX_STATISTICS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_rx_fw_statistics_pram.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + ugeth->p_rx_fw_statistics_pram = + (ucc_geth_rx_firmware_statistics_pram_t *) + qe_muram_addr(ugeth->rx_fw_statistics_pram_offset); + /* Zero out p_rx_fw_statistics_pram */ + memset(ugeth->p_rx_fw_statistics_pram, 0, + sizeof(ucc_geth_rx_firmware_statistics_pram_t)); + } + + /* intCoalescingPtr */ + + /* Size varies with number of Rx queues */ + ugeth->rx_irq_coalescing_tbl_offset = + qe_muram_alloc(ug_info->numQueuesRx * + sizeof(ucc_geth_rx_interrupt_coalescing_entry_t), + UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_rx_irq_coalescing_tbl.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_rx_irq_coalescing_tbl = + (ucc_geth_rx_interrupt_coalescing_table_t *) + qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset); + out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr, + ugeth->rx_irq_coalescing_tbl_offset); + + /* Fill interrupt coalescing table */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. + interruptcoalescingmaxvalue, + ug_info->interruptcoalescingmaxvalue[i]); + out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i]. + interruptcoalescingcounter, + ug_info->interruptcoalescingmaxvalue[i]); + } + + /* MRBLR */ + init_max_rx_buff_len(uf_info->max_rx_buf_length, + &ugeth->p_rx_glbl_pram->mrblr); + /* MFLR */ + out_be16(&ugeth->p_rx_glbl_pram->mflr, ug_info->maxFrameLength); + /* MINFLR */ + init_min_frame_len(ug_info->minFrameLength, + &ugeth->p_rx_glbl_pram->minflr, + &ugeth->p_rx_glbl_pram->mrblr); + /* MAXD1 */ + out_be16(&ugeth->p_rx_glbl_pram->maxd1, ug_info->maxD1Length); + /* MAXD2 */ + out_be16(&ugeth->p_rx_glbl_pram->maxd2, ug_info->maxD2Length); + + /* l2qt */ + l2qt = 0; + for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) + l2qt |= (ug_info->l2qt[i] << (28 - 4 * i)); + out_be32(&ugeth->p_rx_glbl_pram->l2qt, l2qt); + + /* l3qt */ + for (j = 0; j < UCC_GETH_IP_PRIORITY_MAX; j += 8) { + l3qt = 0; + for (i = 0; i < 8; i++) + l3qt |= (ug_info->l3qt[j + i] << (28 - 4 * i)); + out_be32(&ugeth->p_rx_glbl_pram->l3qt[j], l3qt); + } + + /* vlantype */ + out_be16(&ugeth->p_rx_glbl_pram->vlantype, ug_info->vlantype); + + /* vlantci */ + out_be16(&ugeth->p_rx_glbl_pram->vlantci, ug_info->vlantci); + + /* ecamptr */ + out_be32(&ugeth->p_rx_glbl_pram->ecamptr, ug_info->ecamptr); + + /* RBDQPTR */ + /* Size varies with number of Rx queues */ + ugeth->rx_bd_qs_tbl_offset = + qe_muram_alloc(ug_info->numQueuesRx * + (sizeof(ucc_geth_rx_bd_queues_entry_t) + + sizeof(ucc_geth_rx_prefetched_bds_t)), + UCC_GETH_RX_BD_QUEUES_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_rx_bd_qs_tbl = + (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth-> + rx_bd_qs_tbl_offset); + out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset); + /* Zero out p_rx_bd_qs_tbl */ + memset(ugeth->p_rx_bd_qs_tbl, + 0, + ug_info->numQueuesRx * (sizeof(ucc_geth_rx_bd_queues_entry_t) + + sizeof(ucc_geth_rx_prefetched_bds_t))); + + /* Setup the table */ + /* Assume BD rings are already established */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) { + out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + (u32) virt_to_phys(ugeth->p_rx_bd_ring[i])); + } else if (ugeth->ug_info->uf_info.bd_mem_part == + MEM_PART_MURAM) { + out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, + (u32) immrbar_virt_to_phys(ugeth-> + p_rx_bd_ring[i])); + } + /* rest of fields handled by QE */ + } + + /* remoder */ + /* Already has speed set */ + + if (ugeth->rx_extended_features) + remoder |= REMODER_RX_EXTENDED_FEATURES; + if (ug_info->rxExtendedFiltering) + remoder |= REMODER_RX_EXTENDED_FILTERING; + if (ug_info->dynamicMaxFrameLength) + remoder |= REMODER_DYNAMIC_MAX_FRAME_LENGTH; + if (ug_info->dynamicMinFrameLength) + remoder |= REMODER_DYNAMIC_MIN_FRAME_LENGTH; + remoder |= + ug_info->vlanOperationTagged << REMODER_VLAN_OPERATION_TAGGED_SHIFT; + remoder |= + ug_info-> + vlanOperationNonTagged << REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT; + remoder |= ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT; + remoder |= ((ug_info->numQueuesRx - 1) << REMODER_NUM_OF_QUEUES_SHIFT); + if (ug_info->ipCheckSumCheck) + remoder |= REMODER_IP_CHECKSUM_CHECK; + if (ug_info->ipAddressAlignment) + remoder |= REMODER_IP_ADDRESS_ALIGNMENT; + out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder); + + /* Note that this function must be called */ + /* ONLY AFTER p_tx_fw_statistics_pram */ + /* andp_UccGethRxFirmwareStatisticsPram are allocated ! */ + init_firmware_statistics_gathering_mode((ug_info-> + statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX), + (ug_info->statisticsMode & + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX), + &ugeth->p_tx_glbl_pram->txrmonbaseptr, + ugeth->tx_fw_statistics_pram_offset, + &ugeth->p_rx_glbl_pram->rxrmonbaseptr, + ugeth->rx_fw_statistics_pram_offset, + &ugeth->p_tx_glbl_pram->temoder, + &ugeth->p_rx_glbl_pram->remoder); + + /* function code register */ + ugeth->p_rx_glbl_pram->rstate = function_code; + + /* initialize extended filtering */ + if (ug_info->rxExtendedFiltering) { + if (!ug_info->extendedFilteringChainPointer) { + ugeth_err("%s: Null Extended Filtering Chain Pointer.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + } + + /* Allocate memory for extended filtering Mode Global + Parameters */ + ugeth->exf_glbl_param_offset = + qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t), + UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT); + if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for" + " p_exf_glbl_param.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + + ugeth->p_exf_glbl_param = + (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth-> + exf_glbl_param_offset); + out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam, + ugeth->exf_glbl_param_offset); + out_be32(&ugeth->p_exf_glbl_param->l2pcdptr, + (u32) ug_info->extendedFilteringChainPointer); + + } else { /* initialize 82xx style address filtering */ + + /* Init individual address recognition registers to disabled */ + + for (j = 0; j < NUM_OF_PADDRS; j++) + ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); + + /* Create CQs for hash tables */ + if (ug_info->maxGroupAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->group_hash_q); + } + if (ug_info->maxIndAddrInHash > 0) { + INIT_LIST_HEAD(&ugeth->ind_hash_q); + } + p_82xx_addr_filt = + (ucc_geth_82xx_address_filtering_pram_t *) ugeth-> + p_rx_glbl_pram->addressfiltering; + + ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, + ENET_ADDR_TYPE_GROUP); + ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth, + ENET_ADDR_TYPE_INDIVIDUAL); + } + + /* + * Initialize UCC at QE level + */ + + command = QE_INIT_TX_RX; + + /* Allocate shadow InitEnet command parameter structure. + * This is needed because after the InitEnet command is executed, + * the structure in DPRAM is released, because DPRAM is a premium + * resource. + * This shadow structure keeps a copy of what was done so that the + * allocated resources can be released when the channel is freed. + */ + if (!(ugeth->p_init_enet_param_shadow = + (ucc_geth_init_pram_t *) kmalloc(sizeof(ucc_geth_init_pram_t), + GFP_KERNEL))) { + ugeth_err + ("%s: Can not allocate memory for" + " p_UccInitEnetParamShadows.", __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + /* Zero out *p_init_enet_param_shadow */ + memset((char *)ugeth->p_init_enet_param_shadow, + 0, sizeof(ucc_geth_init_pram_t)); + + /* Fill shadow InitEnet command parameter structure */ + + ugeth->p_init_enet_param_shadow->resinit1 = + ENET_INIT_PARAM_MAGIC_RES_INIT1; + ugeth->p_init_enet_param_shadow->resinit2 = + ENET_INIT_PARAM_MAGIC_RES_INIT2; + ugeth->p_init_enet_param_shadow->resinit3 = + ENET_INIT_PARAM_MAGIC_RES_INIT3; + ugeth->p_init_enet_param_shadow->resinit4 = + ENET_INIT_PARAM_MAGIC_RES_INIT4; + ugeth->p_init_enet_param_shadow->resinit5 = + ENET_INIT_PARAM_MAGIC_RES_INIT5; + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ((u32) ug_info->numThreadsRx) << ENET_INIT_PARAM_RGF_SHIFT; + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ((u32) ug_info->numThreadsTx) << ENET_INIT_PARAM_TGF_SHIFT; + + ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= + ugeth->rx_glbl_pram_offset | ug_info->riscRx; + if ((ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) + && (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + && (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { + ugeth_err("%s: Invalid largest External Lookup Key Size.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -EINVAL; + } + ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = + ug_info->largestexternallookupkeysize; + size = sizeof(ucc_geth_thread_rx_pram_t); + if (ug_info->rxExtendedFiltering) { + size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING; + if (ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8; + if (ug_info->largestexternallookupkeysize == + QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES) + size += + THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16; + } + + if ((ret_val = fill_init_enet_entries(ugeth, &(ugeth-> + p_init_enet_param_shadow->rxthread[0]), + (u8) (numThreadsRxNumerical + 1) + /* Rx needs one extra for terminator */ + , size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT, + ug_info->riscRx, 1)) != 0) { + ugeth_err("%s: Can not fill p_init_enet_param_shadow.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + ugeth->p_init_enet_param_shadow->txglobal = + ugeth->tx_glbl_pram_offset | ug_info->riscTx; + if ((ret_val = + fill_init_enet_entries(ugeth, + &(ugeth->p_init_enet_param_shadow-> + txthread[0]), numThreadsTxNumerical, + sizeof(ucc_geth_thread_tx_pram_t), + UCC_GETH_THREAD_TX_PRAM_ALIGNMENT, + ug_info->riscTx, 0)) != 0) { + ugeth_err("%s: Can not fill p_init_enet_param_shadow.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + + /* Load Rx bds with buffers */ + for (i = 0; i < ug_info->numQueuesRx; i++) { + if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) { + ugeth_err("%s: Can not fill Rx bds with buffers.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return ret_val; + } + } + + /* Allocate InitEnet command parameter structure */ + init_enet_pram_offset = qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4); + if (IS_MURAM_ERR(init_enet_pram_offset)) { + ugeth_err + ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", + __FUNCTION__); + ucc_geth_memclean(ugeth); + return -ENOMEM; + } + p_init_enet_pram = + (ucc_geth_init_pram_t *) qe_muram_addr(init_enet_pram_offset); + + /* Copy shadow InitEnet command parameter structure into PRAM */ + p_init_enet_pram->resinit1 = ugeth->p_init_enet_param_shadow->resinit1; + p_init_enet_pram->resinit2 = ugeth->p_init_enet_param_shadow->resinit2; + p_init_enet_pram->resinit3 = ugeth->p_init_enet_param_shadow->resinit3; + p_init_enet_pram->resinit4 = ugeth->p_init_enet_param_shadow->resinit4; + out_be16(&p_init_enet_pram->resinit5, + ugeth->p_init_enet_param_shadow->resinit5); + p_init_enet_pram->largestexternallookupkeysize = + ugeth->p_init_enet_param_shadow->largestexternallookupkeysize; + out_be32(&p_init_enet_pram->rgftgfrxglobal, + ugeth->p_init_enet_param_shadow->rgftgfrxglobal); + for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++) + out_be32(&p_init_enet_pram->rxthread[i], + ugeth->p_init_enet_param_shadow->rxthread[i]); + out_be32(&p_init_enet_pram->txglobal, + ugeth->p_init_enet_param_shadow->txglobal); + for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++) + out_be32(&p_init_enet_pram->txthread[i], + ugeth->p_init_enet_param_shadow->txthread[i]); + + /* Issue QE command */ + cecr_subblock = + ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num); + qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, + init_enet_pram_offset); + + /* Free InitEnet command parameter */ + qe_muram_free(init_enet_pram_offset); + + return 0; +} + +/* returns a net_device_stats structure pointer */ +static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + return &(ugeth->stats); +} + +/* ucc_geth_timeout gets called when a packet has not been + * transmitted after a set amount of time. + * For now, assume that clearing out all the structures, and + * starting over will fix the problem. */ +static void ucc_geth_timeout(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ugeth->stats.tx_errors++; + + ugeth_dump_regs(ugeth); + + if (dev->flags & IFF_UP) { + ucc_geth_stop(ugeth); + ucc_geth_startup(ugeth); + } + + netif_schedule(dev); +} + +/* This is called by the kernel when a frame is ready for transmission. */ +/* It is pointed to by the dev->hard_start_xmit function pointer */ +static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + u8 *bd; /* BD pointer */ + u32 bd_status; + u8 txQ = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + ugeth->stats.tx_bytes += skb->len; + + /* Start from the next BD that should be filled */ + bd = ugeth->txBd[txQ]; + bd_status = BD_STATUS_AND_LENGTH(bd); + /* Save the skb pointer so we can free it later */ + ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb; + + /* Update the current skb pointer (wrapping if this was the last) */ + ugeth->skb_curtx[txQ] = + (ugeth->skb_curtx[txQ] + + 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); + + /* set up the buffer descriptor */ + BD_BUFFER_SET(bd, + dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE)); + + //printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); + + bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len; + + BD_STATUS_AND_LENGTH_SET(bd, bd_status); + + dev->trans_start = jiffies; + + /* Move to next BD in the ring */ + if (!(bd_status & T_W)) + ugeth->txBd[txQ] = bd + UCC_GETH_SIZE_OF_BD; + else + ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + + /* If the next BD still needs to be cleaned up, then the bds + are full. We need to tell the kernel to stop sending us stuff. */ + if (bd == ugeth->confBd[txQ]) { + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); + } + + if (ugeth->p_scheduler) { + ugeth->cpucount[txQ]++; + /* Indicate to QE that there are more Tx bds ready for + transmission */ + /* This is done by writing a running counter of the bd + count to the scheduler PRAM. */ + out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); + } + + spin_unlock_irq(&ugeth->lock); + + return 0; +} + +static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit) +{ + struct sk_buff *skb; + u8 *bd; + u16 length, howmany = 0; + u32 bd_status; + u8 *bdBuffer; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + spin_lock(&ugeth->lock); + /* collect received buffers */ + bd = ugeth->rxBd[rxQ]; + + bd_status = BD_STATUS_AND_LENGTH(bd); + + /* while there are received buffers and BD is full (~R_E) */ + while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) { + bdBuffer = (u8 *) BD_BUFFER(bd); + length = (u16) ((bd_status & BD_LENGTH_MASK) - 4); + skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]]; + + /* determine whether buffer is first, last, first and last + (single buffer frame) or middle (not first and not last) */ + if (!skb || + (!(bd_status & (R_F | R_L))) || + (bd_status & R_ERRORS_FATAL)) { + ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x", + __FUNCTION__, __LINE__, (u32) skb); + if (skb) + dev_kfree_skb_any(skb); + + ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL; + ugeth->stats.rx_dropped++; + } else { + ugeth->stats.rx_packets++; + howmany++; + + /* Prep the skb for the packet */ + skb_put(skb, length); + + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, ugeth->dev); + + ugeth->stats.rx_bytes += length; + /* Send the packet up the stack */ +#ifdef CONFIG_UGETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif /* CONFIG_UGETH_NAPI */ + } + + ugeth->dev->last_rx = jiffies; + + skb = get_new_skb(ugeth, bd); + if (!skb) { + ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); + spin_unlock(&ugeth->lock); + ugeth->stats.rx_dropped++; + break; + } + + ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = skb; + + /* update to point at the next skb */ + ugeth->skb_currx[rxQ] = + (ugeth->skb_currx[rxQ] + + 1) & RX_RING_MOD_MASK(ugeth->ug_info->bdRingLenRx[rxQ]); + + if (bd_status & R_W) + bd = ugeth->p_rx_bd_ring[rxQ]; + else + bd += UCC_GETH_SIZE_OF_BD; + + bd_status = BD_STATUS_AND_LENGTH(bd); + } + + ugeth->rxBd[rxQ] = bd; + spin_unlock(&ugeth->lock); + return howmany; +} + +static int ucc_geth_tx(struct net_device *dev, u8 txQ) +{ + /* Start from the next BD that should be filled */ + ucc_geth_private_t *ugeth = netdev_priv(dev); + u8 *bd; /* BD pointer */ + u32 bd_status; + + bd = ugeth->confBd[txQ]; + bd_status = BD_STATUS_AND_LENGTH(bd); + + /* Normal processing. */ + while ((bd_status & T_R) == 0) { + /* BD contains already transmitted buffer. */ + /* Handle the transmitted buffer and release */ + /* the BD to be used with the current frame */ + + if ((bd = ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) + break; + + ugeth->stats.tx_packets++; + + /* Free the sk buffer associated with this TxBD */ + dev_kfree_skb_irq(ugeth-> + tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]); + ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL; + ugeth->skb_dirtytx[txQ] = + (ugeth->skb_dirtytx[txQ] + + 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]); + + /* We freed a buffer, so now we can restart transmission */ + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + /* Advance the confirmation BD pointer */ + if (!(bd_status & T_W)) + ugeth->confBd[txQ] += UCC_GETH_SIZE_OF_BD; + else + ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + } + return 0; +} + +#ifdef CONFIG_UGETH_NAPI +static int ucc_geth_poll(struct net_device *dev, int *budget) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + int howmany; + int rx_work_limit = *budget; + u8 rxQ = 0; + + if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + + howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); + + dev->quota -= howmany; + rx_work_limit -= howmany; + *budget -= howmany; + + if (rx_work_limit >= 0) + netif_rx_complete(dev); + + return (rx_work_limit < 0) ? 1 : 0; +} +#endif /* CONFIG_UGETH_NAPI */ + +static irqreturn_t ucc_geth_irq_handler(int irq, void *info, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)info; + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_fast_private_t *uccf; + ucc_geth_info_t *ug_info; + register u32 ucce = 0; + register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; + register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; + register u8 i; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + if (!ugeth) + return IRQ_NONE; + + uccf = ugeth->uccf; + ug_info = ugeth->ug_info; + + do { + ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); + + /* clear event bits for next time */ + /* Side effect here is to mask ucce variable + for future processing below. */ + out_be32(uccf->p_ucce, ucce); /* Clear with ones, + but only bits in UCCM */ + + /* We ignore Tx interrupts because Tx confirmation is + done inside Tx routine */ + + for (i = 0; i < ug_info->numQueuesRx; i++) { + if (ucce & bit_mask) + ucc_geth_rx(ugeth, i, + (int)ugeth->ug_info-> + bdRingLenRx[i]); + ucce &= ~bit_mask; + bit_mask <<= 1; + } + + for (i = 0; i < ug_info->numQueuesTx; i++) { + if (ucce & tx_mask) + ucc_geth_tx(dev, i); + ucce &= ~tx_mask; + tx_mask <<= 1; + } + + /* Exceptions */ + if (ucce & UCCE_BSY) { + ugeth_vdbg("Got BUSY irq!!!!"); + ugeth->stats.rx_errors++; + ucce &= ~UCCE_BSY; + } + if (ucce & UCCE_OTHER) { + ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", + ucce); + ugeth->stats.rx_errors++; + ucce &= ~ucce; + } + } + while (ucce); + + return IRQ_HANDLED; +} + +static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupt */ + mii_clear_phy_interrupt(ugeth->mii_info); + + /* Disable PHY interrupts */ + mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); + + /* Schedule the phy change */ + schedule_work(&ugeth->tq); + + return IRQ_HANDLED; +} + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void ugeth_phy_change(void *data) +{ + struct net_device *dev = (struct net_device *)data; + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_geth_t *ug_regs; + int result = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ug_regs = ugeth->ug_regs; + + /* Delay to give the PHY a chance to change the + * register state */ + msleep(1); + + /* Update the link, speed, duplex */ + result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); + + /* Adjust the known status as long as the link + * isn't still coming up */ + if ((0 == result) || (ugeth->mii_info->link == 0)) + adjust_link(dev); + + /* Reenable interrupts, if needed */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); +} + +/* Called every so often on systems that don't interrupt + * the core for PHY changes */ +static void ugeth_phy_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + ucc_geth_private_t *ugeth = netdev_priv(dev); + + schedule_work(&ugeth->tq); + + mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); +} + +/* Keep trying aneg for some time + * If, after GFAR_AN_TIMEOUT seconds, it has not + * finished, we switch to forced. + * Either way, once the process has completed, we either + * request the interrupt, or switch the timer over to + * using ugeth_phy_timer to check status */ +static void ugeth_phy_startup_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + ucc_geth_private_t *ugeth = netdev_priv(mii_info->dev); + static int secondary = UGETH_AN_TIMEOUT; + int result; + + /* Configure the Auto-negotiation */ + result = mii_info->phyinfo->config_aneg(mii_info); + + /* If autonegotiation failed to start, and + * we haven't timed out, reset the timer, and return */ + if (result && secondary--) { + mod_timer(&ugeth->phy_info_timer, jiffies + HZ); + return; + } else if (result) { + /* Couldn't start autonegotiation. + * Try switching to forced */ + mii_info->autoneg = 0; + result = mii_info->phyinfo->config_aneg(mii_info); + + /* Forcing failed! Give up */ + if (result) { + ugeth_err("%s: Forcing failed!", mii_info->dev->name); + return; + } + } + + /* Kill the timer so it can be restarted */ + del_timer_sync(&ugeth->phy_info_timer); + + /* Grab the PHY interrupt, if necessary/possible */ + if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { + if (request_irq(ugeth->ug_info->phy_interrupt, + phy_interrupt, + SA_SHIRQ, "phy_interrupt", mii_info->dev) < 0) { + ugeth_err("%s: Can't get IRQ %d (PHY)", + mii_info->dev->name, + ugeth->ug_info->phy_interrupt); + } else { + mii_configure_phy_interrupt(ugeth->mii_info, + MII_INTERRUPT_ENABLED); + return; + } + } + + /* Start the timer again, this time in order to + * handle a change in status */ + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_timer; + ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; + mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); +} + +/* Called when something needs to use the ethernet device */ +/* Returns 0 for success. */ +static int ucc_geth_open(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + int err; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + /* Test station address */ + if (dev->dev_addr[0] & ENET_GROUP_ADDR) { + ugeth_err("%s: Multicast address used for station address" + " - is this what you wanted?", __FUNCTION__); + return -EINVAL; + } + + err = ucc_geth_startup(ugeth); + if (err) { + ugeth_err("%s: Cannot configure net device, aborting.", + dev->name); + return err; + } + + err = adjust_enet_interface(ugeth); + if (err) { + ugeth_err("%s: Cannot configure net device, aborting.", + dev->name); + return err; + } + + /* Set MACSTNADDR1, MACSTNADDR2 */ + /* For more details see the hardware spec. */ + init_mac_station_addr_regs(dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5], + &ugeth->ug_regs->macstnaddr1, + &ugeth->ug_regs->macstnaddr2); + + err = init_phy(dev); + if (err) { + ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); + return err; + } +#ifndef CONFIG_UGETH_NAPI + err = + request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, + "UCC Geth", dev); + if (err) { + ugeth_err("%s: Cannot get IRQ for net device, aborting.", + dev->name); + ucc_geth_stop(ugeth); + return err; + } +#endif /* CONFIG_UGETH_NAPI */ + + /* Set up the PHY change work queue */ + INIT_WORK(&ugeth->tq, ugeth_phy_change, dev); + + init_timer(&ugeth->phy_info_timer); + ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; + ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; + mod_timer(&ugeth->phy_info_timer, jiffies + HZ); + + err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + if (err) { + ugeth_err("%s: Cannot enable net device, aborting.", dev->name); + ucc_geth_stop(ugeth); + return err; + } + + netif_start_queue(dev); + + return err; +} + +/* Stops the kernel queue, and halts the controller */ +static int ucc_geth_close(struct net_device *dev) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ucc_geth_stop(ugeth); + + /* Shutdown the PHY */ + if (ugeth->mii_info->phyinfo->close) + ugeth->mii_info->phyinfo->close(ugeth->mii_info); + + kfree(ugeth->mii_info); + + netif_stop_queue(dev); + + return 0; +} + +struct ethtool_ops ucc_geth_ethtool_ops = { + .get_settings = NULL, + .get_drvinfo = NULL, + .get_regs_len = NULL, + .get_regs = NULL, + .get_link = NULL, + .get_coalesce = NULL, + .set_coalesce = NULL, + .get_ringparam = NULL, + .set_ringparam = NULL, + .get_strings = NULL, + .get_stats_count = NULL, + .get_ethtool_stats = NULL, +}; + +static int ucc_geth_probe(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct ucc_geth_platform_data *ugeth_pdata; + struct net_device *dev = NULL; + struct ucc_geth_private *ugeth = NULL; + struct ucc_geth_info *ug_info; + int err; + static int mii_mng_configured = 0; + + ugeth_vdbg("%s: IN", __FUNCTION__); + + ugeth_pdata = (struct ucc_geth_platform_data *)pdev->dev.platform_data; + + ug_info = &ugeth_info[pdev->id]; + ug_info->uf_info.ucc_num = pdev->id; + ug_info->uf_info.rx_clock = ugeth_pdata->rx_clock; + ug_info->uf_info.tx_clock = ugeth_pdata->tx_clock; + ug_info->uf_info.regs = ugeth_pdata->phy_reg_addr; + ug_info->uf_info.irq = platform_get_irq(pdev, 0); + ug_info->phy_address = ugeth_pdata->phy_id; + ug_info->enet_interface = ugeth_pdata->phy_interface; + ug_info->board_flags = ugeth_pdata->board_flags; + ug_info->phy_interrupt = ugeth_pdata->phy_interrupt; + + printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", + ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, + ug_info->uf_info.irq); + + if (ug_info == NULL) { + ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__, + pdev->id); + return -ENODEV; + } + + if (!mii_mng_configured) { + ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num); + mii_mng_configured = 1; + } + + /* Create an ethernet device instance */ + dev = alloc_etherdev(sizeof(*ugeth)); + + if (dev == NULL) + return -ENOMEM; + + ugeth = netdev_priv(dev); + spin_lock_init(&ugeth->lock); + + dev_set_drvdata(device, dev); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long)(ug_info->uf_info.regs); + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, device); + + /* Fill in the dev structure */ + dev->open = ucc_geth_open; + dev->hard_start_xmit = ucc_geth_start_xmit; + dev->tx_timeout = ucc_geth_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_UGETH_NAPI + dev->poll = ucc_geth_poll; + dev->weight = UCC_GETH_DEV_WEIGHT; +#endif /* CONFIG_UGETH_NAPI */ + dev->stop = ucc_geth_close; + dev->get_stats = ucc_geth_get_stats; +// dev->change_mtu = ucc_geth_change_mtu; + dev->mtu = 1500; + dev->set_multicast_list = ucc_geth_set_multi; + dev->ethtool_ops = &ucc_geth_ethtool_ops; + + err = register_netdev(dev); + if (err) { + ugeth_err("%s: Cannot register net device, aborting.", + dev->name); + free_netdev(dev); + return err; + } + + ugeth->ug_info = ug_info; + ugeth->dev = dev; + memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6); + + return 0; +} + +static int ucc_geth_remove(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + struct ucc_geth_private *ugeth = netdev_priv(dev); + + dev_set_drvdata(device, NULL); + ucc_geth_memclean(ugeth); + free_netdev(dev); + + return 0; +} + +/* Structure for a device driver */ +static struct device_driver ucc_geth_driver = { + .name = DRV_NAME, + .bus = &platform_bus_type, + .probe = ucc_geth_probe, + .remove = ucc_geth_remove, +}; + +static int __init ucc_geth_init(void) +{ + int i; + printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); + for (i = 0; i < 8; i++) + memcpy(&(ugeth_info[i]), &ugeth_primary_info, + sizeof(ugeth_primary_info)); + + return driver_register(&ucc_geth_driver); +} + +static void __exit ucc_geth_exit(void) +{ + driver_unregister(&ucc_geth_driver); +} + +module_init(ucc_geth_init); +module_exit(ucc_geth_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION(DRV_DESC); +MODULE_LICENSE("GPL"); diff -puN /dev/null drivers/net/ucc_geth.h --- /dev/null +++ a/drivers/net/ucc_geth.h @@ -0,0 +1,1339 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * Internal header file for UCC Gigabit Ethernet unit routines. + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __UCC_GETH_H__ +#define __UCC_GETH_H__ + +#include +#include +#include + +#include +#include + +#include +#include + +#define NUM_TX_QUEUES 8 +#define NUM_RX_QUEUES 8 +#define NUM_BDS_IN_PREFETCHED_BDS 4 +#define TX_IP_OFFSET_ENTRY_MAX 8 +#define NUM_OF_PADDRS 4 +#define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 +#define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 + +typedef struct ucc_mii_mng { + u32 miimcfg; /* MII management configuration reg */ + u32 miimcom; /* MII management command reg */ + u32 miimadd; /* MII management address reg */ + u32 miimcon; /* MII management control reg */ + u32 miimstat; /* MII management status reg */ + u32 miimind; /* MII management indication reg */ +} __attribute__ ((packed)) ucc_mii_mng_t; + +typedef struct ucc_geth { + ucc_fast_t uccf; + + u32 maccfg1; /* mac configuration reg. 1 */ + u32 maccfg2; /* mac configuration reg. 2 */ + u32 ipgifg; /* interframe gap reg. */ + u32 hafdup; /* half-duplex reg. */ + u8 res1[0x10]; + ucc_mii_mng_t miimng; /* MII management structure */ + u32 ifctl; /* interface control reg */ + u32 ifstat; /* interface statux reg */ + u32 macstnaddr1; /* mac station address part 1 reg */ + u32 macstnaddr2; /* mac station address part 2 reg */ + u8 res2[0x8]; + u32 uempr; /* UCC Ethernet Mac parameter reg */ + u32 utbipar; /* UCC tbi address reg */ + u16 uescr; /* UCC Ethernet statistics control reg */ + u8 res3[0x180 - 0x15A]; + u32 tx64; /* Total number of frames (including bad + frames) transmitted that were exactly of the + minimal length (64 for un tagged, 68 for + tagged, or with length exactly equal to the + parameter MINLength */ + u32 tx127; /* Total number of frames (including bad + frames) transmitted that were between + MINLength (Including FCS length==4) and 127 + octets */ + u32 tx255; /* Total number of frames (including bad + frames) transmitted that were between 128 + (Including FCS length==4) and 255 octets */ + u32 rx64; /* Total number of frames received including + bad frames that were exactly of the mninimal + length (64 bytes) */ + u32 rx127; /* Total number of frames (including bad + frames) received that were between MINLength + (Including FCS length==4) and 127 octets */ + u32 rx255; /* Total number of frames (including bad + frames) received that were between 128 + (Including FCS length==4) and 255 octets */ + u32 txok; /* Total number of octets residing in frames + that where involved in succesfull + transmission */ + u16 txcf; /* Total number of PAUSE control frames + transmitted by this MAC */ + u8 res4[0x2]; + u32 tmca; /* Total number of frames that were transmitted + succesfully with the group address bit set + that are not broadcast frames */ + u32 tbca; /* Total number of frames transmitted + succesfully that had destination address + field equal to the broadcast address */ + u32 rxfok; /* Total number of frames received OK */ + u32 rxbok; /* Total number of octets received OK */ + u32 rbyt; /* Total number of octets received including + octets in bad frames. Must be implemented in + HW because it includes octets in frames that + never even reach the UCC */ + u32 rmca; /* Total number of frames that were received + succesfully with the group address bit set + that are not broadcast frames */ + u32 rbca; /* Total number of frames received succesfully + that had destination address equal to the + broadcast address */ + u32 scar; /* Statistics carry register */ + u32 scam; /* Statistics caryy mask register */ + u8 res5[0x200 - 0x1c4]; +} __attribute__ ((packed)) ucc_geth_t; + +/* UCC GETH TEMODR Register */ +#define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics + */ +#define TEMODER_SCHEDULER_ENABLE 0x2000 /* enable scheduler */ +#define TEMODER_IP_CHECKSUM_GENERATE 0x0400 /* generate IPv4 + checksums */ +#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200 /* enable performance + optimization + enhancement (mode1) */ +#define TEMODER_RMON_STATISTICS 0x0100 /* enable tx statistics + */ +#define TEMODER_NUM_OF_QUEUES_SHIFT (15-15) /* Number of queues << + shift */ + +/* UCC GETH TEMODR Register */ +#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000 /* enable Rx + statistics */ +#define REMODER_RX_EXTENDED_FEATURES 0x80000000 /* enable + extended + features */ +#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31-9 ) /* vlan operation + tagged << shift */ +#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10) /* vlan operation non + tagged << shift */ +#define REMODER_RX_QOS_MODE_SHIFT (31-15) /* rx QoS mode << shift + */ +#define REMODER_RMON_STATISTICS 0x00001000 /* enable rx + statistics */ +#define REMODER_RX_EXTENDED_FILTERING 0x00000800 /* extended + filtering + vs. + mpc82xx-like + filtering */ +#define REMODER_NUM_OF_QUEUES_SHIFT (31-23) /* Number of queues << + shift */ +#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008 /* enable + dynamic max + frame length + */ +#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004 /* enable + dynamic min + frame length + */ +#define REMODER_IP_CHECKSUM_CHECK 0x00000002 /* check IPv4 + checksums */ +#define REMODER_IP_ADDRESS_ALIGNMENT 0x00000001 /* align ip + address to + 4-byte + boundary */ + +/* UCC GETH Event Register */ +#define UCCE_MPD 0x80000000 /* Magic packet + detection */ +#define UCCE_SCAR 0x40000000 +#define UCCE_GRA 0x20000000 /* Tx graceful + stop + complete */ +#define UCCE_CBPR 0x10000000 +#define UCCE_BSY 0x08000000 +#define UCCE_RXC 0x04000000 +#define UCCE_TXC 0x02000000 +#define UCCE_TXE 0x01000000 +#define UCCE_TXB7 0x00800000 +#define UCCE_TXB6 0x00400000 +#define UCCE_TXB5 0x00200000 +#define UCCE_TXB4 0x00100000 +#define UCCE_TXB3 0x00080000 +#define UCCE_TXB2 0x00040000 +#define UCCE_TXB1 0x00020000 +#define UCCE_TXB0 0x00010000 +#define UCCE_RXB7 0x00008000 +#define UCCE_RXB6 0x00004000 +#define UCCE_RXB5 0x00002000 +#define UCCE_RXB4 0x00001000 +#define UCCE_RXB3 0x00000800 +#define UCCE_RXB2 0x00000400 +#define UCCE_RXB1 0x00000200 +#define UCCE_RXB0 0x00000100 +#define UCCE_RXF7 0x00000080 +#define UCCE_RXF6 0x00000040 +#define UCCE_RXF5 0x00000020 +#define UCCE_RXF4 0x00000010 +#define UCCE_RXF3 0x00000008 +#define UCCE_RXF2 0x00000004 +#define UCCE_RXF1 0x00000002 +#define UCCE_RXF0 0x00000001 + +#define UCCE_RXBF_SINGLE_MASK (UCCE_RXF0) +#define UCCE_TXBF_SINGLE_MASK (UCCE_TXB0) + +#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 |\ + UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0) +#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 |\ + UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0) +#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 |\ + UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0) +#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ + UCCE_RXC | UCCE_TXC | UCCE_TXE) + +/* UCC GETH UPSMR (Protocol Specific Mode Register) */ +#define UPSMR_ECM 0x04000000 /* Enable CAM + Miss or + Enable + Filtering + Miss */ +#define UPSMR_HSE 0x02000000 /* Hardware + Statistics + Enable */ +#define UPSMR_PRO 0x00400000 /* Promiscuous*/ +#define UPSMR_CAP 0x00200000 /* CAM polarity + */ +#define UPSMR_RSH 0x00100000 /* Receive + Short Frames + */ +#define UPSMR_RPM 0x00080000 /* Reduced Pin + Mode + interfaces */ +#define UPSMR_R10M 0x00040000 /* RGMII/RMII + 10 Mode */ +#define UPSMR_RLPB 0x00020000 /* RMII + Loopback + Mode */ +#define UPSMR_TBIM 0x00010000 /* Ten-bit + Interface + Mode */ +#define UPSMR_RMM 0x00001000 /* RMII/RGMII + Mode */ +#define UPSMR_CAM 0x00000400 /* CAM Address + Matching */ +#define UPSMR_BRO 0x00000200 /* Broadcast + Address */ +#define UPSMR_RES1 0x00002000 /* Reserved + feild - must + be 1 */ + +/* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ +#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control + Rx */ +#define MACCFG1_FLOW_TX 0x00000010 /* Flow Control + Tx */ +#define MACCFG1_ENABLE_SYNCHED_RX 0x00000008 /* Rx Enable + synchronized + to Rx stream + */ +#define MACCFG1_ENABLE_RX 0x00000004 /* Enable Rx */ +#define MACCFG1_ENABLE_SYNCHED_TX 0x00000002 /* Tx Enable + synchronized + to Tx stream + */ +#define MACCFG1_ENABLE_TX 0x00000001 /* Enable Tx */ + +/* UCC GETH MACCFG2 (MAC Configuration 2 Register) */ +#define MACCFG2_PREL_SHIFT (31 - 19) /* Preamble + Length << + shift */ +#define MACCFG2_PREL_MASK 0x0000f000 /* Preamble + Length mask */ +#define MACCFG2_SRP 0x00000080 /* Soft Receive + Preamble */ +#define MACCFG2_STP 0x00000040 /* Soft + Transmit + Preamble */ +#define MACCFG2_RESERVED_1 0x00000020 /* Reserved - + must be set + to 1 */ +#define MACCFG2_LC 0x00000010 /* Length Check + */ +#define MACCFG2_MPE 0x00000008 /* Magic packet + detect */ +#define MACCFG2_FDX 0x00000001 /* Full Duplex */ +#define MACCFG2_FDX_MASK 0x00000001 /* Full Duplex + mask */ +#define MACCFG2_PAD_CRC 0x00000004 +#define MACCFG2_CRC_EN 0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_NONE 0x00000000 /* Neither + Padding + short frames + nor CRC */ +#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY 0x00000002 /* Append CRC + only */ +#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC 0x00000004 +#define MACCFG2_INTERFACE_MODE_NIBBLE 0x00000100 /* nibble mode + (MII/RMII/RGMII + 10/100bps) */ +#define MACCFG2_INTERFACE_MODE_BYTE 0x00000200 /* byte mode + (GMII/TBI/RTB/RGMII + 1000bps ) */ +#define MACCFG2_INTERFACE_MODE_MASK 0x00000300 /* mask + covering all + relevant + bits */ + +/* UCC GETH IPGIFG (Inter-frame Gap / Inter-Frame Gap Register) */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT (31 - 7) /* Non + back-to-back + inter frame + gap part 1. + << shift */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT (31 - 15) /* Non + back-to-back + inter frame + gap part 2. + << shift */ +#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT (31 - 23) /* Mimimum IFG + Enforcement + << shift */ +#define IPGIFG_BACK_TO_BACK_IFG_SHIFT (31 - 31) /* back-to-back + inter frame + gap << shift + */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX 127 /* Non back-to-back + inter frame gap part + 1. max val */ +#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX 127 /* Non back-to-back + inter frame gap part + 2. max val */ +#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX 255 /* Mimimum IFG + Enforcement max val */ +#define IPGIFG_BACK_TO_BACK_IFG_MAX 127 /* back-to-back inter + frame gap max val */ +#define IPGIFG_NBTB_CS_IPG_MASK 0x7F000000 +#define IPGIFG_NBTB_IPG_MASK 0x007F0000 +#define IPGIFG_MIN_IFG_MASK 0x0000FF00 +#define IPGIFG_BTB_IPG_MASK 0x0000007F + +/* UCC GETH HAFDUP (Half Duplex Register) */ +#define HALFDUP_ALT_BEB_TRUNCATION_SHIFT (31 - 11) /* Alternate + Binary + Exponential + Backoff + Truncation + << shift */ +#define HALFDUP_ALT_BEB_TRUNCATION_MAX 0xf /* Alternate Binary + Exponential Backoff + Truncation max val */ +#define HALFDUP_ALT_BEB 0x00080000 /* Alternate + Binary + Exponential + Backoff */ +#define HALFDUP_BACK_PRESSURE_NO_BACKOFF 0x00040000 /* Back + pressure no + backoff */ +#define HALFDUP_NO_BACKOFF 0x00020000 /* No Backoff */ +#define HALFDUP_EXCESSIVE_DEFER 0x00010000 /* Excessive + Defer */ +#define HALFDUP_MAX_RETRANSMISSION_SHIFT (31 - 19) /* Maximum + Retransmission + << shift */ +#define HALFDUP_MAX_RETRANSMISSION_MAX 0xf /* Maximum + Retransmission max + val */ +#define HALFDUP_COLLISION_WINDOW_SHIFT (31 - 31) /* Collision + Window << + shift */ +#define HALFDUP_COLLISION_WINDOW_MAX 0x3f /* Collision Window max + val */ +#define HALFDUP_ALT_BEB_TR_MASK 0x00F00000 +#define HALFDUP_RETRANS_MASK 0x0000F000 +#define HALFDUP_COL_WINDOW_MASK 0x0000003F + +/* UCC GETH UCCS (Ethernet Status Register) */ +#define UCCS_BPR 0x02 /* Back pressure (in + half duplex mode) */ +#define UCCS_PAU 0x02 /* Pause state (in full + duplex mode) */ +#define UCCS_MPD 0x01 /* Magic Packet + Detected */ + +/* UCC GETH MIIMCFG (MII Management Configuration Register) */ +#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset + management */ +#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble + suppress */ +#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide + << shift */ +#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 + */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by + 112 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by + 160 */ +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by + 224 */ + +/* UCC GETH MIIMCOM (MII Management Command Register) */ +#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ + +/* UCC GETH MIIMADD (MII Management Address Register) */ +#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address + << shift */ +#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register + << shift */ + +/* UCC GETH MIIMCON (MII Management Control Register) */ +#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control + << shift */ +#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status + << shift */ + +/* UCC GETH MIIMIND (MII Management Indicator Register) */ +#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ +#define MIIMIND_SCAN 0x00000002 /* Scan in + progress */ +#define MIIMIND_BUSY 0x00000001 + +/* UCC GETH IFSTAT (Interface Status Register) */ +#define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive + transmission + defer */ + +/* UCC GETH MACSTNADDR1 (Station Address Part 1 Register) */ +#define MACSTNADDR1_OCTET_6_SHIFT (31 - 7) /* Station + address 6th + octet << + shift */ +#define MACSTNADDR1_OCTET_5_SHIFT (31 - 15) /* Station + address 5th + octet << + shift */ +#define MACSTNADDR1_OCTET_4_SHIFT (31 - 23) /* Station + address 4th + octet << + shift */ +#define MACSTNADDR1_OCTET_3_SHIFT (31 - 31) /* Station + address 3rd + octet << + shift */ + +/* UCC GETH MACSTNADDR2 (Station Address Part 2 Register) */ +#define MACSTNADDR2_OCTET_2_SHIFT (31 - 7) /* Station + address 2nd + octet << + shift */ +#define MACSTNADDR2_OCTET_1_SHIFT (31 - 15) /* Station + address 1st + octet << + shift */ + +/* UCC GETH UEMPR (Ethernet Mac Parameter Register) */ +#define UEMPR_PAUSE_TIME_VALUE_SHIFT (31 - 15) /* Pause time + value << + shift */ +#define UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT (31 - 31) /* Extended + pause time + value << + shift */ + +/* UCC GETH UTBIPAR (Ten Bit Interface Physical Address Register) */ +#define UTBIPAR_PHY_ADDRESS_SHIFT (31 - 31) /* Phy address + << shift */ +#define UTBIPAR_PHY_ADDRESS_MASK 0x0000001f /* Phy address + mask */ + +/* UCC GETH UESCR (Ethernet Statistics Control Register) */ +#define UESCR_AUTOZ 0x8000 /* Automatically zero + addressed + statistical counter + values */ +#define UESCR_CLRCNT 0x4000 /* Clear all statistics + counters */ +#define UESCR_MAXCOV_SHIFT (15 - 7) /* Max + Coalescing + Value << + shift */ +#define UESCR_SCOV_SHIFT (15 - 15) /* Status + Coalescing + Value << + shift */ + +/* UCC GETH UDSR (Data Synchronization Register) */ +#define UDSR_MAGIC 0x067E + +typedef struct ucc_geth_thread_data_tx { + u8 res0[104]; +} __attribute__ ((packed)) ucc_geth_thread_data_tx_t; + +typedef struct ucc_geth_thread_data_rx { + u8 res0[40]; +} __attribute__ ((packed)) ucc_geth_thread_data_rx_t; + +/* Send Queue Queue-Descriptor */ +typedef struct ucc_geth_send_queue_qd { + u32 bd_ring_base; /* pointer to BD ring base address */ + u8 res0[0x8]; + u32 last_bd_completed_address;/* initialize to last entry in BD ring */ + u8 res1[0x30]; +} __attribute__ ((packed)) ucc_geth_send_queue_qd_t; + +typedef struct ucc_geth_send_queue_mem_region { + ucc_geth_send_queue_qd_t sqqd[NUM_TX_QUEUES]; +} __attribute__ ((packed)) ucc_geth_send_queue_mem_region_t; + +typedef struct ucc_geth_thread_tx_pram { + u8 res0[64]; +} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t; + +typedef struct ucc_geth_thread_rx_pram { + u8 res0[128]; +} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t; + +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64 +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64 +#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16 96 + +typedef struct ucc_geth_scheduler { + u16 cpucount0; /* CPU packet counter */ + u16 cpucount1; /* CPU packet counter */ + u16 cecount0; /* QE packet counter */ + u16 cecount1; /* QE packet counter */ + u16 cpucount2; /* CPU packet counter */ + u16 cpucount3; /* CPU packet counter */ + u16 cecount2; /* QE packet counter */ + u16 cecount3; /* QE packet counter */ + u16 cpucount4; /* CPU packet counter */ + u16 cpucount5; /* CPU packet counter */ + u16 cecount4; /* QE packet counter */ + u16 cecount5; /* QE packet counter */ + u16 cpucount6; /* CPU packet counter */ + u16 cpucount7; /* CPU packet counter */ + u16 cecount6; /* QE packet counter */ + u16 cecount7; /* QE packet counter */ + u32 weightstatus[NUM_TX_QUEUES]; /* accumulated weight factor */ + u32 rtsrshadow; /* temporary variable handled by QE */ + u32 time; /* temporary variable handled by QE */ + u32 ttl; /* temporary variable handled by QE */ + u32 mblinterval; /* max burst length interval */ + u16 nortsrbytetime; /* normalized value of byte time in tsr units */ + u8 fracsiz; /* radix 2 log value of denom. of + NorTSRByteTime */ + u8 res0[1]; + u8 strictpriorityq; /* Strict Priority Mask register */ + u8 txasap; /* Transmit ASAP register */ + u8 extrabw; /* Extra BandWidth register */ + u8 oldwfqmask; /* temporary variable handled by QE */ + u8 weightfactor[NUM_TX_QUEUES]; + /**< weight factor for queues */ + u32 minw; /* temporary variable handled by QE */ + u8 res1[0x70 - 0x64]; +} __attribute__ ((packed)) ucc_geth_scheduler_t; + +typedef struct ucc_geth_tx_firmware_statistics_pram { + u32 sicoltx; /* single collision */ + u32 mulcoltx; /* multiple collision */ + u32 latecoltxfr; /* late collision */ + u32 frabortduecol; /* frames aborted due to transmit collision */ + u32 frlostinmactxer; /* frames lost due to internal MAC error + transmission that are not counted on any + other counter */ + u32 carriersenseertx; /* carrier sense error */ + u32 frtxok; /* frames transmitted OK */ + u32 txfrexcessivedefer; /* frames with defferal time greater than + specified threshold */ + u32 txpkts256; /* total packets (including bad) between 256 + and 511 octets */ + u32 txpkts512; /* total packets (including bad) between 512 + and 1023 octets */ + u32 txpkts1024; /* total packets (including bad) between 1024 + and 1518 octets */ + u32 txpktsjumbo; /* total packets (including bad) between 1024 + and MAXLength octets */ +} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t; + +typedef struct ucc_geth_rx_firmware_statistics_pram { + u32 frrxfcser; /* frames with crc error */ + u32 fraligner; /* frames with alignment error */ + u32 inrangelenrxer; /* in range length error */ + u32 outrangelenrxer; /* out of range length error */ + u32 frtoolong; /* frame too long */ + u32 runt; /* runt */ + u32 verylongevent; /* very long event */ + u32 symbolerror; /* symbol error */ + u32 dropbsy; /* drop because of BD not ready */ + u8 res0[0x8]; + u32 mismatchdrop; /* drop because of MAC filtering (e.g. address + or type mismatch) */ + u32 underpkts; /* total frames less than 64 octets */ + u32 pkts256; /* total frames (including bad) between 256 and + 511 octets */ + u32 pkts512; /* total frames (including bad) between 512 and + 1023 octets */ + u32 pkts1024; /* total frames (including bad) between 1024 + and 1518 octets */ + u32 pktsjumbo; /* total frames (including bad) between 1024 + and MAXLength octets */ + u32 frlossinmacer; /* frames lost because of internal MAC error + that is not counted in any other counter */ + u32 pausefr; /* pause frames */ + u8 res1[0x4]; + u32 removevlan; /* total frames that had their VLAN tag removed + */ + u32 replacevlan; /* total frames that had their VLAN tag + replaced */ + u32 insertvlan; /* total frames that had their VLAN tag + inserted */ +} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t; + +typedef struct ucc_geth_rx_interrupt_coalescing_entry { + u32 interruptcoalescingmaxvalue; /* interrupt coalescing max + value */ + u32 interruptcoalescingcounter; /* interrupt coalescing counter, + initialize to + interruptcoalescingmaxvalue */ +} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_entry_t; + +typedef struct ucc_geth_rx_interrupt_coalescing_table { + ucc_geth_rx_interrupt_coalescing_entry_t coalescingentry[NUM_RX_QUEUES]; + /**< interrupt coalescing entry */ +} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t; + +typedef struct ucc_geth_rx_prefetched_bds { + qe_bd_t bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */ +} __attribute__ ((packed)) ucc_geth_rx_prefetched_bds_t; + +typedef struct ucc_geth_rx_bd_queues_entry { + u32 bdbaseptr; /* BD base pointer */ + u32 bdptr; /* BD pointer */ + u32 externalbdbaseptr; /* external BD base pointer */ + u32 externalbdptr; /* external BD pointer */ +} __attribute__ ((packed)) ucc_geth_rx_bd_queues_entry_t; + +typedef struct ucc_geth_tx_global_pram { + u16 temoder; + u8 res0[0x38 - 0x02]; + u32 sqptr; /* a base pointer to send queue memory region */ + u32 schedulerbasepointer; /* a base pointer to scheduler memory + region */ + u32 txrmonbaseptr; /* base pointer to Tx RMON statistics counter */ + u32 tstate; /* tx internal state. High byte contains + function code */ + u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; + u32 vtagtable[0x8]; /* 8 4-byte VLAN tags */ + u32 tqptr; /* a base pointer to the Tx Queues Memory + Region */ + u8 res2[0x80 - 0x74]; +} __attribute__ ((packed)) ucc_geth_tx_global_pram_t; + +/* structure representing Extended Filtering Global Parameters in PRAM */ +typedef struct ucc_geth_exf_global_pram { + u32 l2pcdptr; /* individual address filter, high */ + u8 res0[0x10 - 0x04]; +} __attribute__ ((packed)) ucc_geth_exf_global_pram_t; + +typedef struct ucc_geth_rx_global_pram { + u32 remoder; /* ethernet mode reg. */ + u32 rqptr; /* base pointer to the Rx Queues Memory Region*/ + u32 res0[0x1]; + u8 res1[0x20 - 0xC]; + u16 typeorlen; /* cutoff point less than which, type/len field + is considered length */ + u8 res2[0x1]; + u8 rxgstpack; /* acknowledgement on GRACEFUL STOP RX command*/ + u32 rxrmonbaseptr; /* base pointer to Rx RMON statistics counter */ + u8 res3[0x30 - 0x28]; + u32 intcoalescingptr; /* Interrupt coalescing table pointer */ + u8 res4[0x36 - 0x34]; + u8 rstate; /* rx internal state. High byte contains + function code */ + u8 res5[0x46 - 0x37]; + u16 mrblr; /* max receive buffer length reg. */ + u32 rbdqptr; /* base pointer to RxBD parameter table + description */ + u16 mflr; /* max frame length reg. */ + u16 minflr; /* min frame length reg. */ + u16 maxd1; /* max dma1 length reg. */ + u16 maxd2; /* max dma2 length reg. */ + u32 ecamptr; /* external CAM address */ + u32 l2qt; /* VLAN priority mapping table. */ + u32 l3qt[0x8]; /* IP priority mapping table. */ + u16 vlantype; /* vlan type */ + u16 vlantci; /* default vlan tci */ + u8 addressfiltering[64]; /* address filtering data structure */ + u32 exfGlobalParam; /* base address for extended filtering global + parameters */ + u8 res6[0x100 - 0xC4]; /* Initialize to zero */ +} __attribute__ ((packed)) ucc_geth_rx_global_pram_t; + +#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01 + +/* structure representing InitEnet command */ +typedef struct ucc_geth_init_pram { + u8 resinit1; + u8 resinit2; + u8 resinit3; + u8 resinit4; + u16 resinit5; + u8 res1[0x1]; + u8 largestexternallookupkeysize; + u32 rgftgfrxglobal; + u32 rxthread[ENET_INIT_PARAM_MAX_ENTRIES_RX]; /* rx threads */ + u8 res2[0x38 - 0x30]; + u32 txglobal; /* tx global */ + u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */ + u8 res3[0x1]; +} __attribute__ ((packed)) ucc_geth_init_pram_t; + +#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4) +#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8) + +#define ENET_INIT_PARAM_RISC_MASK 0x0000003f +#define ENET_INIT_PARAM_PTR_MASK 0x00ffffc0 +#define ENET_INIT_PARAM_SNUM_MASK 0xff000000 +#define ENET_INIT_PARAM_SNUM_SHIFT 24 + +#define ENET_INIT_PARAM_MAGIC_RES_INIT1 0x06 +#define ENET_INIT_PARAM_MAGIC_RES_INIT2 0x30 +#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0xff +#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x00 +#define ENET_INIT_PARAM_MAGIC_RES_INIT5 0x0400 + +/* structure representing 82xx Address Filtering Enet Address in PRAM */ +typedef struct ucc_geth_82xx_enet_address { + u8 res1[0x2]; + u16 h; /* address (MSB) */ + u16 m; /* address */ + u16 l; /* address (LSB) */ +} __attribute__ ((packed)) ucc_geth_82xx_enet_address_t; + +/* structure representing 82xx Address Filtering PRAM */ +typedef struct ucc_geth_82xx_address_filtering_pram { + u32 iaddr_h; /* individual address filter, high */ + u32 iaddr_l; /* individual address filter, low */ + u32 gaddr_h; /* group address filter, high */ + u32 gaddr_l; /* group address filter, low */ + ucc_geth_82xx_enet_address_t taddr; + ucc_geth_82xx_enet_address_t paddr[NUM_OF_PADDRS]; + u8 res0[0x40 - 0x38]; +} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t; + +/* GETH Tx firmware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_tx_firmware_statistics { + u32 sicoltx; /* single collision */ + u32 mulcoltx; /* multiple collision */ + u32 latecoltxfr; /* late collision */ + u32 frabortduecol; /* frames aborted due to transmit collision */ + u32 frlostinmactxer; /* frames lost due to internal MAC error + transmission that are not counted on any + other counter */ + u32 carriersenseertx; /* carrier sense error */ + u32 frtxok; /* frames transmitted OK */ + u32 txfrexcessivedefer; /* frames with defferal time greater than + specified threshold */ + u32 txpkts256; /* total packets (including bad) between 256 + and 511 octets */ + u32 txpkts512; /* total packets (including bad) between 512 + and 1023 octets */ + u32 txpkts1024; /* total packets (including bad) between 1024 + and 1518 octets */ + u32 txpktsjumbo; /* total packets (including bad) between 1024 + and MAXLength octets */ +} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t; + +/* GETH Rx firmware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_rx_firmware_statistics { + u32 frrxfcser; /* frames with crc error */ + u32 fraligner; /* frames with alignment error */ + u32 inrangelenrxer; /* in range length error */ + u32 outrangelenrxer; /* out of range length error */ + u32 frtoolong; /* frame too long */ + u32 runt; /* runt */ + u32 verylongevent; /* very long event */ + u32 symbolerror; /* symbol error */ + u32 dropbsy; /* drop because of BD not ready */ + u8 res0[0x8]; + u32 mismatchdrop; /* drop because of MAC filtering (e.g. address + or type mismatch) */ + u32 underpkts; /* total frames less than 64 octets */ + u32 pkts256; /* total frames (including bad) between 256 and + 511 octets */ + u32 pkts512; /* total frames (including bad) between 512 and + 1023 octets */ + u32 pkts1024; /* total frames (including bad) between 1024 + and 1518 octets */ + u32 pktsjumbo; /* total frames (including bad) between 1024 + and MAXLength octets */ + u32 frlossinmacer; /* frames lost because of internal MAC error + that is not counted in any other counter */ + u32 pausefr; /* pause frames */ + u8 res1[0x4]; + u32 removevlan; /* total frames that had their VLAN tag removed + */ + u32 replacevlan; /* total frames that had their VLAN tag + replaced */ + u32 insertvlan; /* total frames that had their VLAN tag + inserted */ +} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t; + +/* GETH hardware statistics structure, used when calling + UCC_GETH_GetStatistics. */ +typedef struct ucc_geth_hardware_statistics { + u32 tx64; /* Total number of frames (including bad + frames) transmitted that were exactly of the + minimal length (64 for un tagged, 68 for + tagged, or with length exactly equal to the + parameter MINLength */ + u32 tx127; /* Total number of frames (including bad + frames) transmitted that were between + MINLength (Including FCS length==4) and 127 + octets */ + u32 tx255; /* Total number of frames (including bad + frames) transmitted that were between 128 + (Including FCS length==4) and 255 octets */ + u32 rx64; /* Total number of frames received including + bad frames that were exactly of the mninimal + length (64 bytes) */ + u32 rx127; /* Total number of frames (including bad + frames) received that were between MINLength + (Including FCS length==4) and 127 octets */ + u32 rx255; /* Total number of frames (including bad + frames) received that were between 128 + (Including FCS length==4) and 255 octets */ + u32 txok; /* Total number of octets residing in frames + that where involved in succesfull + transmission */ + u16 txcf; /* Total number of PAUSE control frames + transmitted by this MAC */ + u32 tmca; /* Total number of frames that were transmitted + succesfully with the group address bit set + that are not broadcast frames */ + u32 tbca; /* Total number of frames transmitted + succesfully that had destination address + field equal to the broadcast address */ + u32 rxfok; /* Total number of frames received OK */ + u32 rxbok; /* Total number of octets received OK */ + u32 rbyt; /* Total number of octets received including + octets in bad frames. Must be implemented in + HW because it includes octets in frames that + never even reach the UCC */ + u32 rmca; /* Total number of frames that were received + succesfully with the group address bit set + that are not broadcast frames */ + u32 rbca; /* Total number of frames received succesfully + that had destination address equal to the + broadcast address */ +} __attribute__ ((packed)) ucc_geth_hardware_statistics_t; + +/* UCC GETH Tx errors returned via TxConf callback */ +#define TX_ERRORS_DEF 0x0200 +#define TX_ERRORS_EXDEF 0x0100 +#define TX_ERRORS_LC 0x0080 +#define TX_ERRORS_RL 0x0040 +#define TX_ERRORS_RC_MASK 0x003C +#define TX_ERRORS_RC_SHIFT 2 +#define TX_ERRORS_UN 0x0002 +#define TX_ERRORS_CSL 0x0001 + +/* UCC GETH Rx errors returned via RxStore callback */ +#define RX_ERRORS_CMR 0x0200 +#define RX_ERRORS_M 0x0100 +#define RX_ERRORS_BC 0x0080 +#define RX_ERRORS_MC 0x0040 + +/* Transmit BD. These are in addition to values defined in uccf. */ +#define T_VID 0x003c0000 /* insert VLAN id index mask. */ +#define T_DEF (((u32) TX_ERRORS_DEF ) << 16) +#define T_EXDEF (((u32) TX_ERRORS_EXDEF ) << 16) +#define T_LC (((u32) TX_ERRORS_LC ) << 16) +#define T_RL (((u32) TX_ERRORS_RL ) << 16) +#define T_RC_MASK (((u32) TX_ERRORS_RC_MASK ) << 16) +#define T_UN (((u32) TX_ERRORS_UN ) << 16) +#define T_CSL (((u32) TX_ERRORS_CSL ) << 16) +#define T_ERRORS_REPORT (T_DEF | T_EXDEF | T_LC | T_RL | T_RC_MASK \ + | T_UN | T_CSL) /* transmit errors to report */ + +/* Receive BD. These are in addition to values defined in uccf. */ +#define R_LG 0x00200000 /* Frame length violation. */ +#define R_NO 0x00100000 /* Non-octet aligned frame. */ +#define R_SH 0x00080000 /* Short frame. */ +#define R_CR 0x00040000 /* CRC error. */ +#define R_OV 0x00020000 /* Overrun. */ +#define R_IPCH 0x00010000 /* IP checksum check failed. */ +#define R_CMR (((u32) RX_ERRORS_CMR ) << 16) +#define R_M (((u32) RX_ERRORS_M ) << 16) +#define R_BC (((u32) RX_ERRORS_BC ) << 16) +#define R_MC (((u32) RX_ERRORS_MC ) << 16) +#define R_ERRORS_REPORT (R_CMR | R_M | R_BC | R_MC) /* receive errors to + report */ +#define R_ERRORS_FATAL (R_LG | R_NO | R_SH | R_CR | \ + R_OV | R_IPCH) /* receive errors to discard */ + +/* Alignments */ +#define UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT 256 +#define UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT 128 +#define UCC_GETH_THREAD_RX_PRAM_ALIGNMENT 128 +#define UCC_GETH_THREAD_TX_PRAM_ALIGNMENT 64 +#define UCC_GETH_THREAD_DATA_ALIGNMENT 256 /* spec gives values + based on num of + threads, but always + using the maximum is + easier */ +#define UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT 32 +#define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */ +#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a + guess */ +#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */ +#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */ +#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This + is a + guess + */ +#define UCC_GETH_RX_BD_RING_ALIGNMENT 32 +#define UCC_GETH_TX_BD_RING_ALIGNMENT 32 +#define UCC_GETH_MRBLR_ALIGNMENT 128 +#define UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT 4 +#define UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT 32 +#define UCC_GETH_RX_DATA_BUF_ALIGNMENT 64 + +#define UCC_GETH_TAD_EF 0x80 +#define UCC_GETH_TAD_V 0x40 +#define UCC_GETH_TAD_REJ 0x20 +#define UCC_GETH_TAD_VTAG_OP_RIGHT_SHIFT 2 +#define UCC_GETH_TAD_VTAG_OP_SHIFT 6 +#define UCC_GETH_TAD_V_NON_VTAG_OP 0x20 +#define UCC_GETH_TAD_RQOS_SHIFT 0 +#define UCC_GETH_TAD_V_PRIORITY_SHIFT 5 +#define UCC_GETH_TAD_CFI 0x10 + +#define UCC_GETH_VLAN_PRIORITY_MAX 8 +#define UCC_GETH_IP_PRIORITY_MAX 64 +#define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX 8 +#define UCC_GETH_RX_BD_RING_SIZE_MIN 8 +#define UCC_GETH_TX_BD_RING_SIZE_MIN 2 + +#define UCC_GETH_SIZE_OF_BD QE_SIZEOF_BD + +/* Driver definitions */ +#define TX_BD_RING_LEN 0x10 +#define RX_BD_RING_LEN 0x10 +#define UCC_GETH_DEV_WEIGHT TX_BD_RING_LEN + +#define TX_RING_MOD_MASK(size) (size-1) +#define RX_RING_MOD_MASK(size) (size-1) + +#define ENET_NUM_OCTETS_PER_ADDRESS 6 +#define ENET_GROUP_ADDR 0x01 /* Group address mask + for ethernet + addresses */ + +#define TX_TIMEOUT (1*HZ) +#define SKB_ALLOC_TIMEOUT 100000 +#define PHY_INIT_TIMEOUT 100000 +#define PHY_CHANGE_TIME 2 + +/* Fast Ethernet (10/100 Mbps) */ +#define UCC_GETH_URFS_INIT 512 /* Rx virtual FIFO size + */ +#define UCC_GETH_URFET_INIT 256 /* 1/2 urfs */ +#define UCC_GETH_URFSET_INIT 384 /* 3/4 urfs */ +#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size + */ +#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */ +#define UCC_GETH_UTFTT_INIT 128 +/* Gigabit Ethernet (1000 Mbps) */ +#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual + FIFO size */ +#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ /* 1/2 urfs */ +#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ /* 3/4 urfs */ +#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ /* Tx virtual + FIFO size */ +#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ /* 1/2 utfs */ +#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ /* */ + +#define UCC_GETH_REMODER_INIT 0 /* bits that must be + set */ +#define UCC_GETH_TEMODER_INIT 0xC000 /* bits that must */ +#define UCC_GETH_UPSMR_INIT (UPSMR_RES1) /* Start value + for this + register */ +#define UCC_GETH_MACCFG1_INIT 0 +#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) +#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ + (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) + +/* Ethernet speed */ +typedef enum enet_speed { + ENET_SPEED_10BT, /* 10 Base T */ + ENET_SPEED_100BT, /* 100 Base T */ + ENET_SPEED_1000BT /* 1000 Base T */ +} enet_speed_e; + +/* Ethernet Address Type. */ +typedef enum enet_addr_type { + ENET_ADDR_TYPE_INDIVIDUAL, + ENET_ADDR_TYPE_GROUP, + ENET_ADDR_TYPE_BROADCAST +} enet_addr_type_e; + +/* TBI / MII Set Register */ +typedef enum enet_tbi_mii_reg { + ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ + ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ + ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ + ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability + (ANLPBPA) */ + ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ + ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ + ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page + (ANLPANP) */ + ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ + ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ + ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ +} enet_tbi_mii_reg_e; + +/* UCC GETH 82xx Ethernet Address Recognition Location */ +typedef enum ucc_geth_enet_address_recognition_location { + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station + address */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_FIRST, /* additional + station + address + paddr1 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR2, /* additional + station + address + paddr2 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR3, /* additional + station + address + paddr3 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_LAST, /* additional + station + address + paddr4 */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH, /* group hash */ + UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH /* individual + hash */ +} ucc_geth_enet_address_recognition_location_e; + +/* UCC GETH vlan operation tagged */ +typedef enum ucc_geth_vlan_operation_tagged { + UCC_GETH_VLAN_OPERATION_TAGGED_NOP = 0x0, /* Tagged - nop */ + UCC_GETH_VLAN_OPERATION_TAGGED_REPLACE_VID_PORTION_OF_Q_TAG + = 0x1, /* Tagged - replace vid portion of q tag */ + UCC_GETH_VLAN_OPERATION_TAGGED_IF_VID0_REPLACE_VID_WITH_DEFAULT_VALUE + = 0x2, /* Tagged - if vid0 replace vid with default value */ + UCC_GETH_VLAN_OPERATION_TAGGED_EXTRACT_Q_TAG_FROM_FRAME + = 0x3 /* Tagged - extract q tag from frame */ +} ucc_geth_vlan_operation_tagged_e; + +/* UCC GETH vlan operation non-tagged */ +typedef enum ucc_geth_vlan_operation_non_tagged { + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP = 0x0, /* Non tagged - nop */ + UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT = 0x1 /* Non tagged - + q tag insert + */ +} ucc_geth_vlan_operation_non_tagged_e; + +/* UCC GETH Rx Quality of Service Mode */ +typedef enum ucc_geth_qos_mode { + UCC_GETH_QOS_MODE_DEFAULT = 0x0, /* default queue */ + UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L2_CRITERIA = 0x1, /* queue + determined + by L2 + criteria */ + UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L3_CRITERIA = 0x2 /* queue + determined + by L3 + criteria */ +} ucc_geth_qos_mode_e; + +/* UCC GETH Statistics Gathering Mode - These are bit flags, 'or' them together + for combined functionality */ +typedef enum ucc_geth_statistics_gathering_mode { + UCC_GETH_STATISTICS_GATHERING_MODE_NONE = 0x00000000, /* No + statistics + gathering */ + UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE = 0x00000001,/* Enable + hardware + statistics + gathering + */ + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX = 0x00000004,/*Enable + firmware + tx + statistics + gathering + */ + UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX = 0x00000008/* Enable + firmware + rx + statistics + gathering + */ +} ucc_geth_statistics_gathering_mode_e; + +/* UCC GETH Pad and CRC Mode - Note, Padding without CRC is not possible */ +typedef enum ucc_geth_maccfg2_pad_and_crc_mode { + UCC_GETH_PAD_AND_CRC_MODE_NONE + = MACCFG2_PAD_AND_CRC_MODE_NONE, /* Neither Padding + short frames + nor CRC */ + UCC_GETH_PAD_AND_CRC_MODE_CRC_ONLY + = MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY, /* Append + CRC only */ + UCC_GETH_PAD_AND_CRC_MODE_PAD_AND_CRC = + MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC +} ucc_geth_maccfg2_pad_and_crc_mode_e; + +/* UCC GETH upsmr Flow Control Mode */ +typedef enum ucc_geth_flow_control_mode { + UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE = 0x00000000, /* No automatic + flow control + */ + UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_PAUSE_WHEN_EMERGENCY + = 0x00004000 /* Send pause frame when RxFIFO reaches its + emergency threshold */ +} ucc_geth_flow_control_mode_e; + +/* UCC GETH number of threads */ +typedef enum ucc_geth_num_of_threads { + UCC_GETH_NUM_OF_THREADS_1 = 0x1, /* 1 */ + UCC_GETH_NUM_OF_THREADS_2 = 0x2, /* 2 */ + UCC_GETH_NUM_OF_THREADS_4 = 0x0, /* 4 */ + UCC_GETH_NUM_OF_THREADS_6 = 0x3, /* 6 */ + UCC_GETH_NUM_OF_THREADS_8 = 0x4 /* 8 */ +} ucc_geth_num_of_threads_e; + +/* UCC GETH number of station addresses */ +typedef enum ucc_geth_num_of_station_addresses { + UCC_GETH_NUM_OF_STATION_ADDRESSES_1, /* 1 */ + UCC_GETH_NUM_OF_STATION_ADDRESSES_5 /* 5 */ +} ucc_geth_num_of_station_addresses_e; + +typedef u8 enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS]; + +/* UCC GETH 82xx Ethernet Address Container */ +typedef struct enet_addr_container { + enet_addr_t address; /* ethernet address */ + ucc_geth_enet_address_recognition_location_e location; /* location in + 82xx address + recognition + hardware */ + struct list_head node; +} enet_addr_container_t; + +#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, enet_addr_container_t, node) + +/* UCC GETH Termination Action Descriptor (TAD) structure. */ +typedef struct ucc_geth_tad_params { + int rx_non_dynamic_extended_features_mode; + int reject_frame; + ucc_geth_vlan_operation_tagged_e vtag_op; + ucc_geth_vlan_operation_non_tagged_e vnontag_op; + ucc_geth_qos_mode_e rqos; + u8 vpri; + u16 vid; +} ucc_geth_tad_params_t; + +/* GETH protocol initialization structure */ +typedef struct ucc_geth_info { + ucc_fast_info_t uf_info; + u8 numQueuesTx; + u8 numQueuesRx; + int ipCheckSumCheck; + int ipCheckSumGenerate; + int rxExtendedFiltering; + u32 extendedFilteringChainPointer; + u16 typeorlen; + int dynamicMaxFrameLength; + int dynamicMinFrameLength; + u8 nonBackToBackIfgPart1; + u8 nonBackToBackIfgPart2; + u8 miminumInterFrameGapEnforcement; + u8 backToBackInterFrameGap; + int ipAddressAlignment; + int lengthCheckRx; + u32 mblinterval; + u16 nortsrbytetime; + u8 fracsiz; + u8 strictpriorityq; + u8 txasap; + u8 extrabw; + int miiPreambleSupress; + u8 altBebTruncation; + int altBeb; + int backPressureNoBackoff; + int noBackoff; + int excessDefer; + u8 maxRetransmission; + u8 collisionWindow; + int pro; + int cap; + int rsh; + int rlpb; + int cam; + int bro; + int ecm; + int receiveFlowControl; + u8 maxGroupAddrInHash; + u8 maxIndAddrInHash; + u8 prel; + u16 maxFrameLength; + u16 minFrameLength; + u16 maxD1Length; + u16 maxD2Length; + u16 vlantype; + u16 vlantci; + u32 ecamptr; + u32 eventRegMask; + u16 pausePeriod; + u16 extensionField; + u8 phy_address; + u32 board_flags; + u32 phy_interrupt; + u8 weightfactor[NUM_TX_QUEUES]; + u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; + u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; + u8 l3qt[UCC_GETH_IP_PRIORITY_MAX]; + u32 vtagtable[UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX]; + u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; + u16 bdRingLenTx[NUM_TX_QUEUES]; + u16 bdRingLenRx[NUM_RX_QUEUES]; + enet_interface_e enet_interface; + ucc_geth_num_of_station_addresses_e numStationAddresses; + qe_fltr_largest_external_tbl_lookup_key_size_e + largestexternallookupkeysize; + ucc_geth_statistics_gathering_mode_e statisticsMode; + ucc_geth_vlan_operation_tagged_e vlanOperationTagged; + ucc_geth_vlan_operation_non_tagged_e vlanOperationNonTagged; + ucc_geth_qos_mode_e rxQoSMode; + ucc_geth_flow_control_mode_e aufc; + ucc_geth_maccfg2_pad_and_crc_mode_e padAndCrc; + ucc_geth_num_of_threads_e numThreadsTx; + ucc_geth_num_of_threads_e numThreadsRx; + qe_risc_allocation_e riscTx; + qe_risc_allocation_e riscRx; +} ucc_geth_info_t; + +/* structure representing UCC GETH */ +typedef struct ucc_geth_private { + ucc_geth_info_t *ug_info; + ucc_fast_private_t *uccf; + struct net_device *dev; + struct net_device_stats stats; /* linux network statistics */ + ucc_geth_t *ug_regs; + ucc_geth_init_pram_t *p_init_enet_param_shadow; + ucc_geth_exf_global_pram_t *p_exf_glbl_param; + u32 exf_glbl_param_offset; + ucc_geth_rx_global_pram_t *p_rx_glbl_pram; + u32 rx_glbl_pram_offset; + ucc_geth_tx_global_pram_t *p_tx_glbl_pram; + u32 tx_glbl_pram_offset; + ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg; + u32 send_q_mem_reg_offset; + ucc_geth_thread_data_tx_t *p_thread_data_tx; + u32 thread_dat_tx_offset; + ucc_geth_thread_data_rx_t *p_thread_data_rx; + u32 thread_dat_rx_offset; + ucc_geth_scheduler_t *p_scheduler; + u32 scheduler_offset; + ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram; + u32 tx_fw_statistics_pram_offset; + ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram; + u32 rx_fw_statistics_pram_offset; + ucc_geth_rx_interrupt_coalescing_table_t *p_rx_irq_coalescing_tbl; + u32 rx_irq_coalescing_tbl_offset; + ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl; + u32 rx_bd_qs_tbl_offset; + u8 *p_tx_bd_ring[NUM_TX_QUEUES]; + u32 tx_bd_ring_offset[NUM_TX_QUEUES]; + u8 *p_rx_bd_ring[NUM_RX_QUEUES]; + u32 rx_bd_ring_offset[NUM_RX_QUEUES]; + u8 *confBd[NUM_TX_QUEUES]; + u8 *txBd[NUM_TX_QUEUES]; + u8 *rxBd[NUM_RX_QUEUES]; + int badFrame[NUM_RX_QUEUES]; + u16 cpucount[NUM_TX_QUEUES]; + volatile u16 *p_cpucount[NUM_TX_QUEUES]; + int indAddrRegUsed[NUM_OF_PADDRS]; + enet_addr_t paddr[NUM_OF_PADDRS]; + u8 numGroupAddrInHash; + u8 numIndAddrInHash; + u8 numIndAddrInReg; + int rx_extended_features; + int rx_non_dynamic_extended_features; + struct list_head conf_skbs; + struct list_head group_hash_q; + struct list_head ind_hash_q; + u32 saved_uccm; + spinlock_t lock; + /* pointers to arrays of skbuffs for tx and rx */ + struct sk_buff **tx_skbuff[NUM_TX_QUEUES]; + struct sk_buff **rx_skbuff[NUM_RX_QUEUES]; + /* indices pointing to the next free sbk in skb arrays */ + u16 skb_curtx[NUM_TX_QUEUES]; + u16 skb_currx[NUM_RX_QUEUES]; + /* index of the first skb which hasn't been transmitted yet. */ + u16 skb_dirtytx[NUM_TX_QUEUES]; + + struct work_struct tq; + struct timer_list phy_info_timer; + struct ugeth_mii_info *mii_info; + int oldspeed; + int oldduplex; + int oldlink; +} ucc_geth_private_t; + +#endif /* __UCC_GETH_H__ */ diff -puN /dev/null drivers/net/ucc_geth_phy.c --- /dev/null +++ a/drivers/net/ucc_geth_phy.c @@ -0,0 +1,801 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ucc_geth.h" +#include "ucc_geth_phy.h" +#include + +#define ugphy_printk(level, format, arg...) \ + printk(level format "\n", ## arg) + +#define ugphy_dbg(format, arg...) \ + ugphy_printk(KERN_DEBUG, format , ## arg) +#define ugphy_err(format, arg...) \ + ugphy_printk(KERN_ERR, format , ## arg) +#define ugphy_info(format, arg...) \ + ugphy_printk(KERN_INFO, format , ## arg) +#define ugphy_warn(format, arg...) \ + ugphy_printk(KERN_WARNING, format , ## arg) + +#ifdef UGETH_VERBOSE_DEBUG +#define ugphy_vdbg ugphy_dbg +#else +#define ugphy_vdbg(fmt, args...) do { } while (0) +#endif /* UGETH_VERBOSE_DEBUG */ + +static void config_genmii_advert(struct ugeth_mii_info *mii_info); +static void genmii_setup_forced(struct ugeth_mii_info *mii_info); +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); +static int gbit_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_config_aneg(struct ugeth_mii_info *mii_info); +static int genmii_update_link(struct ugeth_mii_info *mii_info); +static int genmii_read_status(struct ugeth_mii_info *mii_info); +u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum); +void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val); + +static u8 *bcsr_regs = NULL; + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_mii_mng_t *mii_regs; + enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + u32 tmp_reg; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Set this UCC to be the master of the MII managment */ + ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); + + /* Stop the MII management read cycle */ + out_be32(&mii_regs->miimcom, 0); + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Setting up the MII Mangement Control Register with the value */ + out_be32(&mii_regs->miimcon, (u32) value); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + spin_unlock_irq(&ugeth->lock); + + udelay(10000); +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value. Clears miimcom first. All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +int read_phy_reg(struct net_device *dev, int mii_id, int regnum) +{ + ucc_geth_private_t *ugeth = netdev_priv(dev); + ucc_mii_mng_t *mii_regs; + enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum; + u32 tmp_reg; + u16 value; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irq(&ugeth->lock); + + mii_regs = ugeth->mii_info->mii_regs; + + /* Setting up the MII Mangement Address Register */ + tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; + out_be32(&mii_regs->miimadd, tmp_reg); + + /* Perform an MII management read cycle */ + out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); + + /* Wait till MII management write is complete */ + while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) + cpu_relax(); + + udelay(10000); + + /* Read MII management status */ + value = (u16) in_be32(&mii_regs->miimstat); + out_be32(&mii_regs->miimcom, 0); + if (value == 0xffff) + ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", + mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); + + spin_unlock_irq(&ugeth->lock); + + return (value); +} + +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->phyinfo->ack_interrupt) + mii_info->phyinfo->ack_interrupt(mii_info); +} + +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + mii_info->interrupts = interrupts; + if (mii_info->phyinfo->config_intr) + mii_info->phyinfo->config_intr(mii_info); +} + +/* Writes MII_ADVERTISE with the appropriate values, after + * sanitizing advertise to make sure only supported features + * are advertised + */ +static void config_genmii_advert(struct ugeth_mii_info *mii_info) +{ + u32 advertise; + u16 adv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Only allow advertising what this PHY supports */ + mii_info->advertising &= mii_info->phyinfo->features; + advertise = mii_info->advertising; + + /* Setup standard advertisement */ + adv = phy_read(mii_info, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + phy_write(mii_info, MII_ADVERTISE, adv); +} + +static void genmii_setup_forced(struct ugeth_mii_info *mii_info) +{ + u16 ctrl; + u32 features = mii_info->phyinfo->features; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + ctrl = phy_read(mii_info, MII_BMCR); + + ctrl &= + ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + ctrl |= BMCR_RESET; + + switch (mii_info->speed) { + case SPEED_1000: + if (features & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + ctrl |= BMCR_SPEED1000; + break; + } + mii_info->speed = SPEED_100; + case SPEED_100: + if (features & (SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full)) { + ctrl |= BMCR_SPEED100; + break; + } + mii_info->speed = SPEED_10; + case SPEED_10: + if (features & (SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full)) + break; + default: /* Unsupported speed! */ + ugphy_err("%s: Bad speed!", mii_info->dev->name); + break; + } + + phy_write(mii_info, MII_BMCR, ctrl); +} + +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) +{ + u16 ctl; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + ctl = phy_read(mii_info, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(mii_info, MII_BMCR, ctl); +} + +static int gbit_config_aneg(struct ugeth_mii_info *mii_info) +{ + u16 adv; + u32 advertise; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->autoneg) { + /* Configure the ADVERTISE register */ + config_genmii_advert(mii_info); + advertise = mii_info->advertising; + + adv = phy_read(mii_info, MII_1000BASETCONTROL); + adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | + MII_1000BASETCONTROL_HALFDUPLEXCAP); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; + phy_write(mii_info, MII_1000BASETCONTROL, adv); + + /* Start/Restart aneg */ + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + +static int genmii_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->autoneg) { + config_genmii_advert(mii_info); + genmii_restart_aneg(mii_info); + } else + genmii_setup_forced(mii_info); + + return 0; +} + +static int genmii_update_link(struct ugeth_mii_info *mii_info) +{ + u16 status; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Do a fake read */ + phy_read(mii_info, MII_BMSR); + + /* Read link and autonegotiation status */ + status = phy_read(mii_info, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + mii_info->link = 0; + else + mii_info->link = 1; + + /* If we are autonegotiating, and not done, + * return an error */ + if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return -EAGAIN; + + return 0; +} + +static int genmii_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + if (mii_info->autoneg) { + status = phy_read(mii_info, MII_LPA); + + if (status & (LPA_10FULL | LPA_100FULL)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + if (status & (LPA_100FULL | LPA_100HALF)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + mii_info->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + +static int marvell_init(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + phy_write(mii_info, 0x14, 0x0cd2); + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) | BMCR_RESET); + msleep(4000); + + return 0; +} + +static int marvell_config_aneg(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + phy_write(mii_info, MII_BMCR, BMCR_RESET); + + phy_write(mii_info, 0x1d, 0x1f); + phy_write(mii_info, 0x1e, 0x200c); + phy_write(mii_info, 0x1d, 0x5); + phy_write(mii_info, 0x1e, 0); + phy_write(mii_info, 0x1e, 0x100); + + gbit_config_aneg(mii_info); + + return 0; +} + +static int marvell_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); + + /* Get the duplexity */ + if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + /* Get the speed */ + speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; + switch (speed) { + case MII_M1011_PHY_SPEC_STATUS_1000: + mii_info->speed = SPEED_1000; + break; + case MII_M1011_PHY_SPEC_STATUS_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + mii_info->pause = 0; + } + + return 0; +} + +static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_M1011_IEVENT); + + return 0; +} + +static int marvell_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + else + phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return 0; +} + +static int cis820x_init(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); + + return 0; +} + +static int cis820x_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + int speed; + + status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); + if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + + speed = status & MII_CIS8201_AUXCONSTAT_SPEED; + + switch (speed) { + case MII_CIS8201_AUXCONSTAT_GBIT: + mii_info->speed = SPEED_1000; + break; + case MII_CIS8201_AUXCONSTAT_100: + mii_info->speed = SPEED_100; + break; + default: + mii_info->speed = SPEED_10; + break; + } + } + + return 0; +} + +static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + phy_read(mii_info, MII_CIS8201_ISTAT); + + return 0; +} + +static int cis820x_config_intr(struct ugeth_mii_info *mii_info) +{ + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); + else + phy_write(mii_info, MII_CIS8201_IMASK, 0); + + return 0; +} + +#define DM9161_DELAY 10 + +static int dm9161_read_status(struct ugeth_mii_info *mii_info) +{ + u16 status; + int err; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Update the link, but return if there + * was an error */ + err = genmii_update_link(mii_info); + if (err) + return err; + + /* If the link is up, read the speed and duplex */ + /* If we aren't autonegotiating, assume speeds + * are as set */ + if (mii_info->autoneg && mii_info->link) { + status = phy_read(mii_info, MII_DM9161_SCSR); + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) + mii_info->speed = SPEED_100; + else + mii_info->speed = SPEED_10; + + if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) + mii_info->duplex = DUPLEX_FULL; + else + mii_info->duplex = DUPLEX_HALF; + } + + return 0; +} + +static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (0 == priv->resetdone) + return -EAGAIN; + + return 0; +} + +static void dm9161_timer(unsigned long data) +{ + struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; + struct dm9161_private *priv = mii_info->priv; + u16 status = phy_read(mii_info, MII_BMSR); + + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (status & BMSR_ANEGCOMPLETE) { + priv->resetdone = 1; + } else + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); +} + +static int dm9161_init(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Allocate the private data structure */ + priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); + + if (NULL == priv) + return -ENOMEM; + + mii_info->priv = priv; + + /* Reset is not done yet */ + priv->resetdone = 0; + + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) | BMCR_RESET); + + phy_write(mii_info, MII_BMCR, + phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); + + config_genmii_advert(mii_info); + /* Start/Restart aneg */ + genmii_config_aneg(mii_info); + + /* Start a timer for DM9161_DELAY seconds to wait + * for the PHY to be ready */ + init_timer(&priv->timer); + priv->timer.function = &dm9161_timer; + priv->timer.data = (unsigned long)mii_info; + mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); + + return 0; +} + +static void dm9161_close(struct ugeth_mii_info *mii_info) +{ + struct dm9161_private *priv = mii_info->priv; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + del_timer_sync(&priv->timer); + kfree(priv); +} + +static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) +{ +/* FIXME: This lines are for BUG fixing in the mpc8325. +Remove this from here when it's fixed */ + if (bcsr_regs == NULL) + bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); + bcsr_regs[14] |= 0x40; + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Clear the interrupts by reading the reg */ + phy_read(mii_info, MII_DM9161_INTR); + + + return 0; +} + +static int dm9161_config_intr(struct ugeth_mii_info *mii_info) +{ +/* FIXME: This lines are for BUG fixing in the mpc8325. +Remove this from here when it's fixed */ + if (bcsr_regs == NULL) { + bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); + bcsr_regs[14] &= ~0x40; + } + ugphy_vdbg("%s: IN", __FUNCTION__); + + if (mii_info->interrupts == MII_INTERRUPT_ENABLED) + phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + else + phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + + return 0; +} + +/* Cicada 820x */ +static struct phy_info phy_info_cis820x = { + .phy_id = 0x000fc440, + .name = "Cicada Cis8204", + .phy_id_mask = 0x000fffc0, + .features = MII_GBIT_FEATURES, + .init = &cis820x_init, + .config_aneg = &gbit_config_aneg, + .read_status = &cis820x_read_status, + .ack_interrupt = &cis820x_ack_interrupt, + .config_intr = &cis820x_config_intr, +}; + +static struct phy_info phy_info_dm9161 = { + .phy_id = 0x0181b880, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161E", + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .close = dm9161_close, +}; + +static struct phy_info phy_info_dm9161a = { + .phy_id = 0x0181b8a0, + .phy_id_mask = 0x0ffffff0, + .name = "Davicom DM9161A", + .features = MII_BASIC_FEATURES, + .init = dm9161_init, + .config_aneg = dm9161_config_aneg, + .read_status = dm9161_read_status, + .ack_interrupt = dm9161_ack_interrupt, + .config_intr = dm9161_config_intr, + .close = dm9161_close, +}; + +static struct phy_info phy_info_marvell = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E11x1", + .features = MII_GBIT_FEATURES, + .init = &marvell_init, + .config_aneg = &marvell_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, +}; + +static struct phy_info phy_info_genmii = { + .phy_id = 0x00000000, + .phy_id_mask = 0x00000000, + .name = "Generic MII", + .features = MII_BASIC_FEATURES, + .config_aneg = genmii_config_aneg, + .read_status = genmii_read_status, +}; + +static struct phy_info *phy_info[] = { + &phy_info_cis820x, + &phy_info_marvell, + &phy_info_dm9161, + &phy_info_dm9161a, + &phy_info_genmii, + NULL +}; + +u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum) +{ + u16 retval; + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); + + return retval; +} + +void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) +{ + unsigned long flags; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + spin_lock_irqsave(&mii_info->mdio_lock, flags); + mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); + spin_unlock_irqrestore(&mii_info->mdio_lock, flags); +} + +/* Use the PHY ID registers to determine what type of PHY is attached + * to device dev. return a struct phy_info structure describing that PHY + */ +struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) +{ + u16 phy_reg; + u32 phy_ID; + int i; + struct phy_info *theInfo = NULL; + struct net_device *dev = mii_info->dev; + + ugphy_vdbg("%s: IN", __FUNCTION__); + + /* Grab the bits from PHYIR1, and put them in the upper half */ + phy_reg = phy_read(mii_info, MII_PHYSID1); + phy_ID = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = phy_read(mii_info, MII_PHYSID2); + phy_ID |= (phy_reg & 0xffff); + + /* loop through all the known PHY types, and find one that */ + /* matches the ID we read from the PHY. */ + for (i = 0; phy_info[i]; i++) + if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ + theInfo = phy_info[i]; + break; + } + + /* This shouldn't happen, as we have generic PHY support */ + if (theInfo == NULL) { + ugphy_info("%s: PHY id %x is not supported!", dev->name, + phy_ID); + return NULL; + } else { + ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, + phy_ID); + } + + return theInfo; +} diff -puN /dev/null drivers/net/ucc_geth_phy.h --- /dev/null +++ a/drivers/net/ucc_geth_phy.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Shlomi Gridish + * + * Description: + * UCC GETH Driver -- PHY handling + * + * Changelog: + * Jun 28, 2006 Li Yang + * - Rearrange code and style fixes + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#ifndef __UCC_GETH_PHY_H__ +#define __UCC_GETH_PHY_H__ + +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) + +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +#define UGETH_AN_TIMEOUT 2000 + +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL 0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 + +/* 88E1011 PHY Status Register */ +#define MII_M1011_PHY_SPEC_STATUS 0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 +#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 + +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 + +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 + +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MII_DM9161_SCSR 0x11 +#define MII_DM9161_SCSR_100F 0x8000 +#define MII_DM9161_SCSR_100H 0x4000 +#define MII_DM9161_SCSR_10F 0x2000 +#define MII_DM9161_SCSR_10H 0x1000 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +#define MII_READ_COMMAND 0x00000001 + +#define MII_INTERRUPT_DISABLED 0x0 +#define MII_INTERRUPT_ENABLED 0x1 +/* Taken from mii_if_info and sungem_phy.h */ +struct ugeth_mii_info { + /* Information about the PHY type */ + /* And management functions */ + struct phy_info *phyinfo; + + ucc_mii_mng_t *mii_regs; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + + /* The most recently read link state */ + int link; + + /* Enabled Interrupts */ + u32 interrupts; + + u32 advertising; + int autoneg; + int mii_id; + + /* private data pointer */ + /* For use by PHYs to maintain extra state */ + void *priv; + + /* Provided by host chip */ + struct net_device *dev; + + /* A lock to ensure that only one thing can read/write + * the MDIO bus at a time */ + spinlock_t mdio_lock; + + /* Provided by ethernet driver */ + int (*mdio_read) (struct net_device * dev, int mii_id, int reg); + void (*mdio_write) (struct net_device * dev, int mii_id, int reg, + int val); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY. During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is. The 32-bit result + * gotten from the PHY will be ANDed with phy_id_mask to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * There are 6 commands which take a ugeth_mii_info structure. + * Each PHY must declare config_aneg, and read_status. + */ +struct phy_info { + u32 phy_id; + char *name; + unsigned int phy_id_mask; + u32 features; + + /* Called to initialize the PHY */ + int (*init) (struct ugeth_mii_info * mii_info); + + /* Called to suspend the PHY for power */ + int (*suspend) (struct ugeth_mii_info * mii_info); + + /* Reconfigures autonegotiation (or disables it) */ + int (*config_aneg) (struct ugeth_mii_info * mii_info); + + /* Determines the negotiated speed and duplex */ + int (*read_status) (struct ugeth_mii_info * mii_info); + + /* Clears any pending interrupts */ + int (*ack_interrupt) (struct ugeth_mii_info * mii_info); + + /* Enables or disables interrupts */ + int (*config_intr) (struct ugeth_mii_info * mii_info); + + /* Clears up any memory if needed */ + void (*close) (struct ugeth_mii_info * mii_info); +}; + +struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); +void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); +int read_phy_reg(struct net_device *dev, int mii_id, int regnum); +void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); +void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, + u32 interrupts); + +struct dm9161_private { + struct timer_list timer; + int resetdone; +}; + +#endif /* __UCC_GETH_PHY_H__ */ diff -puN drivers/net/via-rhine.c~git-netdev-all drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c~git-netdev-all +++ a/drivers/net/via-rhine.c @@ -30,8 +30,8 @@ */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.4.0" -#define DRV_RELDATE "June-27-2006" +#define DRV_VERSION "1.4.1" +#define DRV_RELDATE "July-24-2006" /* A few user-configurable values. @@ -44,6 +44,10 @@ static int max_interrupt_work = 20; Setting to > 1518 effectively disables this feature. */ static int rx_copybreak; +/* Work-around for broken BIOSes: they are unable to get the chip back out of + power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */ +static int avoid_D3; + /* * In case you are looking for 'options[]' or 'full_duplex[]', they * are gone. Use ethtool(8) instead. @@ -63,7 +67,11 @@ static const int multicast_filter_limit There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#ifdef CONFIG_VIA_RHINE_NAPI +#define RX_RING_SIZE 64 +#else #define RX_RING_SIZE 16 +#endif /* Operational parameters that usually are not changed. */ @@ -116,9 +124,11 @@ MODULE_LICENSE("GPL"); module_param(max_interrupt_work, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); +module_param(avoid_D3, bool, 0); MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)"); /* Theory of Operation @@ -396,7 +406,7 @@ static void rhine_tx_timeout(struct net_ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void rhine_tx(struct net_device *dev); -static void rhine_rx(struct net_device *dev); +static int rhine_rx(struct net_device *dev, int limit); static void rhine_error(struct net_device *dev, int intr_status); static void rhine_set_rx_mode(struct net_device *dev); static struct net_device_stats *rhine_get_stats(struct net_device *dev); @@ -564,6 +574,32 @@ static void rhine_poll(struct net_device } #endif +#ifdef CONFIG_VIA_RHINE_NAPI +static int rhine_napipoll(struct net_device *dev, int *budget) +{ + struct rhine_private *rp = netdev_priv(dev); + void __iomem *ioaddr = rp->base; + int done, limit = min(dev->quota, *budget); + + done = rhine_rx(dev, limit); + *budget -= done; + dev->quota -= done; + + if (done < limit) { + netif_rx_complete(dev); + + iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | + IntrRxDropped | IntrRxNoBuf | IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange, + ioaddr + IntrEnable); + return 0; + } + else + return 1; +} +#endif + static void rhine_hw_init(struct net_device *dev, long pioaddr) { struct rhine_private *rp = netdev_priv(dev); @@ -744,6 +780,10 @@ static int __devinit rhine_init_one(stru #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = rhine_poll; #endif +#ifdef CONFIG_VIA_RHINE_NAPI + dev->poll = rhine_napipoll; + dev->weight = 64; +#endif if (rp->quirks & rqRhineI) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -789,6 +829,9 @@ static int __devinit rhine_init_one(stru } } rp->mii_if.phy_id = phy_id; + if (debug > 1 && avoid_D3) + printk(KERN_INFO "%s: No D3 power state at shutdown.\n", + dev->name); return 0; @@ -1014,6 +1057,8 @@ static void init_registers(struct net_de rhine_set_rx_mode(dev); + netif_poll_enable(dev); + /* Enable interrupts by setting the interrupt mask. */ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | @@ -1268,8 +1313,18 @@ static irqreturn_t rhine_interrupt(int i dev->name, intr_status); if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | - IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) - rhine_rx(dev); + IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { +#ifdef CONFIG_VIA_RHINE_NAPI + iowrite16(IntrTxAborted | + IntrTxDone | IntrTxError | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange, + ioaddr + IntrEnable); + + netif_rx_schedule(dev); +#else + rhine_rx(dev, RX_RING_SIZE); +#endif + } if (intr_status & (IntrTxErrSummary | IntrTxDone)) { if (intr_status & IntrTxErrSummary) { @@ -1367,13 +1422,12 @@ static void rhine_tx(struct net_device * spin_unlock(&rp->lock); } -/* This routine is logically part of the interrupt handler, but isolated - for clarity and better register allocation. */ -static void rhine_rx(struct net_device *dev) +/* Process up to limit frames from receive ring */ +static int rhine_rx(struct net_device *dev, int limit) { struct rhine_private *rp = netdev_priv(dev); + int count; int entry = rp->cur_rx % RX_RING_SIZE; - int boguscnt = rp->dirty_rx + RX_RING_SIZE - rp->cur_rx; if (debug > 4) { printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n", @@ -1382,16 +1436,18 @@ static void rhine_rx(struct net_device * } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (!(rp->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) { + for (count = 0; count < limit; ++count) { struct rx_desc *desc = rp->rx_head_desc; u32 desc_status = le32_to_cpu(desc->rx_status); int data_size = desc_status >> 16; + if (desc_status & DescOwn) + break; + if (debug > 4) printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n", desc_status); - if (--boguscnt < 0) - break; + if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet " @@ -1460,7 +1516,11 @@ static void rhine_rx(struct net_device * PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); +#ifdef CONFIG_VIA_RHINE_NAPI + netif_receive_skb(skb); +#else netif_rx(skb); +#endif dev->last_rx = jiffies; rp->stats.rx_bytes += pkt_len; rp->stats.rx_packets++; @@ -1487,6 +1547,8 @@ static void rhine_rx(struct net_device * } rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn); } + + return count; } /* @@ -1776,6 +1838,7 @@ static int rhine_close(struct net_device spin_lock_irq(&rp->lock); netif_stop_queue(dev); + netif_poll_disable(dev); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, " @@ -1857,7 +1920,8 @@ static void rhine_shutdown (struct pci_d } /* Hit power state D3 (sleep) */ - iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + if (!avoid_D3) + iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); /* TODO: Check use of pci_enable_wake() */ @@ -1941,7 +2005,7 @@ static int __init rhine_init(void) #ifdef MODULE printk(version); #endif - return pci_module_init(&rhine_driver); + return pci_register_driver(&rhine_driver); } diff -puN drivers/net/via-velocity.c~git-netdev-all drivers/net/via-velocity.c --- a/drivers/net/via-velocity.c~git-netdev-all +++ a/drivers/net/via-velocity.c @@ -2250,7 +2250,7 @@ static int __init velocity_init_module(v int ret; velocity_register_notifier(); - ret = pci_module_init(&velocity_driver); + ret = pci_register_driver(&velocity_driver); if (ret < 0) velocity_unregister_notifier(); return ret; diff -puN drivers/net/via-velocity.h~git-netdev-all drivers/net/via-velocity.h --- a/drivers/net/via-velocity.h~git-netdev-all +++ a/drivers/net/via-velocity.h @@ -262,25 +262,6 @@ struct velocity_rd_info { dma_addr_t skb_dma; }; -/** - * alloc_rd_info - allocate an rd info block - * - * Alocate and initialize a receive info structure used for keeping - * track of kernel side information related to each receive - * descriptor we are using - */ - -static inline struct velocity_rd_info *alloc_rd_info(void) -{ - struct velocity_rd_info *ptr; - if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL) - return NULL; - else { - memset(ptr, 0, sizeof(struct velocity_rd_info)); - return ptr; - } -} - /* * Used to track transmit side buffers. */ diff -puN drivers/net/wan/c101.c~git-netdev-all drivers/net/wan/c101.c --- a/drivers/net/wan/c101.c~git-netdev-all +++ a/drivers/net/wan/c101.c @@ -118,7 +118,7 @@ static inline void openwin(card_t *card, static inline void set_carrier(port_t *port) { - if (!sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD) + if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)) netif_carrier_on(port_to_dev(port)); else netif_carrier_off(port_to_dev(port)); @@ -127,10 +127,10 @@ static inline void set_carrier(port_t *p static void sca_msci_intr(port_t *port) { - u8 stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI ST1 status */ + u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */ - /* Reset MSCI TX underrun status bit */ - sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, port); + /* Reset MSCI TX underrun and CDCD (ignored) status bit */ + sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); if (stat & ST1_UDRN) { struct net_device_stats *stats = hdlc_stats(port_to_dev(port)); @@ -138,6 +138,7 @@ static void sca_msci_intr(port_t *port) stats->tx_fifo_errors++; } + stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port); diff -puN drivers/net/wan/cycx_main.c~git-netdev-all drivers/net/wan/cycx_main.c --- a/drivers/net/wan/cycx_main.c~git-netdev-all +++ a/drivers/net/wan/cycx_main.c @@ -40,7 +40,6 @@ * 1998/08/08 acme Initial version. */ -#include /* OS configuration options */ #include /* offsetof(), etc. */ #include /* return codes */ #include /* inline memset(), etc. */ diff -puN drivers/net/wan/dlci.c~git-netdev-all drivers/net/wan/dlci.c --- a/drivers/net/wan/dlci.c~git-netdev-all +++ a/drivers/net/wan/dlci.c @@ -28,7 +28,6 @@ * 2 of the License, or (at your option) any later version. */ -#include /* for CONFIG_DLCI_COUNT */ #include #include #include diff -puN drivers/net/wan/dscc4.c~git-netdev-all drivers/net/wan/dscc4.c --- a/drivers/net/wan/dscc4.c~git-netdev-all +++ a/drivers/net/wan/dscc4.c @@ -2062,7 +2062,7 @@ static struct pci_driver dscc4_driver = static int __init dscc4_init_module(void) { - return pci_module_init(&dscc4_driver); + return pci_register_driver(&dscc4_driver); } static void __exit dscc4_cleanup_module(void) diff -puN drivers/net/wan/farsync.c~git-netdev-all drivers/net/wan/farsync.c --- a/drivers/net/wan/farsync.c~git-netdev-all +++ a/drivers/net/wan/farsync.c @@ -2697,7 +2697,7 @@ fst_init(void) for (i = 0; i < FST_MAX_CARDS; i++) fst_card_array[i] = NULL; spin_lock_init(&fst_work_q_lock); - return pci_module_init(&fst_driver); + return pci_register_driver(&fst_driver); } static void __exit diff -puN drivers/net/wan/lmc/lmc_main.c~git-netdev-all drivers/net/wan/lmc/lmc_main.c --- a/drivers/net/wan/lmc/lmc_main.c~git-netdev-all +++ a/drivers/net/wan/lmc/lmc_main.c @@ -1790,7 +1790,7 @@ static struct pci_driver lmc_driver = { static int __init init_lmc(void) { - return pci_module_init(&lmc_driver); + return pci_register_driver(&lmc_driver); } static void __exit exit_lmc(void) diff -puN drivers/net/wan/pc300_drv.c~git-netdev-all drivers/net/wan/pc300_drv.c --- a/drivers/net/wan/pc300_drv.c~git-netdev-all +++ a/drivers/net/wan/pc300_drv.c @@ -3677,7 +3677,7 @@ static struct pci_driver cpc_driver = { static int __init cpc_init(void) { - return pci_module_init(&cpc_driver); + return pci_register_driver(&cpc_driver); } static void __exit cpc_cleanup_module(void) diff -puN drivers/net/wan/pci200syn.c~git-netdev-all drivers/net/wan/pci200syn.c --- a/drivers/net/wan/pci200syn.c~git-netdev-all +++ a/drivers/net/wan/pci200syn.c @@ -476,7 +476,7 @@ static int __init pci200_init_module(voi printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); return -EINVAL; } - return pci_module_init(&pci200_pci_driver); + return pci_register_driver(&pci200_pci_driver); } diff -puN drivers/net/wan/sdla.c~git-netdev-all drivers/net/wan/sdla.c --- a/drivers/net/wan/sdla.c~git-netdev-all +++ a/drivers/net/wan/sdla.c @@ -32,7 +32,6 @@ * 2 of the License, or (at your option) any later version. */ -#include /* for CONFIG_DLCI_MAX */ #include #include #include diff -puN drivers/net/wan/wanxl.c~git-netdev-all drivers/net/wan/wanxl.c --- a/drivers/net/wan/wanxl.c~git-netdev-all +++ a/drivers/net/wan/wanxl.c @@ -837,7 +837,7 @@ static int __init wanxl_init_module(void #ifdef MODULE printk(KERN_INFO "%s\n", version); #endif - return pci_module_init(&wanxl_pci_driver); + return pci_register_driver(&wanxl_pci_driver); } static void __exit wanxl_cleanup_module(void) diff -puN drivers/net/wd.c~git-netdev-all drivers/net/wd.c --- a/drivers/net/wd.c~git-netdev-all +++ a/drivers/net/wd.c @@ -500,8 +500,8 @@ MODULE_LICENSE("GPL"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ -int -init_module(void) + +int __init init_module(void) { struct net_device *dev; int this_dev, found = 0; diff -puN drivers/net/wireless/airo.c~git-netdev-all drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c~git-netdev-all +++ a/drivers/net/wireless/airo.c @@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info pRsp->rsp0 = IN4500(ai, RESP0); pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp2 = IN4500(ai, RESP2); - if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { - airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd); - airo_print_err(ai->dev->name, "status= %x\n", pRsp->status); - airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0); - airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1); - airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2); - } + if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) + airo_print_err(ai->dev->name, + "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", + pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, + pRsp->rsp2); // clear stuck command busy if necessary if (IN4500(ai, COMMAND) & COMMAND_BUSY) { diff -puN drivers/net/wireless/atmel_pci.c~git-netdev-all drivers/net/wireless/atmel_pci.c --- a/drivers/net/wireless/atmel_pci.c~git-netdev-all +++ a/drivers/net/wireless/atmel_pci.c @@ -76,7 +76,7 @@ static void __devexit atmel_pci_remove(s static int __init atmel_init_module(void) { - return pci_module_init(&atmel_driver); + return pci_register_driver(&atmel_driver); } static void __exit atmel_cleanup_module(void) diff -puN drivers/net/wireless/bcm43xx/bcm43xx.h~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx.h --- a/drivers/net/wireless/bcm43xx/bcm43xx.h~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -504,6 +504,12 @@ struct bcm43xx_phyinfo { * This lock is only used by bcm43xx_phy_{un}lock() */ spinlock_t lock; + + /* Firmware. */ + const struct firmware *ucode; + const struct firmware *pcm; + const struct firmware *initvals0; + const struct firmware *initvals1; }; @@ -593,12 +599,14 @@ struct bcm43xx_coreinfo { u8 available:1, enabled:1, initialized:1; - /** core_id ID number */ - u16 id; /** core_rev revision number */ u8 rev; /** Index number for _switch_core() */ u8 index; + /** core_id ID number */ + u16 id; + /** Core-specific data. */ + void *priv; }; /* Additional information for each 80211 core. */ @@ -647,7 +655,23 @@ enum { BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ }; #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) -#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) +#define bcm43xx_set_status(bcm, stat) do { \ + atomic_set(&(bcm)->init_status, (stat)); \ + smp_wmb(); \ + } while (0) + +/* *** THEORY OF LOCKING *** + * + * We have two different locks in the bcm43xx driver. + * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private + * and the device registers. This mutex does _not_ protect + * against concurrency from the IRQ handler. + * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. + * + * Please note that, if you only take the irq_lock, you are not protected + * against concurrency from the periodic work handlers. + * Most times you want to take _both_ locks. + */ struct bcm43xx_private { struct ieee80211_device *ieee; @@ -659,7 +683,6 @@ struct bcm43xx_private { void __iomem *mmio_addr; - /* Locking, see "theory of locking" text below. */ spinlock_t irq_lock; struct mutex mutex; @@ -691,6 +714,7 @@ struct bcm43xx_private { struct bcm43xx_sprominfo sprom; #define BCM43xx_NR_LEDS 4 struct bcm43xx_led leds[BCM43xx_NR_LEDS]; + spinlock_t leds_lock; /* The currently active core. */ struct bcm43xx_coreinfo *current_core; @@ -708,10 +732,6 @@ struct bcm43xx_private { struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; /* Additional information, specific to the 80211 cores. */ struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; - /* Index of the current 80211 core. If current_core is not - * an 80211 core, this is -1. - */ - int current_80211_core_idx; /* Number of available 80211 cores. */ int nr_80211_available; @@ -724,6 +744,8 @@ struct bcm43xx_private { u32 irq_savedstate; /* Link Quality calculation context. */ struct bcm43xx_noise_calculation noisecalc; + /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ + int mac_suspended; /* Threshold values. */ //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. @@ -746,12 +768,6 @@ struct bcm43xx_private { struct bcm43xx_key key[54]; u8 default_key_idx; - /* Firmware. */ - const struct firmware *ucode; - const struct firmware *pcm; - const struct firmware *initvals0; - const struct firmware *initvals1; - /* Random Number Generator. */ struct hwrng rng; char rng_name[20 + 1]; @@ -763,55 +779,6 @@ struct bcm43xx_private { }; -/* *** THEORY OF LOCKING *** - * - * We have two different locks in the bcm43xx driver. - * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private - * and the device registers. - * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. - * - * We have three types of helper function pairs to utilize these locks. - * (Always use the helper functions.) - * 1) bcm43xx_{un}lock_noirq(): - * Takes bcm->mutex. Does _not_ protect against IRQ concurrency, - * so it is almost always unsafe, if device IRQs are enabled. - * So only use this, if device IRQs are masked. - * Locking may sleep. - * You can sleep within the critical section. - * 2) bcm43xx_{un}lock_irqonly(): - * Takes bcm->irq_lock. Does _not_ protect against - * bcm43xx_lock_noirq() critical sections. - * Does only protect against the IRQ handler path and other - * irqonly() critical sections. - * Locking does not sleep. - * You must not sleep within the critical section. - * 3) bcm43xx_{un}lock_irqsafe(): - * This is the cummulative lock and takes both, mutex and irq_lock. - * Protects against noirq() and irqonly() critical sections (and - * the IRQ handler path). - * Locking may sleep. - * You must not sleep within the critical section. - */ - -/* Lock type 1 */ -#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex) -#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex) -/* Lock type 2 */ -#define bcm43xx_lock_irqonly(bcm, flags) \ - spin_lock_irqsave(&(bcm)->irq_lock, flags) -#define bcm43xx_unlock_irqonly(bcm, flags) \ - spin_unlock_irqrestore(&(bcm)->irq_lock, flags) -/* Lock type 3 */ -#define bcm43xx_lock_irqsafe(bcm, flags) do { \ - bcm43xx_lock_noirq(bcm); \ - bcm43xx_lock_irqonly(bcm, flags); \ - } while (0) -#define bcm43xx_unlock_irqsafe(bcm, flags) do { \ - bcm43xx_unlock_irqonly(bcm, flags); \ - bcm43xx_unlock_noirq(bcm); \ - } while (0) - - static inline struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) { @@ -863,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_pri * any of these functions. */ static inline +struct bcm43xx_coreinfo_80211 * +bcm43xx_current_80211_priv(struct bcm43xx_private *bcm) +{ + assert(bcm->current_core->id == BCM43xx_COREID_80211); + return bcm->current_core->priv; +} +static inline struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) { assert(bcm43xx_using_pio(bcm)); - assert(bcm->current_80211_core_idx >= 0); - assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); - return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); + return &(bcm43xx_current_80211_priv(bcm)->pio); } static inline struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) { assert(!bcm43xx_using_pio(bcm)); - assert(bcm->current_80211_core_idx >= 0); - assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); - return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); + return &(bcm43xx_current_80211_priv(bcm)->dma); } static inline struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) { - assert(bcm->current_80211_core_idx >= 0); - assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); - return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); + return &(bcm43xx_current_80211_priv(bcm)->phy); } static inline struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) { - assert(bcm->current_80211_core_idx >= 0); - assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); - return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); + return &(bcm43xx_current_80211_priv(bcm)->radio); } diff -puN drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct down(&big_buffer_sem); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; @@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct fappend("\n"); out: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struc unsigned long flags; down(&big_buffer_sem); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; @@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struc fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); out: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file u64 tsf; down(&big_buffer_sem); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; @@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file (unsigned int)(tsf & 0xFFFFFFFFULL)); out: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct fil res = -EFAULT; goto out_up; } - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); res = -EFAULT; @@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct fil res = buf_size; out_unlock: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); out_up: up(&big_buffer_sem); return res; @@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct f int i, cnt, j = 0; down(&big_buffer_sem); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", BCM43xx_NR_LOGGED_XMITSTATUS); @@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct f i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - bcm43xx_lock_irqsafe(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); if (*ppos == pos) { /* Done. Drop the copied data. */ e->xmitstatus_printing = 0; } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); + up(&big_buffer_sem); + return res; +} + +static ssize_t restart_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags; + + buf_size = min(count, sizeof (really_big_buffer) - 1); + down(&big_buffer_sem); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_up; + } + mutex_lock(&(bcm)->mutex); + spin_lock_irqsave(&(bcm)->irq_lock, flags); + if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -EFAULT; + goto out_unlock; + } + if (count > 0 && buf[0] == '1') { + bcm43xx_controller_restart(bcm, "manually restarted"); + res = count; + } else + res = -EINVAL; + +out_unlock: + spin_unlock_irqrestore(&(bcm)->irq_lock, flags); + mutex_unlock(&(bcm)->mutex); +out_up: up(&big_buffer_sem); return res; } @@ -339,6 +385,11 @@ static struct file_operations txstat_fop .open = open_file_generic, }; +static struct file_operations restart_fops = { + .write = restart_write_file, + .open = open_file_generic, +}; + void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { @@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct b bcm, &txstat_fops); if (!e->dentry_txstat) printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); + e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, + bcm, &restart_fops); + if (!e->dentry_restart) + printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); } void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) @@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struc debugfs_remove(e->dentry_devinfo); debugfs_remove(e->dentry_tsf); debugfs_remove(e->dentry_txstat); + debugfs_remove(e->dentry_restart); debugfs_remove(e->subdir); kfree(e->xmitstatus_buffer); kfree(e->xmitstatus_print_buffer); diff -puN drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h @@ -20,6 +20,7 @@ struct bcm43xx_dfsentry { struct dentry *dentry_spromdump; struct dentry *dentry_tsf; struct dentry *dentry_txstat; + struct dentry *dentry_restart; struct bcm43xx_private *bcm; diff -puN drivers/net/wireless/bcm43xx/bcm43xx_leds.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_leds.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned l struct bcm43xx_private *bcm = led->bcm; unsigned long flags; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->leds_lock, flags); if (led->blink_interval) { bcm43xx_led_changestate(led); mod_timer(&led->blink_timer, jiffies + led->blink_interval); } - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->leds_lock, flags); } static void bcm43xx_led_blink_start(struct bcm43xx_led *led, @@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_ int i, turn_on; unsigned long interval = 0; u16 ledctl; + unsigned long flags; + spin_lock_irqsave(&bcm->leds_lock, flags); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); @@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_ ledctl &= ~(1 << i); } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&bcm->leds_lock, flags); } void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) @@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm4 u16 ledctl; int i; int bit_on; + unsigned long flags; + spin_lock_irqsave(&bcm->leds_lock, flags); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); @@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm4 ledctl &= ~(1 << i); } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); + spin_unlock_irqrestore(&bcm->leds_lock, flags); } diff -puN drivers/net/wireless/bcm43xx/bcm43xx_main.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_main.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(stru } /* Make sure we don't receive more data from the device. */ -static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) +static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm) { unsigned long flags; - u32 old; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); return -EBUSY; } - old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_unlock_irqonly(bcm, flags); + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + spin_unlock_irqrestore(&bcm->irq_lock, flags); bcm43xx_synchronize_irq(bcm); - if (oldstate) - *oldstate = old; - return 0; } @@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct u16 manufact; u16 version; u8 revision; - s8 i; if (bcm->chip_id == 0x4317) { if (bcm->chip_rev == 0x00) @@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct radio->version = version; radio->revision = revision; - /* Set default attenuation values. */ - radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); - radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); - radio->txctl1 = bcm43xx_default_txctl1(bcm); - radio->txctl2 = 0xFFFF; if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else radio->txpower_desired = bcm->sprom.maxpower_bgphy; - /* Initialize the in-memory nrssi Lookup Table. */ - for (i = 0; i < 64; i++) - radio->nrssi_lt[i] = i; - return 0; err_unsupported_radio: @@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_p goto out; bcm->current_core = new_core; - bcm->current_80211_core_idx = -1; - if (new_core->id == BCM43xx_COREID_80211) - bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); - out: return err; } @@ -1423,43 +1405,23 @@ static void bcm43xx_wireless_core_disabl bcm43xx_core_disable(bcm, 0); } -/* Mark the current 80211 core inactive. - * "active_80211_core" is the other 80211 core, which is used. - */ -static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, - struct bcm43xx_coreinfo *active_80211_core) +/* Mark the current 80211 core inactive. */ +static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm) { u32 sbtmstatelow; - struct bcm43xx_coreinfo *old_core; - int err = 0; bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_radio_turn_off(bcm); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow &= ~0x200a0000; - sbtmstatelow |= 0xa0000; + sbtmstatelow &= 0xDFF5FFFF; + sbtmstatelow |= 0x000A0000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow &= ~0xa0000; - sbtmstatelow |= 0x80000; + sbtmstatelow &= 0xFFF5FFFF; + sbtmstatelow |= 0x00080000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); - - if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, active_80211_core); - if (err) - goto out; - sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); - sbtmstatelow &= ~0x20000000; - sbtmstatelow |= 0x20000000; - bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); - err = bcm43xx_switch_core(bcm, old_core); - } - -out: - return err; } static void handle_irq_transmit_status(struct bcm43xx_private *bcm) @@ -1720,7 +1682,7 @@ static void bcm43xx_interrupt_tasklet(st # define bcmirq_handled(irq) do { /* nothing */ } while (0) #endif /* CONFIG_BCM43XX_DEBUG*/ - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); reason = bcm->irq_reason; dma_reason[0] = bcm->dma_reason[0]; dma_reason[1] = bcm->dma_reason[1]; @@ -1746,7 +1708,7 @@ static void bcm43xx_interrupt_tasklet(st dma_reason[2], dma_reason[3]); bcm43xx_controller_restart(bcm, "DMA error"); mmiowb(); - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); return; } if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | @@ -1834,7 +1796,7 @@ static void bcm43xx_interrupt_tasklet(st bcm43xx_leds_update(bcm, activity); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); mmiowb(); - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); } static void pio_irq_workaround(struct bcm43xx_private *bcm, @@ -1885,14 +1847,8 @@ static irqreturn_t bcm43xx_interrupt_han spin_lock(&bcm->irq_lock); - /* Only accept IRQs, if we are initialized properly. - * This avoids an RX race while initializing. - * We should probably not enable IRQs before we are initialized - * completely, but some careful work is needed to fix this. I think it - * is best to stay with this cheap workaround for now... . - */ - if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) - goto out; + assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); + assert(bcm->current_core->id == BCM43xx_COREID_80211); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) { @@ -1930,16 +1886,18 @@ out: static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + if (bcm->firmware_norelease && !force) return; /* Suspending or controller reset. */ - release_firmware(bcm->ucode); - bcm->ucode = NULL; - release_firmware(bcm->pcm); - bcm->pcm = NULL; - release_firmware(bcm->initvals0); - bcm->initvals0 = NULL; - release_firmware(bcm->initvals1); - bcm->initvals1 = NULL; + release_firmware(phy->ucode); + phy->ucode = NULL; + release_firmware(phy->pcm); + phy->pcm = NULL; + release_firmware(phy->initvals0); + phy->initvals0 = NULL; + release_firmware(phy->initvals1); + phy->initvals1 = NULL; } static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) @@ -1950,11 +1908,11 @@ static int bcm43xx_request_firmware(stru int nr; char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; - if (!bcm->ucode) { + if (!phy->ucode) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", (rev >= 5 ? 5 : rev), modparam_fwpostfix); - err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); + err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: Microcode \"%s\" not available or load failed.\n", @@ -1963,12 +1921,12 @@ static int bcm43xx_request_firmware(stru } } - if (!bcm->pcm) { + if (!phy->pcm) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_pcm%d%s.fw", (rev < 5 ? 4 : 5), modparam_fwpostfix); - err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); + err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: PCM \"%s\" not available or load failed.\n", @@ -1977,7 +1935,7 @@ static int bcm43xx_request_firmware(stru } } - if (!bcm->initvals0) { + if (!phy->initvals0) { if (rev == 2 || rev == 4) { switch (phy->type) { case BCM43xx_PHYTYPE_A: @@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(stru snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", nr, modparam_fwpostfix); - err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); + err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: InitVals \"%s\" not available or load failed.\n", buf); goto error; } - if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { + if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) { printk(KERN_ERR PFX "InitVals fileformat error.\n"); goto error; } } - if (!bcm->initvals1) { + if (!phy->initvals1) { if (rev >= 5) { u32 sbtmstatehigh; @@ -2043,14 +2001,14 @@ static int bcm43xx_request_firmware(stru snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", nr, modparam_fwpostfix); - err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); + err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: InitVals \"%s\" not available or load failed.\n", buf); goto error; } - if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { + if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) { printk(KERN_ERR PFX "InitVals fileformat error.\n"); goto error; } @@ -2070,12 +2028,13 @@ err_noinitval: static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const u32 *data; unsigned int i, len; /* Upload Microcode. */ - data = (u32 *)(bcm->ucode->data); - len = bcm->ucode->size / sizeof(u32); + data = (u32 *)(phy->ucode->data); + len = phy->ucode->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); for (i = 0; i < len; i++) { bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, @@ -2084,8 +2043,8 @@ static void bcm43xx_upload_microcode(str } /* Upload PCM data. */ - data = (u32 *)(bcm->pcm->data); - len = bcm->pcm->size / sizeof(u32); + data = (u32 *)(phy->pcm->data); + len = phy->pcm->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); @@ -2131,15 +2090,16 @@ err_format: static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, - bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data, + phy->initvals0->size / sizeof(struct bcm43xx_initval)); if (err) goto out; - if (bcm->initvals1) { - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, - bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + if (phy->initvals1) { + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data, + phy->initvals1->size / sizeof(struct bcm43xx_initval)); if (err) goto out; } @@ -2156,9 +2116,7 @@ static struct pci_device_id bcm43xx_47xx static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) { - int res; - unsigned int i; - u32 data; + int err; bcm->irq = bcm->pci_dev->irq; #ifdef CONFIG_BCM947XX @@ -2175,32 +2133,12 @@ static int bcm43xx_initialize_irq(struct } } #endif - res = request_irq(bcm->irq, bcm43xx_interrupt_handler, + err = request_irq(bcm->irq, bcm43xx_interrupt_handler, IRQF_SHARED, KBUILD_MODNAME, bcm); - if (res) { + if (err) printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); - return -ENODEV; - } - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); - i = 0; - while (1) { - data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (data == BCM43xx_IRQ_READY) - break; - i++; - if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { - printk(KERN_ERR PFX "Card IRQ register not responding. " - "Giving up.\n"); - free_irq(bcm->irq, bcm); - return -ENODEV; - } - udelay(10); - } - // dummy read - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - return 0; + return err; } /* Switch to the core used to write the GPIO register. @@ -2298,13 +2236,17 @@ static int bcm43xx_gpio_cleanup(struct b /* http://bcm-specs.sipsolutions.net/EnableMac */ void bcm43xx_mac_enable(struct bcm43xx_private *bcm) { - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - | BCM43xx_SBF_MAC_ENABLED); - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + bcm->mac_suspended--; + assert(bcm->mac_suspended >= 0); + if (bcm->mac_suspended == 0) { + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_MAC_ENABLED); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } } /* http://bcm-specs.sipsolutions.net/SuspendMAC */ @@ -2313,18 +2255,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_ int i; u32 tmp; - bcm43xx_power_saving_ctl_bits(bcm, -1, 1); - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) - & ~BCM43xx_SBF_MAC_ENABLED); - bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - for (i = 100000; i; i--) { - tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (tmp & BCM43xx_IRQ_READY) - return; - udelay(10); + assert(bcm->mac_suspended >= 0); + if (bcm->mac_suspended == 0) { + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~BCM43xx_SBF_MAC_ENABLED); + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + for (i = 10000; i; i--) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (tmp & BCM43xx_IRQ_READY) + goto out; + udelay(1); + } + printkl(KERN_ERR PFX "MAC suspend failed\n"); } - printkl(KERN_ERR PFX "MAC suspend failed\n"); +out: + bcm->mac_suspended++; } void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, @@ -2394,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct if (!modparam_noleds) bcm43xx_leds_exit(bcm); bcm43xx_gpio_cleanup(bcm); - free_irq(bcm->irq, bcm); bcm43xx_release_firmware(bcm, 0); } @@ -2406,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm4 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; - int tmp; + int i, tmp; u32 value32; u16 value16; @@ -2419,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm4 goto out; bcm43xx_upload_microcode(bcm); - err = bcm43xx_initialize_irq(bcm); - if (err) - goto err_release_fw; + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); + i = 0; + while (1) { + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (value32 == BCM43xx_IRQ_READY) + break; + i++; + if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { + printk(KERN_ERR PFX "IRQ_READY timeout\n"); + err = -ENODEV; + goto err_release_fw; + } + udelay(10); + } + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ err = bcm43xx_gpio_init(bcm); if (err) - goto err_free_irq; + goto err_release_fw; err = bcm43xx_upload_initvals(bcm); if (err) @@ -2509,8 +2468,6 @@ err_radio_off: bcm43xx_radio_turn_off(bcm); err_gpio_cleanup: bcm43xx_gpio_cleanup(bcm); -err_free_irq: - free_irq(bcm->irq, bcm); err_release_fw: bcm43xx_release_firmware(bcm, 1); goto out; @@ -2550,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo( { /* Initialize a "phyinfo" structure. The structure is already * zeroed out. + * This is called on insmod time to initialize members. */ - phy->antenna_diversity = 0xFFFF; phy->savedpctlreg = 0xFFFF; - phy->minlowsig[0] = 0xFFFF; - phy->minlowsig[1] = 0xFFFF; spin_lock_init(&phy->lock); } @@ -2562,14 +2517,11 @@ static void bcm43xx_init_struct_radioinf { /* Initialize a "radioinfo" structure. The structure is already * zeroed out. + * This is called on insmod time to initialize members. */ radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; radio->channel = 0xFF; radio->initial_channel = 0xFF; - radio->lofcal = 0xFFFF; - radio->initval = 0xFFFF; - radio->nrssi[0] = -1000; - radio->nrssi[1] = -1000; } static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) @@ -2587,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bc * BCM43xx_MAX_80211_CORES); memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) * BCM43xx_MAX_80211_CORES); - bcm->current_80211_core_idx = -1; bcm->nr_80211_available = 0; bcm->current_core = NULL; bcm->active_80211_core = NULL; @@ -2757,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bc goto out; } bcm->nr_80211_available++; + core->priv = ext_80211; bcm43xx_init_struct_phyinfo(&ext_80211->phy); bcm43xx_init_struct_radioinfo(&ext_80211->radio); break; @@ -2857,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanu } /* http://bcm-specs.sipsolutions.net/80211Init */ -static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) +static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, + int active_wlcore) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); @@ -2939,19 +2892,26 @@ static int bcm43xx_wireless_core_init(st if (bcm->current_core->rev >= 5) bcm43xx_write16(bcm, 0x043C, 0x000C); - if (bcm43xx_using_pio(bcm)) - err = bcm43xx_pio_init(bcm); - else - err = bcm43xx_dma_init(bcm); - if (err) - goto err_chip_cleanup; + if (active_wlcore) { + if (bcm43xx_using_pio(bcm)) + err = bcm43xx_pio_init(bcm); + else + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; + } bcm43xx_write16(bcm, 0x0612, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); - bcm43xx_mac_enable(bcm); - bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + if (active_wlcore) { + if (radio->initial_channel != 0xFF) + bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0); + } + /* Don't enable MAC/IRQ here, as it will race with the IRQ handler. + * We enable it later. + */ bcm->current_core->initialized = 1; out: return err; @@ -3066,11 +3026,6 @@ out: return err; } -static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) -{ - ieee80211softmac_start(bcm->net_dev); -} - static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); @@ -3182,39 +3137,40 @@ static void bcm43xx_periodic_work_handle /* Periodic work will take a long time, so we want it to * be preemtible. */ - bcm43xx_lock_irqonly(bcm, flags); netif_stop_queue(bcm->net_dev); + synchronize_net(); + spin_lock_irqsave(&bcm->irq_lock, flags); + bcm43xx_mac_suspend(bcm); if (bcm43xx_using_pio(bcm)) bcm43xx_pio_freeze_txqueues(bcm); savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_unlock_irqonly(bcm, flags); - bcm43xx_lock_noirq(bcm); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_lock(&bcm->mutex); bcm43xx_synchronize_irq(bcm); } else { /* Periodic work should take short time, so we want low * locking overhead. */ - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); } do_periodic_work(bcm); if (badness > BADNESS_LIMIT) { - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { tasklet_enable(&bcm->isr_tasklet); bcm43xx_interrupt_enable(bcm, savedirqs); if (bcm43xx_using_pio(bcm)) bcm43xx_pio_thaw_txqueues(bcm); + bcm43xx_mac_enable(bcm); } netif_wake_queue(bcm->net_dev); - mmiowb(); - bcm43xx_unlock_irqonly(bcm, flags); - bcm43xx_unlock_noirq(bcm); - } else { - mmiowb(); - bcm43xx_unlock_irqsafe(bcm, flags); } + mmiowb(); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); } static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) @@ -3243,9 +3199,9 @@ static int bcm43xx_rng_read(struct hwrng struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; unsigned long flags; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&(bcm)->irq_lock, flags); *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&(bcm)->irq_lock, flags); return (sizeof(u16)); } @@ -3271,139 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43 return err; } -/* This is the opposite of bcm43xx_init_board() */ -static void bcm43xx_free_board(struct bcm43xx_private *bcm) +static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) { + int ret = 0; int i, err; + struct bcm43xx_coreinfo *core; - bcm43xx_lock_noirq(bcm); + bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); + for (i = 0; i < bcm->nr_80211_available; i++) { + core = &(bcm->core_80211[i]); + assert(core->available); + if (!core->initialized) + continue; + err = bcm43xx_switch_core(bcm, core); + if (err) { + dprintk(KERN_ERR PFX "shutdown_all_wireless_cores " + "switch_core failed (%d)\n", err); + ret = err; + continue; + } + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + bcm43xx_wireless_core_cleanup(bcm); + if (core == bcm->active_80211_core) + bcm->active_80211_core = NULL; + } + free_irq(bcm->irq, bcm); + bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); + + return ret; +} + +/* This is the opposite of bcm43xx_init_board() */ +static void bcm43xx_free_board(struct bcm43xx_private *bcm) +{ bcm43xx_sysfs_unregister(bcm); bcm43xx_periodic_tasks_delete(bcm); - bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); + mutex_lock(&(bcm)->mutex); + bcm43xx_shutdown_all_wireless_cores(bcm); + bcm43xx_pctl_set_crystal(bcm, 0); + mutex_unlock(&(bcm)->mutex); +} + +static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy) +{ + phy->antenna_diversity = 0xFFFF; + memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); + memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); + + /* Flags */ + phy->calibrated = 0; + phy->is_locked = 0; + + if (phy->_lo_pairs) { + memset(phy->_lo_pairs, 0, + sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT); + } + memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); +} + +static void prepare_radiodata_for_init(struct bcm43xx_private *bcm, + struct bcm43xx_radioinfo *radio) +{ + int i; + + /* Set default attenuation values. */ + radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); + radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); + radio->txctl1 = bcm43xx_default_txctl1(bcm); + radio->txctl2 = 0xFFFF; + radio->txpwr_offset = 0; + + /* NRSSI */ + radio->nrssislope = 0; + for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++) + radio->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++) + radio->nrssi_lt[i] = i; + + radio->lofcal = 0xFFFF; + radio->initval = 0xFFFF; + + radio->aci_enable = 0; + radio->aci_wlan_automatic = 0; + radio->aci_hw_rssi = 0; +} + +static void prepare_priv_for_init(struct bcm43xx_private *bcm) +{ + int i; + struct bcm43xx_coreinfo *core; + struct bcm43xx_coreinfo_80211 *wlext; - bcm43xx_rng_exit(bcm); + assert(!bcm->active_80211_core); + + bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); + + /* Flags */ + bcm->was_initialized = 0; + bcm->reg124_set_0x4 = 0; + + /* Stats */ + memset(&bcm->stats, 0, sizeof(bcm->stats)); + + /* Wireless core data */ for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - if (!bcm->core_80211[i].available) - continue; - if (!bcm->core_80211[i].initialized) + core = &(bcm->core_80211[i]); + wlext = core->priv; + + if (!core->available) continue; + assert(wlext == &(bcm->core_80211_ext[i])); - err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); - assert(err == 0); - bcm43xx_wireless_core_cleanup(bcm); + prepare_phydata_for_init(&wlext->phy); + prepare_radiodata_for_init(bcm, &wlext->radio); } - bcm43xx_pctl_set_crystal(bcm, 0); + /* IRQ related flags */ + bcm->irq_reason = 0; + memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason)); + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; - bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); - bcm43xx_unlock_noirq(bcm); + /* Noise calculation context */ + memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc)); + + /* Periodic work context */ + bcm->periodic_state = 0; } -static int bcm43xx_init_board(struct bcm43xx_private *bcm) +static int wireless_core_up(struct bcm43xx_private *bcm, + int active_wlcore) +{ + int err; + + if (!bcm43xx_core_enabled(bcm)) + bcm43xx_wireless_core_reset(bcm, 1); + if (!active_wlcore) + bcm43xx_wireless_core_mark_inactive(bcm); + err = bcm43xx_wireless_core_init(bcm, active_wlcore); + if (err) + goto out; + if (!active_wlcore) + bcm43xx_radio_turn_off(bcm); +out: + return err; +} + +/* Select and enable the "to be used" wireless core. + * Locking: bcm->mutex must be aquired before calling this. + * bcm->irq_lock must not be aquired. + */ +int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, + int phytype) { int i, err; - int connect_phy; + struct bcm43xx_coreinfo *active_core = NULL; + struct bcm43xx_coreinfo_80211 *active_wlext = NULL; + struct bcm43xx_coreinfo *core; + struct bcm43xx_coreinfo_80211 *wlext; + int adjust_active_sbtmstatelow = 0; might_sleep(); - bcm43xx_lock_noirq(bcm); - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); + if (phytype < 0) { + /* If no phytype is requested, select the first core. */ + assert(bcm->core_80211[0].available); + wlext = bcm->core_80211[0].priv; + phytype = wlext->phy.type; + } + /* Find the requested core. */ + for (i = 0; i < bcm->nr_80211_available; i++) { + core = &(bcm->core_80211[i]); + wlext = core->priv; + if (wlext->phy.type == phytype) { + active_core = core; + active_wlext = wlext; + break; + } + } + if (!active_core) + return -ESRCH; /* No such PHYTYPE on this board. */ + + if (bcm->active_80211_core) { + /* We already selected a wl core in the past. + * So first clean up everything. + */ + dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n"); + ieee80211softmac_stop(bcm->net_dev); + bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); + err = bcm43xx_disable_interrupts_sync(bcm); + assert(!err); + tasklet_enable(&bcm->isr_tasklet); + err = bcm43xx_shutdown_all_wireless_cores(bcm); + if (err) + goto error; + /* Ok, everything down, continue to re-initialize. */ + bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); + } + + /* Reset all data structures. */ + prepare_priv_for_init(bcm); - err = bcm43xx_pctl_set_crystal(bcm, 1); - if (err) - goto out; - err = bcm43xx_pctl_init(bcm); - if (err) - goto err_crystal_off; err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); if (err) - goto err_crystal_off; + goto error; - tasklet_enable(&bcm->isr_tasklet); + /* Mark all unused cores "inactive". */ for (i = 0; i < bcm->nr_80211_available; i++) { - err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); - assert(err != -ENODEV); - if (err) - goto err_80211_unwind; + core = &(bcm->core_80211[i]); + wlext = core->priv; - /* Enable the selected wireless core. - * Connect PHY only on the first core. - */ - if (!bcm43xx_core_enabled(bcm)) { - if (bcm->nr_80211_available == 1) { - connect_phy = bcm43xx_current_phy(bcm)->connected; - } else { - if (i == 0) - connect_phy = 1; - else - connect_phy = 0; - } - bcm43xx_wireless_core_reset(bcm, connect_phy); + if (core == active_core) + continue; + err = bcm43xx_switch_core(bcm, core); + if (err) { + dprintk(KERN_ERR PFX "Could not switch to inactive " + "802.11 core (%d)\n", err); + goto error; } + err = wireless_core_up(bcm, 0); + if (err) { + dprintk(KERN_ERR PFX "core_up for inactive 802.11 core " + "failed (%d)\n", err); + goto error; + } + adjust_active_sbtmstatelow = 1; + } - if (i != 0) - bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); - - err = bcm43xx_wireless_core_init(bcm); - if (err) - goto err_80211_unwind; + /* Now initialize the active 802.11 core. */ + err = bcm43xx_switch_core(bcm, active_core); + if (err) { + dprintk(KERN_ERR PFX "Could not switch to active " + "802.11 core (%d)\n", err); + goto error; + } + if (adjust_active_sbtmstatelow && + active_wlext->phy.type == BCM43xx_PHYTYPE_G) { + u32 sbtmstatelow; - if (i != 0) { - bcm43xx_mac_suspend(bcm); - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_radio_turn_off(bcm); - } + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow |= 0x20000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); } - bcm->active_80211_core = &bcm->core_80211[0]; - if (bcm->nr_80211_available >= 2) { - bcm43xx_switch_core(bcm, &bcm->core_80211[0]); - bcm43xx_mac_enable(bcm); + err = wireless_core_up(bcm, 1); + if (err) { + dprintk(KERN_ERR PFX "core_up for active 802.11 core " + "failed (%d)\n", err); + goto error; } - err = bcm43xx_rng_init(bcm); + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); if (err) - goto err_80211_unwind; + goto error; + bcm->active_80211_core = active_core; + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); - dprintk(KERN_INFO PFX "80211 cores initialized\n"); bcm43xx_security_init(bcm); - bcm43xx_softmac_init(bcm); + ieee80211softmac_start(bcm->net_dev); - bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); + /* Let's go! Be careful after enabling the IRQs. + * Don't switch cores, for example. + */ + bcm43xx_mac_enable(bcm); + bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); + err = bcm43xx_initialize_irq(bcm); + if (err) + goto error; + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { - bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); - bcm43xx_mac_enable(bcm); - } + dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n", + active_wlext->phy.type); - /* Initialization of the board is done. Flag it as such. */ - bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); + return 0; + +error: + bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + return err; +} + +static int bcm43xx_init_board(struct bcm43xx_private *bcm) +{ + int err; + + mutex_lock(&(bcm)->mutex); + + tasklet_enable(&bcm->isr_tasklet); + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto err_tasklet; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_crystal_off; + err = bcm43xx_select_wireless_core(bcm, -1); + if (err) + goto err_crystal_off; bcm43xx_periodic_tasks_setup(bcm); - bcm43xx_sysfs_register(bcm); - //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... + err = bcm43xx_sysfs_register(bcm); + if (err) + goto err_wlshutdown; /*FIXME: This should be handled by softmac instead. */ schedule_work(&bcm->softmac->associnfo.work); - assert(err == 0); out: - bcm43xx_unlock_noirq(bcm); + mutex_unlock(&(bcm)->mutex); return err; -err_80211_unwind: - tasklet_disable(&bcm->isr_tasklet); - /* unwind all 80211 initialization */ - for (i = 0; i < bcm->nr_80211_available; i++) { - if (!bcm->core_80211[i].initialized) - continue; - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_wireless_core_cleanup(bcm); - } +err_wlshutdown: + bcm43xx_shutdown_all_wireless_cores(bcm); err_crystal_off: bcm43xx_pctl_set_crystal(bcm, 0); +err_tasklet: + tasklet_disable(&bcm->isr_tasklet); goto out; } @@ -3647,7 +3786,8 @@ static void bcm43xx_ieee80211_set_chan(s struct bcm43xx_radioinfo *radio; unsigned long flags; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { bcm43xx_mac_suspend(bcm); bcm43xx_radio_selectchannel(bcm, channel, 0); @@ -3656,7 +3796,8 @@ static void bcm43xx_ieee80211_set_chan(s radio = bcm43xx_current_radio(bcm); radio->initial_channel = channel; } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); } /* set_security() callback in struct ieee80211_device */ @@ -3670,7 +3811,8 @@ static void bcm43xx_ieee80211_set_securi dprintk(KERN_INFO PFX "set security called"); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); for (keyidx = 0; keyidxflags & (1<irq_lock, flags); + mutex_unlock(&bcm->mutex); } /* hard_start_xmit() callback in struct ieee80211_device */ @@ -3751,10 +3894,10 @@ static int bcm43xx_ieee80211_hard_start_ int err = -ENODEV; unsigned long flags; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) err = bcm43xx_tx(bcm, txb); - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); return err; } @@ -3769,9 +3912,9 @@ static void bcm43xx_net_tx_timeout(struc struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm43xx_controller_restart(bcm, "TX timeout"); - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3781,7 +3924,8 @@ static void bcm43xx_net_poll_controller( unsigned long flags; local_irq_save(flags); - bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); + if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) + bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); local_irq_restore(flags); } #endif /* CONFIG_NET_POLL_CONTROLLER */ @@ -3799,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_d int err; ieee80211softmac_stop(net_dev); - err = bcm43xx_disable_interrupts_sync(bcm, NULL); + err = bcm43xx_disable_interrupts_sync(bcm); assert(!err); bcm43xx_free_board(bcm); @@ -3818,10 +3962,12 @@ static int bcm43xx_init_private(struct b bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + bcm->mac_suspended = 1; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; bcm->bad_frames_preempt = modparam_bad_frames_preempt; spin_lock_init(&bcm->irq_lock); + spin_lock_init(&bcm->leds_lock); mutex_init(&bcm->mutex); tasklet_init(&bcm->isr_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, @@ -3940,7 +4086,6 @@ static void __devexit bcm43xx_remove_one bcm43xx_debugfs_remove_device(bcm); unregister_netdev(net_dev); bcm43xx_detach_board(bcm); - assert(bcm->ucode == NULL); free_ieee80211softmac(net_dev); } @@ -3950,47 +4095,25 @@ static void __devexit bcm43xx_remove_one static void bcm43xx_chip_reset(void *_bcm) { struct bcm43xx_private *bcm = _bcm; - struct net_device *net_dev = bcm->net_dev; - struct pci_dev *pci_dev = bcm->pci_dev; + struct bcm43xx_phyinfo *phy; int err; - int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - netif_stop_queue(bcm->net_dev); - tasklet_disable(&bcm->isr_tasklet); + mutex_lock(&(bcm)->mutex); + phy = bcm43xx_current_phy(bcm); + err = bcm43xx_select_wireless_core(bcm, phy->type); + mutex_unlock(&(bcm)->mutex); - bcm->firmware_norelease = 1; - if (was_initialized) - bcm43xx_free_board(bcm); - bcm->firmware_norelease = 0; - bcm43xx_detach_board(bcm); - err = bcm43xx_init_private(bcm, net_dev, pci_dev); - if (err) - goto failure; - err = bcm43xx_attach_board(bcm); - if (err) - goto failure; - if (was_initialized) { - err = bcm43xx_init_board(bcm); - if (err) - goto failure; - } - netif_wake_queue(bcm->net_dev); - printk(KERN_INFO PFX "Controller restarted\n"); - - return; -failure: - printk(KERN_ERR PFX "Controller restart failed\n"); + printk(KERN_ERR PFX "Controller restart%s\n", + (err == 0) ? "ed" : " failed"); } /* Hard-reset the chip. * This can be called from interrupt or process context. - * Make sure to _not_ re-enable device interrupts after this has been called. -*/ + */ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) { + assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); - bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); schedule_work(&bcm->restart_work); @@ -4002,21 +4125,16 @@ static int bcm43xx_suspend(struct pci_de { struct net_device *net_dev = pci_get_drvdata(pdev); struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - int try_to_shutdown = 0, err; + int err; dprintk(KERN_INFO PFX "Suspending...\n"); - bcm43xx_lock_irqsafe(bcm, flags); - bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - if (bcm->was_initialized) - try_to_shutdown = 1; - bcm43xx_unlock_irqsafe(bcm, flags); - netif_device_detach(net_dev); - if (try_to_shutdown) { + bcm->was_initialized = 0; + if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { + bcm->was_initialized = 1; ieee80211softmac_stop(net_dev); - err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); + err = bcm43xx_disable_interrupts_sync(bcm); if (unlikely(err)) { dprintk(KERN_ERR PFX "Suspend failed.\n"); return -EAGAIN; @@ -4049,17 +4167,14 @@ static int bcm43xx_resume(struct pci_dev pci_restore_state(pdev); bcm43xx_chipset_attach(bcm); - if (bcm->was_initialized) { - bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + if (bcm->was_initialized) err = bcm43xx_init_board(bcm); - } if (err) { printk(KERN_ERR PFX "Resume failed!\n"); return err; } - netif_device_attach(net_dev); - + dprintk(KERN_INFO PFX "Device resumed.\n"); return 0; diff -puN drivers/net/wireless/bcm43xx/bcm43xx_main.h~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_main.h --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct b int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); +int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, + int phytype); + void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); diff -puN drivers/net/wireless/bcm43xx/bcm43xx_phy.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_phy.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); +static inline +void bcm43xx_voluntary_preempt(void) +{ + assert(!in_atomic() && !in_irq() && + !in_interrupt() && !irqs_disabled()); +#ifndef CONFIG_PREEMPT + cond_resched(); +#endif /* CONFIG_PREEMPT */ +} + void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); @@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_pr void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - unsigned long flags; bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ if (phy->calibrated) return; if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { - /* We do not want to be preempted while calibrating - * the hardware. - */ - local_irq_save(flags); - bcm43xx_wireless_core_reset(bcm, 0); bcm43xx_phy_initg(bcm); bcm43xx_wireless_core_reset(bcm, 1); - - local_irq_restore(flags); } phy->calibrated = 1; } @@ -1299,7 +1301,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str { int i; u16 ret = 0; + unsigned long flags; + local_irq_save(flags); for (i = 0; i < 10; i++){ bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); udelay(1); @@ -1309,6 +1313,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str udelay(40); ret += bcm43xx_phy_read(bcm, 0x002C); } + local_irq_restore(flags); + bcm43xx_voluntary_preempt(); return ret; } @@ -1435,6 +1441,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(st } ret = bcm43xx_phy_read(bcm, 0x002D); local_irq_restore(flags); + bcm43xx_voluntary_preempt(); return ret; } @@ -1760,6 +1767,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm bcm43xx_radio_write16(bcm, 0x43, i); bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); udelay(10); + bcm43xx_voluntary_preempt(); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); @@ -1803,6 +1811,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm radio->txctl2 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? udelay(10); + bcm43xx_voluntary_preempt(); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); @@ -1824,6 +1833,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); udelay(2); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); + bcm43xx_voluntary_preempt(); } else bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); bcm43xx_phy_lo_adjust(bcm, is_initializing); @@ -2188,12 +2198,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err = -ENODEV; - unsigned long flags; - - /* We do not want to be preempted while calibrating - * the hardware. - */ - local_irq_save(flags); switch (phy->type) { case BCM43xx_PHYTYPE_A: @@ -2227,7 +2231,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv err = 0; break; } - local_irq_restore(flags); if (err) printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); diff -puN drivers/net/wireless/bcm43xx/bcm43xx_pio.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_pio.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d) int err; u16 txctl; - bcm43xx_lock_irqonly(bcm, flags); + spin_lock_irqsave(&bcm->irq_lock, flags); if (queue->tx_frozen) goto out_unlock; @@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d) continue; } out_unlock: - bcm43xx_unlock_irqonly(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); } static void setup_txqueues(struct bcm43xx_pioqueue *queue) diff -puN drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(s GFP_KERNEL); if (!sprom) return -ENOMEM; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); err = bcm43xx_sprom_read(bcm, sprom); if (!err) err = sprom2hex(sprom, buf, PAGE_SIZE); mmiowb(); - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); kfree(sprom); return err; @@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store( err = hex2sprom(sprom, buf, count); if (err) goto out_kfree; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); + spin_lock(&bcm->leds_lock); err = bcm43xx_sprom_write(bcm, sprom); mmiowb(); - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock(&bcm->leds_lock); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); out_kfree: kfree(sprom); @@ -176,7 +182,7 @@ static ssize_t bcm43xx_attr_interfmode_s if (!capable(CAP_NET_ADMIN)) return -EPERM; - bcm43xx_lock_noirq(bcm); + mutex_lock(&bcm->mutex); switch (bcm43xx_current_radio(bcm)->interfmode) { case BCM43xx_RADIO_INTERFMODE_NONE: @@ -193,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_s } err = 0; - bcm43xx_unlock_noirq(bcm); + mutex_unlock(&bcm->mutex); return err ? err : count; @@ -229,7 +235,8 @@ static ssize_t bcm43xx_attr_interfmode_s return -EINVAL; } - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); err = bcm43xx_radio_set_interference_mitigation(bcm, mode); if (err) { @@ -237,7 +244,8 @@ static ssize_t bcm43xx_attr_interfmode_s "supported by device\n"); } mmiowb(); - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; } @@ -257,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_sho if (!capable(CAP_NET_ADMIN)) return -EPERM; - bcm43xx_lock_noirq(bcm); + mutex_lock(&bcm->mutex); if (bcm->short_preamble) count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); @@ -265,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_sho count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); err = 0; - bcm43xx_unlock_noirq(bcm); + mutex_unlock(&bcm->mutex); return err ? err : count; } @@ -285,12 +293,14 @@ static ssize_t bcm43xx_attr_preamble_sto value = get_boolean(buf, count); if (value < 0) return value; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm->short_preamble = !!value; err = 0; - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err ? err : count; } @@ -299,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644, bcm43xx_attr_preamble_show, bcm43xx_attr_preamble_store); +static ssize_t bcm43xx_attr_phymode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = dev_to_bcm(dev); + int phytype; + int err = -EINVAL; + + if (count < 1) + goto out; + switch (buf[0]) { + case 'a': case 'A': + phytype = BCM43xx_PHYTYPE_A; + break; + case 'b': case 'B': + phytype = BCM43xx_PHYTYPE_B; + break; + case 'g': case 'G': + phytype = BCM43xx_PHYTYPE_G; + break; + default: + goto out; + } + + mutex_lock(&(bcm)->mutex); + err = bcm43xx_select_wireless_core(bcm, phytype); + mutex_unlock(&(bcm)->mutex); + if (err == -ESRCH) + err = -ENODEV; + +out: + return err ? err : count; +} + +static ssize_t bcm43xx_attr_phymode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = dev_to_bcm(dev); + ssize_t count = 0; + + mutex_lock(&(bcm)->mutex); + switch (bcm43xx_current_phy(bcm)->type) { + case BCM43xx_PHYTYPE_A: + snprintf(buf, PAGE_SIZE, "A"); + break; + case BCM43xx_PHYTYPE_B: + snprintf(buf, PAGE_SIZE, "B"); + break; + case BCM43xx_PHYTYPE_G: + snprintf(buf, PAGE_SIZE, "G"); + break; + default: + assert(0); + } + mutex_unlock(&(bcm)->mutex); + + return count; +} + +static DEVICE_ATTR(phymode, 0644, + bcm43xx_attr_phymode_show, + bcm43xx_attr_phymode_store); + int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) { struct device *dev = &bcm->pci_dev->dev; @@ -315,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43x err = device_create_file(dev, &dev_attr_shortpreamble); if (err) goto err_remove_interfmode; + err = device_create_file(dev, &dev_attr_phymode); + if (err) + goto err_remove_shortpreamble; out: return err; +err_remove_shortpreamble: + device_remove_file(dev, &dev_attr_shortpreamble); err_remove_interfmode: device_remove_file(dev, &dev_attr_interference); err_remove_sprom: @@ -329,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm { struct device *dev = &bcm->pci_dev->dev; + device_remove_file(dev, &dev_attr_phymode); device_remove_file(dev, &dev_attr_shortpreamble); device_remove_file(dev, &dev_attr_interference); device_remove_file(dev, &dev_attr_sprom); diff -puN drivers/net/wireless/bcm43xx/bcm43xx_wx.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_wx.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -47,6 +47,8 @@ #define BCM43xx_WX_VERSION 18 #define MAX_WX_STRING 80 +/* FIXME: the next line is a guess as to what the maximum RSSI value might be */ +#define RX_RSSI_MAX 60 static int bcm43xx_wx_get_name(struct net_device *net_dev, @@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct ne { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int i; - unsigned long flags; struct bcm43xx_phyinfo *phy; char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); for (i = 0; i < bcm->nr_80211_available; i++) { phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { @@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct ne assert(0); } } - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); i = 0; if (have_a) { @@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(st int freq; int err = -EINVAL; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); + if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(st err = 0; } out_unlock: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(st { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_radioinfo *radio; - unsigned long flags; int err = -ENODEV; u16 channel; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); radio = bcm43xx_current_radio(bcm); channel = radio->channel; if (channel == 0xFF) { @@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(st err = 0; out_unlock: - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct ne if (mode == IW_MODE_AUTO) mode = BCM43xx_INITIAL_IWMODE; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { if (bcm->ieee->iw_mode != mode) bcm43xx_set_iwmode(bcm, mode); } else bcm->ieee->iw_mode = mode; - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct ne char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); data->mode = bcm->ieee->iw_mode; - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(st struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct iw_range *range = (struct iw_range *)extra; const struct ieee80211_geo *geo; - unsigned long flags; int i, j; struct bcm43xx_phyinfo *phy; @@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(st range->throughput = 27 * 1000 * 1000; range->max_qual.qual = 100; - /* TODO: Real max RSSI */ - range->max_qual.level = 3; - range->max_qual.noise = 100; - range->max_qual.updated = 7; - - range->avg_qual.qual = 70; - range->avg_qual.level = 2; - range->avg_qual.noise = 40; - range->avg_qual.updated = 7; + range->max_qual.level = 152; /* set floor at -104 dBm (152 - 256) */ + range->max_qual.noise = 152; + range->max_qual.updated = IW_QUAL_ALL_UPDATED; + + range->avg_qual.qual = 50; + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED; range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; @@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(st IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); phy = bcm43xx_current_phy(bcm); range->num_bitrates = 0; @@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(st } range->num_frequency = j; - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct ne struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); size_t len; - bcm43xx_lock_noirq(bcm); + mutex_lock(&bcm->mutex); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); memcpy(bcm->nick, extra, len); bcm->nick[len] = '\0'; - bcm43xx_unlock_noirq(bcm); + mutex_unlock(&bcm->mutex); return 0; } @@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct ne struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); size_t len; - bcm43xx_lock_noirq(bcm); + mutex_lock(&bcm->mutex); len = strlen(bcm->nick) + 1; memcpy(extra, bcm->nick, len); data->data.length = (__u16)len; data->data.flags = 1; - bcm43xx_unlock_noirq(bcm); + mutex_unlock(&bcm->mutex); return 0; } @@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net unsigned long flags; int err = -EINVAL; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (data->rts.disabled) { bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; err = 0; @@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net err = 0; } } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); data->rts.value = bcm->rts_threshold; data->rts.fixed = 0; data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct ne unsigned long flags; int err = -EINVAL; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (data->frag.disabled) { bcm->ieee->fts = MAX_FRAG_THRESHOLD; err = 0; @@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct ne err = 0; } } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct ne char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); data->frag.value = bcm->ieee->fts; data->frag.fixed = 0; data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(stru return -EOPNOTSUPP; } - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) goto out_unlock; radio = bcm43xx_current_radio(bcm); @@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(stru err = 0; out_unlock: - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(stru { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct bcm43xx_radioinfo *radio; - unsigned long flags; int err = -ENODEV; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) goto out_unlock; radio = bcm43xx_current_radio(bcm); @@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(stru err = 0; out_unlock: - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(str return -EINVAL; } - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { err = bcm43xx_radio_set_interference_mitigation(bcm, mode); if (err) { @@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(str } else bcm43xx_current_radio(bcm)->interfmode = mode; } - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return err; } @@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(str char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; int mode; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); mode = bcm43xx_current_radio(bcm)->interfmode; - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONE: @@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble( int on; on = *((int *)extra); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm->short_preamble = !!on; - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble( char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; int on; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); on = bcm->short_preamble; - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); if (on) strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); @@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(s on = *((int *)extra); - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); bcm->ieee->host_encrypt = !!on; bcm->ieee->host_decrypt = !!on; bcm->ieee->host_build_iv = !on; - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); return 0; } @@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(s char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - unsigned long flags; int on; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); on = bcm->ieee->host_encrypt; - bcm43xx_unlock_irqsafe(bcm, flags); + mutex_unlock(&bcm->mutex); if (on) strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); @@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct if (!sprom) goto out; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); err = -ENODEV; if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) err = bcm43xx_sprom_read(bcm, sprom); - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); if (!err) data->data.length = sprom2hex(sprom, extra); kfree(sprom); @@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct if (err) goto out_kfree; - bcm43xx_lock_irqsafe(bcm, flags); + mutex_lock(&bcm->mutex); + spin_lock_irqsave(&bcm->irq_lock, flags); + spin_lock(&bcm->leds_lock); err = -ENODEV; if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) err = bcm43xx_sprom_write(bcm, sprom); - bcm43xx_unlock_irqsafe(bcm, flags); + spin_unlock(&bcm->leds_lock); + spin_unlock_irqrestore(&bcm->irq_lock, flags); + mutex_unlock(&bcm->mutex); out_kfree: kfree(sprom); out: @@ -827,6 +841,10 @@ static struct iw_statistics *bcm43xx_get struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); struct iw_statistics *wstats; + struct ieee80211_network *network = NULL; + static int tmp_level = 0; + static int tmp_qual = 0; + unsigned long flags; wstats = &bcm->stats.wstats; if (!mac->associated) { @@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get wstats->qual.level = 0; wstats->qual.noise = 0; wstats->qual.updated = 7; - wstats->qual.updated |= IW_QUAL_NOISE_INVALID | - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; return wstats; } /* fill in the real statistics when iface associated */ - wstats->qual.qual = 100; // TODO: get the real signal quality - wstats->qual.level = 3 - bcm->stats.link_quality; + spin_lock_irqsave(&mac->ieee->lock, flags); + list_for_each_entry(network, &mac->ieee->network_list, list) { + if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { + if (!tmp_level) { /* get initial values */ + tmp_level = network->stats.signal; + tmp_qual = network->stats.rssi; + } else { /* smooth results */ + tmp_level = (15 * tmp_level + network->stats.signal)/16; + tmp_qual = (15 * tmp_qual + network->stats.rssi)/16; + } + break; + } + } + spin_unlock_irqrestore(&mac->ieee->lock, flags); + wstats->qual.level = tmp_level; + wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX; wstats->qual.noise = bcm->stats.noise; - wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | - IW_QUAL_NOISE_UPDATED; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; diff -puN drivers/net/wireless/bcm43xx/bcm43xx_xmit.c~git-netdev-all drivers/net/wireless/bcm43xx/bcm43xx_xmit.c --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c~git-netdev-all +++ a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -492,16 +492,15 @@ int bcm43xx_rx(struct bcm43xx_private *b memset(&stats, 0, sizeof(stats)); stats.mac_time = le16_to_cpu(rxhdr->mactime); - stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + stats.rssi = rxhdr->rssi; + stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); - stats.signal = rxhdr->signal_quality; //FIXME //TODO stats.noise = if (is_ofdm) stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); else stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); -//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); stats.received_channel = radio->channel; //TODO stats.control = stats.mask = IEEE80211_STATMASK_SIGNAL | diff -puN drivers/net/wireless/hostap/hostap_hw.c~git-netdev-all drivers/net/wireless/hostap/hostap_hw.c --- a/drivers/net/wireless/hostap/hostap_hw.c~git-netdev-all +++ a/drivers/net/wireless/hostap/hostap_hw.c @@ -1042,6 +1042,9 @@ static int prism2_reset_port(struct net_ dev->name, local->fragm_threshold); } + /* Some firmwares lose antenna selection settings on reset */ + (void) hostap_set_antsel(local); + return res; } diff -puN drivers/net/wireless/ipw2100.c~git-netdev-all drivers/net/wireless/ipw2100.c --- a/drivers/net/wireless/ipw2100.c~git-netdev-all +++ a/drivers/net/wireless/ipw2100.c @@ -6531,7 +6531,7 @@ static int __init ipw2100_init(void) printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); - ret = pci_module_init(&ipw2100_pci_driver); + ret = pci_register_driver(&ipw2100_pci_driver); #ifdef CONFIG_IPW2100_DEBUG ipw2100_debug_level = debug; diff -puN drivers/net/wireless/ipw2200.c~git-netdev-all drivers/net/wireless/ipw2200.c --- a/drivers/net/wireless/ipw2200.c~git-netdev-all +++ a/drivers/net/wireless/ipw2200.c @@ -2667,7 +2667,7 @@ static void ipw_fw_dma_abort(struct ipw_ IPW_DEBUG_FW(">> :\n"); - //set the Stop and Abort bit + /* set the Stop and Abort bit */ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); priv->sram_desc.last_cb_index = 0; @@ -3002,8 +3002,6 @@ static int ipw_load_ucode(struct ipw_pri if (rc < 0) return rc; -// spin_lock_irqsave(&priv->lock, flags); - for (addr = IPW_SHARED_LOWER_BOUND; addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { ipw_write32(priv, addr, 0); @@ -3097,8 +3095,6 @@ static int ipw_load_ucode(struct ipw_pri firmware have problem getting alive resp. */ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); -// spin_unlock_irqrestore(&priv->lock, flags); - return rc; } @@ -6387,13 +6383,6 @@ static int ipw_wx_set_genie(struct net_d (wrqu->data.length && extra == NULL)) return -EINVAL; - //mutex_lock(&priv->mutex); - - //if (!ieee->wpa_enabled) { - // err = -EOPNOTSUPP; - // goto out; - //} - if (wrqu->data.length) { buf = kmalloc(wrqu->data.length, GFP_KERNEL); if (buf == NULL) { @@ -6413,7 +6402,6 @@ static int ipw_wx_set_genie(struct net_d ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); out: - //mutex_unlock(&priv->mutex); return err; } @@ -6426,13 +6414,6 @@ static int ipw_wx_get_genie(struct net_d struct ieee80211_device *ieee = priv->ieee; int err = 0; - //mutex_lock(&priv->mutex); - - //if (!ieee->wpa_enabled) { - // err = -EOPNOTSUPP; - // goto out; - //} - if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { wrqu->data.length = 0; goto out; @@ -6447,7 +6428,6 @@ static int ipw_wx_get_genie(struct net_d memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); out: - //mutex_unlock(&priv->mutex); return err; } @@ -6558,7 +6538,6 @@ static int ipw_wx_set_auth(struct net_de ieee->ieee802_1x = param->value; break; - //case IW_AUTH_ROAMING_CONTROL: case IW_AUTH_PRIVACY_INVOKED: ieee->privacy_invoked = param->value; break; @@ -6680,7 +6659,7 @@ static int ipw_wx_set_mlme(struct net_de switch (mlme->cmd) { case IW_MLME_DEAUTH: - // silently ignore + /* silently ignore */ break; case IW_MLME_DISASSOC: @@ -9766,7 +9745,7 @@ static int ipw_wx_set_monitor(struct net return 0; } -#endif // CONFIG_IPW2200_MONITOR +#endif /* CONFIG_IPW2200_MONITOR */ static int ipw_wx_reset(struct net_device *dev, struct iw_request_info *info, @@ -10009,7 +9988,7 @@ static void init_sys_config(struct ipw_ sys_config->dot11g_auto_detection = 0; sys_config->enable_cts_to_self = 0; sys_config->bt_coexist_collision_thr = 0; - sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 + sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */ sys_config->silence_threshold = 0x1e; } @@ -11774,7 +11753,7 @@ static int __init ipw_init(void) printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - ret = pci_module_init(&ipw_driver); + ret = pci_register_driver(&ipw_driver); if (ret) { IPW_ERROR("Unable to initialize PCI module\n"); return ret; diff -puN drivers/net/wireless/orinoco_nortel.c~git-netdev-all drivers/net/wireless/orinoco_nortel.c --- a/drivers/net/wireless/orinoco_nortel.c~git-netdev-all +++ a/drivers/net/wireless/orinoco_nortel.c @@ -304,7 +304,7 @@ MODULE_LICENSE("Dual MPL/GPL"); static int __init orinoco_nortel_init(void) { printk(KERN_DEBUG "%s\n", version); - return pci_module_init(&orinoco_nortel_driver); + return pci_register_driver(&orinoco_nortel_driver); } static void __exit orinoco_nortel_exit(void) diff -puN drivers/net/wireless/orinoco_pci.c~git-netdev-all drivers/net/wireless/orinoco_pci.c --- a/drivers/net/wireless/orinoco_pci.c~git-netdev-all +++ a/drivers/net/wireless/orinoco_pci.c @@ -244,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL"); static int __init orinoco_pci_init(void) { printk(KERN_DEBUG "%s\n", version); - return pci_module_init(&orinoco_pci_driver); + return pci_register_driver(&orinoco_pci_driver); } static void __exit orinoco_pci_exit(void) diff -puN drivers/net/wireless/orinoco_plx.c~git-netdev-all drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c~git-netdev-all +++ a/drivers/net/wireless/orinoco_plx.c @@ -351,7 +351,7 @@ MODULE_LICENSE("Dual MPL/GPL"); static int __init orinoco_plx_init(void) { printk(KERN_DEBUG "%s\n", version); - return pci_module_init(&orinoco_plx_driver); + return pci_register_driver(&orinoco_plx_driver); } static void __exit orinoco_plx_exit(void) diff -puN drivers/net/wireless/orinoco_tmd.c~git-netdev-all drivers/net/wireless/orinoco_tmd.c --- a/drivers/net/wireless/orinoco_tmd.c~git-netdev-all +++ a/drivers/net/wireless/orinoco_tmd.c @@ -228,7 +228,7 @@ MODULE_LICENSE("Dual MPL/GPL"); static int __init orinoco_tmd_init(void) { printk(KERN_DEBUG "%s\n", version); - return pci_module_init(&orinoco_tmd_driver); + return pci_register_driver(&orinoco_tmd_driver); } static void __exit orinoco_tmd_exit(void) diff -puN drivers/net/wireless/prism54/isl_ioctl.c~git-netdev-all drivers/net/wireless/prism54/isl_ioctl.c --- a/drivers/net/wireless/prism54/isl_ioctl.c~git-netdev-all +++ a/drivers/net/wireless/prism54/isl_ioctl.c @@ -35,10 +35,14 @@ #include /* New driver API */ +#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ +#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ +/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */ +#define KEY_SIZE_TKIP 32 /* TKIP keys */ -static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, +static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, u8 *wpa_ie, size_t wpa_ie_len); -static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); +static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); static int prism54_set_wpa(struct net_device *, struct iw_request_info *, __u32 *, char *); @@ -468,6 +472,9 @@ prism54_get_range(struct net_device *nde range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP; + if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; @@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device struct iw_event iwe; /* Temporary buffer */ short cap; islpci_private *priv = netdev_priv(ndev); + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; /* The first entry must be the MAC address */ memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); @@ -627,27 +636,13 @@ prism54_translate_bss(struct net_device current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - if (priv->wpa) { - u8 wpa_ie[MAX_WPA_IE_LEN]; - char *buf, *p; - size_t wpa_ie_len; - int i; - - wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); - if (wpa_ie_len > 0 && - (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { - p = buf; - p += sprintf(p, "wpa_ie="); - for (i = 0; i < wpa_ie_len; i++) { - p += sprintf(p, "%02x", wpa_ie[i]); - } - memset(&iwe, 0, sizeof (iwe)); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - kfree(buf); - } + /* Add WPA/RSN Information Element, if any */ + wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); + if (wpa_ie_len > 0) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, wpa_ie); } return current_ev; } @@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *nd current_index = r.u; /* Verify that the key is not marked as invalid */ if (!(dwrq->flags & IW_ENCODE_NOKEY)) { - key.length = dwrq->length > sizeof (key.key) ? - sizeof (key.key) : dwrq->length; - memcpy(key.key, extra, key.length); - if (key.length == 32) - /* we want WPA-PSK */ + if (dwrq->length > KEY_SIZE_TKIP) { + /* User-provided key data too big */ + return -EINVAL; + } + if (dwrq->length > KEY_SIZE_WEP104) { + /* WPA-PSK TKIP */ key.type = DOT11_PRIV_TKIP; + key.length = KEY_SIZE_TKIP; + } else if (dwrq->length > KEY_SIZE_WEP40) { + /* WEP 104/128 */ + key.length = KEY_SIZE_WEP104; + } else { + /* WEP 40/64 */ + key.length = KEY_SIZE_WEP40; + } + memset(key.key, 0, sizeof (key.key)); + memcpy(key.key, extra, dwrq->length); + if ((index < 0) || (index > 3)) /* no index provided use the current one */ index = current_index; @@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *n } } +static int prism54_set_genie(struct net_device *ndev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int alen, ret = 0; + struct obj_attachment *attach; + + if (data->length > MAX_WPA_IE_LEN || + (data->length && extra == NULL)) + return -EINVAL; + + memcpy(priv->wpa_ie, extra, data->length); + priv->wpa_ie_len = data->length; + + alen = sizeof(*attach) + priv->wpa_ie_len; + attach = kzalloc(alen, GFP_KERNEL); + if (attach == NULL) + return -ENOMEM; + +#define WLAN_FC_TYPE_MGMT 0 +#define WLAN_FC_STYPE_ASSOC_REQ 0 +#define WLAN_FC_STYPE_REASSOC_REQ 2 + + /* Note: endianness is covered by mgt_set_varlen */ + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_ASSOC_REQ << 4); + attach->id = -1; + attach->size = priv->wpa_ie_len; + memcpy(attach->data, extra, priv->wpa_ie_len); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, + priv->wpa_ie_len); + if (ret == 0) { + attach->type = (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_REASSOC_REQ << 4); + + ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, + priv->wpa_ie_len); + if (ret == 0) + printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", + ndev->name); + } + + kfree(attach); + return ret; +} + + +static int prism54_get_genie(struct net_device *ndev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + int len = priv->wpa_ie_len; + + if (len <= 0) { + data->length = 0; + return 0; + } + + if (data->length < len) + return -E2BIG; + + data->length = len; + memcpy(extra, priv->wpa_ie, len); + + return 0; +} + +static int prism54_set_auth(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct iw_param *param = &wrqu->param; + u32 mlmelevel = 0, authen = 0, dot1x = 0; + u32 exunencrypt = 0, privinvoked = 0, wpa = 0; + u32 old_wpa; + int ret = 0; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* first get the flags */ + down_write(&priv->mib_sem); + wpa = old_wpa = priv->wpa; + up_write(&priv->mib_sem); + ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + privinvoked = r.u; + ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); + dot1x = r.u; + ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r); + mlmelevel = r.u; + + if (ret < 0) + goto out; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + break; + + case IW_AUTH_WPA_ENABLED: + /* Do the same thing as IW_AUTH_WPA_VERSION */ + if (param->value) { + wpa = 1; + privinvoked = 1; /* For privacy invoked */ + exunencrypt = 1; /* Filter out all unencrypted frames */ + dot1x = 0x01; /* To enable eap filter */ + mlmelevel = DOT11_MLME_EXTENDED; + authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ + } else { + wpa = 0; + privinvoked = 0; + exunencrypt = 0; /* Do not filter un-encrypted data */ + dot1x = 0; + mlmelevel = DOT11_MLME_AUTO; + } + break; + + case IW_AUTH_WPA_VERSION: + if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { + wpa = 0; + privinvoked = 0; + exunencrypt = 0; /* Do not filter un-encrypted data */ + dot1x = 0; + mlmelevel = DOT11_MLME_AUTO; + } else { + if (param->value & IW_AUTH_WPA_VERSION_WPA) + wpa = 1; + else if (param->value & IW_AUTH_WPA_VERSION_WPA2) + wpa = 2; + privinvoked = 1; /* For privacy invoked */ + exunencrypt = 1; /* Filter out all unencrypted frames */ + dot1x = 0x01; /* To enable eap filter */ + mlmelevel = DOT11_MLME_EXTENDED; + authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ + } + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + dot1x = param->value ? 1 : 0; + break; + + case IW_AUTH_PRIVACY_INVOKED: + privinvoked = param->value ? 1 : 0; + + case IW_AUTH_DROP_UNENCRYPTED: + exunencrypt = param->value ? 1 : 0; + break; + + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) { + /* Only WEP uses _SK and _BOTH */ + if (wpa > 0) { + ret = -EINVAL; + goto out; + } + authen = DOT11_AUTH_SK; + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { + authen = DOT11_AUTH_OS; + } else { + ret = -EINVAL; + goto out; + } + break; + + default: + return -EOPNOTSUPP; + } + + /* Set all the values */ + down_write(&priv->mib_sem); + priv->wpa = wpa; + up_write(&priv->mib_sem); + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked); + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); + mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); + mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel); + +out: + return ret; +} + +static int prism54_get_auth(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct iw_param *param = &wrqu->param; + u32 wpa = 0; + int ret = 0; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* first get the flags */ + down_write(&priv->mib_sem); + wpa = priv->wpa; + up_write(&priv->mib_sem); + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * wpa_supplicant will control these internally + */ + ret = -EOPNOTSUPP; + break; + + case IW_AUTH_WPA_VERSION: + switch (wpa) { + case 1: + param->value = IW_AUTH_WPA_VERSION_WPA; + break; + case 2: + param->value = IW_AUTH_WPA_VERSION_WPA2; + break; + case 0: + default: + param->value = IW_AUTH_WPA_VERSION_DISABLED; + break; + } + break; + + case IW_AUTH_DROP_UNENCRYPTED: + ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + if (ret >= 0) + param->value = r.u > 0 ? 1 : 0; + break; + + case IW_AUTH_80211_AUTH_ALG: + ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + if (ret >= 0) { + switch (r.u) { + case DOT11_AUTH_OS: + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case DOT11_AUTH_BOTH: + case DOT11_AUTH_SK: + param->value = IW_AUTH_ALG_SHARED_KEY; + case DOT11_AUTH_NONE: + default: + param->value = 0; + break; + } + } + break; + + case IW_AUTH_WPA_ENABLED: + param->value = wpa > 0 ? 1 : 0; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); + if (ret >= 0) + param->value = r.u > 0 ? 1 : 0; + break; + + case IW_AUTH_PRIVACY_INVOKED: + ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + if (ret >= 0) + param->value = r.u > 0 ? 1 : 0; + break; + + default: + return -EOPNOTSUPP; + } + return ret; +} + +static int prism54_set_encodeext(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, alg = ext->alg, set_key = 1; + union oid_res_t r; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + int ret = 0; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* Determine and validate the key index */ + idx = (encoding->flags & IW_ENCODE_INDEX) - 1; + if (idx) { + if (idx < 0 || idx > 3) + return -EINVAL; + } else { + ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + if (ret < 0) + goto out; + idx = r.u; + } + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + /* Only set transmit key index here, actual + * key is set below if needed. + */ + ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx); + set_key = ext->key_len > 0 ? 1 : 0; + } + + if (set_key) { + struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; + switch (alg) { + case IW_ENCODE_ALG_NONE: + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len > KEY_SIZE_WEP104) { + ret = -EINVAL; + goto out; + } + if (ext->key_len > KEY_SIZE_WEP40) + key.length = KEY_SIZE_WEP104; + else + key.length = KEY_SIZE_WEP40; + break; + case IW_ENCODE_ALG_TKIP: + if (ext->key_len > KEY_SIZE_TKIP) { + ret = -EINVAL; + goto out; + } + key.type = DOT11_PRIV_TKIP; + key.length = KEY_SIZE_TKIP; + default: + return -EINVAL; + } + + if (key.length) { + memset(key.key, 0, sizeof(key.key)); + memcpy(key.key, ext->key, ext->key_len); + ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx, + &key); + if (ret < 0) + goto out; + } + } + + /* Read the flags */ + if (encoding->flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (encoding->flags & IW_ENCODE_OPEN) { + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + } + if (encoding->flags & IW_ENCODE_RESTRICTED) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + + /* do the change if requested */ + if (encoding->flags & IW_ENCODE_MODE) { + ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, + &authen); + ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, + &invoke); + ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + +out: + return ret; +} + + +static int prism54_get_encodeext(struct net_device *ndev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + islpci_private *priv = netdev_priv(ndev); + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int idx, max_key_len; + union oid_res_t r; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; + int ret = 0; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* first get the flags */ + ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + invoke = r.u; + ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + if (ret < 0) + goto out; + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = (encoding->flags & IW_ENCODE_INDEX) - 1; + if (idx) { + if (idx < 0 || idx > 3) + return -EINVAL; + } else { + ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + if (ret < 0) + goto out; + idx = r.u; + } + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + switch (authen) { + case DOT11_AUTH_BOTH: + case DOT11_AUTH_SK: + wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; + case DOT11_AUTH_OS: + default: + wrqu->encoding.flags |= IW_ENCODE_OPEN; + break; + } + + down_write(&priv->mib_sem); + wpa = priv->wpa; + up_write(&priv->mib_sem); + + if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { + /* No encryption */ + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + wrqu->encoding.flags |= IW_ENCODE_DISABLED; + } else { + struct obj_key *key; + + ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r); + if (ret < 0) + goto out; + key = r.ptr; + if (max_key_len < key->length) { + ret = -E2BIG; + goto out; + } + memcpy(ext->key, key->key, key->length); + ext->key_len = key->length; + + switch (key->type) { + case DOT11_PRIV_TKIP: + ext->alg = IW_ENCODE_ALG_TKIP; + break; + default: + case DOT11_PRIV_WEP: + ext->alg = IW_ENCODE_ALG_WEP; + break; + } + wrqu->encoding.flags |= IW_ENCODE_ENABLED; + } + +out: + return ret; +} + + static int prism54_reset(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra) @@ -1591,8 +2081,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" static void -prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, - u8 *wpa_ie, size_t wpa_ie_len) +prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len) { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; @@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv, } static size_t -prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) +prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; @@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv, } void -prism54_wpa_ie_init(islpci_private *priv) +prism54_wpa_bss_ie_init(islpci_private *priv) { INIT_LIST_HEAD(&priv->bss_wpa_list); sema_init(&priv->wpa_sem, 1); } void -prism54_wpa_ie_clean(islpci_private *priv) +prism54_wpa_bss_ie_clean(islpci_private *priv) { struct list_head *ptr, *n; @@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && memcmp(pos + 2, wpa_oid, 4) == 0) { - prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); + prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2); return; } pos += 2 + pos[1]; @@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_priva send_formatted_event(priv, "Associate request (ex)", mlme, 1); if (priv->iw_mode != IW_MODE_MASTER - && mlmeex->state != DOT11_STATE_AUTHING) + && mlmeex->state != DOT11_STATE_ASSOCING) break; confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); @@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_priva confirm->state = 0; /* not used */ confirm->code = 0; - wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { printk(KERN_DEBUG "No WPA IE found from " @@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_priva confirm->state = 0; /* not used */ confirm->code = 0; - wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); + wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { printk(KERN_DEBUG "No WPA IE found from " @@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[ (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ (iw_handler) NULL, /* SIOCSIWPOWER */ (iw_handler) NULL, /* SIOCGIWPOWER */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */ + (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */ + (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */ + (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */ + (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */ + NULL, /* SIOCSIWPMKSA */ }; /* The low order bit identify a SET (0) or a GET (1) ioctl. */ diff -puN drivers/net/wireless/prism54/isl_ioctl.h~git-netdev-all drivers/net/wireless/prism54/isl_ioctl.h --- a/drivers/net/wireless/prism54/isl_ioctl.h~git-netdev-all +++ a/drivers/net/wireless/prism54/isl_ioctl.h @@ -27,7 +27,7 @@ #include /* New driver API */ -#define SUPPORTED_WIRELESS_EXT 16 +#define SUPPORTED_WIRELESS_EXT 19 void prism54_mib_init(islpci_private *); @@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl void prism54_process_trap(void *); -void prism54_wpa_ie_init(islpci_private *priv); -void prism54_wpa_ie_clean(islpci_private *priv); +void prism54_wpa_bss_ie_init(islpci_private *priv); +void prism54_wpa_bss_ie_clean(islpci_private *priv); int prism54_set_mac_address(struct net_device *, void *); diff -puN drivers/net/wireless/prism54/islpci_dev.c~git-netdev-all drivers/net/wireless/prism54/islpci_dev.c --- a/drivers/net/wireless/prism54/islpci_dev.c~git-netdev-all +++ a/drivers/net/wireless/prism54/islpci_dev.c @@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv } prism54_acl_init(&priv->acl); - prism54_wpa_ie_init(priv); + prism54_wpa_bss_ie_init(priv); if (mgt_init(priv)) goto out_free; @@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv) /* Free the acces control list and the WPA list */ prism54_acl_clean(&priv->acl); - prism54_wpa_ie_clean(priv); + prism54_wpa_bss_ie_clean(priv); mgt_clean(priv); return 0; diff -puN drivers/net/wireless/prism54/islpci_dev.h~git-netdev-all drivers/net/wireless/prism54/islpci_dev.h --- a/drivers/net/wireless/prism54/islpci_dev.h~git-netdev-all +++ a/drivers/net/wireless/prism54/islpci_dev.h @@ -179,6 +179,8 @@ typedef struct { struct list_head bss_wpa_list; int num_bss_wpa; struct semaphore wpa_sem; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; struct work_struct reset_task; int reset_task_pending; diff -puN drivers/net/wireless/prism54/islpci_hotplug.c~git-netdev-all drivers/net/wireless/prism54/islpci_hotplug.c --- a/drivers/net/wireless/prism54/islpci_hotplug.c~git-netdev-all +++ a/drivers/net/wireless/prism54/islpci_hotplug.c @@ -313,7 +313,7 @@ prism54_module_init(void) __bug_on_wrong_struct_sizes (); - return pci_module_init(&prism54_driver); + return pci_register_driver(&prism54_driver); } /* by the time prism54_module_exit() terminates, as a postcondition diff -puN drivers/net/wireless/ray_cs.c~git-netdev-all drivers/net/wireless/ray_cs.c --- a/drivers/net/wireless/ray_cs.c~git-netdev-all +++ a/drivers/net/wireless/ray_cs.c @@ -52,8 +52,8 @@ #include #include -#include #include +#include #include #include diff -puN drivers/net/wireless/spectrum_cs.c~git-netdev-all drivers/net/wireless/spectrum_cs.c diff -puN drivers/net/wireless/zd1211rw/Makefile~git-netdev-all drivers/net/wireless/zd1211rw/Makefile --- a/drivers/net/wireless/zd1211rw/Makefile~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o zd1211rw-objs := zd_chip.o zd_ieee80211.o \ zd_mac.o zd_netdev.o \ zd_rf_al2230.o zd_rf_rf2959.o \ + zd_rf_al7230b.o \ zd_rf.o zd_usb.o zd_util.o ifeq ($(CONFIG_ZD1211RW_DEBUG),y) diff -puN drivers/net/wireless/zd1211rw/zd_chip.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_chip.c --- a/drivers/net/wireless/zd1211rw/zd_chip.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_chip.c @@ -42,12 +42,11 @@ void zd_chip_init(struct zd_chip *chip, void zd_chip_clear(struct zd_chip *chip) { - mutex_lock(&chip->mutex); + ZD_ASSERT(!mutex_is_locked(&chip->mutex)); zd_usb_clear(&chip->usb); zd_rf_clear(&chip->rf); - mutex_unlock(&chip->mutex); mutex_destroy(&chip->mutex); - memset(chip, 0, sizeof(*chip)); + ZD_MEMCLEAR(chip, sizeof(*chip)); } static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size) @@ -68,10 +67,11 @@ 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", chip->pa_type, + i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type, chip->patch_cck_gain ? 'g' : '-', chip->patch_cr157 ? '7' : '-', - chip->patch_6m_band_edge ? '6' : '-'); + chip->patch_6m_band_edge ? '6' : '-', + chip->new_phy_layout ? 'N' : '-'); return i; } @@ -330,13 +330,14 @@ static int read_pod(struct zd_chip *chip chip->patch_cck_gain = (value >> 8) & 0x1; chip->patch_cr157 = (value >> 13) & 0x1; chip->patch_6m_band_edge = (value >> 21) & 0x1; + chip->new_phy_layout = (value >> 31) & 0x1; dev_dbg_f(zd_chip_dev(chip), "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d " - "patch 6M %d\n", + "patch 6M %d new PHY %d\n", zd_rf_name(*rf_type), *rf_type, chip->pa_type, chip->patch_cck_gain, - chip->patch_cr157, chip->patch_6m_band_edge); + chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout); return 0; error: *rf_type = 0; @@ -344,6 +345,7 @@ error: chip->patch_cck_gain = 0; chip->patch_cr157 = 0; chip->patch_6m_band_edge = 0; + chip->new_phy_layout = 0; return r; } @@ -717,7 +719,7 @@ static int zd1211b_hw_reset_phy(struct z { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, - { CR30, 0x49 }, /* jointly decoder, no ASIC */ + { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, @@ -807,7 +809,6 @@ static int zd1211_hw_init_hmac(struct zd { CR_ACK_TIMEOUT_EXT, 0x80 }, { CR_ADDA_PWR_DWN, 0x00 }, { CR_ACK_TIME_80211, 0x100 }, - { CR_IFS_VALUE, 0x547c032 }, { CR_RX_PE_DELAY, 0x70 }, { CR_PS_CTRL, 0x10000000 }, { CR_RTS_CTS_RATE, 0x02030203 }, @@ -854,11 +855,10 @@ static int zd1211b_hw_init_hmac(struct z { CR_ACK_TIMEOUT_EXT, 0x80 }, { CR_ADDA_PWR_DWN, 0x00 }, { CR_ACK_TIME_80211, 0x100 }, - { CR_IFS_VALUE, 0x547c032 }, { CR_RX_PE_DELAY, 0x70 }, { CR_PS_CTRL, 0x10000000 }, { CR_RTS_CTS_RATE, 0x02030203 }, - { CR_RX_THRESHOLD, 0x000c0640 }, + { CR_RX_THRESHOLD, 0x000c0eff, }, { CR_AFTER_PNP, 0x1 }, { CR_WEP_PROTECT, 0x114 }, }; @@ -970,10 +970,15 @@ static int hw_init(struct zd_chip *chip) r = hw_init_hmac(chip); if (r) return r; - r = set_beacon_interval(chip, 100); + + /* Although the vendor driver defaults to a different value during + * init, it overwrites the IFS value with the following every time + * the channel changes. We should aim to be more intelligent... */ + r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE); if (r) return r; - return 0; + + return set_beacon_interval(chip, 100); } #ifdef DEBUG @@ -1613,3 +1618,34 @@ int zd_rfwritev_locked(struct zd_chip *c return 0; } + +/* + * We can optionally program the RF directly through CR regs, if supported by + * the hardware. This is much faster than the older method. + */ +int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) +{ + struct zd_ioreq16 ioreqs[] = { + { CR244, (value >> 16) & 0xff }, + { CR243, (value >> 8) & 0xff }, + { CR242, value & 0xff }, + }; + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +int zd_rfwritev_cr_locked(struct zd_chip *chip, + const u32 *values, unsigned int count) +{ + int r; + unsigned int i; + + for (i = 0; i < count; i++) { + r = zd_rfwrite_cr_locked(chip, values[i]); + if (r) + return r; + } + + return 0; +} + diff -puN drivers/net/wireless/zd1211rw/zd_chip.h~git-netdev-all drivers/net/wireless/zd1211rw/zd_chip.h --- a/drivers/net/wireless/zd1211rw/zd_chip.h~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_chip.h @@ -473,7 +473,15 @@ #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690) #define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694) + #define CR_IFS_VALUE CTL_REG(0x0698) +#define IFS_VALUE_DIFS_SH 0 +#define IFS_VALUE_EIFS_SH 12 +#define IFS_VALUE_SIFS_SH 24 +#define IFS_VALUE_DEFAULT (( 50 << IFS_VALUE_DIFS_SH) | \ + (1148 << IFS_VALUE_EIFS_SH) | \ + ( 10 << IFS_VALUE_SIFS_SH)) + #define CR_RX_TIME_OUT CTL_REG(0x069C) #define CR_TOTAL_RX_FRM CTL_REG(0x06A0) #define CR_CRC32_CNT CTL_REG(0x06A4) @@ -630,6 +638,7 @@ enum { LOAD_CODE_SIZE = 0xe, /* words */ LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */ EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE, + EEPROM_REGS_SIZE = 0x7e, /* words */ E2P_BASE_OFFSET = EEPROM_START_OFFSET + EEPROM_REGS_OFFSET, }; @@ -655,7 +664,7 @@ struct zd_chip { /* SetPointOFDM in the vendor driver */ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT]; u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, - is_zd1211b:1; + new_phy_layout:1, is_zd1211b:1; }; static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) @@ -739,8 +748,12 @@ static inline int zd_rfwrite_locked(stru return zd_usb_rfwrite(&chip->usb, value, bits); } +int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value); + int zd_rfwritev_locked(struct zd_chip *chip, const u32* values, unsigned int count, u8 bits); +int zd_rfwritev_cr_locked(struct zd_chip *chip, + const u32* values, unsigned int count); /* Locking functions for reading and writing registers. * The different parameters are intentional. diff -puN drivers/net/wireless/zd1211rw/zd_def.h~git-netdev-all drivers/net/wireless/zd1211rw/zd_def.h --- a/drivers/net/wireless/zd1211rw/zd_def.h~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_def.h @@ -45,4 +45,10 @@ do { \ # define ZD_ASSERT(x) do { } while (0) #endif +#ifdef DEBUG +# define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size)) +#else +# define ZD_MEMCLEAR(pointer, size) do { } while (0) +#endif + #endif /* _ZD_DEF_H */ diff -puN drivers/net/wireless/zd1211rw/zd_mac.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_mac.c --- a/drivers/net/wireless/zd1211rw/zd_mac.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_mac.c @@ -127,11 +127,9 @@ out: void zd_mac_clear(struct zd_mac *mac) { - /* Aquire the lock. */ - spin_lock(&mac->lock); - spin_unlock(&mac->lock); zd_chip_clear(&mac->chip); - memset(mac, 0, sizeof(*mac)); + ZD_ASSERT(!spin_is_locked(&mac->lock)); + ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); } static int reset_mode(struct zd_mac *mac) diff -puN drivers/net/wireless/zd1211rw/zd_mac.h~git-netdev-all drivers/net/wireless/zd1211rw/zd_mac.h --- a/drivers/net/wireless/zd1211rw/zd_mac.h~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_mac.h @@ -121,9 +121,9 @@ enum mac_flags { }; struct zd_mac { - struct net_device *netdev; struct zd_chip chip; spinlock_t lock; + struct net_device *netdev; /* Unlocked reading possible */ struct iw_statistics iw_stats; u8 qual_average; diff -puN drivers/net/wireless/zd1211rw/zd_netdev.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_netdev.c --- a/drivers/net/wireless/zd1211rw/zd_netdev.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_netdev.c @@ -72,10 +72,18 @@ static int iw_get_name(struct net_device struct iw_request_info *info, union iwreq_data *req, char *extra) { - /* FIXME: check whether 802.11a will also supported, add also - * zd1211B, if we support it. - */ - strlcpy(req->name, "802.11g zd1211", IFNAMSIZ); + /* FIXME: check whether 802.11a will also supported */ + strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ); + return 0; +} + +static int iw_get_nick(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *req, char *extra) +{ + strcpy(extra, "zd1211"); + req->data.length = strlen(extra) + 1; + req->data.flags = 1; return 0; } @@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_d static const iw_handler zd_standard_iw_handlers[] = { WX(SIOCGIWNAME) = iw_get_name, + WX(SIOCGIWNICKN) = iw_get_nick, WX(SIOCSIWFREQ) = iw_set_freq, WX(SIOCGIWFREQ) = iw_get_freq, WX(SIOCSIWMODE) = iw_set_mode, diff -puN drivers/net/wireless/zd1211rw/zd_rf.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_rf.c --- a/drivers/net/wireless/zd1211rw/zd_rf.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_rf.c @@ -56,7 +56,7 @@ void zd_rf_init(struct zd_rf *rf) void zd_rf_clear(struct zd_rf *rf) { - memset(rf, 0, sizeof(*rf)); + ZD_MEMCLEAR(rf, sizeof(*rf)); } int zd_rf_init_hw(struct zd_rf *rf, u8 type) @@ -76,6 +76,11 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 t if (r) return r; break; + case AL7230B_RF: + r = zd_rf_init_al7230b(rf); + if (r) + return r; + break; default: dev_err(zd_chip_dev(chip), "RF %s %#x is not supported\n", zd_rf_name(type), type); diff -puN drivers/net/wireless/zd1211rw/zd_rf.h~git-netdev-all drivers/net/wireless/zd1211rw/zd_rf.h --- a/drivers/net/wireless/zd1211rw/zd_rf.h~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_rf.h @@ -78,5 +78,6 @@ int zd_switch_radio_off(struct zd_rf *rf int zd_rf_init_rf2959(struct zd_rf *rf); int zd_rf_init_al2230(struct zd_rf *rf); +int zd_rf_init_al7230b(struct zd_rf *rf); #endif /* _ZD_RF_H */ diff -puN drivers/net/wireless/zd1211rw/zd_rf_al2230.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_rf_al2230.c --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -21,7 +21,7 @@ #include "zd_usb.h" #include "zd_chip.h" -static const u32 al2230_table[][3] = { +static const u32 zd1211_al2230_table[][3] = { RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, }, RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, }, RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, }, @@ -38,6 +38,53 @@ static const u32 al2230_table[][3] = { RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, }, }; +static const u32 zd1211b_al2230_table[][3] = { + RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, }, + RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, }, + RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, }, +}; + +static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { + { CR240, 0x57 }, { CR9, 0xe0 }, +}; + +static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) +{ + int r; + static const struct zd_ioreq16 ioreqs[] = { + { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, + { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, + { CR203, 0x06 }, + { }, + + { CR240, 0x80 }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + /* related to antenna selection? */ + if (chip->new_phy_layout) { + r = zd_iowrite16_locked(chip, 0xe1, CR9); + if (r) + return r; + } + + return zd_iowrite16_locked(chip, 0x06, CR203); +} + static int zd1211_al2230_init_hw(struct zd_rf *rf) { int r; @@ -139,7 +186,7 @@ static int zd1211b_al2230_init_hw(struct { CR47, 0x1e }, /* ZD1211B 05.06.10 */ - { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, + { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, { CR69, 0x28 }, @@ -172,79 +219,78 @@ static int zd1211b_al2230_init_hw(struct { CR137, 0x50 }, /* 5614 */ { CR138, 0xa8 }, { CR144, 0xac }, /* 5621 */ - { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 }, + { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, }; static const u32 rv1[] = { - /* channel 1 */ - 0x03f790, - 0x033331, - 0x00000d, + 0x8cccd0, + 0x481dc0, + 0xcfff00, + 0x25a000, + + /* To improve AL2230 yield, improve phase noise, 4713 */ + 0x25a000, + 0xa3b2f0, + + 0x6da010, /* Reg6 update for MP versio */ + 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ + 0x116000, + 0x9dc020, /* External control TX power (CR31) */ + 0x5ddb00, /* RegA update for MP version */ + 0xd99000, /* RegB update for MP version */ + 0x3ffbd0, /* RegC update for MP version */ + 0xb00000, /* RegD update for MP version */ - 0x0b3331, - 0x03b812, - 0x00fff3, - 0x0005a4, - 0x0f4dc5, /* fix freq shift 0x044dc5 */ - 0x0805b6, - 0x0146c7, - 0x000688, - 0x0403b9, /* External control TX power (CR31) */ - 0x00dbba, - 0x00099b, - 0x0bdffc, - 0x00000d, - 0x00580f, + /* improve phase noise and remove phase calibration,4713 */ + 0xf01a00, }; static const struct zd_ioreq16 ioreqs2[] = { - { CR47, 0x1e }, { CR_RFCFG, 0x03 }, + { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ + { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; static const u32 rv2[] = { - 0x00880f, - 0x00080f, + /* To improve AL2230 yield, 4713 */ + 0xf01b00, + 0xf01e00, + 0xf01a00, }; static const struct zd_ioreq16 ioreqs3[] = { - { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f }, - }; - - static const u32 rv3[] = { - 0x00d80f, - 0x00780f, - 0x00580f, - }; - - static const struct zd_ioreq16 ioreqs4[] = { - { CR138, 0x28 }, { CR203, 0x06 }, + /* related to 6M band edge patching, happens unconditionally */ + { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, }; + r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, + ARRAY_SIZE(zd1211b_ioreqs_shared_1)); + if (r) + return r; r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); if (r) return r; - r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS); + r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); + r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); if (r) return r; - r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS); + r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); + r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); if (r) return r; - r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS); + r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); if (r) return r; - return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4)); + return zd1211b_al2230_finalize_rf(chip); } -static int al2230_set_channel(struct zd_rf *rf, u8 channel) +static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) { int r; - const u32 *rv = al2230_table[channel-1]; + const u32 *rv = zd1211_al2230_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { { CR138, 0x28 }, @@ -257,6 +303,24 @@ static int al2230_set_channel(struct zd_ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } +static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel) +{ + int r; + const u32 *rv = zd1211b_al2230_table[channel-1]; + struct zd_chip *chip = zd_rf_to_chip(rf); + + r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, + ARRAY_SIZE(zd1211b_ioreqs_shared_1)); + if (r) + return r; + + r = zd_rfwritev_cr_locked(chip, rv, 3); + if (r) + return r; + + return zd1211b_al2230_finalize_rf(chip); +} + static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); @@ -294,13 +358,14 @@ int zd_rf_init_al2230(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); - rf->set_channel = al2230_set_channel; rf->switch_radio_off = al2230_switch_radio_off; if (chip->is_zd1211b) { rf->init_hw = zd1211b_al2230_init_hw; + rf->set_channel = zd1211b_al2230_set_channel; rf->switch_radio_on = zd1211b_al2230_switch_radio_on; } else { rf->init_hw = zd1211_al2230_init_hw; + rf->set_channel = zd1211_al2230_set_channel; rf->switch_radio_on = zd1211_al2230_switch_radio_on; } rf->patch_6m_band_edge = 1; diff -puN /dev/null drivers/net/wireless/zd1211rw/zd_rf_al7230b.c --- /dev/null +++ a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -0,0 +1,274 @@ +/* zd_rf_al7230b.c: Functions for the AL7230B RF controller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "zd_rf.h" +#include "zd_usb.h" +#include "zd_chip.h" + +static const u32 chan_rv[][2] = { + RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 }, + RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 }, + RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 }, + RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 }, + RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 }, + RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 }, + RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 }, + RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 }, + RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 }, + RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 }, + RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 }, + RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 }, + RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 }, + RF_CHANNEL(14) = { 0x03ec00, 0x866660 }, +}; + +static const u32 std_rv[] = { + 0x4ff821, + 0xc5fbfc, + 0x21ebfe, + 0xafd401, /* freq shift 0xaad401 */ + 0x6cf56a, + 0xe04073, + 0x193d76, + 0x9dd844, + 0x500007, + 0xd8c010, +}; + +static int al7230b_init_hw(struct zd_rf *rf) +{ + int i, r; + struct zd_chip *chip = zd_rf_to_chip(rf); + + /* All of these writes are identical to AL2230 unless otherwise + * specified */ + static const struct zd_ioreq16 ioreqs_1[] = { + /* This one is 7230-specific, and happens before the rest */ + { CR240, 0x57 }, + { }, + + { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, + { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, + { CR44, 0x33 }, + /* This value is different for 7230 (was: 0x2a) */ + { CR106, 0x22 }, + { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, + { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, + /* This happened further down in AL2230, + * and the value changed (was: 0xe0) */ + { CR122, 0xfc }, + { CR10, 0x89 }, + /* for newest (3rd cut) AL2300 */ + { CR17, 0x28 }, + { CR26, 0x93 }, { CR34, 0x30 }, + /* for newest (3rd cut) AL2300 */ + { CR35, 0x3e }, + { CR41, 0x24 }, { CR44, 0x32 }, + /* for newest (3rd cut) AL2300 */ + { CR46, 0x96 }, + { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, + { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, + { CR92, 0x0a }, { CR99, 0x28 }, + /* This value is different for 7230 (was: 0x00) */ + { CR100, 0x02 }, + { CR101, 0x13 }, { CR102, 0x27 }, + /* This value is different for 7230 (was: 0x24) */ + { CR106, 0x22 }, + /* This value is different for 7230 (was: 0x2a) */ + { CR107, 0x3f }, + { CR109, 0x09 }, + /* This value is different for 7230 (was: 0x13) */ + { CR110, 0x1f }, + { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, + { CR114, 0x27 }, + /* for newest (3rd cut) AL2300 */ + { CR115, 0x24 }, + /* This value is different for 7230 (was: 0x24) */ + { CR116, 0x3f }, + /* This value is different for 7230 (was: 0xf4) */ + { CR117, 0xfa }, + { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, + { CR121, 0x77 }, { CR137, 0x88 }, + /* This one is 7230-specific */ + { CR138, 0xa8 }, + /* This value is different for 7230 (was: 0xff) */ + { CR252, 0x34 }, + /* This value is different for 7230 (was: 0xff) */ + { CR253, 0x34 }, + + /* PLL_OFF */ + { CR251, 0x2f }, + }; + + static const struct zd_ioreq16 ioreqs_2[] = { + /* PLL_ON */ + { CR251, 0x3f }, + { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { CR38, 0x38 }, { CR136, 0xdf }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); + if (r) + return r; + + r = zd_rfwrite_cr_locked(chip, 0x09ec04); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0x8cccc8); + if (r) + return r; + + for (i = 0; i < ARRAY_SIZE(std_rv); i++) { + r = zd_rfwrite_cr_locked(chip, std_rv[i]); + if (r) + return r; + } + + r = zd_rfwrite_cr_locked(chip, 0x3c9000); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xbfffff); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0x700000); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xf15d58); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); + if (r) + return r; + + r = zd_rfwrite_cr_locked(chip, 0xf15d59); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xf15d5c); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xf15d58); + if (r) + return r; + + r = zd_iowrite16_locked(chip, 0x06, CR203); + if (r) + return r; + r = zd_iowrite16_locked(chip, 0x80, CR240); + if (r) + return r; + + return 0; +} + +static int al7230b_set_channel(struct zd_rf *rf, u8 channel) +{ + int i, r; + const u32 *rv = chan_rv[channel-1]; + struct zd_chip *chip = zd_rf_to_chip(rf); + + struct zd_ioreq16 ioreqs_1[] = { + { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { CR38, 0x38 }, { CR136, 0xdf }, + }; + + struct zd_ioreq16 ioreqs_2[] = { + /* PLL_ON */ + { CR251, 0x3f }, + { CR203, 0x06 }, { CR240, 0x08 }, + }; + + r = zd_iowrite16_locked(chip, 0x57, CR240); + if (r) + return r; + + /* PLL_OFF */ + r = zd_iowrite16_locked(chip, 0x2f, CR251); + if (r) + return r; + + for (i = 0; i < ARRAY_SIZE(std_rv); i++) { + r = zd_rfwrite_cr_locked(chip, std_rv[i]); + if (r) + return r; + } + + r = zd_rfwrite_cr_locked(chip, 0x3c9000); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xf15d58); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); + if (r) + return r; + + for (i = 0; i < 2; i++) { + r = zd_rfwrite_cr_locked(chip, rv[i]); + if (r) + return r; + } + + r = zd_rfwrite_cr_locked(chip, 0x3c9000); + if (r) + return r; + + return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); +} + +static int al7230b_switch_radio_on(struct zd_rf *rf) +{ + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { + { CR11, 0x00 }, + { CR251, 0x3f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int al7230b_switch_radio_off(struct zd_rf *rf) +{ + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { + { CR11, 0x04 }, + { CR251, 0x2f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +int zd_rf_init_al7230b(struct zd_rf *rf) +{ + struct zd_chip *chip = zd_rf_to_chip(rf); + + if (chip->is_zd1211b) { + dev_err(zd_chip_dev(chip), "AL7230B is currently not " + "supported for ZD1211B devices\n"); + return -ENODEV; + } + + rf->init_hw = al7230b_init_hw; + rf->set_channel = al7230b_set_channel; + rf->switch_radio_on = al7230b_switch_radio_on; + rf->switch_radio_off = al7230b_switch_radio_off; + rf->patch_6m_band_edge = 1; + return 0; +} diff -puN drivers/net/wireless/zd1211rw/zd_usb.c~git-netdev-all drivers/net/wireless/zd1211rw/zd_usb.c --- a/drivers/net/wireless/zd1211rw/zd_usb.c~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_usb.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -39,9 +40,17 @@ static struct usb_device_id usb_ids[] = { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, + /* "Driverless" devices that need ejecting */ + { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} }; @@ -263,6 +272,39 @@ static char *get_fw_name(char *buffer, s return buffer; } +static int handle_version_mismatch(struct usb_device *udev, u8 device_type, + const struct firmware *ub_fw) +{ + const struct firmware *ur_fw = NULL; + int offset; + int r = 0; + char fw_name[128]; + + r = request_fw_file(&ur_fw, + get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"), + &udev->dev); + if (r) + goto error; + + r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET, + REBOOT); + if (r) + goto error; + + offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16)); + r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset, + E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT); + + /* At this point, the vendor driver downloads the whole firmware + * image, hacks around with version IDs, and uploads it again, + * completely overwriting the boot code. We do not do this here as + * it is not required on any tested devices, and it is suspected to + * cause problems. */ +error: + release_firmware(ur_fw); + return r; +} + static int upload_firmware(struct usb_device *udev, u8 device_type) { int r; @@ -282,15 +324,17 @@ static int upload_firmware(struct usb_de fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET); - /* FIXME: do we have any reason to perform the kludge that the vendor - * driver does when there is a version mismatch? (their driver uploads - * different firmwares and stuff) - */ if (fw_bcdDevice != bcdDevice) { dev_info(&udev->dev, - "firmware device id %#06x and actual device id " - "%#06x differ, continuing anyway\n", - fw_bcdDevice, bcdDevice); + "firmware version %#06x and device bootcode version " + "%#06x differ\n", fw_bcdDevice, bcdDevice); + if (bcdDevice <= 0x4313) + dev_warn(&udev->dev, "device has old bootcode, please " + "report success or failure\n"); + + r = handle_version_mismatch(udev, device_type, ub_fw); + if (r) + goto error; } else { dev_dbg_f(&udev->dev, "firmware device id %#06x is equal to the " @@ -620,7 +664,7 @@ resubmit: usb_submit_urb(urb, GFP_ATOMIC); } -struct urb *alloc_urb(struct zd_usb *usb) +static struct urb *alloc_urb(struct zd_usb *usb) { struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; @@ -644,7 +688,7 @@ struct urb *alloc_urb(struct zd_usb *usb return urb; } -void free_urb(struct urb *urb) +static void free_urb(struct urb *urb) { if (!urb) return; @@ -864,7 +908,7 @@ void zd_usb_clear(struct zd_usb *usb) { usb_set_intfdata(usb->intf, NULL); usb_put_intf(usb->intf); - memset(usb, 0, sizeof(*usb)); + ZD_MEMCLEAR(usb, sizeof(*usb)); /* FIXME: usb_interrupt, usb_tx, usb_rx? */ } @@ -910,6 +954,55 @@ static void print_id(struct usb_device * #define print_id(udev) do { } while (0) #endif +static int eject_installer(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_interface *iface_desc = &intf->altsetting[0]; + struct usb_endpoint_descriptor *endpoint; + unsigned char *cmd; + u8 bulk_out_ep; + int r; + + /* Find bulk out endpoint */ + endpoint = &iface_desc->endpoint[1].desc; + if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT && + (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK) { + bulk_out_ep = endpoint->bEndpointAddress; + } else { + dev_err(&udev->dev, + "zd1211rw: Could not find bulk out endpoint\n"); + return -ENODEV; + } + + cmd = kzalloc(31, GFP_KERNEL); + if (cmd == NULL) + return -ENODEV; + + /* USB bulk command block */ + cmd[0] = 0x55; /* bulk command signature */ + cmd[1] = 0x53; /* bulk command signature */ + cmd[2] = 0x42; /* bulk command signature */ + cmd[3] = 0x43; /* bulk command signature */ + cmd[14] = 6; /* command length */ + + cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */ + cmd[19] = 0x2; /* eject disc */ + + dev_info(&udev->dev, "Ejecting virtual installer media...\n"); + r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), + cmd, 31, NULL, 2000); + kfree(cmd); + if (r) + return r; + + /* At this point, the device disconnects and reconnects with the real + * ID numbers. */ + + usb_set_intfdata(intf, NULL); + return 0; +} + static int probe(struct usb_interface *intf, const struct usb_device_id *id) { int r; @@ -918,6 +1011,9 @@ static int probe(struct usb_interface *i print_id(udev); + if (id->driver_info & DEVICE_INSTALLER) + return eject_installer(intf); + switch (udev->speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: @@ -983,6 +1079,11 @@ static void disconnect(struct usb_interf struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_usb *usb = &mac->chip.usb; + /* Either something really bad happened, or we're just dealing with + * a DEVICE_INSTALLER. */ + if (netdev == NULL) + return; + dev_dbg_f(zd_usb_dev(usb), "\n"); zd_netdev_disconnect(netdev); @@ -998,7 +1099,6 @@ static void disconnect(struct usb_interf */ usb_reset_device(interface_to_usbdev(intf)); - /* If somebody still waits on this lock now, this is an error. */ zd_netdev_free(netdev); dev_dbg(&intf->dev, "disconnected\n"); } diff -puN drivers/net/wireless/zd1211rw/zd_usb.h~git-netdev-all drivers/net/wireless/zd1211rw/zd_usb.h --- a/drivers/net/wireless/zd1211rw/zd_usb.h~git-netdev-all +++ a/drivers/net/wireless/zd1211rw/zd_usb.h @@ -30,6 +30,7 @@ enum devicetype { DEVICE_ZD1211 = 0, DEVICE_ZD1211B = 1, + DEVICE_INSTALLER = 2, }; enum endpoints { diff -puN drivers/net/yellowfin.c~git-netdev-all drivers/net/yellowfin.c --- a/drivers/net/yellowfin.c~git-netdev-all +++ a/drivers/net/yellowfin.c @@ -1434,7 +1434,7 @@ static int __init yellowfin_init (void) #ifdef MODULE printk(version); #endif - return pci_module_init (&yellowfin_driver); + return pci_register_driver(&yellowfin_driver); } diff -puN drivers/s390/net/qeth_main.c~git-netdev-all drivers/s390/net/qeth_main.c --- a/drivers/s390/net/qeth_main.c~git-netdev-all +++ a/drivers/s390/net/qeth_main.c @@ -8510,9 +8510,9 @@ static int qeth_ipv6_init(void) { qeth_old_arp_constructor = arp_tbl.constructor; - write_lock(&arp_tbl.lock); + write_lock_bh(&arp_tbl.lock); arp_tbl.constructor = qeth_arp_constructor; - write_unlock(&arp_tbl.lock); + write_unlock_bh(&arp_tbl.lock); arp_direct_ops = (struct neigh_ops*) kmalloc(sizeof(struct neigh_ops), GFP_KERNEL); @@ -8528,9 +8528,9 @@ qeth_ipv6_init(void) static void qeth_ipv6_uninit(void) { - write_lock(&arp_tbl.lock); + write_lock_bh(&arp_tbl.lock); arp_tbl.constructor = qeth_old_arp_constructor; - write_unlock(&arp_tbl.lock); + write_unlock_bh(&arp_tbl.lock); kfree(arp_direct_ops); } #endif /* CONFIG_QETH_IPV6 */ diff -puN include/asm-ppc/cpm2.h~git-netdev-all include/asm-ppc/cpm2.h --- a/include/asm-ppc/cpm2.h~git-netdev-all +++ a/include/asm-ppc/cpm2.h @@ -1093,5 +1093,100 @@ typedef struct im_idma { #define FCC_PSMR_RMII ((uint)0x00020000) /* Use RMII interface */ +/* FCC iop & clock configuration. BSP code is responsible to define Fx_RXCLK & Fx_TXCLK + * in order to use clock-computing stuff below for the FCC x + */ + +/* Automatically generates register configurations */ +#define PC_CLK(x) ((uint)(1<<(x-1))) /* FCC CLK I/O ports */ + +#define CMXFCR_RF1CS(x) ((uint)((x-5)<<27)) /* FCC1 Receive Clock Source */ +#define CMXFCR_TF1CS(x) ((uint)((x-5)<<24)) /* FCC1 Transmit Clock Source */ +#define CMXFCR_RF2CS(x) ((uint)((x-9)<<19)) /* FCC2 Receive Clock Source */ +#define CMXFCR_TF2CS(x) ((uint)((x-9)<<16)) /* FCC2 Transmit Clock Source */ +#define CMXFCR_RF3CS(x) ((uint)((x-9)<<11)) /* FCC3 Receive Clock Source */ +#define CMXFCR_TF3CS(x) ((uint)((x-9)<<8)) /* FCC3 Transmit Clock Source */ + +#define PC_F1RXCLK PC_CLK(F1_RXCLK) +#define PC_F1TXCLK PC_CLK(F1_TXCLK) +#define CMX1_CLK_ROUTE (CMXFCR_RF1CS(F1_RXCLK) | CMXFCR_TF1CS(F1_TXCLK)) +#define CMX1_CLK_MASK ((uint)0xff000000) + +#define PC_F2RXCLK PC_CLK(F2_RXCLK) +#define PC_F2TXCLK PC_CLK(F2_TXCLK) +#define CMX2_CLK_ROUTE (CMXFCR_RF2CS(F2_RXCLK) | CMXFCR_TF2CS(F2_TXCLK)) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +#define PC_F3RXCLK PC_CLK(F3_RXCLK) +#define PC_F3TXCLK PC_CLK(F3_TXCLK) +#define CMX3_CLK_ROUTE (CMXFCR_RF3CS(F3_RXCLK) | CMXFCR_TF3CS(F3_TXCLK)) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +#define CPMUX_CLK_MASK (CMX3_CLK_MASK | CMX2_CLK_MASK) +#define CPMUX_CLK_ROUTE (CMX3_CLK_ROUTE | CMX2_CLK_ROUTE) + +#define CLK_TRX (PC_F3TXCLK | PC_F3RXCLK | PC_F2TXCLK | PC_F2RXCLK) + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL 0x00000001U +#define PA1_CRS 0x00000002U +#define PA1_TXER 0x00000004U +#define PA1_TXEN 0x00000008U +#define PA1_RXDV 0x00000010U +#define PA1_RXER 0x00000020U +#define PA1_TXDAT 0x00003c00U +#define PA1_RXDAT 0x0003c000U +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER 0x00000001U +#define PB2_RXDV 0x00000002U +#define PB2_TXEN 0x00000004U +#define PB2_RXER 0x00000008U +#define PB2_COL 0x00000010U +#define PB2_CRS 0x00000020U +#define PB2_TXDAT 0x000003c0U +#define PB2_RXDAT 0x00003c00U +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV 0x00004000U +#define PB3_RXER 0x00008000U +#define PB3_TXER 0x00010000U +#define PB3_TXEN 0x00020000U +#define PB3_COL 0x00040000U +#define PB3_CRS 0x00080000U +#define PB3_TXDAT 0x0f000000U +#define PC3_TXDAT 0x00000010U +#define PB3_RXDAT 0x00f00000U +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 0 +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) +#define PC3_DIRC1 (PC3_TXDAT) + +/* Handy macro to specify mem for FCCs*/ +#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128)) +#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0) +#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1) +#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2) + #endif /* __CPM2__ */ #endif /* __KERNEL__ */ diff -puN include/asm-ppc/mpc8260.h~git-netdev-all include/asm-ppc/mpc8260.h --- a/include/asm-ppc/mpc8260.h~git-netdev-all +++ a/include/asm-ppc/mpc8260.h @@ -82,6 +82,7 @@ enum ppc_sys_devices { MPC82xx_CPM_SMC2, MPC82xx_CPM_USB, MPC82xx_SEC1, + MPC82xx_MDIO_BB, NUM_PPC_SYS_DEVS, }; diff -puN include/asm-ppc/mpc8xx.h~git-netdev-all include/asm-ppc/mpc8xx.h --- a/include/asm-ppc/mpc8xx.h~git-netdev-all +++ a/include/asm-ppc/mpc8xx.h @@ -110,6 +110,7 @@ enum ppc_sys_devices { MPC8xx_CPM_SMC1, MPC8xx_CPM_SMC2, MPC8xx_CPM_USB, + MPC8xx_MDIO_FEC, NUM_PPC_SYS_DEVS, }; diff -puN include/linux/fs_enet_pd.h~git-netdev-all include/linux/fs_enet_pd.h --- a/include/linux/fs_enet_pd.h~git-netdev-all +++ a/include/linux/fs_enet_pd.h @@ -69,34 +69,21 @@ enum fs_ioport { fsiop_porte, }; -struct fs_mii_bus_info { - int method; /* mii method */ - int id; /* the id of the mii_bus */ - int disable_aneg; /* if the controller needs to negothiate speed & duplex */ - int lpa; /* the default board-specific vallues will be applied otherwise */ - - union { - struct { - int duplex; - int speed; - } fixed; - - struct { - /* nothing */ - } fec; - - struct { - /* nothing */ - } scc; - - struct { - int mdio_port; /* port & bit for MDIO */ - int mdio_bit; - int mdc_port; /* port & bit for MDC */ - int mdc_bit; - int delay; /* delay in us */ - } bitbang; - } i; +struct fs_mii_bit { + u32 offset; + u8 bit; + u8 polarity; +}; +struct fs_mii_bb_platform_info { + struct fs_mii_bit mdio_dir; + struct fs_mii_bit mdio_dat; + struct fs_mii_bit mdc_dat; + int mdio_port; /* port & bit for MDIO */ + int mdio_bit; + int mdc_port; /* port & bit for MDC */ + int mdc_bit; + int delay; /* delay in us */ + int irq[32]; /* irqs per phy's */ }; struct fs_platform_info { @@ -119,6 +106,7 @@ struct fs_platform_info { u32 device_flags; int phy_addr; /* the phy address (-1 no phy) */ + const char* bus_id; int phy_irq; /* the phy irq (if it exists) */ const struct fs_mii_bus_info *bus_info; @@ -130,6 +118,10 @@ struct fs_platform_info { int napi_weight; /* NAPI weight */ int use_rmii; /* use RMII mode */ + int has_phy; /* if the network is phy container as well...*/ +}; +struct fs_mii_fec_platform_info { + u32 irq[32]; + u32 mii_speed; }; - #endif diff -puN include/linux/phy.h~git-netdev-all include/linux/phy.h --- a/include/linux/phy.h~git-netdev-all +++ a/include/linux/phy.h @@ -378,6 +378,7 @@ int phy_mii_ioctl(struct phy_device *phy struct mii_ioctl_data *mii_data, int cmd); int phy_start_interrupts(struct phy_device *phydev); void phy_print_status(struct phy_device *phydev); +struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id); extern struct bus_type mdio_bus_type; #endif /* __PHY_H */ diff -puN include/net/ieee80211.h~git-netdev-all include/net/ieee80211.h --- a/include/net/ieee80211.h~git-netdev-all +++ a/include/net/ieee80211.h @@ -240,6 +240,11 @@ struct ieee80211_snap_hdr { #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) +/* 802.11g ERP information element */ +#define WLAN_ERP_NON_ERP_PRESENT (1<<0) +#define WLAN_ERP_USE_PROTECTION (1<<1) +#define WLAN_ERP_BARKER_PREAMBLE (1<<2) + /* Status codes */ enum ieee80211_statuscode { WLAN_STATUS_SUCCESS = 0, @@ -747,6 +752,8 @@ struct ieee80211_txb { #define NETWORK_HAS_IBSS_DFS (1<<8) #define NETWORK_HAS_TPC_REPORT (1<<9) +#define NETWORK_HAS_ERP_VALUE (1<<10) + #define QOS_QUEUE_NUM 4 #define QOS_OUI_LEN 3 #define QOS_OUI_TYPE 2 @@ -1252,6 +1259,8 @@ extern int ieee80211_tx_frame(struct iee int total_len, int encrypt_mpdu); /* ieee80211_rx.c */ +extern void ieee80211_rx_any(struct ieee80211_device *ieee, + struct sk_buff *skb, struct ieee80211_rx_stats *stats); extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); /* make sure to set stats->len */ diff -puN include/net/ieee80211softmac.h~git-netdev-all include/net/ieee80211softmac.h --- a/include/net/ieee80211softmac.h~git-netdev-all +++ a/include/net/ieee80211softmac.h @@ -86,9 +86,6 @@ struct ieee80211softmac_assoc_info { /* BSSID we're trying to associate to */ char bssid[ETH_ALEN]; - - /* Rates supported by the network */ - struct ieee80211softmac_ratesinfo supported_rates; /* some flags. * static_essid is valid if the essid is constant, @@ -103,6 +100,7 @@ struct ieee80211softmac_assoc_info { * bssfixed is used for SIOCSIWAP. */ u8 static_essid:1, + short_preamble_available:1, associating:1, assoc_wait:1, bssvalid:1, @@ -115,6 +113,19 @@ struct ieee80211softmac_assoc_info { struct work_struct timeout; }; +struct ieee80211softmac_bss_info { + /* Rates supported by the network */ + struct ieee80211softmac_ratesinfo supported_rates; + + /* This indicates whether frames can currently be transmitted with + * short preamble (only use this variable during TX at CCK rates) */ + u8 short_preamble:1; + + /* This indicates whether protection (e.g. self-CTS) should be used + * when transmitting with OFDM modulation */ + u8 use_protection:1; +}; + enum { IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1, IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2, @@ -157,6 +168,10 @@ struct ieee80211softmac_txrates { #define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */ +#define IEEE80211SOFTMAC_BSSINFOCHG_RATES (1 << 0) /* supported_rates */ +#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE (1 << 1) /* short_preamble */ +#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION (1 << 2) /* use_protection */ + struct ieee80211softmac_device { /* 802.11 structure for data stuff */ struct ieee80211_device *ieee; @@ -200,10 +215,16 @@ struct ieee80211softmac_device { * The driver just needs to read them. */ struct ieee80211softmac_txrates txrates; - /* If the driver needs to do stuff on TX rate changes, assign this callback. */ + + /* If the driver needs to do stuff on TX rate changes, assign this + * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */ void (*txrates_change)(struct net_device *dev, - u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */ - const struct ieee80211softmac_txrates *rates_before_change); + u32 changes); + + /* If the driver needs to do stuff when BSS properties change, assign + * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */ + void (*bssinfo_change)(struct net_device *dev, + u32 changes); /* private stuff follows */ /* this lock protects this structure */ @@ -216,6 +237,7 @@ struct ieee80211softmac_device { struct ieee80211softmac_scaninfo *scaninfo; struct ieee80211softmac_assoc_info associnfo; + struct ieee80211softmac_bss_info bssinfo; struct list_head auth_queue; struct list_head events; @@ -257,6 +279,14 @@ extern void ieee80211softmac_fragment_lo * Note that the rates need to be sorted. */ extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates); +/* Finds the highest rate which is: + * 1. Present in ri (optionally a basic rate) + * 2. Supported by the device + * 3. Less than or equal to the user-defined rate + */ +extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac, + struct ieee80211softmac_ratesinfo *ri, int basic_only); + /* Helper function which advises you the rate at which a frame should be * transmitted at. */ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac, @@ -279,6 +309,24 @@ static inline u8 ieee80211softmac_sugges return txrates->mcast_rate; } +/* Helper function which advises you when it is safe to transmit with short + * preamble. + * You should only call this function when transmitting at CCK rates. */ +static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac, + int is_multicast, + int is_mgt) +{ + return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble; +} + +/* Helper function which advises you whether protection (e.g. self-CTS) is + * needed. 1 = protection needed, 0 = no protection needed + * Only use this function when transmitting with OFDM modulation. */ +static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac) +{ + return mac->bssinfo.use_protection; +} + /* Start the SoftMAC. Call this after you initialized the device * and it is ready to run. */ diff -puN net/ieee80211/ieee80211_rx.c~git-netdev-all net/ieee80211/ieee80211_rx.c --- a/net/ieee80211/ieee80211_rx.c~git-netdev-all +++ a/net/ieee80211/ieee80211_rx.c @@ -779,33 +779,44 @@ int ieee80211_rx(struct ieee80211_device return 0; } -/* Filter out unrelated packets, call ieee80211_rx[_mgt] */ -int ieee80211_rx_any(struct ieee80211_device *ieee, +/* Filter out unrelated packets, call ieee80211_rx[_mgt] + * This function takes over the skb, it should not be used again after calling + * this function. */ +void ieee80211_rx_any(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *stats) { struct ieee80211_hdr_4addr *hdr; int is_packet_for_us; u16 fc; - if (ieee->iw_mode == IW_MODE_MONITOR) - return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL; + if (ieee->iw_mode == IW_MODE_MONITOR) { + if (!ieee80211_rx(ieee, skb, stats)) + dev_kfree_skb_irq(skb); + return; + } + + if (skb->len < sizeof(struct ieee80211_hdr)) + goto drop_free; hdr = (struct ieee80211_hdr_4addr *)skb->data; fc = le16_to_cpu(hdr->frame_ctl); if ((fc & IEEE80211_FCTL_VERS) != 0) - return -EINVAL; + goto drop_free; switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: + if (skb->len < sizeof(struct ieee80211_hdr_3addr)) + goto drop_free; ieee80211_rx_mgt(ieee, hdr, stats); - return 0; + dev_kfree_skb_irq(skb); + return; case IEEE80211_FTYPE_DATA: break; case IEEE80211_FTYPE_CTL: - return 0; + return; default: - return -EINVAL; + return; } is_packet_for_us = 0; @@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_de } if (is_packet_for_us) - return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL); - return 0; + if (!ieee80211_rx(ieee, skb, stats)) + dev_kfree_skb_irq(skb); + return; + +drop_free: + dev_kfree_skb_irq(skb); + ieee->stats.rx_dropped++; + return; } #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 @@ -1166,6 +1183,7 @@ static int ieee80211_parse_info_param(st case MFIE_TYPE_ERP_INFO: network->erp_value = info_element->data[0]; + network->flags |= NETWORK_HAS_ERP_VALUE; IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n", network->erp_value); break; @@ -1729,5 +1747,6 @@ void ieee80211_rx_mgt(struct ieee80211_d } } +EXPORT_SYMBOL_GPL(ieee80211_rx_any); EXPORT_SYMBOL(ieee80211_rx_mgt); EXPORT_SYMBOL(ieee80211_rx); diff -puN net/ieee80211/softmac/ieee80211softmac_assoc.c~git-netdev-all net/ieee80211/softmac/ieee80211softmac_assoc.c --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c~git-netdev-all +++ a/net/ieee80211/softmac/ieee80211softmac_assoc.c @@ -96,7 +96,7 @@ ieee80211softmac_disassoc(struct ieee802 mac->associated = 0; mac->associnfo.bssvalid = 0; mac->associnfo.associating = 0; - ieee80211softmac_init_txrates(mac); + ieee80211softmac_init_bss(mac); ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); spin_unlock_irqrestore(&mac->lock, flags); } @@ -334,11 +334,19 @@ ieee80211softmac_associated(struct ieee8 struct ieee80211_assoc_response * resp, struct ieee80211softmac_network *net) { + u16 cap = le16_to_cpu(resp->capability); + u8 erp_value = net->erp_value; + mac->associnfo.associating = 0; - mac->associnfo.supported_rates = net->supported_rates; + mac->bssinfo.supported_rates = net->supported_rates; ieee80211softmac_recalc_txrates(mac); mac->associated = 1; + + mac->associnfo.short_preamble_available = + (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0; + ieee80211softmac_process_erp(mac, erp_value); + if (mac->set_bssid_filter) mac->set_bssid_filter(mac->dev, net->bssid); memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN); @@ -351,9 +359,9 @@ ieee80211softmac_associated(struct ieee8 int ieee80211softmac_handle_assoc_response(struct net_device * dev, struct ieee80211_assoc_response * resp, - struct ieee80211_network * _ieee80211_network_do_not_use) + struct ieee80211_network * _ieee80211_network) { - /* NOTE: the network parameter has to be ignored by + /* NOTE: the network parameter has to be mostly ignored by * this code because it is the ieee80211's pointer * to the struct, not ours (we made a copy) */ @@ -385,6 +393,11 @@ ieee80211softmac_handle_assoc_response(s /* now that we know it was for us, we can cancel the timeout */ cancel_delayed_work(&mac->associnfo.timeout); + /* if the association response included an ERP IE, update our saved + * copy */ + if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE) + network->erp_value = _ieee80211_network->erp_value; + switch (status) { case 0: dprintk(KERN_INFO PFX "associated!\n"); diff -puN net/ieee80211/softmac/ieee80211softmac_io.c~git-netdev-all net/ieee80211/softmac/ieee80211softmac_io.c --- a/net/ieee80211/softmac/ieee80211softmac_io.c~git-netdev-all +++ a/net/ieee80211/softmac/ieee80211softmac_io.c @@ -467,3 +467,17 @@ ieee80211softmac_send_mgt_frame(struct i kfree(pkt); return 0; } + +/* Beacon handling */ +int ieee80211softmac_handle_beacon(struct net_device *dev, + struct ieee80211_beacon *beacon, + struct ieee80211_network *network) +{ + struct ieee80211softmac_device *mac = ieee80211_priv(dev); + + if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0) + ieee80211softmac_process_erp(mac, network->erp_value); + + return 0; +} + diff -puN net/ieee80211/softmac/ieee80211softmac_module.c~git-netdev-all net/ieee80211/softmac/ieee80211softmac_module.c --- a/net/ieee80211/softmac/ieee80211softmac_module.c~git-netdev-all +++ a/net/ieee80211/softmac/ieee80211softmac_module.c @@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softma softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response; softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req; softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc; + softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon; softmac->scaninfo = NULL; softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; @@ -178,21 +179,14 @@ int ieee80211softmac_ratesinfo_rate_supp return 0; } -/* Finds the highest rate which is: - * 1. Present in ri (optionally a basic rate) - * 2. Supported by the device - * 3. Less than or equal to the user-defined rate - */ -static u8 highest_supported_rate(struct ieee80211softmac_device *mac, +u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac, struct ieee80211softmac_ratesinfo *ri, int basic_only) { u8 user_rate = mac->txrates.user_rate; int i; - if (ri->count == 0) { - dprintk(KERN_ERR PFX "empty ratesinfo?\n"); + if (ri->count == 0) return IEEE80211_CCK_RATE_1MB; - } for (i = ri->count - 1; i >= 0; i--) { u8 rate = ri->rates[i]; @@ -208,36 +202,61 @@ static u8 highest_supported_rate(struct /* If we haven't found a suitable rate by now, just trust the user */ return user_rate; } +EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate); + +void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac, + u8 erp_value) +{ + int use_protection; + int short_preamble; + u32 changes = 0; + + /* Barker preamble mode */ + short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0 + && mac->associnfo.short_preamble_available) ? 1 : 0; + + /* Protection needed? */ + use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + + if (mac->bssinfo.short_preamble != short_preamble) { + changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE; + mac->bssinfo.short_preamble = short_preamble; + } + + if (mac->bssinfo.use_protection != use_protection) { + changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION; + mac->bssinfo.use_protection = use_protection; + } + + if (mac->bssinfo_change && changes) + mac->bssinfo_change(mac->dev, changes); +} void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac) { struct ieee80211softmac_txrates *txrates = &mac->txrates; - struct ieee80211softmac_txrates oldrates; u32 change = 0; - if (mac->txrates_change) - oldrates = mac->txrates; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0); + txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0); change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; txrates->default_fallback = lower_rate(mac, txrates->default_rate); change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; - txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1); + txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1); if (mac->txrates_change) - mac->txrates_change(mac->dev, change, &oldrates); + mac->txrates_change(mac->dev, change); } -void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac) +void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac) { struct ieee80211_device *ieee = mac->ieee; u32 change = 0; struct ieee80211softmac_txrates *txrates = &mac->txrates; - struct ieee80211softmac_txrates oldrates; + struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo; /* TODO: We need some kind of state machine to lower the default rates * if we loose too many packets. @@ -245,8 +264,6 @@ void ieee80211softmac_init_txrates(struc /* Change the default txrate to the highest possible value. * The txrate machine will lower it, if it is too high. */ - if (mac->txrates_change) - oldrates = mac->txrates; /* FIXME: We don't correctly handle backing down to lower rates, so 801.11g devices start off at 11M for now. People can manually change it if they really need to, but 11M is @@ -272,7 +289,23 @@ void ieee80211softmac_init_txrates(struc change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; if (mac->txrates_change) - mac->txrates_change(mac->dev, change, &oldrates); + mac->txrates_change(mac->dev, change); + + change = 0; + + bssinfo->supported_rates.count = 0; + memset(bssinfo->supported_rates.rates, 0, + sizeof(bssinfo->supported_rates.rates)); + change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES; + + bssinfo->short_preamble = 0; + change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE; + + bssinfo->use_protection = 0; + change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION; + + if (mac->bssinfo_change) + mac->bssinfo_change(mac->dev, change); mac->running = 1; } @@ -282,7 +315,7 @@ void ieee80211softmac_start(struct net_d struct ieee80211softmac_device *mac = ieee80211_priv(dev); ieee80211softmac_start_check_rates(mac); - ieee80211softmac_init_txrates(mac); + ieee80211softmac_init_bss(mac); } EXPORT_SYMBOL_GPL(ieee80211softmac_start); @@ -335,7 +368,6 @@ u8 ieee80211softmac_lower_rate_delta(str static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac, int amount) { - struct ieee80211softmac_txrates oldrates; u8 default_rate = mac->txrates.default_rate; u8 default_fallback = mac->txrates.default_fallback; u32 changes = 0; @@ -348,8 +380,6 @@ printk("badness %d\n", mac->txrate_badne mac->txrate_badness += amount; if (mac->txrate_badness <= -1000) { /* Very small badness. Try a faster bitrate. */ - if (mac->txrates_change) - memcpy(&oldrates, &mac->txrates, sizeof(oldrates)); default_rate = raise_rate(mac, default_rate); changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; default_fallback = get_fallback_rate(mac, default_rate); @@ -358,8 +388,6 @@ printk("badness %d\n", mac->txrate_badne printk("Bitrate raised to %u\n", default_rate); } else if (mac->txrate_badness >= 10000) { /* Very high badness. Try a slower bitrate. */ - if (mac->txrates_change) - memcpy(&oldrates, &mac->txrates, sizeof(oldrates)); default_rate = lower_rate(mac, default_rate); changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; default_fallback = get_fallback_rate(mac, default_rate); @@ -372,7 +400,7 @@ printk("Bitrate lowered to %u\n", defaul mac->txrates.default_fallback = default_fallback; if (changes && mac->txrates_change) - mac->txrates_change(mac->dev, changes, &oldrates); + mac->txrates_change(mac->dev, changes); } void ieee80211softmac_fragment_lost(struct net_device *dev, @@ -416,7 +444,11 @@ ieee80211softmac_create_network(struct i memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len); softnet->supported_rates.count += net->rates_ex_len; sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL); - + + /* we save the ERP value because it is needed at association time, and + * many AP's do not include an ERP IE in the association response. */ + softnet->erp_value = net->erp_value; + softnet->capabilities = net->capability; return softnet; } diff -puN net/ieee80211/softmac/ieee80211softmac_priv.h~git-netdev-all net/ieee80211/softmac/ieee80211softmac_priv.h --- a/net/ieee80211/softmac/ieee80211softmac_priv.h~git-netdev-all +++ a/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(st struct ieee80211softmac_essid *essid); /* Rates related */ +void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac, + u8 erp_value); int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate); u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); -void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac); +void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac); void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac); static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { return ieee80211softmac_lower_rate_delta(mac, rate, 1); @@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struc /*** prototypes from _io.c */ int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, void* ptrarg, u32 type, u32 arg); +int ieee80211softmac_handle_beacon(struct net_device *dev, + struct ieee80211_beacon *beacon, + struct ieee80211_network *network); /*** prototypes from _auth.c */ /* do these have to go into the public header? */ @@ -189,6 +194,7 @@ struct ieee80211softmac_network { authenticated:1, auth_desynced_once:1; + u8 erp_value; /* Saved ERP value */ u16 capabilities; /* Capabilities bitfield */ u8 challenge_len; /* Auth Challenge length */ char *challenge; /* Challenge Text */ _