[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] merge with linux-2.6.18-xen.hg
# HG changeset patch # User Alex Williamson <alex.williamson@xxxxxx> # Date 1203444905 25200 # Node ID 594bfb5cbe40d04f7e2ec1cef164bc98c8aa4383 # Parent 31d71546a6442785e55d9ba2b94796701cc40276 # Parent 9dea529497fe546d25b5dc965d8161494c27d127 merge with linux-2.6.18-xen.hg --- MAINTAINERS | 7 buildconfigs/linux-defconfig_xen0_x86_32 | 8 buildconfigs/linux-defconfig_xen0_x86_64 | 122 buildconfigs/linux-defconfig_xenU_x86_32 | 6 buildconfigs/linux-defconfig_xenU_x86_64 | 670 - buildconfigs/linux-defconfig_xen_x86_32 | 9 buildconfigs/linux-defconfig_xen_x86_64 | 10 drivers/net/Kconfig | 2 drivers/net/Makefile | 2 drivers/net/sfc/Kconfig | 35 drivers/net/sfc/Makefile | 43 drivers/net/sfc/alaska.c | 159 drivers/net/sfc/bitfield.h | 544 + drivers/net/sfc/boards.c | 528 + drivers/net/sfc/boards.h | 51 drivers/net/sfc/config.h | 1 drivers/net/sfc/debugfs.c | 924 ++ drivers/net/sfc/debugfs.h | 172 drivers/net/sfc/driverlink.c | 544 + drivers/net/sfc/driverlink.h | 93 drivers/net/sfc/driverlink_api.h | 612 + drivers/net/sfc/efx.c | 2783 +++++++ drivers/net/sfc/efx.h | 103 drivers/net/sfc/enum.h | 117 drivers/net/sfc/ethtool.c | 734 + drivers/net/sfc/ethtool.h | 44 drivers/net/sfc/extraversion.h | 4 drivers/net/sfc/falcon.c | 3708 ++++++++++ drivers/net/sfc/falcon.h | 177 drivers/net/sfc/falcon_gmac.c | 320 drivers/net/sfc/falcon_hwdefs.h | 1620 ++++ drivers/net/sfc/falcon_io.h | 259 drivers/net/sfc/falcon_xmac.c | 691 + drivers/net/sfc/gmii.h | 212 drivers/net/sfc/i2c-direct.c | 398 + drivers/net/sfc/i2c-direct.h | 108 drivers/net/sfc/kernel_compat.c | 654 + drivers/net/sfc/kernel_compat.h | 925 ++ drivers/net/sfc/lm87_support.c | 295 drivers/net/sfc/lm87_support.h | 58 drivers/net/sfc/mac.h | 38 drivers/net/sfc/mdio_10g.c | 441 + drivers/net/sfc/mdio_10g.h | 295 drivers/net/sfc/mentormac.c | 506 + drivers/net/sfc/mtd.c | 602 + drivers/net/sfc/net_driver.h | 1096 ++ drivers/net/sfc/null_phy.c | 62 drivers/net/sfc/phy.c | 28 drivers/net/sfc/phy.h | 90 drivers/net/sfc/pm8358_phy.c | 206 drivers/net/sfc/rx.c | 798 ++ drivers/net/sfc/rx.h | 44 drivers/net/sfc/selftest.c | 815 ++ drivers/net/sfc/selftest.h | 67 drivers/net/sfc/sfc_resource/Makefile | 15 drivers/net/sfc/sfc_resource/assert_valid.c | 95 drivers/net/sfc/sfc_resource/buddy.c | 307 drivers/net/sfc/sfc_resource/buffer_table.c | 210 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h | 199 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h | 68 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h | 420 + drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h | 1149 +++ drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h | 75 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h | 155 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_grmon.h | 129 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h | 44 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_mac.h | 711 + drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_xgrmon.h | 125 drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h | 75 drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h | 276 drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h | 76 drivers/net/sfc/sfc_resource/ci/efhw/checks.h | 118 drivers/net/sfc/sfc_resource/ci/efhw/common.h | 102 drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h | 67 drivers/net/sfc/sfc_resource/ci/efhw/debug.h | 84 drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h | 43 drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h | 342 drivers/net/sfc/sfc_resource/ci/efhw/eventq.h | 73 drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h | 81 drivers/net/sfc/sfc_resource/ci/efhw/falcon.h | 93 drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h | 58 drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h | 84 drivers/net/sfc/sfc_resource/ci/efhw/iopage.h | 58 drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h | 188 drivers/net/sfc/sfc_resource/ci/efhw/nic.h | 62 drivers/net/sfc/sfc_resource/ci/efhw/public.h | 83 drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h | 72 drivers/net/sfc/sfc_resource/ci/efrm/buddy.h | 69 drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h | 86 drivers/net/sfc/sfc_resource/ci/efrm/debug.h | 78 drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h | 86 drivers/net/sfc/sfc_resource/ci/efrm/filter.h | 147 drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h | 123 drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h | 104 drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h | 98 drivers/net/sfc/sfc_resource/ci/efrm/private.h | 141 drivers/net/sfc/sfc_resource/ci/efrm/resource.h | 122 drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h | 104 drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h | 54 drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h | 248 drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h | 171 drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h | 182 drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h | 83 drivers/net/sfc/sfc_resource/driver_object.c | 174 drivers/net/sfc/sfc_resource/driverlink_new.c | 290 drivers/net/sfc/sfc_resource/efx_vi_shm.c | 701 + drivers/net/sfc/sfc_resource/eventq.c | 320 drivers/net/sfc/sfc_resource/falcon.c | 2758 +++++++ drivers/net/sfc/sfc_resource/falcon_hash.c | 178 drivers/net/sfc/sfc_resource/falcon_mac.c | 171 drivers/net/sfc/sfc_resource/filter_resource.c | 317 drivers/net/sfc/sfc_resource/iobufset_resource.c | 373 + drivers/net/sfc/sfc_resource/iopage.c | 101 drivers/net/sfc/sfc_resource/kernel_compat.c | 584 + drivers/net/sfc/sfc_resource/kernel_compat.h | 239 drivers/net/sfc/sfc_resource/kernel_proc.c | 111 drivers/net/sfc/sfc_resource/kfifo.c | 212 drivers/net/sfc/sfc_resource/linux_resource_internal.h | 75 drivers/net/sfc/sfc_resource/nic.c | 190 drivers/net/sfc/sfc_resource/resource_driver.c | 640 + drivers/net/sfc/sfc_resource/resource_manager.c | 263 drivers/net/sfc/sfc_resource/resources.c | 94 drivers/net/sfc/sfc_resource/vi_resource_alloc.c | 876 ++ drivers/net/sfc/sfc_resource/vi_resource_event.c | 232 drivers/net/sfc/sfc_resource/vi_resource_flush.c | 506 + drivers/net/sfc/sfc_resource/vi_resource_manager.c | 259 drivers/net/sfc/sfe4001.c | 315 drivers/net/sfc/spi.h | 186 drivers/net/sfc/tenxpress.c | 695 + drivers/net/sfc/tx.c | 522 + drivers/net/sfc/tx.h | 41 drivers/net/sfc/txc43128_phy.c | 725 + drivers/net/sfc/workarounds.h | 97 drivers/net/sfc/xenpack.h | 80 drivers/net/sfc/xfp_phy.c | 206 drivers/xen/Kconfig | 16 drivers/xen/Makefile | 3 drivers/xen/core/smpboot.c | 9 drivers/xen/sfc_netback/Makefile | 12 drivers/xen/sfc_netback/accel.c | 129 drivers/xen/sfc_netback/accel.h | 393 + drivers/xen/sfc_netback/accel_debugfs.c | 170 drivers/xen/sfc_netback/accel_fwd.c | 415 + drivers/xen/sfc_netback/accel_msg.c | 392 + drivers/xen/sfc_netback/accel_solarflare.c | 1253 +++ drivers/xen/sfc_netback/accel_solarflare.h | 88 drivers/xen/sfc_netback/accel_xenbus.c | 831 ++ drivers/xen/sfc_netback/ci/compat.h | 53 drivers/xen/sfc_netback/ci/compat/gcc.h | 158 drivers/xen/sfc_netback/ci/compat/gcc_x86.h | 115 drivers/xen/sfc_netback/ci/compat/primitive.h | 77 drivers/xen/sfc_netback/ci/compat/sysdep.h | 166 drivers/xen/sfc_netback/ci/compat/utils.h | 269 drivers/xen/sfc_netback/ci/compat/x86.h | 48 drivers/xen/sfc_netback/ci/compat/x86_64.h | 54 drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h | 276 drivers/xen/sfc_netback/ci/efhw/common.h | 102 drivers/xen/sfc_netback/ci/efhw/common_sysdep.h | 67 drivers/xen/sfc_netback/ci/efhw/debug.h | 84 drivers/xen/sfc_netback/ci/efhw/efhw_config.h | 43 drivers/xen/sfc_netback/ci/efhw/efhw_types.h | 342 drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h | 84 drivers/xen/sfc_netback/ci/efhw/iopage_types.h | 188 drivers/xen/sfc_netback/ci/efhw/public.h | 83 drivers/xen/sfc_netback/ci/efhw/sysdep.h | 72 drivers/xen/sfc_netback/ci/efrm/nic_table.h | 98 drivers/xen/sfc_netback/ci/efrm/sysdep.h | 54 drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h | 248 drivers/xen/sfc_netback/ci/tools/config.h | 49 drivers/xen/sfc_netback/ci/tools/debug.h | 336 drivers/xen/sfc_netback/ci/tools/log.h | 262 drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h | 361 drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h | 362 drivers/xen/sfc_netback/ci/tools/sysdep.h | 132 drivers/xen/sfc_netfront/Makefile | 11 drivers/xen/sfc_netfront/accel.h | 477 + drivers/xen/sfc_netfront/accel_bufs.c | 393 + drivers/xen/sfc_netfront/accel_bufs.h | 181 drivers/xen/sfc_netfront/accel_debugfs.c | 234 drivers/xen/sfc_netfront/accel_msg.c | 566 + drivers/xen/sfc_netfront/accel_netfront.c | 318 drivers/xen/sfc_netfront/accel_ssr.c | 308 drivers/xen/sfc_netfront/accel_ssr.h | 88 drivers/xen/sfc_netfront/accel_tso.c | 512 + drivers/xen/sfc_netfront/accel_tso.h | 57 drivers/xen/sfc_netfront/accel_vi.c | 1194 +++ drivers/xen/sfc_netfront/accel_xenbus.c | 776 ++ drivers/xen/sfc_netfront/ef_vi_falcon.h | 172 drivers/xen/sfc_netfront/ef_vi_falcon_core.h | 1075 ++ drivers/xen/sfc_netfront/ef_vi_falcon_desc.h | 43 drivers/xen/sfc_netfront/ef_vi_falcon_event.h | 123 drivers/xen/sfc_netfront/ef_vi_internal.h | 256 drivers/xen/sfc_netfront/etherfabric/ef_vi.h | 665 + drivers/xen/sfc_netfront/falcon_event.c | 346 drivers/xen/sfc_netfront/falcon_vi.c | 465 + drivers/xen/sfc_netfront/pt_tx.c | 91 drivers/xen/sfc_netfront/sysdep.h | 184 drivers/xen/sfc_netfront/vi_init.c | 183 drivers/xen/sfc_netutil/Makefile | 10 drivers/xen/sfc_netutil/accel_cuckoo_hash.c | 651 + drivers/xen/sfc_netutil/accel_cuckoo_hash.h | 227 drivers/xen/sfc_netutil/accel_msg_iface.c | 301 drivers/xen/sfc_netutil/accel_msg_iface.h | 414 + drivers/xen/sfc_netutil/accel_shared_fifo.h | 127 drivers/xen/sfc_netutil/accel_util.c | 333 drivers/xen/sfc_netutil/accel_util.h | 127 206 files changed, 61232 insertions(+), 574 deletions(-) diff -r 31d71546a644 -r 594bfb5cbe40 MAINTAINERS --- a/MAINTAINERS Thu Feb 14 09:35:01 2008 -0700 +++ b/MAINTAINERS Tue Feb 19 11:15:05 2008 -0700 @@ -2558,6 +2558,13 @@ L: linux-ia64@xxxxxxxxxxxxxxx L: linux-ia64@xxxxxxxxxxxxxxx S: Supported +SFC NETWORK DRIVER +P: Steve Hodgson +P: Ben Hutchings +P: Robert Stonehouse +M: linux-net-drivers@xxxxxxxxxxxxxx +S: Supported + SGI VISUAL WORKSTATION 320 AND 540 P: Andrey Panin M: pazke@xxxxxxxxx diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xen0_x86_32 --- a/buildconfigs/linux-defconfig_xen0_x86_32 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xen0_x86_32 Tue Feb 19 11:15:05 2008 -0700 @@ -752,6 +752,7 @@ CONFIG_BNX2=y # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set +# CONFIG_SFC is not set # # Token Ring devices @@ -1392,7 +1393,7 @@ CONFIG_CRYPTO_CRC32C=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -1406,6 +1407,8 @@ CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_NETDEV_BACKEND=y # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set # CONFIG_XEN_NETDEV_LOOPBACK is not set CONFIG_XEN_PCIDEV_BACKEND=y # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set @@ -1416,6 +1419,8 @@ CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_GRANT_DEV=y +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y @@ -1429,7 +1434,6 @@ CONFIG_XEN_SMPBOOT=y CONFIG_XEN_SMPBOOT=y CONFIG_XEN_BALLOON=y CONFIG_XEN_DEVMEM=y -CONFIG_XEN_GRANT_DEV=y # # Library routines diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xen0_x86_64 --- a/buildconfigs/linux-defconfig_xen0_x86_64 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xen0_x86_64 Tue Feb 19 11:15:05 2008 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18.8 -# Tue Oct 16 09:32:39 2007 +# Mon Feb 18 10:41:04 2008 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -26,7 +26,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNA # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 # @@ -41,6 +41,7 @@ CONFIG_SYSVIPC=y # CONFIG_TASKSTATS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +# CONFIG_CPUSETS is not set # CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -74,6 +75,7 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y # # Block layer @@ -111,16 +113,17 @@ CONFIG_X86_INTERNODE_CACHE_BYTES=128 CONFIG_X86_INTERNODE_CACHE_BYTES=128 CONFIG_X86_GOOD_APIC=y CONFIG_MICROCODE=y -# CONFIG_X86_MSR is not set -# CONFIG_X86_CPUID is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y CONFIG_X86_IO_APIC=y CONFIG_X86_XEN_GENAPIC=y CONFIG_X86_LOCAL_APIC=y CONFIG_MTRR=y -# CONFIG_SMP is not set +CONFIG_SMP=y CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set +CONFIG_PREEMPT_BKL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -131,6 +134,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_SWIOTLB=y CONFIG_KEXEC=y @@ -142,10 +147,10 @@ CONFIG_HZ_100=y # CONFIG_HZ_1000 is not set CONFIG_HZ=100 # CONFIG_REORDER is not set -CONFIG_K8_NB=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_ISA_DMA_API=y +CONFIG_GENERIC_PENDING_IRQ=y # # Power management options @@ -154,6 +159,7 @@ CONFIG_PM_LEGACY=y CONFIG_PM_LEGACY=y # CONFIG_PM_DEBUG is not set # CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SUSPEND_SMP=y # # ACPI (Advanced Configuration and Power Interface) Support @@ -166,20 +172,22 @@ CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m CONFIG_ACPI_VIDEO=m -# CONFIG_ACPI_HOTKEY is not set +CONFIG_ACPI_HOTKEY=m CONFIG_ACPI_FAN=m CONFIG_ACPI_DOCK=m CONFIG_ACPI_PROCESSOR=m +CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_THERMAL=m CONFIG_ACPI_ASUS=m CONFIG_ACPI_IBM=m CONFIG_ACPI_TOSHIBA=m +# CONFIG_ACPI_CUSTOM_DSDT is not set CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_EC=y CONFIG_ACPI_POWER=y CONFIG_ACPI_SYSTEM=y -# CONFIG_ACPI_CONTAINER is not set +CONFIG_ACPI_CONTAINER=m CONFIG_ACPI_PV_SLEEP=y # @@ -192,7 +200,7 @@ CONFIG_ACPI_PV_SLEEP=y # CONFIG_PCI=y CONFIG_PCI_DIRECT=y -# CONFIG_PCI_MMCONFIG is not set +CONFIG_PCI_MMCONFIG=y CONFIG_XEN_PCIDEV_FRONTEND=y # CONFIG_XEN_PCIDEV_FE_DEBUG is not set # CONFIG_PCIEPORTBUS is not set @@ -212,9 +220,9 @@ CONFIG_XEN_PCIDEV_FRONTEND=y # Executable file formats / Emulations # CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y +# CONFIG_BINFMT_MISC is not set CONFIG_IA32_EMULATION=y -# CONFIG_IA32_AOUT is not set +CONFIG_IA32_AOUT=y CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y @@ -230,6 +238,8 @@ CONFIG_PACKET=y CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -248,8 +258,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_IPCOMP is not set # CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y # CONFIG_INET_DIAG is not set # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y @@ -343,8 +353,8 @@ CONFIG_LLC=y # # Generic Driver Options # -CONFIG_STANDALONE=y -# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_STANDALONE is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set CONFIG_SYS_HYPERVISOR=y @@ -392,7 +402,7 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set @@ -491,7 +501,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set -CONFIG_SCSI_ISCSI_ATTRS=y +# CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_ATTRS is not set # @@ -505,7 +515,6 @@ CONFIG_SCSI_AIC7XXX=y CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set CONFIG_AIC7XXX_DEBUG_ENABLE=y CONFIG_AIC7XXX_DEBUG_MASK=0 CONFIG_AIC7XXX_REG_PRETTY_PRINT=y @@ -513,7 +522,6 @@ CONFIG_SCSI_AIC79XX=y CONFIG_SCSI_AIC79XX=y CONFIG_AIC79XX_CMDS_PER_DEVICE=32 CONFIG_AIC79XX_RESET_DELAY_MS=15000 -# CONFIG_AIC79XX_BUILD_FIRMWARE is not set # CONFIG_AIC79XX_ENABLE_RD_STRM is not set CONFIG_AIC79XX_DEBUG_ENABLE=y CONFIG_AIC79XX_DEBUG_MASK=0 @@ -540,8 +548,7 @@ CONFIG_SCSI_SATA_SIL24=y # CONFIG_SCSI_SATA_VIA is not set # CONFIG_SCSI_SATA_VITESSE is not set CONFIG_SCSI_SATA_INTEL_COMBINED=y -CONFIG_SCSI_BUSLOGIC=y -# CONFIG_SCSI_OMIT_FLASHPOINT is not set +# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set @@ -563,21 +570,19 @@ CONFIG_SCSI_BUSLOGIC=y # CONFIG_MD=y CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y +# CONFIG_MD_LINEAR is not set CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y # CONFIG_MD_RAID10 is not set -CONFIG_MD_RAID456=y -# CONFIG_MD_RAID5_RESHAPE is not set -CONFIG_MD_MULTIPATH=y +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set # CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y +# CONFIG_DM_CRYPT is not set CONFIG_DM_SNAPSHOT=y CONFIG_DM_MIRROR=y # CONFIG_DM_ZERO is not set -CONFIG_DM_MULTIPATH=y -CONFIG_DM_MULTIPATH_EMC=y +# CONFIG_DM_MULTIPATH is not set # # Fusion MPT device support @@ -698,6 +703,7 @@ CONFIG_BNX2=y # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set +# CONFIG_SFC is not set # # Token Ring devices @@ -785,7 +791,7 @@ CONFIG_VT=y CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y -# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_SERIAL_NONSTANDARD is not set # @@ -811,7 +817,8 @@ CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set # CONFIG_NVRAM is not set -CONFIG_RTC=y +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -819,16 +826,18 @@ CONFIG_RTC=y # # Ftape, the floppy tape device driver # -# CONFIG_FTAPE is not set CONFIG_AGP=m -CONFIG_AGP_AMD64=m -# CONFIG_AGP_INTEL is not set +# CONFIG_AGP_AMD64 is not set +CONFIG_AGP_INTEL=m CONFIG_AGP_SIS=m CONFIG_AGP_VIA=m CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m CONFIG_DRM_RADEON=m +CONFIG_DRM_I810=m +CONFIG_DRM_I830=m +CONFIG_DRM_I915=m CONFIG_DRM_MGA=m CONFIG_DRM_SIS=m # CONFIG_DRM_VIA is not set @@ -1027,8 +1036,7 @@ CONFIG_USB_MON=y # # LED devices # -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=m +# CONFIG_NEW_LEDS is not set # # LED drivers @@ -1037,25 +1045,11 @@ CONFIG_LEDS_CLASS=m # # LED Triggers # -CONFIG_LEDS_TRIGGERS=y -CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_IDE_DISK=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y # # InfiniBand support # -CONFIG_INFINIBAND=y -# CONFIG_INFINIBAND_USER_MAD is not set -# CONFIG_INFINIBAND_USER_ACCESS is not set -CONFIG_INFINIBAND_ADDR_TRANS=y -CONFIG_INFINIBAND_MTHCA=y -CONFIG_INFINIBAND_MTHCA_DEBUG=y -CONFIG_INFINIBAND_IPOIB=y -CONFIG_INFINIBAND_IPOIB_DEBUG=y -CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y -CONFIG_INFINIBAND_SRP=y -CONFIG_INFINIBAND_ISER=y +# CONFIG_INFINIBAND is not set # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) @@ -1079,11 +1073,11 @@ CONFIG_RTC_INTF_DEV=m # # RTC drivers # -CONFIG_RTC_DRV_DS1553=m -CONFIG_RTC_DRV_DS1742=m +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set CONFIG_RTC_DRV_M48T86=m CONFIG_RTC_DRV_TEST=m -CONFIG_RTC_DRV_V3020=m +# CONFIG_RTC_DRV_V3020 is not set # # DMA Engine support @@ -1148,9 +1142,9 @@ CONFIG_ZISOFS_FS=y # # DOS/FAT/NT Filesystems # -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set @@ -1275,7 +1269,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ=y CONFIG_UNUSED_SYMBOLS=y CONFIG_DEBUG_KERNEL=y -CONFIG_LOG_BUF_SHIFT=15 +CONFIG_LOG_BUF_SHIFT=14 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set @@ -1289,7 +1283,7 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set CONFIG_FRAME_POINTER=y @@ -1340,7 +1334,7 @@ CONFIG_CRYPTO_CRC32C=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -1354,6 +1348,8 @@ CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_NETDEV_BACKEND=y # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set # CONFIG_XEN_NETDEV_LOOPBACK is not set CONFIG_XEN_PCIDEV_BACKEND=y # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set @@ -1361,9 +1357,11 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y # CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set # CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set # CONFIG_XEN_PCIDEV_BE_DEBUG is not set -CONFIG_XEN_TPMDEV_BACKEND=m +# CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_GRANT_DEV=y +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y @@ -1374,9 +1372,9 @@ CONFIG_XEN_COMPAT=0x030002 CONFIG_XEN_COMPAT=0x030002 CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y CONFIG_NO_IDLE_HZ=y +CONFIG_XEN_SMPBOOT=y CONFIG_XEN_BALLOON=y CONFIG_XEN_DEVMEM=y -CONFIG_XEN_GRANT_DEV=y # # Library routines @@ -1384,6 +1382,6 @@ CONFIG_XEN_GRANT_DEV=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set CONFIG_CRC32=y -CONFIG_LIBCRC32C=m +CONFIG_LIBCRC32C=y CONFIG_ZLIB_INFLATE=y CONFIG_PLIST=y diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xenU_x86_32 --- a/buildconfigs/linux-defconfig_xenU_x86_32 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xenU_x86_32 Tue Feb 19 11:15:05 2008 -0700 @@ -903,7 +903,7 @@ CONFIG_CRYPTO_CRC32C=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -913,8 +913,11 @@ CONFIG_XEN_PRIVCMD=y CONFIG_XEN_PRIVCMD=y CONFIG_XEN_XENBUS_DEV=y # CONFIG_XEN_BACKEND is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +# CONFIG_XEN_GRANT_DEV is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y @@ -928,7 +931,6 @@ CONFIG_XEN_SMPBOOT=y CONFIG_XEN_SMPBOOT=y CONFIG_XEN_BALLOON=y CONFIG_XEN_DEVMEM=y -# CONFIG_XEN_GRANT_DEV is not set # # Library routines diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xenU_x86_64 --- a/buildconfigs/linux-defconfig_xenU_x86_64 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xenU_x86_64 Tue Feb 19 11:15:05 2008 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18.8 -# Tue Oct 16 09:32:52 2007 +# Mon Feb 18 10:42:42 2008 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -36,12 +36,10 @@ CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -CONFIG_AUDIT=y -CONFIG_AUDITSYSCALL=y +# CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set # CONFIG_CPUSETS is not set # CONFIG_RELAY is not set @@ -52,7 +50,7 @@ CONFIG_SYSCTL=y CONFIG_SYSCTL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set -CONFIG_KALLSYMS_EXTRA_PASS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y @@ -74,7 +72,7 @@ CONFIG_MODULES=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_MODVERSIONS=y +# CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y CONFIG_STOP_MACHINE=y @@ -82,7 +80,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # -CONFIG_LBD=y +# CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set CONFIG_LSF=y @@ -105,8 +103,8 @@ CONFIG_X86_PC=y CONFIG_X86_PC=y # CONFIG_X86_VSMP is not set # CONFIG_MK8 is not set -CONFIG_MPSC=y -# CONFIG_GENERIC_CPU is not set +# CONFIG_MPSC is not set +CONFIG_GENERIC_CPU=y CONFIG_X86_64_XEN=y CONFIG_X86_NO_TSS=y CONFIG_X86_NO_IDT=y @@ -133,8 +131,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_RESOURCES_64BIT=y -CONFIG_NR_CPUS=16 -# CONFIG_HOTPLUG_CPU is not set +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_SWIOTLB=y # CONFIG_CRASH_DUMP is not set @@ -168,9 +166,9 @@ CONFIG_GENERIC_PENDING_IRQ=y # Executable file formats / Emulations # CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y +# CONFIG_BINFMT_MISC is not set CONFIG_IA32_EMULATION=y -# CONFIG_IA32_AOUT is not set +CONFIG_IA32_AOUT=y CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y @@ -184,146 +182,38 @@ CONFIG_NET=y # # CONFIG_NETDEBUG is not set CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y +# CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y CONFIG_XFRM=y -CONFIG_XFRM_USER=y -CONFIG_NET_KEY=m +# CONFIG_XFRM_USER is not set +# CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_ASK_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_FWMARK=y -CONFIG_IP_ROUTE_MULTIPATH=y -# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set -CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NET_IPIP=m -CONFIG_NET_IPGRE=m -CONFIG_NET_IPGRE_BROADCAST=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_TUNNEL=m -CONFIG_INET_TUNNEL=m +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y # CONFIG_INET_DIAG is not set # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y - -# -# IP: Virtual Server Configuration -# -CONFIG_IP_VS=m -# CONFIG_IP_VS_DEBUG is not set -CONFIG_IP_VS_TAB_BITS=12 - -# -# IPVS transport protocol load balancing support -# -CONFIG_IP_VS_PROTO_TCP=y -CONFIG_IP_VS_PROTO_UDP=y -CONFIG_IP_VS_PROTO_ESP=y -CONFIG_IP_VS_PROTO_AH=y - -# -# IPVS scheduler -# -CONFIG_IP_VS_RR=m -CONFIG_IP_VS_WRR=m -CONFIG_IP_VS_LC=m -CONFIG_IP_VS_WLC=m -CONFIG_IP_VS_LBLC=m -CONFIG_IP_VS_LBLCR=m -CONFIG_IP_VS_DH=m -CONFIG_IP_VS_SH=m -CONFIG_IP_VS_SED=m -CONFIG_IP_VS_NQ=m - -# -# IPVS application helper -# -CONFIG_IP_VS_FTP=m -CONFIG_IPV6=m -CONFIG_IPV6_PRIVACY=y -# CONFIG_IPV6_ROUTER_PREF is not set -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -CONFIG_INET6_XFRM_TUNNEL=m -CONFIG_INET6_TUNNEL=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_IPV6_TUNNEL=m +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set # CONFIG_NETWORK_SECMARK is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set -CONFIG_BRIDGE_NETFILTER=y - -# -# Core Netfilter Configuration -# -# CONFIG_NETFILTER_NETLINK is not set -# CONFIG_NETFILTER_XTABLES is not set - -# -# IP: Netfilter Configuration -# -CONFIG_IP_NF_CONNTRACK=m -CONFIG_IP_NF_CT_ACCT=y -# CONFIG_IP_NF_CONNTRACK_MARK is not set -# CONFIG_IP_NF_CONNTRACK_EVENTS is not set -CONFIG_IP_NF_CT_PROTO_SCTP=m -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -# CONFIG_IP_NF_NETBIOS_NS is not set -CONFIG_IP_NF_TFTP=m -CONFIG_IP_NF_AMANDA=m -# CONFIG_IP_NF_PPTP is not set -# CONFIG_IP_NF_H323 is not set -# CONFIG_IP_NF_SIP is not set -CONFIG_IP_NF_QUEUE=m - -# -# IPv6: Netfilter Configuration (EXPERIMENTAL) -# -# CONFIG_IP6_NF_QUEUE is not set - -# -# Bridge: Netfilter Configuration -# -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE_EBT_BROUTE=m -CONFIG_BRIDGE_EBT_T_FILTER=m -CONFIG_BRIDGE_EBT_T_NAT=m -CONFIG_BRIDGE_EBT_802_3=m -CONFIG_BRIDGE_EBT_AMONG=m -CONFIG_BRIDGE_EBT_ARP=m -CONFIG_BRIDGE_EBT_IP=m -CONFIG_BRIDGE_EBT_LIMIT=m -CONFIG_BRIDGE_EBT_MARK=m -CONFIG_BRIDGE_EBT_PKTTYPE=m -CONFIG_BRIDGE_EBT_STP=m -CONFIG_BRIDGE_EBT_VLAN=m -CONFIG_BRIDGE_EBT_ARPREPLY=m -CONFIG_BRIDGE_EBT_DNAT=m -CONFIG_BRIDGE_EBT_MARK_T=m -CONFIG_BRIDGE_EBT_REDIRECT=m -CONFIG_BRIDGE_EBT_SNAT=m -CONFIG_BRIDGE_EBT_LOG=m -# CONFIG_BRIDGE_EBT_ULOG is not set +# CONFIG_NETFILTER is not set # # DCCP Configuration (EXPERIMENTAL) @@ -333,167 +223,37 @@ CONFIG_BRIDGE_EBT_LOG=m # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IP_SCTP=m -# CONFIG_SCTP_DBG_MSG is not set -# CONFIG_SCTP_DBG_OBJCNT is not set -# CONFIG_SCTP_HMAC_NONE is not set -# CONFIG_SCTP_HMAC_SHA1 is not set -CONFIG_SCTP_HMAC_MD5=y +# CONFIG_IP_SCTP is not set # # TIPC Configuration (EXPERIMENTAL) # # CONFIG_TIPC is not set -CONFIG_ATM=m -CONFIG_ATM_CLIP=m -# CONFIG_ATM_CLIP_NO_ICMP is not set -CONFIG_ATM_LANE=m -# CONFIG_ATM_MPOA is not set -CONFIG_ATM_BR2684=m -# CONFIG_ATM_BR2684_IPFILTER is not set -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set -CONFIG_LLC=m # CONFIG_LLC2 is not set -CONFIG_IPX=m -# CONFIG_IPX_INTERN is not set -CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y -CONFIG_IPDDP_DECAP=y +# CONFIG_IPX is not set +# CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_ECONET is not set -CONFIG_WAN_ROUTER=m +# CONFIG_WAN_ROUTER is not set # # QoS and/or fair queueing # -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CLK_JIFFIES=y -# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set -# CONFIG_NET_SCH_CLK_CPU is not set - -# -# Queueing/Scheduling -# -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_ATM=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_INGRESS=m - -# -# Classification -# -CONFIG_NET_CLS=y -# CONFIG_NET_CLS_BASIC is not set -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_ROUTE=y -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -# CONFIG_CLS_U32_MARK is not set -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -# CONFIG_NET_EMATCH is not set -# CONFIG_NET_CLS_ACT is not set -CONFIG_NET_CLS_POLICE=y -CONFIG_NET_CLS_IND=y -CONFIG_NET_ESTIMATOR=y +# CONFIG_NET_SCHED is not set # # Network testing # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set -CONFIG_IRDA=m - -# -# IrDA protocols -# -CONFIG_IRLAN=m -CONFIG_IRNET=m -CONFIG_IRCOMM=m -# CONFIG_IRDA_ULTRA is not set - -# -# IrDA options -# -CONFIG_IRDA_CACHE_LAST_LSAP=y -CONFIG_IRDA_FAST_RR=y -# CONFIG_IRDA_DEBUG is not set - -# -# Infrared-port device drivers -# - -# -# SIR device drivers -# -CONFIG_IRTTY_SIR=m - -# -# Dongle support -# -CONFIG_DONGLE=y -CONFIG_ESI_DONGLE=m -CONFIG_ACTISYS_DONGLE=m -CONFIG_TEKRAM_DONGLE=m -# CONFIG_TOIM3232_DONGLE is not set -CONFIG_LITELINK_DONGLE=m -CONFIG_MA600_DONGLE=m -CONFIG_GIRBIL_DONGLE=m -CONFIG_MCP2120_DONGLE=m -CONFIG_OLD_BELKIN_DONGLE=m -CONFIG_ACT200L_DONGLE=m - -# -# Old SIR device drivers -# - -# -# Old Serial dongle support -# - -# -# FIR device drivers -# -# CONFIG_NSC_FIR is not set -# CONFIG_WINBOND_FIR is not set -# CONFIG_SMC_IRCC_FIR is not set -# CONFIG_ALI_FIR is not set -# CONFIG_VIA_FIR is not set -CONFIG_BT=m -CONFIG_BT_L2CAP=m -CONFIG_BT_SCO=m -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=m - -# -# Bluetooth device drivers -# -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_H4=y -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIVHCI=m +# CONFIG_IRDA is not set +# CONFIG_BT is not set # CONFIG_IEEE80211 is not set -CONFIG_WIRELESS_EXT=y # # Device Drivers @@ -504,7 +264,7 @@ CONFIG_WIRELESS_EXT=y # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=y +# CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set CONFIG_SYS_HYPERVISOR=y @@ -530,14 +290,14 @@ CONFIG_SYS_HYPERVISOR=y # # Block devices # -CONFIG_BLK_DEV_FD=m +# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set @@ -559,25 +319,24 @@ CONFIG_SCSI_PROC_FS=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=m -CONFIG_CHR_DEV_ST=m -CONFIG_CHR_DEV_OSST=m -CONFIG_BLK_DEV_SR=m -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set # CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set # # SCSI Transport Attributes # -CONFIG_SCSI_SPI_ATTRS=m -CONFIG_SCSI_FC_ATTRS=m +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_ATTRS is not set @@ -585,27 +344,13 @@ CONFIG_SCSI_FC_ATTRS=m # SCSI low-level drivers # # CONFIG_ISCSI_TCP is not set -CONFIG_SCSI_SATA=m +# CONFIG_SCSI_SATA is not set # CONFIG_SCSI_DEBUG is not set # # Multi-device support (RAID and LVM) # -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_RAID10=m -# CONFIG_MD_RAID456 is not set -CONFIG_MD_MULTIPATH=m -# CONFIG_MD_FAULTY is not set -CONFIG_BLK_DEV_DM=m -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_MIRROR=m -CONFIG_DM_ZERO=m -# CONFIG_DM_MULTIPATH is not set +# CONFIG_MD is not set # # Fusion MPT device support @@ -624,21 +369,19 @@ CONFIG_DM_ZERO=m # Network device support # CONFIG_NETDEVICES=y -CONFIG_DUMMY=m -CONFIG_BONDING=m -CONFIG_EQUALIZER=m -CONFIG_TUN=m +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # # PHY device support # -# CONFIG_PHYLIB is not set # # Ethernet (10 or 100Mbit) # -CONFIG_NET_ETHERNET=y -CONFIG_MII=m +# CONFIG_NET_ETHERNET is not set # # Ethernet (1000 Mbit) @@ -655,42 +398,18 @@ CONFIG_MII=m # # Wireless LAN (non-hamradio) # -CONFIG_NET_RADIO=y -# CONFIG_NET_WIRELESS_RTNETLINK is not set - -# -# Obsolete Wireless cards support (pre-802.11) -# -# CONFIG_STRIP is not set -# CONFIG_HOSTAP is not set +# CONFIG_NET_RADIO is not set # # Wan interfaces # # CONFIG_WAN is not set - -# -# ATM drivers -# -# CONFIG_ATM_DUMMY is not set -CONFIG_ATM_TCP=m -CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPP_FILTER=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -# CONFIG_PPP_BSDCOMP is not set -# CONFIG_PPP_MPPE is not set -CONFIG_PPPOE=m -CONFIG_PPPOATM=m +# CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_SHAPER is not set -CONFIG_NETCONSOLE=m -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -CONFIG_NETPOLL_TRAP=y -CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set # # ISDN subsystem @@ -920,9 +639,7 @@ CONFIG_DUMMY_CONSOLE=y # File systems # CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XATTR is not set # CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y @@ -933,33 +650,20 @@ CONFIG_FS_MBCACHE=y CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set -CONFIG_REISERFS_PROC_INFO=y -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -# CONFIG_JFS_SECURITY is not set -# CONFIG_JFS_DEBUG is not set -# CONFIG_JFS_STATISTICS is not set -CONFIG_FS_POSIX_ACL=y -CONFIG_XFS_FS=m -# CONFIG_XFS_QUOTA is not set -CONFIG_XFS_SECURITY=y -CONFIG_XFS_POSIX_ACL=y -# CONFIG_XFS_RT is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set # CONFIG_OCFS2_FS is not set -CONFIG_MINIX_FS=m -CONFIG_ROMFS_FS=m +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y CONFIG_INOTIFY_USER=y -CONFIG_QUOTA=y -# CONFIG_QFMT_V1 is not set -CONFIG_QFMT_V2=y -CONFIG_QUOTACTL=y +# CONFIG_QUOTA is not set CONFIG_DNOTIFY=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y # CONFIG_FUSE_FS is not set # @@ -969,8 +673,7 @@ CONFIG_JOLIET=y CONFIG_JOLIET=y CONFIG_ZISOFS=y CONFIG_ZISOFS_FS=y -CONFIG_UDF_FS=m -CONFIG_UDF_NLS=y +# CONFIG_UDF_FS is not set # # DOS/FAT/NT Filesystems @@ -979,7 +682,7 @@ CONFIG_MSDOS_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -997,61 +700,38 @@ CONFIG_RAMFS=y # Miscellaneous filesystems # # CONFIG_ADFS_FS is not set -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -CONFIG_BEFS_FS=m -# CONFIG_BEFS_DEBUG is not set -CONFIG_BFS_FS=m -CONFIG_EFS_FS=m +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set CONFIG_CRAMFS=y -CONFIG_VXFS_FS=m +# CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set -CONFIG_QNX4FS_FS=m -CONFIG_SYSV_FS=m -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set -# CONFIG_UFS_DEBUG is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set # # Network File Systems # -CONFIG_NFS_FS=m +CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set -CONFIG_NFS_V4=y -CONFIG_NFS_DIRECTIO=y -CONFIG_NFSD=m -CONFIG_NFSD_V3=y -# CONFIG_NFSD_V3_ACL is not set -CONFIG_NFSD_V4=y -CONFIG_NFSD_TCP=y -CONFIG_LOCKD=m +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=m CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=m -CONFIG_SUNRPC_GSS=m -CONFIG_RPCSEC_GSS_KRB5=m -CONFIG_RPCSEC_GSS_SPKM3=m -CONFIG_SMB_FS=m -# CONFIG_SMB_NLS_DEFAULT is not set -CONFIG_CIFS=m -# CONFIG_CIFS_STATS is not set -# CONFIG_CIFS_WEAK_PW_HASH is not set -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -# CONFIG_CIFS_DEBUG2 is not set -# CONFIG_CIFS_EXPERIMENTAL is not set -CONFIG_NCP_FS=m -CONFIG_NCPFS_PACKET_SIGNING=y -CONFIG_NCPFS_IOCTL_LOCKING=y -CONFIG_NCPFS_STRONG=y -CONFIG_NCPFS_NFS_NS=y -CONFIG_NCPFS_OS2_NS=y -CONFIG_NCPFS_SMALLDOS=y -CONFIG_NCPFS_NLS=y -CONFIG_NCPFS_EXTRAS=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set # CONFIG_9P_FS is not set @@ -1059,67 +739,52 @@ CONFIG_NCPFS_EXTRAS=y # # Partition Types # -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -CONFIG_OSF_PARTITION=y -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -CONFIG_MAC_PARTITION=y +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -# CONFIG_LDM_PARTITION is not set -CONFIG_SGI_PARTITION=y -# CONFIG_ULTRIX_PARTITION is not set -CONFIG_SUN_PARTITION=y -# CONFIG_KARMA_PARTITION is not set -CONFIG_EFI_PARTITION=y # # Native Language Support # CONFIG_NLS=y -CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set # # Instrumentation Support @@ -1135,7 +800,7 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ=y CONFIG_UNUSED_SYMBOLS=y CONFIG_DEBUG_KERNEL=y -CONFIG_LOG_BUF_SHIFT=15 +CONFIG_LOG_BUF_SHIFT=14 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set @@ -1170,29 +835,29 @@ CONFIG_FORCED_INLINING=y # Cryptographic options # CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_WP512=m +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=m +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_SERPENT=m +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set # CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_AES_X86_64 is not set -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_KHAZAD=m +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set # CONFIG_CRYPTO_ANUBIS is not set -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set CONFIG_CRYPTO_CRC32C=m # CONFIG_CRYPTO_TEST is not set @@ -1200,7 +865,7 @@ CONFIG_CRYPTO_CRC32C=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -1210,8 +875,11 @@ CONFIG_XEN_PRIVCMD=y CONFIG_XEN_PRIVCMD=y CONFIG_XEN_XENBUS_DEV=y # CONFIG_XEN_BACKEND is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_GRANT_DEV=y +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y @@ -1225,17 +893,13 @@ CONFIG_XEN_SMPBOOT=y CONFIG_XEN_SMPBOOT=y CONFIG_XEN_BALLOON=y CONFIG_XEN_DEVMEM=y -# CONFIG_XEN_GRANT_DEV is not set # # Library routines # -CONFIG_CRC_CCITT=m +# CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set -CONFIG_CRC32=y +# CONFIG_CRC32 is not set CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=m -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m CONFIG_PLIST=y diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xen_x86_32 --- a/buildconfigs/linux-defconfig_xen_x86_32 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xen_x86_32 Tue Feb 19 11:15:05 2008 -0700 @@ -1276,6 +1276,7 @@ CONFIG_I2O=m CONFIG_I2O=m CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y CONFIG_I2O_CONFIG=m CONFIG_I2O_CONFIG_OLD_IOCTL=y CONFIG_I2O_BUS=m @@ -1418,6 +1419,7 @@ CONFIG_S2IO=m CONFIG_S2IO=m CONFIG_S2IO_NAPI=y CONFIG_MYRI10GE=m +# CONFIG_SFC is not set # # Token Ring devices @@ -3249,7 +3251,7 @@ CONFIG_CRYPTO_TEST=m # # CONFIG_CRYPTO_DEV_PADLOCK is not set CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -3263,6 +3265,8 @@ CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_NETDEV_BACKEND=y # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set # CONFIG_XEN_NETDEV_LOOPBACK is not set CONFIG_XEN_PCIDEV_BACKEND=m CONFIG_XEN_PCIDEV_BACKEND_VPCI=y @@ -3273,8 +3277,9 @@ CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_GRANT_DEV=y +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_GRANT_DEV=y CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y diff -r 31d71546a644 -r 594bfb5cbe40 buildconfigs/linux-defconfig_xen_x86_64 --- a/buildconfigs/linux-defconfig_xen_x86_64 Thu Feb 14 09:35:01 2008 -0700 +++ b/buildconfigs/linux-defconfig_xen_x86_64 Tue Feb 19 11:15:05 2008 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18.8 -# Tue Oct 16 09:32:25 2007 +# Mon Feb 18 10:38:24 2008 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -1358,6 +1358,7 @@ CONFIG_S2IO=m CONFIG_S2IO=m CONFIG_S2IO_NAPI=y CONFIG_MYRI10GE=m +# CONFIG_SFC is not set # # Token Ring devices @@ -3080,7 +3081,7 @@ CONFIG_CRYPTO_TEST=m # Hardware crypto devices # CONFIG_XEN=y -CONFIG_XEN_INTERFACE_VERSION=0x00030206 +CONFIG_XEN_INTERFACE_VERSION=0x00030207 # # XEN @@ -3094,6 +3095,8 @@ CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_BLKDEV_TAP=y CONFIG_XEN_NETDEV_BACKEND=y # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set +# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set # CONFIG_XEN_NETDEV_LOOPBACK is not set CONFIG_XEN_PCIDEV_BACKEND=m # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set @@ -3104,8 +3107,9 @@ CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_TPMDEV_BACKEND=m CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_GRANT_DEV=y +# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set CONFIG_XEN_FRAMEBUFFER=y -CONFIG_XEN_GRANT_DEV=y CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/Kconfig --- a/drivers/net/Kconfig Thu Feb 14 09:35:01 2008 -0700 +++ b/drivers/net/Kconfig Tue Feb 19 11:15:05 2008 -0700 @@ -2399,6 +2399,8 @@ config MYRI10GE <file:Documentation/networking/net-modules.txt>. The module will be called myri10ge. +source "drivers/net/sfc/Kconfig" + endmenu source "drivers/net/tokenring/Kconfig" diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/Makefile --- a/drivers/net/Makefile Thu Feb 14 09:35:01 2008 -0700 +++ b/drivers/net/Makefile Tue Feb 19 11:15:05 2008 -0700 @@ -219,3 +219,5 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o obj-$(CONFIG_FS_ENET) += fs_enet/ +obj-$(CONFIG_SFC) += sfc/ + diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/Kconfig --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/Kconfig Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,35 @@ +config SFC + tristate "Solarflare Solarstorm SFC4000 support" + depends on PCI && INET + select MII + help + This driver supports 10-gigabit Ethernet cards based on + the Solarflare Communications Solarstorm SFC4000 controller. + + To compile this driver as a module, choose M here. The module + will be called sfc. + +config SFC_DEBUGFS + bool "Solarflare Solarstorm SFC4000 debugging support" + depends on SFC && DEBUG_FS + default N + help + This option creates an "sfc" subdirectory of debugfs with + debugging information for the SFC4000 driver. + + If unsure, say N. + +config SFC_MTD + depends on SFC && MTD && MTD_PARTITIONS + tristate "Solarflare Solarstorm SFC4000 flash/EEPROM support" + help + This module exposes the on-board flash and/or EEPROM memory as + MTD devices (e.g. /dev/mtd1). This makes it possible to upload a + new boot ROM to the NIC. + +config SFC_RESOURCE + depends on SFC + tristate "Solarflare Solarstorm SFC4000 resource driver" + help + This module provides the SFC resource manager driver. + diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/Makefile Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,43 @@ + +# Final objects +sfc_o = sfc.o +sfc_mtd_o = sfc_mtd.o + +# Constituent objects +sfc_elements_o := +sfc_elements_o += efx.o +sfc_elements_o += falcon.o +sfc_elements_o += tx.o +sfc_elements_o += rx.o +sfc_elements_o += mentormac.o +sfc_elements_o += falcon_gmac.o +sfc_elements_o += falcon_xmac.o +sfc_elements_o += alaska.o +sfc_elements_o += i2c-direct.o +sfc_elements_o += selftest.o +sfc_elements_o += driverlink.o +ifeq ($(CONFIG_SFC_DEBUGFS),y) +sfc_elements_o += debugfs.o +endif +sfc_elements_o += ethtool.o +sfc_elements_o += xfp_phy.o +sfc_elements_o += mdio_10g.o +sfc_elements_o += txc43128_phy.o +sfc_elements_o += tenxpress.o +sfc_elements_o += lm87_support.o +sfc_elements_o += boards.o +sfc_elements_o += sfe4001.o +sfc_elements_o += pm8358_phy.o +sfc_elements_o += null_phy.o +sfc_elements_o += phy.o +sfc_elements_o += kernel_compat.o + +sfc_mtd_elements_o := mtd.o + +obj-$(CONFIG_SFC) += $(sfc_o) +obj-$(CONFIG_SFC_MTD) += $(sfc_mtd_o) + +sfc-objs = $(sfc_elements_o) +sfc_mtd-objs = $(sfc_mtd_elements_o) + +obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/alaska.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/alaska.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,159 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005: Fen Systems Ltd. + * Copyright 2006-2007: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include "net_driver.h" +#include <linux/ethtool.h> +#include "gmii.h" +#include "phy.h" + +/* Marvell 88E1111 "Alaska" PHY control */ +#define ALASKA_PHY_SPECIFIC 16 +#define ALASKA_ALLOW_SLEEP 0x0200 + +#define ALASKA_EXTENDED_CONTROL 20 +#define EXTENDED_LINE_LOOPBACK 0x8000 + +#define ALASKA_LED_CONTROL 24 +#define LED_BLINK_MASK 0x0700 +#define LED_BLINK_FAST 0x0100 +#define LED_BLINK_SLOW 0x0300 +#define LED_TX_CTRL_MASK 0x0041 +#define LED_TX_CTRL_LINK_AND_ACTIVITY 0x0001 + +#define ALASKA_LED_OVERRIDE 25 +#define LED_LINK1000_MASK 0x0030 +#define LED_LINK1000_BLINK 0x0010 +#define LED_TX_MASK 0x0003 +#define LED_TX_BLINK 0x0001 + +static void alaska_reconfigure(struct efx_nic *efx) +{ + struct mii_if_info *gmii = &efx->mii; + u32 bmcr, phy_ext; + + /* Configure line loopback if requested */ + phy_ext = gmii->mdio_read(gmii->dev, gmii->phy_id, + ALASKA_EXTENDED_CONTROL); + if (efx->loopback_mode == LOOPBACK_NETWORK) + phy_ext |= EXTENDED_LINE_LOOPBACK; + else + phy_ext &= ~EXTENDED_LINE_LOOPBACK; + gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_EXTENDED_CONTROL, + phy_ext); + + /* Configure PHY loopback if requested */ + bmcr = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR); + if (efx->loopback_mode == LOOPBACK_PHY) + bmcr |= BMCR_LOOPBACK; + else + bmcr &= ~BMCR_LOOPBACK; + gmii->mdio_write(gmii->dev, gmii->phy_id, MII_BMCR, bmcr); + + /* Read link up status */ + if (efx->loopback_mode == LOOPBACK_NONE) + efx->link_up = mii_link_ok(gmii); + else + efx->link_up = 1; + + /* Determine link options from PHY */ + if (gmii->force_media) { + efx->link_options = gmii_forced_result(bmcr); + } else { + int lpa = gmii_lpa(gmii); + int adv = gmii_advertised(gmii); + efx->link_options = gmii_nway_result(adv & lpa); + } +} + +static void alaska_clear_interrupt(struct efx_nic *efx) +{ + struct mii_if_info *gmii = &efx->mii; + + /* Read interrupt status register to clear */ + gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR); +} + +static int alaska_init(struct efx_nic *efx) +{ + struct mii_if_info *gmii = &efx->mii; + u32 ier, leds, ctrl_1g, phy_spec; + + /* Read ISR to clear any outstanding PHY interrupts */ + gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR); + + /* Enable PHY interrupts */ + ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER); + ier |= IER_LINK_CHG; + gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier); + + /* Remove 1G half-duplex as unsupported in Mentor MAC */ + ctrl_1g = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000); + ctrl_1g &= ~(ADVERTISE_1000HALF); + gmii->mdio_write(gmii->dev, gmii->phy_id, MII_CTRL1000, ctrl_1g); + + /* + * The PHY can save power when there is no external connection + * (sleep mode). However, this is incompatible with PHY + * loopback, and if enable and disable it quickly the PHY can + * go to sleep even when sleep mode is disabled. (SFC bug + * 9309.) Therefore we disable it all the time. + */ + phy_spec = gmii->mdio_read(gmii->dev, gmii->phy_id, + ALASKA_PHY_SPECIFIC); + phy_spec &= ~ALASKA_ALLOW_SLEEP; + gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_PHY_SPECIFIC, + phy_spec); + + /* Configure LEDs */ + leds = gmii->mdio_read(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL); + leds &= ~(LED_BLINK_MASK | LED_TX_CTRL_MASK); + leds |= (LED_BLINK_FAST | LED_TX_CTRL_LINK_AND_ACTIVITY); + gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL, leds); + + return 0; +} + +static void alaska_fini(struct efx_nic *efx) +{ + struct mii_if_info *gmii = &efx->mii; + u32 ier; + + /* Disable PHY interrupts */ + ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER); + ier &= ~IER_LINK_CHG; + gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier); +} + + +struct efx_phy_operations alaska_phy_operations = { + .init = alaska_init, + .fini = alaska_fini, + .reconfigure = alaska_reconfigure, + .clear_interrupt = alaska_clear_interrupt, + .loopbacks = (1 << LOOPBACK_PHY) | (1 << LOOPBACK_NETWORK), + .startup_loopback = LOOPBACK_PHY, +}; diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/bitfield.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/bitfield.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,544 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_BITFIELD_H +#define EFX_BITFIELD_H + +/* + * Efx bitfield access + * + * Efx NICs make extensive use of bitfields up to 128 bits + * wide. Since there is no native 128-bit datatype on most systems, + * and since 64-bit datatypes are inefficient on 32-bit systems and + * vice versa, we wrap accesses in a way that uses the most efficient + * datatype. + * + * The NICs are PCI devices and therefore little-endian. Since most + * of the quantities that we deal with are DMAed to/from host memory, + * we define our datatypes (efx_oword_t, efx_qword_t and + * efx_dword_t) to be little-endian. + */ + +/* Lowest bit numbers and widths */ +#define EFX_DUMMY_FIELD_LBN 0 +#define EFX_DUMMY_FIELD_WIDTH 0 +#define EFX_DWORD_0_LBN 0 +#define EFX_DWORD_0_WIDTH 32 +#define EFX_DWORD_1_LBN 32 +#define EFX_DWORD_1_WIDTH 32 +#define EFX_DWORD_2_LBN 64 +#define EFX_DWORD_2_WIDTH 32 +#define EFX_DWORD_3_LBN 96 +#define EFX_DWORD_3_WIDTH 32 + +#define EFX_BYTE 1 +#define EFX_WORD 2 +#define EFX_DWORD 4 +#define EFX_OWORD 8 + +/* Specified attribute (e.g. LBN) of the specified field */ +#define EFX_VAL(field, attribute) field ## _ ## attribute +/* Low bit number of the specified field */ +#define EFX_LOW_BIT(field) EFX_VAL(field, LBN) +/* Bit width of the specified field */ +#define EFX_WIDTH(field) EFX_VAL(field, WIDTH) +/* High bit number of the specified field */ +#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1) +/* Mask equal in width to the specified field. + * + * For example, a field with width 5 would have a mask of 0x1f. + * + * The maximum width mask that can be generated is 64 bits. + */ +#define EFX_MASK64(field) \ + (EFX_WIDTH(field) == 64 ? ~((u64) 0) : \ + (((((u64) 1) << EFX_WIDTH(field))) - 1)) + +/* Mask equal in width to the specified field. + * + * For example, a field with width 5 would have a mask of 0x1f. + * + * The maximum width mask that can be generated is 32 bits. Use + * EFX_MASK64 for higher width fields. + */ +#define EFX_MASK32(field) \ + (EFX_WIDTH(field) == 32 ? ~((u32) 0) : \ + (((((u32) 1) << EFX_WIDTH(field))) - 1)) + +/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */ +typedef union efx_dword { + __le32 u32[1]; +} efx_dword_t; + +/* A quadword (i.e. 8 byte) datatype - little-endian in HW */ +typedef union efx_qword { + __le64 u64[1]; + __le32 u32[2]; + efx_dword_t dword[2]; +} efx_qword_t; + +/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */ +typedef union efx_oword { + __le64 u64[2]; + efx_qword_t qword[2]; + __le32 u32[4]; + efx_dword_t dword[4]; +} efx_oword_t; + +/* Format string and value expanders for printk */ +#define EFX_DWORD_FMT "%08x" +#define EFX_QWORD_FMT "%08x:%08x" +#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x" +#define EFX_DWORD_VAL(dword) \ + ((unsigned int) le32_to_cpu((dword).u32[0])) +#define EFX_QWORD_VAL(qword) \ + ((unsigned int) le32_to_cpu((qword).u32[1])), \ + ((unsigned int) le32_to_cpu((qword).u32[0])) +#define EFX_OWORD_VAL(oword) \ + ((unsigned int) le32_to_cpu((oword).u32[3])), \ + ((unsigned int) le32_to_cpu((oword).u32[2])), \ + ((unsigned int) le32_to_cpu((oword).u32[1])), \ + ((unsigned int) le32_to_cpu((oword).u32[0])) + +/* + * Extract bit field portion [low,high) from the native-endian element + * which contains bits [min,max). + * + * For example, suppose "element" represents the high 32 bits of a + * 64-bit value, and we wish to extract the bits belonging to the bit + * field occupying bits 28-45 of this 64-bit value. + * + * Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give + * + * ( element ) << 4 + * + * The result will contain the relevant bits filled in in the range + * [0,high-low), with garbage in bits [high-low+1,...). + */ +#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \ + (((low > max) || (high < min)) ? 0 : \ + ((low > min) ? \ + ((native_element) >> (low - min)) : \ + ((native_element) << (min - low)))) + +/* + * Extract bit field portion [low,high) from the 64-bit little-endian + * element which contains bits [min,max) + */ +#define EFX_EXTRACT64(element, min, max, low, high) \ + EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high) + +/* + * Extract bit field portion [low,high) from the 32-bit little-endian + * element which contains bits [min,max) + */ +#define EFX_EXTRACT32(element, min, max, low, high) \ + EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high) + +#define EFX_EXTRACT_OWORD64(oword, low, high) \ + (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \ + EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) + +#define EFX_EXTRACT_QWORD64(qword, low, high) \ + EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) + +#define EFX_EXTRACT_OWORD32(oword, low, high) \ + (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \ + EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \ + EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \ + EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) + +#define EFX_EXTRACT_QWORD32(qword, low, high) \ + (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \ + EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) + +#define EFX_EXTRACT_DWORD(dword, low, high) \ + EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) + +#define EFX_OWORD_FIELD64(oword, field) \ + (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ + & EFX_MASK64(field)) + +#define EFX_QWORD_FIELD64(qword, field) \ + (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ + & EFX_MASK64(field)) + +#define EFX_OWORD_FIELD32(oword, field) \ + (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ + & EFX_MASK32(field)) + +#define EFX_QWORD_FIELD32(qword, field) \ + (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ + & EFX_MASK32(field)) + +#define EFX_DWORD_FIELD(dword, field) \ + (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \ + & EFX_MASK32(field)) + +#define EFX_OWORD_IS_ZERO64(oword) \ + (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0) + +#define EFX_QWORD_IS_ZERO64(qword) \ + (((qword).u64[0]) == (__force __le64) 0) + +#define EFX_OWORD_IS_ZERO32(oword) \ + (((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \ + == (__force __le32) 0) + +#define EFX_QWORD_IS_ZERO32(qword) \ + (((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0) + +#define EFX_DWORD_IS_ZERO(dword) \ + (((dword).u32[0]) == (__force __le32) 0) + +#define EFX_OWORD_IS_ALL_ONES64(oword) \ + (((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0)) + +#define EFX_QWORD_IS_ALL_ONES64(qword) \ + ((qword).u64[0] == ~((__force __le64) 0)) + +#define EFX_OWORD_IS_ALL_ONES32(oword) \ + (((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \ + == ~((__force __le32) 0)) + +#define EFX_QWORD_IS_ALL_ONES32(qword) \ + (((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0)) + +#define EFX_DWORD_IS_ALL_ONES(dword) \ + ((dword).u32[0] == ~((__force __le32) 0)) + +#if BITS_PER_LONG == 64 +#define EFX_OWORD_FIELD EFX_OWORD_FIELD64 +#define EFX_QWORD_FIELD EFX_QWORD_FIELD64 +#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64 +#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64 +#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64 +#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64 +#else +#define EFX_OWORD_FIELD EFX_OWORD_FIELD32 +#define EFX_QWORD_FIELD EFX_QWORD_FIELD32 +#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32 +#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32 +#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32 +#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32 +#endif + +/* + * Construct bit field portion + * + * Creates the portion of the bit field [low,high) that lies within + * the range [min,max). + */ +#define EFX_INSERT_NATIVE64(min, max, low, high, value) \ + (((low > max) || (high < min)) ? 0 : \ + ((low > min) ? \ + (((u64) (value)) << (low - min)) : \ + (((u64) (value)) >> (min - low)))) + +#define EFX_INSERT_NATIVE32(min, max, low, high, value) \ + (((low > max) || (high < min)) ? 0 : \ + ((low > min) ? \ + (((u32) (value)) << (low - min)) : \ + (((u32) (value)) >> (min - low)))) + +#define EFX_INSERT_NATIVE(min, max, low, high, value) \ + ((((max - min) >= 32) || ((high - low) >= 32)) ? \ + EFX_INSERT_NATIVE64(min, max, low, high, value) : \ + EFX_INSERT_NATIVE32(min, max, low, high, value)) + +/* + * Construct bit field portion + * + * Creates the portion of the named bit field that lies within the + * range [min,max). + */ +#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \ + EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \ + EFX_HIGH_BIT(field), value) + +/* + * Construct bit field + * + * Creates the portion of the named bit fields that lie within the + * range [min,max). + */ +#define EFX_INSERT_FIELDS_NATIVE(min, max, \ + field1, value1, \ + field2, value2, \ + field3, value3, \ + field4, value4, \ + field5, value5, \ + field6, value6, \ + field7, value7, \ + field8, value8, \ + field9, value9, \ + field10, value10) \ + (EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \ + EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10))) + +#define EFX_INSERT_FIELDS64(...) \ + cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__)) + +#define EFX_INSERT_FIELDS32(...) \ + cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__)) + +#define EFX_POPULATE_OWORD64(oword, ...) do { \ + (oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \ + (oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \ + } while (0) + +#define EFX_POPULATE_QWORD64(qword, ...) do { \ + (qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \ + } while (0) + +#define EFX_POPULATE_OWORD32(oword, ...) do { \ + (oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \ + (oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \ + (oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \ + (oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \ + } while (0) + +#define EFX_POPULATE_QWORD32(qword, ...) do { \ + (qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \ + (qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \ + } while (0) + +#define EFX_POPULATE_DWORD(dword, ...) do { \ + (dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \ + } while (0) + +#if BITS_PER_LONG == 64 +#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64 +#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64 +#else +#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32 +#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32 +#endif + +/* Populate an octword field with various numbers of arguments */ +#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD +#define EFX_POPULATE_OWORD_9(oword, ...) \ + EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_8(oword, ...) \ + EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_7(oword, ...) \ + EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_6(oword, ...) \ + EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_5(oword, ...) \ + EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_4(oword, ...) \ + EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_3(oword, ...) \ + EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_2(oword, ...) \ + EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_OWORD_1(oword, ...) \ + EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_ZERO_OWORD(oword) \ + EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0) +#define EFX_SET_OWORD(oword) \ + EFX_POPULATE_OWORD_4(oword, \ + EFX_DWORD_0, 0xffffffff, \ + EFX_DWORD_1, 0xffffffff, \ + EFX_DWORD_2, 0xffffffff, \ + EFX_DWORD_3, 0xffffffff) + +/* Populate a quadword field with various numbers of arguments */ +#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD +#define EFX_POPULATE_QWORD_9(qword, ...) \ + EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_8(qword, ...) \ + EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_7(qword, ...) \ + EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_6(qword, ...) \ + EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_5(qword, ...) \ + EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_4(qword, ...) \ + EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_3(qword, ...) \ + EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_2(qword, ...) \ + EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_QWORD_1(qword, ...) \ + EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_ZERO_QWORD(qword) \ + EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0) +#define EFX_SET_QWORD(qword) \ + EFX_POPULATE_QWORD_2(qword, \ + EFX_DWORD_0, 0xffffffff, \ + EFX_DWORD_1, 0xffffffff) + +/* Populate a dword field with various numbers of arguments */ +#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD +#define EFX_POPULATE_DWORD_9(dword, ...) \ + EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_8(dword, ...) \ + EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_7(dword, ...) \ + EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_6(dword, ...) \ + EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_5(dword, ...) \ + EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_4(dword, ...) \ + EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_3(dword, ...) \ + EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_2(dword, ...) \ + EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_POPULATE_DWORD_1(dword, ...) \ + EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__) +#define EFX_ZERO_DWORD(dword) \ + EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0) +#define EFX_SET_DWORD(dword) \ + EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff) + +/* + * Modify a named field within an already-populated structure. Used + * for read-modify-write operations. + * + */ + +#define EFX_INVERT_OWORD(oword) do { \ + (oword).u64[0] = ~((oword).u64[0]); \ + (oword).u64[1] = ~((oword).u64[1]); \ + } while (0) + +#define EFX_INSERT_FIELD64(...) \ + cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__)) + +#define EFX_INSERT_FIELD32(...) \ + cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__)) + +#define EFX_INPLACE_MASK64(min, max, field) \ + EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field)) + +#define EFX_INPLACE_MASK32(min, max, field) \ + EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field)) + +#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \ + (oword).u64[0] = (((oword).u64[0] \ + & ~EFX_INPLACE_MASK64(0, 63, field)) \ + | EFX_INSERT_FIELD64(0, 63, field, value)); \ + (oword).u64[1] = (((oword).u64[1] \ + & ~EFX_INPLACE_MASK64(64, 127, field)) \ + | EFX_INSERT_FIELD64(64, 127, field, value)); \ + } while (0) + +#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \ + (qword).u64[0] = (((qword).u64[0] \ + & ~EFX_INPLACE_MASK64(0, 63, field)) \ + | EFX_INSERT_FIELD64(0, 63, field, value)); \ + } while (0) + +#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \ + (oword).u32[0] = (((oword).u32[0] \ + & ~EFX_INPLACE_MASK32(0, 31, field)) \ + | EFX_INSERT_FIELD32(0, 31, field, value)); \ + (oword).u32[1] = (((oword).u32[1] \ + & ~EFX_INPLACE_MASK32(32, 63, field)) \ + | EFX_INSERT_FIELD32(32, 63, field, value)); \ + (oword).u32[2] = (((oword).u32[2] \ + & ~EFX_INPLACE_MASK32(64, 95, field)) \ + | EFX_INSERT_FIELD32(64, 95, field, value)); \ + (oword).u32[3] = (((oword).u32[3] \ + & ~EFX_INPLACE_MASK32(96, 127, field)) \ + | EFX_INSERT_FIELD32(96, 127, field, value)); \ + } while (0) + +#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \ + (qword).u32[0] = (((qword).u32[0] \ + & ~EFX_INPLACE_MASK32(0, 31, field)) \ + | EFX_INSERT_FIELD32(0, 31, field, value)); \ + (qword).u32[1] = (((qword).u32[1] \ + & ~EFX_INPLACE_MASK32(32, 63, field)) \ + | EFX_INSERT_FIELD32(32, 63, field, value)); \ + } while (0) + +#define EFX_SET_DWORD_FIELD(dword, field, value) do { \ + (dword).u32[0] = (((dword).u32[0] \ + & ~EFX_INPLACE_MASK32(0, 31, field)) \ + | EFX_INSERT_FIELD32(0, 31, field, value)); \ + } while (0) + +#if BITS_PER_LONG == 64 +#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64 +#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64 +#else +#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32 +#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32 +#endif + +#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \ + if (FALCON_REV(efx) == FALCON_REV_B0) { \ + EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \ + } else { \ + EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \ + } \ +} while (0) + +#define EFX_QWORD_FIELD_VER(efx, qword, field) \ + (FALCON_REV(efx) == FALCON_REV_B0 ? \ + EFX_QWORD_FIELD((qword), field##_B0) : \ + EFX_QWORD_FIELD((qword), field##_A1)) + +/* Used to avoid compiler warnings about shift range exceeding width + * of the data types when dma_addr_t is only 32 bits wide. + */ +#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t)) +#define EFX_DMA_TYPE_WIDTH(width) \ + (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH) +#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \ + ~((u64) 0) : ~((u32) 0)) +#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK) + +/* + * Determine if a DMA address is over the 4GB threshold + * + * Defined in a slightly tortuous way to avoid compiler warnings. + */ +static inline int efx_is_over_4gb(dma_addr_t address) +{ + if (DMA_ADDR_T_WIDTH > 32) + return (((u64) address) >> 32) ? 1 : 0; + else + /* Can never be true */ + return 0; +} + +#endif /* EFX_BITFIELD_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/boards.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/boards.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,528 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2007: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Developed by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include "net_driver.h" +#include "phy.h" +#include "lm87_support.h" +#include "boards.h" +#include "efx.h" + +/* Macros for unpacking the board revision */ +/* The revision info is in host byte order. */ +#define BOARD_TYPE(_rev) (_rev >> 8) +#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) +#define BOARD_MINOR(_rev) (_rev & 0xf) + +/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */ +#define BLINK_INTERVAL (HZ/2) + +static void blink_led_timer(unsigned long context) +{ + struct efx_nic *efx = (struct efx_nic *)context; + struct efx_blinker *bl = &efx->board_info.blinker; + efx->board_info.set_fault_led(efx, bl->state); + bl->state = !bl->state; + if (bl->resubmit) { + bl->timer.expires = jiffies + BLINK_INTERVAL; + add_timer(&bl->timer); + } +} + +static void board_blink(struct efx_nic *efx, int blink) +{ + struct efx_blinker *blinker = &efx->board_info.blinker; + + /* The rtnl mutex serialises all ethtool ioctls, so + * nothing special needs doing here. */ + if (blink) { + blinker->resubmit = 1; + blinker->state = 0; + setup_timer(&blinker->timer, blink_led_timer, + (unsigned long)efx); + blinker->timer.expires = jiffies + BLINK_INTERVAL; + add_timer(&blinker->timer); + } else { + blinker->resubmit = 0; + if (blinker->timer.function) + del_timer_sync(&blinker->timer); + efx->board_info.set_fault_led(efx, 0); + } +} + + +struct sensor_conf { + const char *name; + const unsigned high; + const unsigned low; +}; + +#define NO_LIMIT ((unsigned)-1) + +#define LM87_SENSOR_BYTES (18) + +static int sensor_limits_to_bytes(const struct sensor_conf *limits, + int nlimits, u8 *bytes, int maxbytes) +{ + int i, nbytes; + nbytes = 0; + for (i = 0; i < nlimits; i++) { + bytes[nbytes++] = limits[i].high; + if (limits[i].low != NO_LIMIT) + bytes[nbytes++] = limits[i].low; + /* We may have overrun by one at this point, but this test + * should only trigger in development drivers as the sizes + * are not dynamic. */ + if (nbytes > maxbytes) { + printk(KERN_ERR "%s: out of space!\n", __func__); + break; + } + } + return nbytes; +} + +/***************************************************************************** + * Support for the SFE4002 + * + */ +/* LM87 configuration data for the sensor on the SFE4002 board */ +static const struct sensor_conf sfe4002_lm87_limits[] = { + {"1.8V line", 0x91, 0x83}, /* 2.5V sensor, scaled for 1.8V */ + {"1.2V line", 0x5a, 0x51}, /* Vccp1 */ + {"3.3V line", 0xca, 0xb6}, + {"5V line", 0xc9, 0xb6}, + {"12V line", 0xe0, 0xb0}, + {"1V line", 0x4b, 0x44}, /* vccp2 */ + {"Ext. temp.", 0x46, 0x0a}, /* ASIC temp. */ + {"Int. temp.", 0x3c, 0x0a}, /* Board temp. */ + {"1.66V line", 0xb2, NO_LIMIT}, /* AIN1 only takes 1 value */ + {"1.5V line", 0xa1, NO_LIMIT} /* AIN2 only takes 1 value */ +}; + +static const int sfe4002_lm87_nlimits = ARRAY_SIZE(sfe4002_lm87_limits); + +static u16 sfe4002_lm87_irq_mask = EFX_LM87_NO_INTS; + +/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two + * bits are set by strap pins */ +#define SFE4002_LM87_I2C_ID (0x2e) + +/****************************************************************************/ +/* LED allocations. Note that on rev A0 boards the schematic and the reality + * differ: red and green are swapped. Below is the fixed (A1) layout (there + * are only 3 A0 boards in existence, so no real reason to make this + * conditional). + */ +#define SFE4002_FAULT_LED (2) /* Red */ +#define SFE4002_RX_LED (0) /* Green */ +#define SFE4002_TX_LED (1) /* Amber */ + +static int sfe4002_init_leds(struct efx_nic *efx) +{ + /* Set the TX and RX LEDs to reflect status and activity, and the + * fault LED off */ + xfp_set_led(efx, SFE4002_TX_LED, + QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); + xfp_set_led(efx, SFE4002_RX_LED, + QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); + xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); + efx->board_info.blinker.led_num = SFE4002_FAULT_LED; + return 0; +} + +static void sfe4002_fault_led(struct efx_nic *efx, int state) +{ + xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : + QUAKE_LED_OFF); +} + +static int sfe4002_sensor_meaning(struct efx_nic *efx, int limit_num, + unsigned val) +{ + const struct sensor_conf *lim = &sfe4002_lm87_limits[limit_num]; + if (lim->low == NO_LIMIT) + EFX_ERR(efx, "%10s 0x%02x (nominal value 0x%02x)\n", lim->name, + val, lim->high); + else + EFX_ERR(efx, "%10s 0x%02x (nominal range 0x%02x - 0x%02x)\n", + lim->name, val, lim->high, lim->low); + return 1; +} + +static int sfe4002_check_hw(struct efx_nic *efx) +{ + int rc; + + /* A0 board rev. 4002s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = (efx->board_info.minor > 0) ? + 0 : ~EFX_LM87_ETMP_INT; + + /* Check the sensor (NOP if not present). */ + rc = efx_check_lm87(efx, alarm_mask); + + /* We treat both lm87 interrupts and failure to talk to the lm87 + * as problems (since failure will only be reported if we did + * find the sensor at probe time. */ + if (rc) + EFX_ERR(efx, "sensor alert!\n"); + return rc; +} + +static int sfe4002_init(struct efx_nic *efx) +{ + u8 lm87_bytes[LM87_SENSOR_BYTES]; + int nbytes; + int rc; + + efx->board_info.monitor = sfe4002_check_hw; + efx->board_info.interpret_sensor = sfe4002_sensor_meaning; + efx->board_info.init_leds = sfe4002_init_leds; + efx->board_info.set_fault_led = sfe4002_fault_led; + efx->board_info.blink = board_blink; + /* To clean up shut down the lm87 (NOP if not present) */ + efx->board_info.fini = efx_remove_lm87; + + nbytes = sensor_limits_to_bytes(sfe4002_lm87_limits, + sfe4002_lm87_nlimits, lm87_bytes, + LM87_SENSOR_BYTES); + + /* Activate the lm87 sensor if present (succeeds if nothing there) */ + rc = efx_probe_lm87(efx, SFE4002_LM87_I2C_ID, + lm87_bytes, nbytes, sfe4002_lm87_irq_mask); + + return rc; +} + +/***************************************************************************** + * Support for the SFE4003 + * + */ +/* LM87 configuration data for the sensor on the SFE4003 board */ +static const struct sensor_conf sfe4003_lm87_limits[] = { + {"1.5V line", 0x78, 0x6d}, /* 2.5V input, values scaled for 1.5V */ + {"1.2V line", 0x5a, 0x51}, /* Vccp1 */ + {"3.3V line", 0xca, 0xb6}, + {"5V line", 0xc0, 0x00}, /* Sensor not connected. */ + {"12V line", 0xe0, 0xb0}, + {"1V line", 0x4b, 0x44}, /* Vccp2 */ + {"Ext. temp.", 0x46, 0x0a}, /* ASIC temp. */ + {"Int. temp.", 0x3c, 0x0a}, /* Board temp. */ + {"", 0xff, NO_LIMIT}, /* FAN1/AIN1 unused */ + {"", 0xff, NO_LIMIT} /* FAN2/AIN2 unused */ +}; + +static const int sfe4003_lm87_nlimits = ARRAY_SIZE(sfe4003_lm87_limits); + +static u16 sfe4003_lm87_irq_mask = EFX_LM87_NO_INTS; + + +static int sfe4003_sensor_meaning(struct efx_nic *efx, int limit_num, + unsigned val) +{ + const struct sensor_conf *lim = &sfe4003_lm87_limits[limit_num]; + if (lim->low == NO_LIMIT) + return 0; /* Neither AIN1 nor AIN2 mean anything to us */ + else + EFX_ERR(efx, "%10s 0x%02x (nominal range 0x%02x - 0x%02x)\n", + lim->name, val, lim->high, lim->low); + return 1; +} + +/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two + * bits are set by strap pins */ +#define SFE4003_LM87_I2C_ID (0x2e) + +/* Board-specific LED info. */ +#define SFE4003_RED_LED_GPIO (11) +#define SFE4003_LED_ON (1) +#define SFE4003_LED_OFF (0) + +static void sfe4003_fault_led(struct efx_nic *efx, int state) +{ + /* The LEDs were not wired to GPIOs before A3 */ + if (efx->board_info.minor < 3 && efx->board_info.major == 0) + return; + + txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, + state ? SFE4003_LED_ON : SFE4003_LED_OFF); +} + +static int sfe4003_init_leds(struct efx_nic *efx) +{ + /* The LEDs were not wired to GPIOs before A3 */ + if (efx->board_info.minor < 3 && efx->board_info.major == 0) + return 0; + + txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT); + txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF); + return 0; +} + +static int sfe4003_check_hw(struct efx_nic *efx) +{ + int rc; + /* A0/A1/A2 board rev. 4003s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + ~(EFX_LM87_ETMP_INT | EFX_LM87_FAN1_INT | EFX_LM87_FAN2_INT); + + /* Check the sensor (NOP if not present). */ + + rc = efx_check_lm87(efx, alarm_mask); + /* We treat both lm87 interrupts and failure to talk to the lm87 + * as problems (since failure will only be reported if we did + * find the sensor at probe time. */ + if (rc) + EFX_ERR(efx, "sensor alert!\n"); + + return rc; +} + +static int sfe4003_init(struct efx_nic *efx) +{ + u8 lm87_bytes[LM87_SENSOR_BYTES]; + int nbytes; + int rc; + efx->board_info.monitor = sfe4003_check_hw; + efx->board_info.interpret_sensor = sfe4003_sensor_meaning; + efx->board_info.init_leds = sfe4003_init_leds; + efx->board_info.set_fault_led = sfe4003_fault_led; + efx->board_info.blink = board_blink; + /* To clean up shut down the lm87 (NOP if not present) */ + efx->board_info.fini = efx_remove_lm87; + + nbytes = sensor_limits_to_bytes(sfe4003_lm87_limits, + sfe4003_lm87_nlimits, lm87_bytes, + LM87_SENSOR_BYTES); + + /* Activate the lm87 sensor if present (succeeds if nothing there) */ + rc = efx_probe_lm87(efx, SFE4003_LM87_I2C_ID, + lm87_bytes, nbytes, sfe4003_lm87_irq_mask); + + if (rc < 0) + EFX_ERR(efx, "Temperature sensor probe failure: " + "please check the jumper position\n"); + return rc; +} + +/***************************************************************************** + * Support for the SFE4005 + * + */ +/* LM87 configuration data for the sensor on the SFE4005 board */ +static const u8 sfe4005_lm87_limits[] = { + 0x51, /* 2.5V high lim. (actually monitor 1.0V line, so 1050mV) */ + 0x49, /* 2.5V low lim. (950mV) */ + 0xf6, /* Vccp1 high lim. (3.3V rail, 3465 mV) */ + 0xde, /* Vcpp1 low lim. (3.3V rail, 3135 mV) */ + 0xca, /* 3.3V AUX high lim. (3465 mV) */ + 0xb6, /* 3.3V AUX low lim. (3135mV) */ + 0xc0, /* 5V high lim. not connected) */ + 0x00, /* 5V low lim. (not connected) */ + 0xd0, /* 12V high lim. (13000mV) */ + 0xb0, /* 12V low lim. (11000mV) */ + 0xc0, /* Vccp2 high lim. (unused) */ + 0x00, /* Vccp2 low lim. (unused) */ + 0x46, /* Ext temp 1 (ASIC) high lim. */ + 0x0a, /* Ext temp 1 low lim. */ + 0x3c, /* Int temp (board) high lim. */ + 0x0a, /* Int temp 1 low lim. */ + 0xff, /* Fan 1 high (unused) */ + 0xff, /* Fan 2 high (unused) */ +}; + +#define SFE4005_LM87_I2C_ID (0x2e) + +/* Until the LM87 monitoring is interrupt driven. */ +#define SFE4005_LM87_IRQMASK EFX_LM87_NO_INTS + +#define SFE4005_PCF8575_I2C_ID (0x20) +/* Definitions for the I/O expander that controls the CX4 chip: + * which PCF8575 pin maps to which function */ +#define SFE4005_PORT0_EXTLOOP (1 << 0) +#define SFE4005_PORT1_EXTLOOP (1 << 1) +#define SFE4005_HOSTPROT_LOOP (1 << 2) +#define SFE4005_BCAST (1 << 3) /* TX on both ports */ +#define SFE4005_PORT0_EQ (1 << 4) +#define SFE4005_PORT1_EQ (1 << 5) +#define SFE4005_HOSTPORT_EQ (1 << 6) +#define SFE4005_PORTSEL (1 << 7) /* Which port (for RX in BCAST mode) */ +#define SFE4005_PORT0_PRE_LBN (8) /* Preemphasis on port 0 (2 bits)*/ +#define SFE4005_PORT1_PRE_LBN (10) /* Preemphasis on port 1 (2 bits)*/ +#define SFE4005_HOSTPORT_PRE_LBN (12) /* Preemphasis on host port (2 bits) */ +#define SFE4005_UNUSED (1 << 14) +#define SFE4005_CX4uC_nRESET (1 << 15) /* Reset the controller on CX4 chip */ + + +/* By default only turn on host port EQ. Can also OR in SFE4005_PORT0_EQ, + * SFE4005_PORT1_EQ but this hasn't been seen to make a difference. */ +#define SFE4005_CX4_DEFAULTS (SFE4005_CX4uC_nRESET | SFE4005_HOSTPORT_EQ) + +static int sfe4005_write_ioexpander(struct efx_nic *efx) +{ + unsigned long iobits = (unsigned long)efx->phy_data; + struct efx_i2c_interface *i2c = &efx->i2c; + u8 send[2], check[2]; + int rc; + /* Do not, EVER, deassert nRESET as that will reset Falcon too, + * and the driver won't know to repush the configuration, so + * nothing will work until the next power cycle. */ + BUG_ON(!(iobits & SFE4005_CX4uC_nRESET)); + send[0] = (iobits & 0xff); + send[1] = ((iobits >> 8) & 0xff); + rc = efx_i2c_send_bytes(i2c, SFE4005_PCF8575_I2C_ID, send, 2); + if (rc) { + EFX_ERR(efx, "failed to write to I/O expander: %d\n", rc); + return rc; + } + /* Paranoia: just check what the I/O expander reads back */ + rc = efx_i2c_recv_bytes(i2c, SFE4005_PCF8575_I2C_ID, check, 2); + if (rc) + EFX_ERR(efx, "failed to read back from I/O expander: %d\n", rc); + else if (check[0] != send[0] || check[1] != send[1]) + EFX_ERR(efx, "read back wrong value from I/O expander: " + "wanted %.2x%.2x, got %.2x%.2x\n", + send[1], send[0], check[1], check[0]); + return rc; +} + +static int sfe4005_init(struct efx_nic *efx) +{ + unsigned long iobits = SFE4005_CX4_DEFAULTS; + int rc; + + /* There is no PHY as such on the SFE4005 so phy_data is ours. */ + efx->phy_data = (void *)iobits; + + /* Push the values */ + rc = sfe4005_write_ioexpander(efx); + if (rc) + return rc; + + /* Activate the lm87 sensor if present (succeeds if nothing there) */ + rc = efx_probe_lm87(efx, SFE4005_LM87_I2C_ID, + sfe4005_lm87_limits, + sizeof(sfe4005_lm87_limits), SFE4005_LM87_IRQMASK); + + /* To clean up shut down the lm87 (NOP if not present) */ + efx->board_info.fini = efx_remove_lm87; + + return rc; +} + +/* This will get expanded as board-specific details get moved out of the + * PHY drivers. */ +struct efx_board_data { + const char *ref_model; + const char *gen_type; + int (*init) (struct efx_nic *nic); + unsigned mwatts; +}; + +static void dummy_fini(struct efx_nic *nic) +{ +} + +static int dummy_init(struct efx_nic *nic) +{ + nic->board_info.fini = dummy_fini; + return 0; +} + +/* Maximum board power (mW) + * Falcon controller ASIC accounts for 2.2W + * 10Xpress PHY accounts for 12W + * + */ +#define SFE4001_POWER 18000 +#define SFE4002_POWER 7500 +#define SFE4003_POWER 4500 +#define SFE4005_POWER 4500 + +static struct efx_board_data board_data[] = { + [EFX_BOARD_INVALID] = + {NULL, NULL, dummy_init, 0}, + [EFX_BOARD_SFE4001] = + {"SFE4001", "10GBASE-T adapter", sfe4001_poweron, SFE4001_POWER }, + [EFX_BOARD_SFE4002] = + {"SFE4002", "XFP adapter", sfe4002_init, SFE4002_POWER }, + [EFX_BOARD_SFE4003] = + {"SFE4003", "10GBASE-CX4 adapter", sfe4003_init, SFE4003_POWER }, + [EFX_BOARD_SFE4005] = + {"SFE4005", "10G blade adapter", sfe4005_init, SFE4005_POWER }, +}; + +int efx_set_board_info(struct efx_nic *efx, u16 revision_info) +{ + int rc = 0; + struct efx_board_data *data; + + if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) { + EFX_ERR(efx, "squashing unknown board type %d\n", + BOARD_TYPE(revision_info)); + revision_info = 0; + } + + if (BOARD_TYPE(revision_info) == 0) { + efx->board_info.major = 0; + efx->board_info.minor = 0; + /* For early boards that don't have revision info. there is + * only 1 board for each PHY type, so we can work it out, with + * the exception of the PHY-less boards. */ + switch (efx->phy_type) { + case PHY_TYPE_10XPRESS: + efx->board_info.type = EFX_BOARD_SFE4001; + break; + case PHY_TYPE_XFP: + efx->board_info.type = EFX_BOARD_SFE4002; + break; + case PHY_TYPE_CX4_RTMR: + efx->board_info.type = EFX_BOARD_SFE4003; + break; + default: + efx->board_info.type = 0; + break; + } + } else { + efx->board_info.type = BOARD_TYPE(revision_info); + efx->board_info.major = BOARD_MAJOR(revision_info); + efx->board_info.minor = BOARD_MINOR(revision_info); + } + + data = &board_data[efx->board_info.type]; + + /* Report the board model number or generic type for recognisable + * boards. */ + if (efx->board_info.type != 0) + EFX_INFO(efx, "board is %s rev %c%d\n", + (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) + ? data->ref_model : data->gen_type, + 'A' + efx->board_info.major, efx->board_info.minor); + + efx->board_info.init = data->init; + efx->board_info.mwatts = data->mwatts; + + return rc; +} diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/boards.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/boards.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,51 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2007: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Developed by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_BOARDS_H +#define EFX_BOARDS_H + +/* Board IDs (must fit in 8 bits). Note that 0 must never be assigned because + * on early boards it means there is no revision info. Board types pre 400x + * are not covered here, but this is not a problem because: + * - the early Falcon boards (FPGA, 401, 403) don't have any extra H/W we + * need care about and aren't being updated. + */ +enum efx_board_type { + EFX_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */ + EFX_BOARD_SFE4001 = 1, + EFX_BOARD_SFE4002 = 2, + EFX_BOARD_SFE4003 = 3, + EFX_BOARD_SFE4005 = 4, + /* Insert new types before here */ + EFX_BOARD_MAX +}; + +extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); + +/* SFE4001 (10GBASE-T) */ +extern int sfe4001_poweron(struct efx_nic *efx); +extern void sfe4001_poweroff(struct efx_nic *efx); + +#endif diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/config.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,1 @@ +/* SFC config options can go here */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/debugfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/debugfs.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,924 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include <linux/module.h> +#include <linux/pci.h> +/* For out-of-tree builds we always need procfs, if only for a compatibility + * symlink. + */ +#include <linux/proc_fs.h> +#include <linux/dcache.h> +#include <linux/seq_file.h> +#include "net_driver.h" +#include "efx.h" +#include "debugfs.h" +#include "falcon.h" + +/* EFX_USE_DEBUGFS is defined by kernel_compat.h so we can't decide whether to + * include this earlier. + */ +#ifdef EFX_USE_DEBUGFS +#include <linux/debugfs.h> +#endif + +#ifndef PRIu64 +# if (BITS_PER_LONG == 64) +# define PRIu64 "lu" +# else +# define PRIu64 "llu" +# endif +#endif + +#ifndef EFX_USE_DEBUGFS + +static void efx_debugfs_remove(struct proc_dir_entry *entry) +{ + if (entry) + remove_proc_entry(entry->name, entry->parent); +} +#define debugfs_remove efx_debugfs_remove + +#define debugfs_create_dir proc_mkdir +#define debugfs_create_symlink proc_symlink + +#endif /* !EFX_USE_DEBUGFS */ + +/* Parameter definition bound to a structure - each file has one of these */ +struct efx_debugfs_bound_param { + const struct efx_debugfs_parameter *param; + void *structure; +}; + + +/* Maximum length for a name component or symlink target */ +#define EFX_DEBUGFS_NAME_LEN 32 + + +/* Top-level debug directory ([/sys/kernel]/debug/sfc) */ +static struct dentry *efx_debug_root; + +/* "cards" directory ([/sys/kernel]/debug/sfc/cards) */ +static struct dentry *efx_debug_cards; + + +/* Sequential file interface to bound parameters */ + +#if defined(EFX_USE_DEBUGFS) + +static int efx_debugfs_seq_show(struct seq_file *file, void *v) +{ + struct efx_debugfs_bound_param *binding = + (struct efx_debugfs_bound_param *)file->private; + + return binding->param->reader(file, + binding->structure + + binding->param->offset); +} + +static int efx_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, efx_debugfs_seq_show, inode->i_private); +} + +#else /* EFX_NOT_UPSTREAM && !EFX_USE_DEBUGFS */ + +static int efx_debugfs_seq_show(struct seq_file *file, void *v) +{ + struct proc_dir_entry *entry = (struct proc_dir_entry *)file->private; + struct efx_debugfs_parameter *param = + (struct efx_debugfs_parameter *)entry->data; + void *structure = (void *)entry->read_proc; + + if (!structure) + return -EIO; + + return param->reader(file, structure + param->offset); +} + +static int efx_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, efx_debugfs_seq_show, PROC_I(inode)->pde); +} + +#endif /* !EFX_NOT_UPSTREAM || EFX_USE_DEBUGFS */ + + +static struct file_operations efx_debugfs_file_ops = { + .owner = THIS_MODULE, + .open = efx_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + + +#if defined(EFX_USE_DEBUGFS) + +/** + * efx_fini_debugfs_child - remove a named child of a debugfs directory + * @dir: Directory + * @name: Name of child + * + * This removes the named child from the directory, if it exists. + */ +void efx_fini_debugfs_child(struct dentry *dir, const char *name) +{ + struct qstr child_name; + struct dentry *child; + + child_name.len = strlen(name); + child_name.name = name; + child_name.hash = full_name_hash(child_name.name, child_name.len); + child = d_lookup(dir, &child_name); + if (child) { + /* If it's a "regular" file, free its parameter binding */ + if (S_ISREG(child->d_inode->i_mode)) + kfree(child->d_inode->i_private); + debugfs_remove(child); + dput(child); + } +} + +#else /* EFX_NOT_UPSTREAM && !EFX_USE_DEBUGFS */ + +void efx_fini_debugfs_child(struct proc_dir_entry *dir, const char *name) +{ + remove_proc_entry(name, dir); +} + +#endif /* !EFX_NOT_UPSTREAM || EFX_USE_DEBUGFS */ + +/* + * Remove a debugfs directory. + * + * This removes the named parameter-files and sym-links from the + * directory, and the directory itself. It does not do any recursion + * to subdirectories. + */ +static void efx_fini_debugfs_dir(struct dentry *dir, + struct efx_debugfs_parameter *params, + const char *const *symlink_names) +{ + if (!dir) + return; + + while (params->name) { + efx_fini_debugfs_child(dir, params->name); + params++; + } + while (symlink_names && *symlink_names) { + efx_fini_debugfs_child(dir, *symlink_names); + symlink_names++; + } + debugfs_remove(dir); +} + +/* Functions for printing various types of parameter. */ + +int efx_debugfs_read_uint(struct seq_file *file, void *data) +{ + return seq_printf(file, "%#x\n", *(unsigned int *)data); +} + +int efx_debugfs_read_int(struct seq_file *file, void *data) +{ + return seq_printf(file, "%d\n", *(int *)data); +} + +int efx_debugfs_read_atomic(struct seq_file *file, void *data) +{ + unsigned int value = atomic_read((atomic_t *) data); + + return seq_printf(file, "%#x\n", value); +} + +int efx_debugfs_read_dword(struct seq_file *file, void *data) +{ + unsigned int value = EFX_DWORD_FIELD(*(efx_dword_t *) data, + EFX_DWORD_0); + + return seq_printf(file, "%#x\n", value); +} + +static int efx_debugfs_read_int_mode(struct seq_file *file, void *data) +{ + unsigned int value = *(enum efx_int_mode *) data; + + return seq_printf(file, "%d => %s\n", value, + STRING_TABLE_LOOKUP(value, efx_interrupt_mode)); +} + +#define EFX_INT_MODE_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + enum efx_int_mode, efx_debugfs_read_int_mode) + +static int efx_debugfs_read_loop_mode(struct seq_file *file, void *data) +{ + unsigned int value = *(enum efx_loopback_mode *)data; + + return seq_printf(file, "%d => %s\n", value, + STRING_TABLE_LOOKUP(value, efx_loopback_mode)); +} + +#define EFX_LOOPBACK_MODE_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + enum efx_loopback_mode, efx_debugfs_read_loop_mode) + +static int efx_debugfs_read_phy_type(struct seq_file *file, void *data) +{ + unsigned int value = *(enum phy_type *) data; + + return seq_printf(file, "%d => %s\n", value, + STRING_TABLE_LOOKUP(value, efx_phy_type)); +} + +#define EFX_PHY_TYPE_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + enum phy_type, efx_debugfs_read_phy_type) + +int efx_debugfs_read_string(struct seq_file *file, void *data) +{ + return seq_puts(file, (const char *)data); +} + + +/** + * efx_init_debugfs_files - create parameter-files in a debugfs directory + * @parent: Containing directory + * @params: Pointer to zero-terminated parameter definition array + * @structure: Structure containing parameters + * + * Add parameter-files to the given debugfs directory. Return a + * negative error code or 0 on success. + */ +static int efx_init_debugfs_files(struct dentry *parent, + struct efx_debugfs_parameter *params, + void *structure) +{ + struct efx_debugfs_parameter *param = params; + + while (param->name) { + struct dentry *entry; +#if defined(EFX_USE_DEBUGFS) + struct efx_debugfs_bound_param *binding; + + binding = kmalloc(sizeof(*binding), GFP_KERNEL); + if (!binding) + goto err; + binding->param = param; + binding->structure = structure; + + entry = debugfs_create_file(param->name, S_IRUGO, parent, + binding, &efx_debugfs_file_ops); + if (!entry) { + kfree(binding); + goto err; + } +#else + entry = create_proc_entry(param->name, S_IRUGO, parent); + if (!entry) + goto err; + /* + * We have no good way to free a binding created here. + * However, once we install our file_operations the + * read_proc pointer becomes redundant and we can + * abuse it as a structure pointer. + */ + entry->data = param; + entry->read_proc = NULL; + smp_wmb(); + entry->proc_fops = &efx_debugfs_file_ops; + smp_wmb(); + entry->read_proc = (read_proc_t *) structure; +#endif + + param++; + } + + return 0; + + err: + while (param != params) { + param--; + efx_fini_debugfs_child(parent, param->name); + } + return -ENOMEM; +} + +/** + * efx_init_debugfs_netdev - create debugfs sym-links for net device + * @net_dev: Net device + * + * Create sym-links named after @net_dev to the debugfs directories for + * the corresponding NIC and port. Return a negative error code or 0 on + * success. The sym-links must be cleaned up using + * efx_fini_debugfs_netdev(). + */ +int efx_init_debugfs_netdev(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + char name[EFX_DEBUGFS_NAME_LEN]; + char target[EFX_DEBUGFS_NAME_LEN]; + size_t len; + + if (snprintf(name, sizeof(name), "nic_%s", net_dev->name) >= + sizeof(name)) + return -ENAMETOOLONG; + if (snprintf(target, sizeof(target), "cards/%s", pci_name(efx->pci_dev)) + >= sizeof(target)) + return -ENAMETOOLONG; + efx->debug_symlink = debugfs_create_symlink(name, + efx_debug_root, target); + if (!efx->debug_symlink) + return -ENOMEM; + + if (snprintf(name, sizeof(name), "if_%s", net_dev->name) >= + sizeof(name)) + return -ENAMETOOLONG; + len = snprintf(target, sizeof(target), + "cards/%s/port0", pci_name(efx->pci_dev)); + if (len >= sizeof(target)) + return -ENAMETOOLONG; + efx->debug_port_symlink = debugfs_create_symlink(name, + efx_debug_root, + target); + if (!efx->debug_port_symlink) + return -ENOMEM; + + return 0; +} + +/** + * efx_fini_debugfs_netdev - remove debugfs sym-links for net device + * @net_dev: Net device + * + * Remove sym-links created for @net_dev by efx_init_debugfs_netdev(). + */ +void efx_fini_debugfs_netdev(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + debugfs_remove(efx->debug_port_symlink); + efx->debug_port_symlink = NULL; + debugfs_remove(efx->debug_symlink); + efx->debug_symlink = NULL; +} + +/* Per-port parameters */ +static struct efx_debugfs_parameter efx_debugfs_port_parameters[] = { + EFX_NAMED_PARAMETER(enabled, struct efx_nic, port_enabled, + int, efx_debugfs_read_int), + EFX_INT_PARAMETER(struct efx_nic, net_dev_registered), + EFX_INT_PARAMETER(struct efx_nic, rx_checksum_enabled), + EFX_ATOMIC_PARAMETER(struct efx_nic, netif_stop_count), + EFX_INT_PARAMETER(struct efx_nic, link_up), + EFX_UINT_PARAMETER(struct efx_nic, link_options), + EFX_INT_PARAMETER(struct efx_nic, promiscuous), + EFX_UINT_PARAMETER(struct efx_nic, loopback_modes), + EFX_LOOPBACK_MODE_PARAMETER(struct efx_nic, loopback_mode), + EFX_PHY_TYPE_PARAMETER(struct efx_nic, phy_type), + EFX_NAMED_PARAMETER(phy_id, struct efx_nic, mii.phy_id, + int, efx_debugfs_read_int), + EFX_UINT_PARAMETER(struct efx_nic, n_link_state_changes), + {NULL}, +}; + +/** + * efx_init_debugfs_port - create debugfs directory for port + * @efx: Efx NIC + * + * Create a debugfs directory containing parameter-files for @efx. + * Return a negative error code or 0 on success. The directory must be + * cleaned up using efx_fini_debugfs_port(). + */ +int efx_init_debugfs_port(struct efx_nic *efx) +{ + int rc; + + /* Create directory */ + efx->debug_port_dir = debugfs_create_dir("port0", efx->debug_dir); + if (!efx->debug_port_dir) + return -ENOMEM; + + /* Create files */ + rc = efx_init_debugfs_files(efx->debug_port_dir, + efx_debugfs_port_parameters, + (void *)efx); + if (rc) + efx_fini_debugfs_port(efx); + + return rc; +} + +/** + * efx_fini_debugfs_port - remove debugfs directory for port + * @efx: Efx NIC + * + * Remove directory created for @efx by efx_init_debugfs_port(). + */ +void efx_fini_debugfs_port(struct efx_nic *efx) +{ + efx_fini_debugfs_dir(efx->debug_port_dir, + efx_debugfs_port_parameters, NULL); + efx->debug_port_dir = NULL; +} + +/** + * efx_extend_debugfs_port - add parameter-files to directory for port + * @efx: Efx NIC + * @structure: Structure containing parameters + * @params: Pointer to zero-terminated parameter definition array + * + * Add parameter-files to the debugfs directory for @efx. Return + * a negative error code or 0 on success. This is intended for + * PHY-specific parameters. The files must be cleaned up using + * efx_trim_debugfs_port(). + */ +int efx_extend_debugfs_port(struct efx_nic *efx, + void *structure, + struct efx_debugfs_parameter *params) +{ + return efx_init_debugfs_files(efx->debug_port_dir, params, structure); +} + +/** + * efx_trim_debugfs_port - remove parameter-files from directory for port + * @efx: Efx NIC + * @params: Pointer to zero-terminated parameter definition array + * + * Remove parameter-files previously added to the debugfs directory + * for @efx using efx_extend_debugfs_port(). + */ +void efx_trim_debugfs_port(struct efx_nic *efx, + struct efx_debugfs_parameter *params) +{ + struct dentry *dir = efx->debug_port_dir; + + if (dir) { + struct efx_debugfs_parameter *field; + for (field = params; field->name; field++) + efx_fini_debugfs_child(dir, field->name); + } +} + +/* Per-TX-queue parameters */ +static struct efx_debugfs_parameter efx_debugfs_tx_queue_parameters[] = { + EFX_UINT_PARAMETER(struct efx_tx_queue, insert_count), + EFX_UINT_PARAMETER(struct efx_tx_queue, write_count), + EFX_UINT_PARAMETER(struct efx_tx_queue, read_count), + EFX_INT_PARAMETER(struct efx_tx_queue, stopped), + {NULL}, +}; + +static void efx_fini_debugfs_tx_queue(struct efx_tx_queue *tx_queue); + +/** + * efx_init_debugfs_tx_queue - create debugfs directory for TX queue + * @tx_queue: Efx TX queue + * + * Create a debugfs directory containing parameter-files for @tx_queue. + * Return a negative error code or 0 on success. The directory must be + * cleaned up using efx_fini_debugfs_tx_queue(). + */ +static int efx_init_debugfs_tx_queue(struct efx_tx_queue *tx_queue) +{ + char name[EFX_DEBUGFS_NAME_LEN]; + char target[EFX_DEBUGFS_NAME_LEN]; + int rc; + + /* Create directory */ + if (snprintf(name, sizeof(name), EFX_TX_QUEUE_NAME(tx_queue)) + >= sizeof(name)) + goto err_len; + tx_queue->debug_dir = debugfs_create_dir(name, + tx_queue->efx->debug_dir); + if (!tx_queue->debug_dir) + goto err_mem; + + /* Create files */ + rc = efx_init_debugfs_files(tx_queue->debug_dir, + efx_debugfs_tx_queue_parameters, + (void *)tx_queue); + if (rc) + goto err; + + /* Create symlink to channel */ + if (snprintf(target, sizeof(target), + "../" EFX_CHANNEL_NAME(tx_queue->channel)) >= + sizeof(target)) + goto err_len; + if (!debugfs_create_symlink("channel", tx_queue->debug_dir, target)) + goto err_mem; + + /* Create symlink to port */ + if (!debugfs_create_symlink("port", tx_queue->debug_dir, "../port0")) + goto err_mem; + + return 0; + + err_len: + rc = -ENAMETOOLONG; + goto err; + err_mem: + rc = -ENOMEM; + err: + efx_fini_debugfs_tx_queue(tx_queue); + return rc; +} + +/** + * efx_fini_debugfs_tx_queue - remove debugfs directory for TX queue + * @tx_queue: Efx TX queue + * + * Remove directory created for @tx_queue by efx_init_debugfs_tx_queue(). + */ +static void efx_fini_debugfs_tx_queue(struct efx_tx_queue *tx_queue) +{ + static const char *const symlink_names[] = { + "channel", "port", NULL + }; + + efx_fini_debugfs_dir(tx_queue->debug_dir, + efx_debugfs_tx_queue_parameters, symlink_names); + tx_queue->debug_dir = NULL; +} + +/* Per-RX-queue parameters */ +static struct efx_debugfs_parameter efx_debugfs_rx_queue_parameters[] = { + EFX_INT_PARAMETER(struct efx_rx_queue, added_count), + EFX_INT_PARAMETER(struct efx_rx_queue, removed_count), + EFX_UINT_PARAMETER(struct efx_rx_queue, max_fill), + EFX_UINT_PARAMETER(struct efx_rx_queue, fast_fill_trigger), + EFX_UINT_PARAMETER(struct efx_rx_queue, fast_fill_limit), + EFX_UINT_PARAMETER(struct efx_rx_queue, min_fill), + EFX_UINT_PARAMETER(struct efx_rx_queue, min_overfill), + EFX_UINT_PARAMETER(struct efx_rx_queue, alloc_page_count), + EFX_UINT_PARAMETER(struct efx_rx_queue, alloc_skb_count), + EFX_UINT_PARAMETER(struct efx_rx_queue, slow_fill_count), + {NULL}, +}; + +static void efx_fini_debugfs_rx_queue(struct efx_rx_queue *rx_queue); + +/** + * efx_init_debugfs_rx_queue - create debugfs directory for RX queue + * @rx_queue: Efx RX queue + * + * Create a debugfs directory containing parameter-files for @rx_queue. + * Return a negative error code or 0 on success. The directory must be + * cleaned up using efx_fini_debugfs_rx_queue(). + */ +static int efx_init_debugfs_rx_queue(struct efx_rx_queue *rx_queue) +{ + char name[EFX_DEBUGFS_NAME_LEN]; + char target[EFX_DEBUGFS_NAME_LEN]; + int rc; + + /* Create directory */ + if (snprintf(name, sizeof(name), EFX_RX_QUEUE_NAME(rx_queue)) + >= sizeof(name)) + goto err_len; + rx_queue->debug_dir = debugfs_create_dir(name, + rx_queue->efx->debug_dir); + if (!rx_queue->debug_dir) + goto err_mem; + + /* Create files */ + rc = efx_init_debugfs_files(rx_queue->debug_dir, + efx_debugfs_rx_queue_parameters, + (void *)rx_queue); + if (rc) + goto err; + + /* Create symlink to channel */ + if (snprintf(target, sizeof(target), + "../" EFX_CHANNEL_NAME(rx_queue->channel)) >= + sizeof(target)) + goto err_len; + if (!debugfs_create_symlink("channel", rx_queue->debug_dir, target)) + goto err_mem; + + return 0; + + err_len: + rc = -ENAMETOOLONG; + goto err; + err_mem: + rc = -ENOMEM; + err: + efx_fini_debugfs_rx_queue(rx_queue); + return rc; +} + +/** + * efx_fini_debugfs_rx_queue - remove debugfs directory for RX queue + * @rx_queue: Efx RX queue + * + * Remove directory created for @rx_queue by efx_init_debugfs_rx_queue(). + */ +static void efx_fini_debugfs_rx_queue(struct efx_rx_queue *rx_queue) +{ + const char *const symlink_names[] = { + "channel", NULL + }; + + efx_fini_debugfs_dir(rx_queue->debug_dir, + efx_debugfs_rx_queue_parameters, symlink_names); + rx_queue->debug_dir = NULL; +} + +/* Per-channel parameters */ +static struct efx_debugfs_parameter efx_debugfs_channel_parameters[] = { + EFX_INT_PARAMETER(struct efx_channel, enabled), + EFX_INT_PARAMETER(struct efx_channel, irq), + EFX_UINT_PARAMETER(struct efx_channel, has_interrupt), + EFX_UINT_PARAMETER(struct efx_channel, irq_moderation), + EFX_UINT_PARAMETER(struct efx_channel, eventq_read_ptr), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_tobe_disc), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_frag_err), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_hdr_chksum_err), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_tcp_udp_chksum_err), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_frm_trunc), + EFX_UINT_PARAMETER(struct efx_channel, n_rx_overlength), + EFX_UINT_PARAMETER(struct efx_channel, n_skbuff_leaks), + EFX_INT_PARAMETER(struct efx_channel, rx_alloc_level), + EFX_INT_PARAMETER(struct efx_channel, rx_alloc_push_pages), + EFX_INT_PARAMETER(struct efx_channel, rx_alloc_pop_pages), + {NULL}, +}; + +static void efx_fini_debugfs_channel(struct efx_channel *channel); + +/** + * efx_init_debugfs_channel - create debugfs directory for channel + * @channel: Efx channel + * + * Create a debugfs directory containing parameter-files for @channel. + * Return a negative error code or 0 on success. The directory must be + * cleaned up using efx_fini_debugfs_channel(). + */ +static int efx_init_debugfs_channel(struct efx_channel *channel) +{ + char name[EFX_DEBUGFS_NAME_LEN]; + int rc; + + /* Create directory */ + if (snprintf(name, sizeof(name), EFX_CHANNEL_NAME(channel)) + >= sizeof(name)) + goto err_len; + channel->debug_dir = debugfs_create_dir(name, channel->efx->debug_dir); + if (!channel->debug_dir) + goto err_mem; + + /* Create files */ + rc = efx_init_debugfs_files(channel->debug_dir, + efx_debugfs_channel_parameters, + (void *)channel); + if (rc) + goto err; + + return 0; + + err_len: + rc = -ENAMETOOLONG; + goto err; + err_mem: + rc = -ENOMEM; + err: + efx_fini_debugfs_channel(channel); + return rc; +} + +/** + * efx_fini_debugfs_channel - remove debugfs directory for channel + * @channel: Efx channel + * + * Remove directory created for @channel by efx_init_debugfs_channel(). + */ +static void efx_fini_debugfs_channel(struct efx_channel *channel) +{ + efx_fini_debugfs_dir(channel->debug_dir, + efx_debugfs_channel_parameters, NULL); + channel->debug_dir = NULL; +} + +/* Per-NIC parameters */ +static struct efx_debugfs_parameter efx_debugfs_nic_parameters[] = { + EFX_INT_PARAMETER(struct efx_nic, legacy_irq), + EFX_INT_PARAMETER(struct efx_nic, rss_queues), + EFX_UINT_PARAMETER(struct efx_nic, rx_buffer_len), + EFX_INT_MODE_PARAMETER(struct efx_nic, interrupt_mode), + {.name = "hardware_desc", + .offset = 0, + .reader = falcon_debugfs_read_hardware_desc}, + {NULL}, +}; + +/* Per-NIC error counts */ +static struct efx_debugfs_parameter efx_debugfs_nic_error_parameters[] = { + EFX_ATOMIC_PARAMETER(struct efx_nic_errors, missing_event), + EFX_ATOMIC_PARAMETER(struct efx_nic_errors, rx_reset), + EFX_ATOMIC_PARAMETER(struct efx_nic_errors, rx_desc_fetch), + EFX_ATOMIC_PARAMETER(struct efx_nic_errors, tx_desc_fetch), + EFX_ATOMIC_PARAMETER(struct efx_nic_errors, spurious_tx), + {NULL}, +}; + +/** + * efx_init_debugfs_channels - create debugfs directories for NIC channels + * @efx: Efx NIC + * + * Create subdirectories of @efx's debugfs directory for all the + * channels, RX queues and TX queues used by this driver. Return a + * negative error code or 0 on success. The subdirectories must be + * cleaned up using efx_fini_debugfs_channels(). + */ +int efx_init_debugfs_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int rc; + + efx_for_each_channel(channel, efx) { + rc = efx_init_debugfs_channel(channel); + if (rc) + goto err; + } + + efx_for_each_rx_queue(rx_queue, efx) { + rc = efx_init_debugfs_rx_queue(rx_queue); + if (rc) + goto err; + } + + efx_for_each_tx_queue(tx_queue, efx) { + rc = efx_init_debugfs_tx_queue(tx_queue); + if (rc) + goto err; + } + + return 0; + + err: + efx_fini_debugfs_channels(efx); + return rc; +} + +/** + * efx_fini_debugfs_channels - remove debugfs directories for NIC queues + * @efx: Efx NIC + * + * Remove subdirectories of @efx's debugfs directory created by + * efx_init_debugfs_channels(). + */ +void efx_fini_debugfs_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + + efx_for_each_tx_queue(tx_queue, efx) + efx_fini_debugfs_tx_queue(tx_queue); + + efx_for_each_rx_queue(rx_queue, efx) + efx_fini_debugfs_rx_queue(rx_queue); + + efx_for_each_channel(channel, efx) + efx_fini_debugfs_channel(channel); +} + +/** + * efx_init_debugfs_nic - create debugfs directory for NIC + * @efx: Efx NIC + * + * Create debugfs directory containing parameter-files for @efx, + * and a subdirectory "errors" containing per-NIC error counts. + * Return a negative error code or 0 on success. The directories + * must be cleaned up using efx_fini_debugfs_nic(). + */ +int efx_init_debugfs_nic(struct efx_nic *efx) +{ + int rc; + + /* Create directory */ + efx->debug_dir = debugfs_create_dir(pci_name(efx->pci_dev), + efx_debug_cards); + if (!efx->debug_dir) + goto err_mem; + + /* Create errors directory */ + efx->errors.debug_dir = debugfs_create_dir("errors", efx->debug_dir); + if (!efx->errors.debug_dir) + goto err_mem; + + /* Create files */ + rc = efx_init_debugfs_files(efx->debug_dir, + efx_debugfs_nic_parameters, (void *)efx); + if (rc) + goto err; + rc = efx_init_debugfs_files(efx->errors.debug_dir, + efx_debugfs_nic_error_parameters, + (void *)&efx->errors); + if (rc) + goto err; + + return 0; + + err_mem: + rc = -ENOMEM; + err: + efx_fini_debugfs_nic(efx); + return rc; +} + +/** + * efx_fini_debugfs_nic - remove debugfs directories for NIC + * @efx: Efx NIC + * + * Remove debugfs directories created for @efx by efx_init_debugfs_nic(). + */ +void efx_fini_debugfs_nic(struct efx_nic *efx) +{ + efx_fini_debugfs_dir(efx->errors.debug_dir, + efx_debugfs_nic_error_parameters, NULL); + efx->errors.debug_dir = NULL; + efx_fini_debugfs_dir(efx->debug_dir, efx_debugfs_nic_parameters, NULL); + efx->debug_dir = NULL; +} + +/** + * efx_init_debugfs - create debugfs directories for sfc driver + * + * Create debugfs directories "sfc" and "sfc/cards". This must be + * called before any of the other functions that create debugfs + * directories. Return a negative error code or 0 on success. The + * directories must be cleaned up using efx_fini_debugfs(). + */ +int efx_init_debugfs(void) +{ + /* Create top-level directory */ +#if defined(EFX_USE_DEBUGFS) + efx_debug_root = debugfs_create_dir("sfc", NULL); +#else + efx_debug_root = proc_mkdir("sfc", proc_root_driver); +#endif + if (!efx_debug_root) + goto err; + + /* Create "cards" directory */ + efx_debug_cards = debugfs_create_dir("cards", efx_debug_root); + if (!efx_debug_cards) + goto err; + +#if defined(EFX_USE_DEBUGFS) + /* Create compatibility sym-link */ + if (!proc_symlink("sfc", proc_root_driver, "/sys/kernel/debug/sfc")) + goto err; +#endif + return 0; + + err: + efx_fini_debugfs(); + return -ENOMEM; +} + +/** + * efx_fini_debugfs - remove debugfs directories for sfc driver + * + * Remove directories created by efx_init_debugfs(). + */ +void efx_fini_debugfs(void) +{ +#if defined(EFX_USE_DEBUGFS) + remove_proc_entry("sfc", proc_root_driver); +#endif + debugfs_remove(efx_debug_cards); + efx_debug_cards = NULL; + debugfs_remove(efx_debug_root); + efx_debug_root = NULL; +} diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/debugfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/debugfs.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,172 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_DEBUGFS_H +#define EFX_DEBUGFS_H + +#ifdef CONFIG_SFC_DEBUGFS + +struct seq_file; + +struct efx_debugfs_parameter { + const char *name; + size_t offset; + int (*reader)(struct seq_file *, void *); +}; + +extern void efx_fini_debugfs_child(struct dentry *dir, const char *name); +extern int efx_init_debugfs_netdev(struct net_device *net_dev); +extern void efx_fini_debugfs_netdev(struct net_device *net_dev); +extern int efx_init_debugfs_port(struct efx_nic *efx); +extern void efx_fini_debugfs_port(struct efx_nic *efx); +extern int efx_init_debugfs_nic(struct efx_nic *efx); +extern void efx_fini_debugfs_nic(struct efx_nic *efx); +extern int efx_init_debugfs_channels(struct efx_nic *efx); +extern void efx_fini_debugfs_channels(struct efx_nic *efx); +extern int efx_init_debugfs(void); +extern void efx_fini_debugfs(void); +extern int efx_extend_debugfs_port(struct efx_nic *efx, + void *context, + struct efx_debugfs_parameter *params); +extern void efx_trim_debugfs_port(struct efx_nic *efx, + struct efx_debugfs_parameter *params); + +/* Helpers for handling debugfs entry reads */ +extern int efx_debugfs_read_uint(struct seq_file *, void *); +extern int efx_debugfs_read_string(struct seq_file *, void *); +extern int efx_debugfs_read_int(struct seq_file *, void *); +extern int efx_debugfs_read_atomic(struct seq_file *, void *); +extern int efx_debugfs_read_dword(struct seq_file *, void *); + +/* Handy macros for filling out parameters */ + +/* Initialiser for a struct efx_debugfs_parameter with type-checking */ +#define EFX_PARAMETER(container_type, parameter, field_type, \ + reader_function) { \ + .name = #parameter, \ + .offset = ((((field_type *) 0) == \ + &((container_type *) 0)->parameter) ? \ + offsetof(container_type, parameter) : \ + offsetof(container_type, parameter)), \ + .reader = reader_function, \ +} + +/* Likewise, but the file name is not taken from the field name */ +#define EFX_NAMED_PARAMETER(_name, container_type, parameter, field_type, \ + reader_function) { \ + .name = #_name, \ + .offset = ((((field_type *) 0) == \ + &((container_type *) 0)->parameter) ? \ + offsetof(container_type, parameter) : \ + offsetof(container_type, parameter)), \ + .reader = reader_function, \ +} + +/* Likewise, but with one file for each of 4 lanes */ +#define EFX_PER_LANE_PARAMETER(prefix, suffix, container_type, parameter, \ + field_type, reader_function) { \ + .name = prefix "0" suffix, \ + .offset = ((((field_type *) 0) == \ + ((container_type *) 0)->parameter) ? \ + offsetof(container_type, parameter[0]) : \ + offsetof(container_type, parameter[0])), \ + .reader = reader_function, \ +}, { \ + .name = prefix "1" suffix, \ + .offset = offsetof(container_type, parameter[1]), \ + .reader = reader_function, \ +}, { \ + .name = prefix "2" suffix, \ + .offset = offsetof(container_type, parameter[2]), \ + .reader = reader_function, \ +}, { \ + .name = prefix "3" suffix, \ + .offset = offsetof(container_type, parameter[3]), \ + .reader = reader_function, \ +} + +/* A string parameter (string embedded in the structure) */ +#define EFX_STRING_PARAMETER(container_type, parameter) { \ + .name = #parameter, \ + .offset = ((((char *) 0) == \ + ((container_type *) 0)->parameter) ? \ + offsetof(container_type, parameter) : \ + offsetof(container_type, parameter)), \ + .reader = efx_debugfs_read_string, \ +} + +/* An unsigned integer parameter */ +#define EFX_UINT_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + unsigned int, efx_debugfs_read_uint) + +/* A dword parameter */ +#define EFX_DWORD_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + efx_dword_t, efx_debugfs_read_dword) + +/* An atomic_t parameter */ +#define EFX_ATOMIC_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + atomic_t, efx_debugfs_read_atomic) + +/* An integer parameter */ +#define EFX_INT_PARAMETER(container_type, parameter) \ + EFX_PARAMETER(container_type, parameter, \ + int, efx_debugfs_read_int) + +#else /* !CONFIG_SFC_DEBUGFS */ + +static inline int efx_init_debugfs_netdev(struct net_device *net_dev) +{ + return 0; +} +static inline void efx_fini_debugfs_netdev(struct net_device *net_dev) {} +static inline int efx_init_debugfs_port(struct efx_nic *efx) +{ + return 0; +} +static inline void efx_fini_debugfs_port(struct efx_nic *efx) {} +static inline int efx_init_debugfs_nic(struct efx_nic *efx) +{ + return 0; +} +static inline void efx_fini_debugfs_nic(struct efx_nic *efx) {} +static inline int efx_init_debugfs_channels(struct efx_nic *efx) +{ + return 0; +} +static inline void efx_fini_debugfs_channels(struct efx_nic *efx) {} +static inline int efx_init_debugfs(void) +{ + return 0; +} +static inline void efx_fini_debugfs(void) {} + +#endif /* CONFIG_SFC_DEBUGFS */ + +#endif /* EFX_DEBUGFS_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/driverlink.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/driverlink.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,544 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005: Fen Systems Ltd. + * Copyright 2005-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include <linux/module.h> +#include <linux/list.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include "net_driver.h" +#include "efx.h" +#include "driverlink.h" + +/* Driverlink semaphore + * This semaphore must be held for any operation that modifies any of + * the driverlink lists. + */ +static DEFINE_MUTEX(efx_driverlink_lock); + +/* List of all registered drivers */ +static LIST_HEAD(efx_driver_list); + +/* List of all registered Efx ports */ +static LIST_HEAD(efx_port_list); + +/* Driver link handle used internally to track devices */ +struct efx_dl_handle { + /* The efx_dl_device consumers see */ + struct efx_dl_device efx_dev; + /* The efx_nic providers provide */ + struct efx_nic *efx; + /* Per-device list */ + struct list_head port_node; + /* Per-driver list */ + struct list_head driver_node; +}; + +/* Get the handle for an efx_dl_device */ +static struct efx_dl_handle *efx_dl_handle(struct efx_dl_device *efx_dev) +{ + return container_of(efx_dev, struct efx_dl_handle, efx_dev); +} + +/* Remove an Efx device + * You must hold the efx_driverlink_lock before calling this + * function. + */ +static void efx_dl_del_device(struct efx_dl_device *efx_dev) +{ + struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); + + EFX_INFO(efx_handle->efx, "%s driverlink client unregistering\n", + efx_dev->driver->name); + + /* Call driver's remove() routine */ + if (efx_dev->driver->remove) + efx_dev->driver->remove(efx_dev); + + /* Remove handle from per-driver and per-NIC lists */ + list_del(&efx_handle->driver_node); + list_del(&efx_handle->port_node); + + /* Free efx_handle structure */ + kfree(efx_handle); +} + +/* Try to add an Efx device + * Attempt to probe the given device with the driver, creating a + * new efx_dl_device. If the probe routine fails, because the driver + * doesn't support this port, then the efx_dl_device is destroyed, + */ +static void efx_dl_try_add_device(struct efx_nic *efx, + struct efx_dl_driver *driver) +{ + struct efx_dl_handle *efx_handle; + struct efx_dl_device *efx_dev; + int rc; + + /* Allocate and initialise new efx_dl_device structure */ + efx_handle = kzalloc(sizeof(*efx_handle), GFP_KERNEL); + efx_dev = &efx_handle->efx_dev; + efx_handle->efx = efx; + efx_dev->driver = driver; + efx_dev->pci_dev = efx->pci_dev; + INIT_LIST_HEAD(&efx_handle->port_node); + INIT_LIST_HEAD(&efx_handle->driver_node); + + /* Attempt driver probe */ + rc = driver->probe(efx_dev, efx->net_dev, + efx->dl_info, efx->silicon_rev); + if (rc) + goto fail; + + /* Add device to per-driver and per-NIC lists */ + list_add_tail(&efx_handle->driver_node, &driver->device_list); + list_add_tail(&efx_handle->port_node, &efx->dl_device_list); + + EFX_INFO(efx, "%s driverlink client registered\n", driver->name); + return; + + fail: + EFX_INFO(efx, "%s driverlink client skipped\n", driver->name); + + kfree(efx_dev); +} + +/** + * efx_dl_unregister_driver - unregister an Efx device driver + * @driver: Efx driverlink driver + * + * Unregisters an Efx driver. The driver's remove() method will be + * called for all Efx devices currently claimed by the driver. + */ +void efx_dl_unregister_driver(struct efx_dl_driver *driver) +{ + struct efx_dl_handle *efx_handle, *efx_handle_n; + + printk(KERN_INFO "Efx driverlink unregistering %s driver\n", + driver->name); + + /* Acquire lock. We can't return failure, so have to use + * down() instead of down_interruptible() + */ + mutex_lock(&efx_driverlink_lock); + + /* Remove all devices claimed by the driver */ + list_for_each_entry_safe(efx_handle, efx_handle_n, + &driver->device_list, driver_node) + efx_dl_del_device(&efx_handle->efx_dev); + + /* Remove driver from driver list */ + list_del(&driver->node); + + /* Release lock */ + mutex_unlock(&efx_driverlink_lock); +} +EXPORT_SYMBOL(efx_dl_unregister_driver); + +/** + * efx_dl_register_driver - register an Efx device driver + * @driver: Efx driverlink driver + * + * Registers a new Efx driver. The driver's probe() method will be + * called for all Efx NICs currently registered. + * + * Return a negative error code or 0 on success. + */ +int efx_dl_register_driver(struct efx_dl_driver *driver) +{ + struct efx_nic *efx; + int rc; + + printk(KERN_INFO "Efx driverlink registering %s driver\n", + driver->name); + + /* Initialise driver list structures */ + INIT_LIST_HEAD(&driver->node); + INIT_LIST_HEAD(&driver->device_list); + + /* Acquire lock */ + rc = mutex_lock_interruptible(&efx_driverlink_lock); + if (rc) + return rc; + + /* Add driver to driver list */ + list_add_tail(&driver->node, &efx_driver_list); + + /* Feed all existing devices to driver */ + list_for_each_entry(efx, &efx_port_list, dl_node) + efx_dl_try_add_device(efx, driver); + + /* Release locks */ + mutex_unlock(&efx_driverlink_lock); + + return 0; +} +EXPORT_SYMBOL(efx_dl_register_driver); + +void efx_dl_unregister_nic(struct efx_nic *efx) +{ + struct efx_dl_handle *efx_handle, *efx_handle_n; + + if (!efx) + return; + + /* Acquire lock. We can't return failure, so have to use + * down() instead of down_interruptible() + */ + mutex_lock(&efx_driverlink_lock); + + /* Remove all devices related to this NIC */ + list_for_each_entry_safe_reverse(efx_handle, efx_handle_n, + &efx->dl_device_list, + port_node) + efx_dl_del_device(&efx_handle->efx_dev); + + /* Remove port from port list */ + list_del(&efx->dl_node); + + /* Release lock */ + mutex_unlock(&efx_driverlink_lock); +} + +int efx_dl_register_nic(struct efx_nic *efx) +{ + struct efx_dl_driver *driver; + int rc; + + /* Acquire lock */ + rc = mutex_lock_interruptible(&efx_driverlink_lock); + if (rc) + return rc; + + /* Add port to port list */ + list_add_tail(&efx->dl_node, &efx_port_list); + + /* Feed port to all existing drivers */ + list_for_each_entry(driver, &efx_driver_list, node) + efx_dl_try_add_device(efx, driver); + + /* Release lock */ + mutex_unlock(&efx_driverlink_lock); + + return 0; +} + +/* + * Dummy callback implementations. + * + * To avoid a branch point on the fast-path, the callbacks are always + * implemented - they are never NULL. + */ +#if defined(EFX_USE_FASTCALL) +static enum efx_veto fastcall +#else +static enum efx_veto +#endif +efx_dummy_tx_packet_callback(struct efx_dl_device *efx_dev, struct sk_buff *skb) +{ + /* Never veto the packet */ + return EFX_ALLOW_PACKET; +} + +#if defined(EFX_USE_FASTCALL) +static enum efx_veto fastcall +#else +static enum efx_veto +#endif +efx_dummy_rx_packet_callback(struct efx_dl_device *efx_dev, + const char *pkt_buf, int len) +{ + /* Never veto the packet */ + return EFX_ALLOW_PACKET; +} + +static void +efx_dummy_link_change_callback(struct efx_dl_device *efx_dev, int link_up) +{ +} + +static int +efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev, int new_mtu) +{ + /* Always allow */ + return 0; +} + +static void +efx_dummy_mtu_changed_callback(struct efx_dl_device *efx_dev, int mtu) +{ + return; +} + +static void efx_dummy_event_callback(struct efx_dl_device *efx_dev, void *event) +{ + return; +} + +struct efx_dl_callbacks efx_default_callbacks = { + .tx_packet = efx_dummy_tx_packet_callback, + .rx_packet = efx_dummy_rx_packet_callback, + .link_change = efx_dummy_link_change_callback, + .request_mtu = efx_dummy_request_mtu_callback, + .mtu_changed = efx_dummy_mtu_changed_callback, + .event = efx_dummy_event_callback, +}; + +#define EFX_DL_UNREGISTER_CALLBACK(_port, _dev, _member) \ + do { \ + BUG_ON((_port)->dl_cb_dev._member != (_dev)); \ + (_port)->dl_cb._member = \ + efx_default_callbacks._member; \ + (_port)->dl_cb_dev._member = NULL; \ + } while (0) + + +#define EFX_DL_REGISTER_CALLBACK(_port, _dev, _from, _member) \ + if ((_from)->_member) { \ + BUG_ON((_port)->dl_cb_dev._member != NULL); \ + (_port)->dl_cb._member = (_from)->_member; \ + (_port)->dl_cb_dev._member = _dev; \ + } + +/** + * efx_dl_unregister_callbacks - unregister callbacks for an Efx NIC + * @efx_dev: Efx driverlink device + * @callbacks: Callback list + * + * This removes a set of callbacks registered with + * efx_dl_register_callbacks(). It should be called as part of the + * client's remove() method. + * + * The net driver will ensure that all callback functions have + * returned to the net driver before efx_dl_unregister_callbacks() + * returns. Note that the device itself may still be running when the + * client's remove() method is called. The client must therefore + * unhook its callbacks using efx_dl_unregister_callbacks() and only + * then ensure that any delayed tasks triggered by callback methods + * (e.g. scheduled tasklets) have completed. + */ +void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev, + struct efx_dl_callbacks *callbacks) +{ + struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); + struct efx_nic *efx = efx_handle->efx; + + /* Suspend net driver operations */ + efx_suspend(efx); + + EFX_INFO(efx, "removing callback hooks into %s driver\n", + efx_dev->driver->name); + + if (callbacks->tx_packet) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, tx_packet); + + if (callbacks->rx_packet) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, rx_packet); + + if (callbacks->link_change) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, link_change); + + if (callbacks->request_mtu) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, request_mtu); + + if (callbacks->mtu_changed) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, mtu_changed); + + if (callbacks->event) + EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, event); + + /* Resume net driver operations */ + efx_resume(efx); +} +EXPORT_SYMBOL(efx_dl_unregister_callbacks); + +/** + * efx_dl_register_callbacks - register callbacks for an Efx NIC + * @efx_dev: Efx driverlink device + * @callbacks: Callback list + * + * This registers a set of callback functions with the net driver. + * These functions will be called at various key points to allow + * external code to monitor and/or modify the behaviour of the network + * driver. Any of the callback function pointers may be %NULL if a + * callback is not required. The intended user of this mechanism is + * the SFC char driver. + * + * This client should call efx_dl_register_callbacks() during its + * probe() method. The client must ensure that it also calls + * efx_dl_unregister_callbacks() as part of its remove() method. + * + * Only one function may be registered for each callback per NIC. + * If a requested callback is already registered for this NIC, this + * function will return -%EBUSY. + * + * The device may already be running, so the client must be prepared + * for callbacks to be triggered immediately after calling + * efx_dl_register_callbacks(). + * + * Return a negative error code or 0 on success. + */ +int efx_dl_register_callbacks(struct efx_dl_device *efx_dev, + struct efx_dl_callbacks *callbacks) +{ + struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); + struct efx_nic *efx = efx_handle->efx; + int rc = 0; + + /* Suspend net driver operations */ + efx_suspend(efx); + + /* Check that the requested callbacks are not already hooked. */ + if ((callbacks->tx_packet && efx->dl_cb_dev.tx_packet) || + (callbacks->rx_packet && efx->dl_cb_dev.rx_packet) || + (callbacks->link_change && efx->dl_cb_dev.link_change) || + (callbacks->request_mtu && efx->dl_cb_dev.request_mtu) || + (callbacks->mtu_changed && efx->dl_cb_dev.mtu_changed) || + (callbacks->event && efx->dl_cb_dev.event)) { + rc = -EBUSY; + goto out; + } + + EFX_INFO(efx, "adding callback hooks to %s driver\n", + efx_dev->driver->name); + + /* Hook in callbacks. For maximum speed, we never check to + * see whether these are NULL before calling; therefore we + * must ensure that they are never NULL. If the set we're + * being asked to hook in is sparse, we leave the default + * values in place for the empty hooks. + */ + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, tx_packet); + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, rx_packet); + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, link_change); + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, request_mtu); + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, mtu_changed); + EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, event); + + out: + /* Resume net driver operations */ + efx_resume(efx); + + return rc; +} +EXPORT_SYMBOL(efx_dl_register_callbacks); + +/** + * efx_dl_schedule_reset - schedule an Efx NIC reset + * @efx_dev: Efx driverlink device + * + * This schedules a hardware reset for a short time in the future. It + * can be called from any context, and so can be used when + * efx_dl_reset() cannot be called. + */ +void efx_dl_schedule_reset(struct efx_dl_device *efx_dev) +{ + struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev); + struct efx_nic *efx = efx_handle->efx; + + efx_schedule_reset(efx, RESET_TYPE_ALL); +} +EXPORT_SYMBOL(efx_dl_schedule_reset); + +/* + * Lock the driverlink layer before a reset + * To avoid deadlock, efx_driverlink_lock needs to be acquired before + * efx->suspend_lock. + */ +void efx_dl_reset_lock(void) +{ + /* Acquire lock */ + mutex_lock(&efx_driverlink_lock); +} + +/* + * Unlock the driverlink layer after a reset + * This call must be matched against efx_dl_reset_lock. + */ +void efx_dl_reset_unlock(void) +{ + /* Acquire lock */ + mutex_unlock(&efx_driverlink_lock); +} + +/* + * Suspend ready for reset + * This calls the reset_suspend method of all drivers registered to + * the specified NIC. It must only be called between + * efx_dl_reset_lock and efx_dl_reset_unlock. + */ +void efx_dl_reset_suspend(struct efx_nic *efx) +{ + struct efx_dl_handle *efx_handle; + struct efx_dl_device *efx_dev; + + BUG_ON(!mutex_is_locked(&efx_driverlink_lock)); + + /* Call suspend method of each driver in turn */ + list_for_each_entry_reverse(efx_handle, + &efx->dl_device_list, + port_node) { + efx_dev = &efx_handle->efx_dev; + if (efx_dev->driver->reset_suspend) + efx_dev->driver->reset_suspend(efx_dev); + } +} + +/* + * Resume after a reset + * This calls the reset_resume method of all drivers registered to the + * specified NIC. It must only be called between efx_dl_reset_lock + * and efx_dl_reset_unlock. + */ +void efx_dl_reset_resume(struct efx_nic *efx, int ok) +{ + struct efx_dl_handle *efx_handle; + struct efx_dl_device *efx_dev; + + BUG_ON(!mutex_is_locked(&efx_driverlink_lock)); + + /* Call resume method of each driver in turn */ + list_for_each_entry(efx_handle, &efx->dl_device_list, + port_node) { + efx_dev = &efx_handle->efx_dev; + if (efx_dev->driver->reset_resume) + efx_dev->driver->reset_resume(efx_dev, ok); + } +} + +/** + * efx_dl_get_nic - obtain the Efx NIC for the given driverlink device + * @efx_dev: Efx driverlink device + * + * Get a pointer to the &struct efx_nic corresponding to + * @efx_dev. This can be used by driverlink clients built along with + * the sfc driver, which may have intimate knowledge of its internals. + */ +struct efx_nic *efx_dl_get_nic(struct efx_dl_device *efx_dev) +{ + return efx_dl_handle(efx_dev)->efx; +} +EXPORT_SYMBOL(efx_dl_get_nic); diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/driverlink.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/driverlink.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,93 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005: Fen Systems Ltd. + * Copyright 2006: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_DRIVERLINK_H +#define EFX_DRIVERLINK_H + +/* Forward declarations */ +struct efx_dl_device; +struct efx_nic; + +/* + * Efx driverlink + * + * This header file defines the portions of the Efx driverlink + * interface that are used only within the sfc module. It also + * declares efx_dl_get_nic(), which may be used by sfc_mtd + * and any other module built along with sfc. + */ + + +/* Efx callback devices + * + * A list of the devices that own each callback. The partner to + * struct efx_dl_callbacks + */ +struct efx_dl_cb_devices { + /* Device owning the tx_packet callback */ + struct efx_dl_device *tx_packet; + /* Device owning the rx_packet callback */ + struct efx_dl_device *rx_packet; + /* Device owning the link_change callback. */ + struct efx_dl_device *link_change; + /* Device owning the request_mtu callback. */ + struct efx_dl_device *request_mtu; + /* Device owning the mtu_changed callback. */ + struct efx_dl_device *mtu_changed; + /* Device owning the event callback. */ + struct efx_dl_device *event; +}; + +/* No-op callbacks used for initialisation */ +extern struct efx_dl_callbacks efx_default_callbacks; + +/* Macro used to invoke callbacks */ +#define EFX_DL_CALLBACK(_port, _name, ...) \ + (_port)->dl_cb._name((_port)->dl_cb_dev._name, __VA_ARGS__) + +/* Register an Efx NIC */ +extern int efx_dl_register_nic(struct efx_nic *efx); + +/* Unregister an Efx NIC */ +extern void efx_dl_unregister_nic(struct efx_nic *efx); + +/* Lock the driverlink layer prior to a reset */ +extern void efx_dl_reset_lock(void); + +/* Unlock the driverlink layer following a reset */ +extern void efx_dl_reset_unlock(void); + +/* Suspend all drivers prior to a hardware reset */ +extern void efx_dl_reset_suspend(struct efx_nic *efx); + +/* Resume all drivers after a hardware reset */ +extern void efx_dl_reset_resume(struct efx_nic *efx, int ok); + +/* Obtain the Efx NIC for the given driverlink device. */ +extern struct efx_nic *efx_dl_get_nic(struct efx_dl_device *efx_dev); + +#endif /* EFX_DRIVERLINK_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/driverlink_api.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/driverlink_api.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,612 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2005-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_DRIVERLINK_API_H +#define EFX_DRIVERLINK_API_H + +#include <linux/list.h> /* for struct list_head */ +#if !defined(EFX_USE_FASTCALL) + #include <linux/version.h> + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #define EFX_USE_FASTCALL yes + #include <linux/linkage.h> + #endif +#endif + +/** + * DOC: Efx driverlink API + * + * This file must be included by any driver that wishes to attach to + * devices claimed by the Solarflare NIC driver (sfc). It allows separate + * kernel modules to expose other functionality offered by the NIC, with + * the sfc driver remaining in overall control. + * + * Overview: + * + * Driverlink clients define a &struct efx_dl_driver, and register + * this structure with the driverlink layer using + * efx_dl_register_driver(), which is exported by the sfc driver. + * + * The probe() routine of each driverlink client driver is called by + * the driverlink layer for each physical port in the system, after + * the sfc driver has performed start-of-day hardware initialisation + * and self-test. If ports are added or removed via pci hotplug then + * the &struct efx_dl_driver probe() or remove() routines are called + * as appropriate. + * + * If the port doesn't provide the necessary hardware resources for a + * client, then that client can return failure from its probe() + * routine. Information provided to the client driver at probe time + * includes + * + * Each probe() routine is given a unique &struct efx_dl_device per + * port, which means it can safely use the @priv member to store any + * useful state it needs. The probe routine also has the opportunity + * to provide a &struct efx_dl_callbacks via + * efx_dl_register_callbacks(), which allows the client to intercept + * the sfc driver's operations at strategic points. + * + * Occasionally, the underlying Efx device may need to be reset to + * recover from an error condition. The client's reset_suspend() and + * reset_resume() methods [if provided] will be called to enable the + * client to suspend operations and preserve any state before the + * reset. The client can itself request a reset using efx_dl_reset() + * or efx_dl_schedule_reset(), should it detect an error condition + * necessitating a reset. + * + * Example: + * + * The MTD driver (mtd.c) uses the driverlink layer. + */ + +/* Forward declarations */ +struct pci_dev; +struct net_device; +struct sk_buff; +struct efx_dl_device; +struct efx_dl_device_info; + +/* + * This is used to guard against the registration of driverlink + * clients using an incorrect version of the API. + */ +#define EFX_DRIVERLINK_API_VERSION 1 + + +/** + * struct efx_dl_driver - An Efx driverlink device driver + * + * This is the analogue of a struct pci_driver for a normal PCI + * driver. Driverlink clients should register themselves using + * efx_dl_register_driver() at module initialisation, and deregister + * themselves using efx_dl_unregister_driver() at module exit. + * + * All calls to members of efx_dl_driver are serialised by a single + * semaphore, so you are allowed to sleep in these functions. Take care + * to not call driverlink methods from within these callbacks, otherwise + * a deadlock is possible. + * + * @name: Name of the driver + * @probe: Called when device added + * @remove: Called when device removed + * @reset_suspend: Called before device is reset + * @reset_resume: Called after device is reset + */ +struct efx_dl_driver { + const char *name; + + /* + * probe - Handle device addition. + * @efx_dev: Efx driverlink device + * @net_dev: The net_dev relevant to this port + * @dev_info: A linked list of device information. + * @silicon_rev: Silicon revision name. + * + * This will be called after driverlink client registration for + * every port on the system, and for every port that appears + * thereafter via hotplug. + * + * The client may use either @efx_dev->pci_dev, the dev_info linked + * list of available driver information, or the silicon revision + * name to determine if they can support this port. If they can, + * they should return 0 to indicate the probe was successful. Any + * other return code indicates that the probe failed, and the + * @efx_dl_dev will be invalidated. + * + * The client should perform whatever initialisation it + * requires, and store a pointer to its private data in + * @efx_dl_dev->priv (which is not shared between clients). + * It may also wish to hook in a callbacks table using + * efx_dl_register_callbacks(). + * + * Return a negative error code or 0 on success. + */ + int (*probe) (struct efx_dl_device *efx_dl_dev, + const struct net_device *net_dev, + const struct efx_dl_device_info *dev_info, + const char *silicon_rev); + + /* + * remove - Handle device removal. + * @efx_dev: Efx driverlink device + * + * This will be called at driver exit (or hotplug removal) for + * each registered driverlink client. + * + * The client must ensure that it has finished all operations + * using this device before returning from this method. If it + * has hooked in a callbacks table using + * efx_dl_register_callbacks(), it must unhook it using + * efx_dl_unregister_callbacks(), and then ensure that all + * callback-triggered operations (e.g. scheduled tasklets) + * have completed before returning. (It does not need to + * explicitly wait for callback methods to finish executing, + * since efx_dl_unregister_callbacks() will sleep until all + * callbacks have returned anyway.) + * + * Note that the device itself may not have been removed; it + * may be simply that the client is being unloaded + * via efx_dl_unregister_driver(). In this case other clients + * (and the sfc driver itself) will still be using the device, + * so the client cannot assume that the device itself is quiescent. + * In particular, callbacks may continue to be triggered at any + * point until efx_dl_unregister_callbacks() is called. + */ + void (*remove) (struct efx_dl_device *efx_dev); + + /* + * reset_suspend - Suspend ready for reset. + * @efx_dev: Efx driverlink device + * + * This method will be called immediately before a hardware + * reset (which may or may not have been initiated by the + * driverlink client). This client must save any state that it + * will need to restore after the reset, and suspend all + * operations that might access the hardware. It must not + * return until the client can guarantee to have stopped + * touching the hardware. + * + * It is guaranteed that callbacks will be inactive by the + * time this method is called; the driverlink layer will + * already have prevented new callbacks being made and waited + * for all callbacks functions to return before calling + * reset_suspend(). However, any delayed work scheduled by + * the callback functions (e.g. tasklets) may not yet have + * completed. + * + * This method is allowed to sleep, so waiting on tasklets, + * work queues etc. is permitted. There will always be a + * corresponding call to the reset_resume() method, so it is + * safe to e.g. down a semaphore within reset_suspend() and up + * it within reset_resume(). (However, you obviously cannot + * do the same with a spinlock). + * + * Note that the reset operation may be being carried out in + * the context of scheduled work, so you cannot use + * flush_scheduled_work() to ensure that any work you may have + * scheduled has completed. + * + * During hardware reset, there is a chance of receiving + * spurious interrupts, so the client's ISR (if any) should be + * unhooked or otherwise disabled. + */ + void (*reset_suspend) (struct efx_dl_device *efx_dev); + + /* + * reset_resume - Restore after a reset. + * @efx_dev: Efx driverlink device + * @ok: Reset success indicator + * + * This method will be called after a hardware reset. There + * will always have been a corresponding call to the + * reset_suspend() method beforehand. + * + * If @ok is non-zero, the client should restore the state + * that it saved during the call to reset_suspend() and resume + * normal operations. + * + * If @ok is zero, the reset operation has failed and the + * hardware is currently in an unusable state. In this case, + * the client should release any locks taken out by + * reset_suspend(), but should not take any other action; in + * particular, it must not access the hardware, nor resume + * normal operations. The hardware is effectively dead at + * this point, and our sole aim is to avoid deadlocking or + * crashing the host. + * + * The driverlink layer will still be locked when + * reset_resume() is called, so the client may not call + * driverlink functions. In particular, if the reset failed, + * the client must not call efx_dl_unregister_callbacks() at + * this point; it should wait until remove() is called. + */ + void (*reset_resume) (struct efx_dl_device *efx_dev, int ok); + +/* private: */ + struct list_head node; + struct list_head device_list; +}; + +/** + * DOC: Efx driverlink device information + * + * Each &struct efx_dl_device makes certain hardware resources visible + * to driverlink clients, and they describe which resources are + * available by passing a linked list of &struct efx_dl_device_info + * into the probe() routine. + * + * The driverlink client's probe function can iterate through the linked list, + * and provided that it understands the resources that are exported, it can + * choose to make use of them through an external interface. + */ + +/** + * enum efx_dl_device_info_type - Device information identifier. + * + * Each distinct hardware resource API will have a member in this + * enumeration. + * + * @EFX_DL_FALCON_RESOURCES: Information type is &struct efx_dl_falcon_resources + */ +enum efx_dl_device_info_type { + /** Falcon resources available for export */ + EFX_DL_FALCON_RESOURCES = 0, +}; + +/** + * struct efx_dl_device_info - device information structure + * @next: Link to next structure, if any + * @type: Type code for this structure + * + * This structure is embedded in other structures provided by the + * driverlink device provider, and implements a linked list of + * resources pertinent to a driverlink client. + * + * Example: &struct efx_dl_falcon_resources + */ +struct efx_dl_device_info { + struct efx_dl_device_info *next; + enum efx_dl_device_info_type type; +}; + +/** + * enum efx_dl_falcon_resource_flags - Falcon resource information flags. + * + * Flags that describe hardware variations for the described Falcon based port. + * + * @EFX_DL_FALCON_DUAL_FUNC: Port is dual-function. + * Certain silicon revisions have two pci functions, and require + * certain hardware resources to be accessed via the secondary + * function. See the discussion of @pci_dev in &struct efx_dl_device + * below. + * @EFX_DL_FALCON_USE_MSI: Port is initialised to use MSI/MSI-X interrupts. + * Falcon supports traditional legacy interrupts and MSI/MSI-X + * interrupts. Since the sfc driver supports either, as a run + * time configuration, driverlink drivers need to be aware of which + * one to use for their interrupting resources. + */ +enum efx_dl_falcon_resource_flags { + EFX_DL_FALCON_DUAL_FUNC = 0x1, + EFX_DL_FALCON_USE_MSI = 0x2, +}; + +/** + * struct efx_dl_falcon_resources - Falcon resource information. + * + * This structure describes Falcon hardware resources available for + * use by a driverlink driver. + * + * @hdr: Resource linked list header + * @biu_lock: Register access lock. + * Some Falcon revisions require register access for configuration + * registers to be serialised between ports and PCI functions. + * The sfc driver will provide the appropriate lock semantics for + * the underlying hardware. + * @buffer_table_min: First available buffer table entry + * @buffer_table_max: Last available buffer table entry + 1 + * @evq_timer_min: First available event queue with timer + * @evq_timer_max: Last available event queue with timer + 1 + * @evq_int_min: First available event queue with interrupt + * @evq_int_max: Last available event queue with interrupt + 1 + * @rxq_min: First available RX queue + * @rxq_max: Last available RX queue + 1 + * @txq_min: First available TX queue + * @txq_max: Last available TX queue + 1 + * @flags: Hardware variation flags + */ +struct efx_dl_falcon_resources { + struct efx_dl_device_info hdr; + spinlock_t *biu_lock; + unsigned buffer_table_min, buffer_table_max; + unsigned evq_timer_min, evq_timer_max; + unsigned evq_int_min, evq_int_max; + unsigned rxq_min, rxq_max; + unsigned txq_min, txq_max; + enum efx_dl_falcon_resource_flags flags; +}; + +/** + * struct efx_dl_device - An Efx driverlink device. + * + * @pci_dev: Underlying PCI device. + * This is the PCI device used by the sfc driver. It will + * already have been enabled for bus-mastering DMA etc. + * @priv: Driver private data + * Driverlink clients can use this to store a pointer to their + * internal per-device data structure. Each (driver, device) + * tuple has a separate &struct efx_dl_device, so clients can use + * this @priv field independently. + * @driver: Efx driverlink driver for this device + */ +struct efx_dl_device { + struct pci_dev *pci_dev; + void *priv; + struct efx_dl_driver *driver; +}; + +/** + * enum efx_veto - Packet veto request flag. + * + * This is the return type for the rx_packet() and tx_packet() methods + * in &struct efx_dl_callbacks. + * + * @EFX_ALLOW_PACKET: Packet may be transmitted/received + * @EFX_VETO_PACKET: Packet must not be transmitted/received + */ +enum efx_veto { + EFX_ALLOW_PACKET = 0, + EFX_VETO_PACKET = 1, +}; + +/** + * struct efx_dl_callbacks - Efx callbacks + * + * These methods can be hooked in to the sfc driver via + * efx_dl_register_callbacks(). They allow clients to intercept and/or + * modify the behaviour of the sfc driver at predetermined points. + * + * For efficiency, only one client can hook each callback. + * + * Since these callbacks are called on packet transmit and reception + * paths, clients should avoid acquiring locks or allocating memory. + * + * @tx_packet: Called when packet is about to be transmitted + * @rx_packet: Called when packet is received + * @link_change: Called when link status has changed + * @request_mtu: Called to request MTU change + * @mtu_changed: Called when MTU has been changed + * @event: Called when NIC event is not handled by the sfc driver + */ +struct efx_dl_callbacks { + /* + * tx_packet - Packet about to be transmitted. + * @efx_dev: Efx driverlink device + * @skb: Socket buffer containing the packet to be sent + * + * This method is called for every packet about to be + * transmitted. It allows the client to snoop on traffic sent + * via the kernel queues. + * + * The method may return %EFX_VETO_PACKET in order to prevent + * the sfc driver from transmitting the packet. The net + * driver will then discard the packet. If the client wishes + * to retain a reference to the packet data after returning + * %EFX_VETO_PACKET, it must obtain its own copy of the + * packet (e.g. by calling skb_get(), or by copying out the + * packet data to an external buffer). + * + * This method must return quickly, since it will have a + * direct performance impact upon the sfc driver. It will be + * called with interrupts disabled (and may be called in + * interrupt context), so may not sleep. Since the sfc driver + * may have multiple TX queues, running in parallel, please avoid + * the need for locking if it all possible. + */ +#if defined(EFX_USE_FASTCALL) + enum efx_veto fastcall (*tx_packet) (struct efx_dl_device *efx_dev, + struct sk_buff *skb); +#else + enum efx_veto (*tx_packet) (struct efx_dl_device *efx_dev, + struct sk_buff *skb); +#endif + + /* + * rx_packet - Packet received. + * @efx_dev: Efx driverlink device + * @pkt_hdr: Pointer to received packet + * @pkt_len: Length of received packet + * + * This method is called for every received packet. It allows + * the client to snoop on traffic received by the kernel + * queues. + * + * The method may return %EFX_VETO_PACKET in order to prevent + * the sfc driver from passing the packet to the kernel. The net + * driver will then discard the packet. + * + * This method must return quickly, since it will have a + * direct performance impact upon the sfc driver. It is + * called in tasklet context, so may not sleep. Note that + * there are per-channel tasklets in the sfc driver, so + * rx_packet() may be called simultaneously on different CPUs + * and must lock appropriately. The design of the sfc driver + * allows for lockless operation between receive channels, so + * please avoid the need for locking if at all possible. + */ +#if defined(EFX_USE_FASTCALL) + enum efx_veto fastcall (*rx_packet) (struct efx_dl_device *efx_dev, + const char *pkt_hdr, int pkt_len); +#else + enum efx_veto (*rx_packet) (struct efx_dl_device *efx_dev, + const char *pkt_hdr, int pkt_len); +#endif + + /* + * link_change - Link status change. + * @efx_dev: Efx driverlink device + * @link_up: Link up indicator + * + * This method is called to inform the driverlink client + * whenever the PHY link status changes. By the time this + * function is called, the MAC has already been reconfigured + * with the new autonegotiation settings from the PHY. + * + * This method is called from tasklet context and may not + * sleep. + */ + void (*link_change) (struct efx_dl_device *efx_dev, int link_up); + + /* + * request_mtu: Request MTU change. + * @efx_dev: Efx driverlink device + * @new_mtu: Requested new MTU + * + * This method is called whenever the user requests an MTU + * change on an interface. The client may return an error, in + * which case the MTU change request will be denied. If the + * client returns success, the MAC will be reconfigured with a + * new maxmimum frame length equal to + * EFX_MAX_FRAME_LEN(new_mtu). The client will be notified + * via the mtu_changed() method once the MAC has been + * reconfigured. + * + * The current MTU for the port can be obtained via + * efx_dl_get_netdev(efx_dl_device)->mtu. + * + * The sfc driver guarantees that no other callback functions + * are in progress when this method is called. This function + * is called in process context and may sleep. + * + * Return a negative error code or 0 on success. + */ + int (*request_mtu) (struct efx_dl_device *efx_dev, int new_mtu); + + /* + * mtu_changed - MTU has been changed. + * @efx_dev: Efx driverlink device + * @mtu: The new MTU + * + * This method is called once the MAC has been reconfigured + * with a new MTU. There will have been a preceding call to + * request_mtu(). + * + * The sfc driver guarantees that no other callback functions + * are in progress when this method is called. This function + * is called in process context and may sleep. + */ + void (*mtu_changed) (struct efx_dl_device *efx_dev, int mtu); + + /* + * event - Event callback. + * @efx_dev: Efx driverlink device + * @p_event: Pointer to event + * + * This method is called for each event that is not handled by the + * sfc driver. + */ + void (*event) (struct efx_dl_device *efx_dev, void *p_event); +}; + +/* Include API version number in symbol used for efx_dl_register_driver */ +#define efx_dl_stringify_1(x, y) x ## y +#define efx_dl_stringify_2(x, y) efx_dl_stringify_1(x, y) +#define efx_dl_register_driver \ + efx_dl_stringify_2(efx_dl_register_driver_api_ver_, \ + EFX_DRIVERLINK_API_VERSION) + +extern int efx_dl_register_driver(struct efx_dl_driver *driver); + +extern void efx_dl_unregister_driver(struct efx_dl_driver *driver); + +extern int efx_dl_register_callbacks(struct efx_dl_device *efx_dev, + struct efx_dl_callbacks *callbacks); + +extern void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev, + struct efx_dl_callbacks *callbacks); + +extern void efx_dl_schedule_reset(struct efx_dl_device *efx_dev); + +/** + * efx_dl_for_each_device_info_matching - iterate an efx_dl_device_info list + * @_dev_info: Pointer to first &struct efx_dl_device_info + * @_type: Type code to look for + * @_info_type: Structure type corresponding to type code + * @_field: Name of &struct efx_dl_device_info field in the type + * @_p: Iterator variable + * + * Example: + * + * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...) + * { + * struct efx_dl_falcon_resources *res; + * + * efx_dl_for_each_device_info_matching(dev_info,EFX_DL_FALCON_RESOURCES, + * struct efx_dl_falcon_resources, + * hdr, res) { + * if (res->flags & EFX_DL_FALCON_DUAL_FUNC) { + * ..... + * } + * } + * } + */ +#define efx_dl_for_each_device_info_matching(_dev_info, _type, \ + _info_type, _field, _p) \ + for ((_p) = container_of((_dev_info), _info_type, _field); \ + (_p) != NULL; \ + (_p) = container_of((_p)->_field.next, _info_type, _field))\ + if ((_p)->_field.type != _type) \ + continue; \ + else + +/** + * efx_dl_search_device_info - search an efx_dl_device_info list + * @_dev_info: Pointer to first &struct efx_dl_device_info + * @_type: Type code to look for + * @_info_type: Structure type corresponding to type code + * @_field: Name of &struct efx_dl_device_info member in this type + * @_p: Result variable + * + * Example: + * + * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...) + * { + * struct efx_dl_falcon_resources *res; + * + * efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES, + * struct efx_dl_falcon_resources, hdr, res); + * if (res != NULL) { + * .... + * } + * } + */ +#define efx_dl_search_device_info(_dev_info, _type, _info_type, \ + _field, _p) \ + efx_dl_for_each_device_info_matching((_dev_info), (_type), \ + _info_type, _field, (_p)) \ + break; + +#endif /* EFX_DRIVERLINK_API_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/efx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/efx.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,2783 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2005-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/delay.h> +#include <linux/notifier.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/in.h> +#include <linux/crc32.h> +#include <linux/ethtool.h> +#include <asm/uaccess.h> +#include "net_driver.h" +#include "gmii.h" +#include "driverlink.h" +#include "selftest.h" +#include "debugfs.h" +#include "ethtool.h" +#include "tx.h" +#include "rx.h" +#include "efx.h" +#include "mdio_10g.h" +#include "falcon.h" +#include "workarounds.h" + +/************************************************************************** + * + * Type name strings + * + ************************************************************************** + */ + +/* Loopback mode names (see LOOPBACK_MODE()) */ +const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; +const char *efx_loopback_mode_names[] = { + [LOOPBACK_NONE] = "NONE", + [LOOPBACK_MAC] = "MAC", + [LOOPBACK_XGMII] = "XGMII", + [LOOPBACK_XGXS] = "XGXS", + [LOOPBACK_XAUI] = "XAUI", + [LOOPBACK_PHY] = "PHY", + [LOOPBACK_PHYXS] = "PHY(XS)", + [LOOPBACK_PCS] = "PHY(PCS)", + [LOOPBACK_PMAPMD] = "PHY(PMAPMD)", + [LOOPBACK_NETWORK] = "NETWORK", +}; + +/* Interrupt mode names (see INT_MODE())) */ +const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; +const char *efx_interrupt_mode_names[] = { + [EFX_INT_MODE_MSIX] = "MSI-X", + [EFX_INT_MODE_MSI] = "MSI", + [EFX_INT_MODE_LEGACY] = "legacy", +}; + +/* PHY type names (see PHY_TYPE())) */ +const unsigned int efx_phy_type_max = PHY_TYPE_MAX; +const char *efx_phy_type_names[] = { + [PHY_TYPE_NONE] = "none", + [PHY_TYPE_CX4_RTMR] = "Mysticom CX4", + [PHY_TYPE_1G_ALASKA] = "1G Alaska", + [PHY_TYPE_10XPRESS] = "SFC 10Xpress", + [PHY_TYPE_XFP] = "Quake XFP", + [PHY_TYPE_PM8358] = "PM8358 XAUI", +}; + +const unsigned int efx_reset_type_max = RESET_TYPE_MAX; +const char *efx_reset_type_names[] = { + [RESET_TYPE_INVISIBLE] = "INVISIBLE", + [RESET_TYPE_ALL] = "ALL", + [RESET_TYPE_WORLD] = "WORLD", + [RESET_TYPE_DISABLE] = "DISABLE", + [RESET_TYPE_MONITOR] = "MONITOR", + [RESET_TYPE_INT_ERROR] = "INT_ERROR", + [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", +}; + +const unsigned int efx_nic_state_max = STATE_MAX; +const char *efx_nic_state_names[] = { + [STATE_INIT] = "INIT", + [STATE_RUNNING] = "RUNNING", + [STATE_FINI] = "FINI", + [STATE_RESETTING] = "RESETTING", + [STATE_DISABLED] = "DISABLED", +}; + +#define EFX_MAX_MTU (9 * 1024) + + +/************************************************************************** + * + * Configurable values + * + *************************************************************************/ + +/* + * Use separate channels for TX and RX events + * + * Set this to 1 to use separate channels for TX and RX. It allows us to + * apply a higher level of interrupt moderation to TX events. + * + * This is forced to 0 for MSI interrupt mode as the interrupt vector + * is not written + */ +static unsigned int separate_tx_and_rx_channels = 1; + +/* This is the weight assigned to each of the (per-channel) virtual + * NAPI devices. + */ +static int napi_weight = 64; + +/* This is the time (in jiffies) between invocations of the hardware + * monitor, which checks for known hardware bugs and resets the + * hardware and driver as necessary. + */ +unsigned int efx_monitor_interval = 1 * HZ; + +/* This controls whether or not the hardware monitor will trigger a + * reset when it detects an error condition. + */ +static unsigned int monitor_reset = 1; + +/* This controls whether or not the driver will initialise devices + * with invalid MAC addresses stored in the EEPROM or flash. If true, + * such devices will be initialised with a random locally-generated + * MAC address. This allows for loading the efx_mtd driver to + * reprogram the flash, even if the flash contents (including the MAC + * address) have previously been erased. + */ +static unsigned int allow_bad_hwaddr; + +/* Initial interrupt moderation settings. They can be modified after + * module load with ethtool. + * + * The default for RX should strike a balance between increasing the + * round-trip latency and reducing overhead. + */ +static unsigned int rx_irq_mod_usec = 60; + +/* Initial interrupt moderation settings. They can be modified after + * module load with ethtool. + * + * This default is chosen to ensure that a 10G link does not go idle + * while a TX queue is stopped after it has become full. A queue is + * restarted when it drops below half full. The time this takes (assuming + * worst case 3 descriptors per packet and 1024 descriptors) is + * 512 / 3 * 1.2 = 205 usec. + */ +static unsigned int tx_irq_mod_usec = 150; + +/* Ignore online self-test failures at load + * + * If set to 1, then the driver will not fail to load + * if the online self-test fails. Useful only during testing + */ +static unsigned int allow_load_on_failure; + +/* Set to 1 to enable the use of Message-Signalled Interrupts (MSI). + * MSI will not work on some motherboards due to limitations of the + * chipset, so the default is off. + * + * This is the highest capability interrupt mode to use + * 0 => MSI-X + * 1 => MSI + * 2 => legacy + */ +static unsigned int interrupt_mode; + +/* If set to 1, then the driver will perform an offline self test + * when each interface first comes up. This will appear like the + * interface bounces up and down + */ +static unsigned int onload_offline_selftest = 1; + +/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS), + * i.e. the number of CPUs among which we may distribute simultaneous + * interrupt handling. + * + * Cards without MSI-X will only target one CPU + * + * Default (0) means to use all CPUs in the system. This parameter + * can be set using "rss_cpus=xxx" when loading the module. + */ +static unsigned int rss_cpus; +module_param(rss_cpus, uint, 0444); +MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); + +/************************************************************************** + * + * Utility functions and prototypes + * + *************************************************************************/ +static void efx_remove_channel(struct efx_channel *channel); +static void efx_remove_port(struct efx_nic *efx); +static void efx_fini_napi(struct efx_nic *efx); +static void efx_fini_channels(struct efx_nic *efx); + +/************************************************************************** + * + * Event queue processing + * + *************************************************************************/ + +/* Process channel's event queue + * + * This function is responsible for processing the event queue of a + * single channel. The caller must guarantee that this function will + * never be concurrently called more than once on the same channel, + * though different channels may be being processed concurrently. + */ +static inline int efx_process_channel(struct efx_channel *channel, int rx_quota) +{ + int rxdmaqs; + struct efx_rx_queue *rx_queue; + + if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE || + !channel->enabled)) + return rx_quota; + + rxdmaqs = falcon_process_eventq(channel, &rx_quota); + + /* Deliver last RX packet. */ + if (channel->rx_pkt) { + __efx_rx_packet(channel, channel->rx_pkt, + channel->rx_pkt_csummed); + channel->rx_pkt = NULL; + } + + efx_rx_strategy(channel); + + /* Refill descriptor rings as necessary */ + rx_queue = &channel->efx->rx_queue[0]; + while (rxdmaqs) { + if (rxdmaqs & 0x01) + efx_fast_push_rx_descriptors(rx_queue); + rx_queue++; + rxdmaqs >>= 1; + } + + return rx_quota; +} + +/* Mark channel as finished processing + * + * Note that since we will not receive further interrupts for this + * channel before we finish processing and call the eventq_read_ack() + * method, there is no need to use the interrupt hold-off timers. + */ +static inline void efx_channel_processed(struct efx_channel *channel) +{ + /* Write to EVQ_RPTR_REG. If a new event arrived in a race + * with finishing processing, a new interrupt will be raised. + */ + channel->work_pending = 0; + smp_wmb(); /* Ensure channel updated before any new interrupt. */ + falcon_eventq_read_ack(channel); +} + +/* NAPI poll handler + * + * NAPI guarantees serialisation of polls of the same device, which + * provides the guarantee required by efx_process_channel(). + */ +#if !defined(EFX_HAVE_OLD_NAPI) +static int efx_poll(struct napi_struct *napi, int budget) +{ + struct efx_channel *channel = + container_of(napi, struct efx_channel, napi_str); + struct net_device *napi_dev = channel->napi_dev; +#else +static int efx_poll(struct net_device *napi, int *budget_ret) +{ + struct net_device *napi_dev = napi; + struct efx_channel *channel = napi_dev->priv; + int budget = min(napi_dev->quota, *budget_ret); +#endif + int unused; + int rx_packets; + + EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", + channel->channel, raw_smp_processor_id()); + + unused = efx_process_channel(channel, budget); + rx_packets = (budget - unused); +#if defined(EFX_HAVE_OLD_NAPI) + napi_dev->quota -= rx_packets; + *budget_ret -= rx_packets; +#endif + + if (rx_packets < budget) { + /* There is no race here; although napi_disable() will + * only wait for netif_rx_complete(), this isn't a problem + * since efx_channel_processed() will have no effect if + * interrupts have already been disabled. + */ + netif_rx_complete(napi_dev, napi); + efx_channel_processed(channel); + } + +#if !defined(EFX_HAVE_OLD_NAPI) + return rx_packets; +#else + return (rx_packets >= budget); +#endif +} + +/* Process the eventq of the specified channel immediately on this CPU + * + * Disable hardware generated interrupts, wait for any existing + * processing to finish, then directly poll (and ack ) the eventq. + * Finally reenable NAPI and interrupts. + * + * Since we are touching interrupts the caller should hold the suspend lock + */ +void efx_process_channel_now(struct efx_channel *channel) +{ + struct efx_nic *efx = channel->efx; + + BUG_ON(!channel->used_flags); + BUG_ON(!channel->enabled); + + /* Disable interrupts and wait for ISRs to complete */ + falcon_disable_interrupts(efx); + if (efx->legacy_irq) + synchronize_irq(efx->legacy_irq); + if (channel->has_interrupt && channel->irq) + synchronize_irq(channel->irq); + + /* Wait for any NAPI processing to complete */ + napi_disable(&channel->napi_str); + + /* Poll the channel */ + (void) efx_process_channel(channel, efx->type->evq_size); + + /* Ack the eventq. This may cause an interrupt to be generated + * when they are reenabled */ + efx_channel_processed(channel); + + /* Reenable NAPI polling */ + napi_enable(&channel->napi_str); + + /* Reenable interrupts */ + falcon_enable_interrupts(efx); +} + +/* Create event queue + * Event queue memory allocations are done only once. If the channel + * is reset, the memory buffer will be reused; this guards against + * errors during channel reset and also simplifies interrupt handling. + */ +static int efx_probe_eventq(struct efx_channel *channel) +{ + EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel); + + return falcon_probe_eventq(channel); +} + +/* Prepare channel's event queue */ +static int efx_init_eventq(struct efx_channel *channel) +{ + EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel); + + ASSERT_RTNL(); + + /* Initialise fields */ + channel->eventq_read_ptr = 0; + + return falcon_init_eventq(channel); +} + +static void efx_fini_eventq(struct efx_channel *channel) +{ + EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel); + + ASSERT_RTNL(); + + falcon_fini_eventq(channel); +} + +static void efx_remove_eventq(struct efx_channel *channel) +{ + EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel); + + falcon_remove_eventq(channel); +} + +/************************************************************************** + * + * Channel handling + * + *************************************************************************/ + +/* Setup per-NIC RX buffer parameters. + * Calculate the rx buffer allocation parameters required to support + * the current MTU, including padding for header alignment and overruns. + */ +static void efx_calc_rx_buffer_params(struct efx_nic *efx) +{ + unsigned int order, len; + + len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) + + EFX_MAX_FRAME_LEN(efx->net_dev->mtu) + + efx->type->rx_buffer_padding); + + /* Page-based allocation page-order */ + for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order) + ; + + efx->rx_buffer_len = len; + efx->rx_buffer_order = order; +} + +static int efx_probe_channel(struct efx_channel *channel) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + int rc; + + EFX_LOG(channel->efx, "creating channel %d\n", channel->channel); + + rc = efx_probe_eventq(channel); + if (rc) + goto fail1; + + efx_for_each_channel_tx_queue(tx_queue, channel) { + rc = efx_probe_tx_queue(tx_queue); + if (rc) + goto fail2; + } + + efx_for_each_channel_rx_queue(rx_queue, channel) { + rc = efx_probe_rx_queue(rx_queue); + if (rc) + goto fail3; + } + + channel->n_rx_frm_trunc = 0; + + return 0; + + fail3: + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_remove_rx_queue(rx_queue); + fail2: + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_remove_tx_queue(tx_queue); + fail1: + return rc; +} + + +/* Channels are shutdown and reinitialised whilst the NIC is running + * to propagate configuration changes (mtu, checksum offload), or + * to clear hardware error conditions + */ +static int efx_init_channels(struct efx_nic *efx) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + struct efx_channel *channel; + int rc = 0; + + /* Recalculate the rx buffer parameters */ + efx_calc_rx_buffer_params(efx); + + /* Initialise the channels */ + efx_for_each_channel(channel, efx) { + EFX_LOG(channel->efx, "init chan %d\n", channel->channel); + + rc = efx_init_eventq(channel); + if (rc) + goto err; + + efx_for_each_channel_tx_queue(tx_queue, channel) { + rc = efx_init_tx_queue(tx_queue); + if (rc) + goto err; + } + + /* The rx buffer allocation strategy is MTU dependent */ + efx_rx_strategy(channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) { + rc = efx_init_rx_queue(rx_queue); + if (rc) + goto err; + } + + WARN_ON(channel->rx_pkt != NULL); + efx_rx_strategy(channel); + } + + return 0; + + err: + EFX_ERR(efx, "failed to initialise channel %d\n", + channel ? channel->channel : -1); + efx_fini_channels(efx); + return rc; +} + +/* This enables event queue processing and packet transmission. + * + * Note that this function is not allowed to fail, since that would + * introduce too much complexity into the suspend/resume path. + */ +static void efx_start_channel(struct efx_channel *channel) +{ + struct efx_rx_queue *rx_queue; + + EFX_LOG(channel->efx, "starting chan %d\n", channel->channel); + + if (!(channel->efx->net_dev->flags & IFF_UP)) + netif_napi_add(channel->napi_dev, &channel->napi_str, + efx_poll, napi_weight); + + /* Mark channel as enabled */ + channel->work_pending = 0; + channel->enabled = 1; + smp_wmb(); /* ensure channel updated before first interrupt */ + + /* Enable NAPI poll handler */ + napi_enable(&channel->napi_str); + + /* Load up RX descriptors */ + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_fast_push_rx_descriptors(rx_queue); +} + +/* This disables event queue processing and packet transmission. + * This function does not guarantee that all queue processing + * (e.g. RX refill) is complete. + */ +static void efx_stop_channel(struct efx_channel *channel) +{ + struct efx_rx_queue *rx_queue; + + if (!channel->enabled) + return; + + EFX_LOG(channel->efx, "stop chan %d\n", channel->channel); + + /* Mark channel as disabled */ + channel->enabled = 0; + + /* Wait for any NAPI processing to complete */ + napi_disable(&channel->napi_str); + + /* Ensure that any worker threads have exited or will be + * no-ops. + */ + efx_for_each_channel_rx_queue(rx_queue, channel) { + spin_lock_bh(&rx_queue->add_lock); + spin_unlock_bh(&rx_queue->add_lock); + } +} + +static void efx_fini_channels(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + + ASSERT_RTNL(); + + efx_for_each_channel(channel, efx) { + EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_fini_rx_queue(rx_queue); + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_fini_tx_queue(tx_queue); + } + + /* Do the event queues last so that we can handle flush events + * for all DMA queues. */ + efx_for_each_channel(channel, efx) { + EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel); + + efx_fini_eventq(channel); + } +} + +static void efx_remove_channel(struct efx_channel *channel) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + + EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel); + + efx_for_each_channel_rx_queue(rx_queue, channel) + efx_remove_rx_queue(rx_queue); + efx_for_each_channel_tx_queue(tx_queue, channel) + efx_remove_tx_queue(tx_queue); + efx_remove_eventq(channel); + + channel->used_flags = 0; +} + +/************************************************************************** + * + * Port handling + * + **************************************************************************/ + +/* This ensures that the kernel is kept informed (via + * netif_carrier_on/off) of the link status, and also maintains the + * link status's stop on the port's TX queue. + */ +static void efx_link_status_changed(struct efx_nic *efx) +{ + unsigned long flags __attribute__ ((unused)); + int carrier_ok; + + /* Ensure no link status notifications get sent to the OS after the net + * device has been unregistered. */ + if (!efx->net_dev_registered) + return; + + carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0; + if (efx->link_up != carrier_ok) { + efx->n_link_state_changes++; + + if (efx->link_up) + netif_carrier_on(efx->net_dev); + else + netif_carrier_off(efx->net_dev); + } + + /* Inform driverlink client */ + EFX_DL_CALLBACK(efx, link_change, efx->link_up); + + /* Status message for kernel log */ + if (efx->link_up) { + struct mii_if_info *gmii = &efx->mii; + unsigned adv, lpa; + /* NONE here means direct XAUI from the controller, with no + * MDIO-attached device we can query. */ + if (efx->phy_type != PHY_TYPE_NONE) { + adv = gmii_advertised(gmii); + lpa = gmii_lpa(gmii); + } else { + lpa = GM_LPA_10000 | LPA_DUPLEX; + adv = lpa; + } + EFX_INFO(efx, "link up at %dMbps %s-duplex " + "(adv %04x lpa %04x) (MTU %d)%s%s%s%s\n", + (efx->link_options & GM_LPA_10000 ? 10000 : + (efx->link_options & GM_LPA_1000 ? 1000 : + (efx->link_options & GM_LPA_100 ? 100 : + 10))), + (efx->link_options & GM_LPA_DUPLEX ? + "full" : "half"), + adv, lpa, + efx->net_dev->mtu, + (efx->loopback_mode ? " [" : ""), + (efx->loopback_mode ? LOOPBACK_MODE(efx) : ""), + (efx->loopback_mode ? " LOOPBACK]" : ""), + (efx->promiscuous ? " [PROMISC]" : "")); + } else { + EFX_INFO(efx, "link down\n"); + } + +} + +/* This call reinitialises the MAC to pick up new PHY settings + * To call from a context that cannot sleep use reconfigure_work work item + * For on_disabled=1 the caller must be serialised against efx_reset, + * ideally by holding the rtnl lock. + */ +void efx_reconfigure_port(struct efx_nic *efx, int on_disabled) +{ + mutex_lock(&efx->mac_lock); + + EFX_LOG(efx, "reconfiguring MAC from PHY settings\n"); + + if (on_disabled) + ASSERT_RTNL(); + else if (!efx->port_enabled) + goto out; + + efx->mac_op->reconfigure(efx); + +out: + /* Inform kernel of loss/gain of carrier */ + efx_link_status_changed(efx); + + mutex_unlock(&efx->mac_lock); +} + +static void efx_reconfigure_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, + reconfigure_work); + + EFX_LOG(efx, "MAC reconfigure executing on CPU %d\n", + raw_smp_processor_id()); + + /* Reinitialise MAC to activate new PHY parameters */ + efx_reconfigure_port(efx, 0); +} + +static int efx_probe_port(struct efx_nic *efx) +{ + unsigned char *dev_addr; + int rc; + + EFX_LOG(efx, "create port\n"); + + /* Connect up MAC/PHY operations table and read MAC address */ + rc = falcon_probe_port(efx); + if (rc) + goto err; + + /* Sanity check MAC address */ + dev_addr = efx->mac_address; + if (!is_valid_ether_addr(dev_addr)) { + DECLARE_MAC_BUF(mac); + + EFX_ERR(efx, "invalid MAC address %s\n", + print_mac(mac, dev_addr)); + if (!allow_bad_hwaddr) { + rc = -EINVAL; + goto err; + } + random_ether_addr(dev_addr); + EFX_INFO(efx, "using locally-generated MAC %s\n", + print_mac(mac, dev_addr)); + } + + /* Register debugfs entries */ + rc = efx_init_debugfs_port(efx); + if (rc) + goto err; + + return 0; + + err: + efx_remove_port(efx); + return rc; +} + +static int efx_init_port(struct efx_nic *efx) +{ + int rc; + + EFX_LOG(efx, "init port\n"); + + /* The default power state is ON */ + efx->phy_powered = 1; + + /* Initialise the MAC and PHY */ + rc = efx->mac_op->init(efx); + if (rc) + return rc; + + efx->port_initialized = 1; + + /* Reconfigure port to program MAC registers */ + efx->mac_op->reconfigure(efx); + + return 0; +} + +/* Allow efx_reconfigure_port() to run, and propagate delayed changes + * to the promiscuous flag to the MAC if needed */ +static void efx_start_port(struct efx_nic *efx) +{ + EFX_LOG(efx, "start port\n"); + ASSERT_RTNL(); + + BUG_ON(efx->port_enabled); + + mutex_lock(&efx->mac_lock); + efx->port_enabled = 1; + mutex_unlock(&efx->mac_lock); + + if (efx->net_dev_registered) { + int promiscuous; + + netif_tx_lock_bh(efx->net_dev); + promiscuous = (efx->net_dev->flags & IFF_PROMISC) ? 1 : 0; + if (efx->promiscuous != promiscuous) { + efx->promiscuous = promiscuous; + queue_work(efx->workqueue, &efx->reconfigure_work); + } + netif_tx_unlock_bh(efx->net_dev); + } +} + +/* Prevents efx_reconfigure_port() from executing, and prevents + * efx_set_multicast_list() from scheduling efx_reconfigure_work. + * efx_reconfigure_work can still be scheduled via NAPI processing + * until efx_flush_all() is called */ +static void efx_stop_port(struct efx_nic *efx) +{ + EFX_LOG(efx, "stop port\n"); + ASSERT_RTNL(); + + mutex_lock(&efx->mac_lock); + efx->port_enabled = 0; + mutex_unlock(&efx->mac_lock); + + /* Serialise against efx_set_multicast_list() */ + if (efx->net_dev_registered) { + netif_tx_lock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); + } +} + +static void efx_fini_port(struct efx_nic *efx) +{ + EFX_LOG(efx, "shut down port\n"); + + if (!efx->port_initialized) + return; + + efx->mac_op->fini(efx); + efx->port_initialized = 0; + + /* Mark the link down */ + efx->link_up = 0; + efx_link_status_changed(efx); +} + +static void efx_remove_port(struct efx_nic *efx) +{ + EFX_LOG(efx, "destroying port\n"); + + efx_fini_debugfs_port(efx); + falcon_remove_port(efx); +} + +/************************************************************************** + * + * NIC handling + * + **************************************************************************/ + +/* This configures the PCI device to enable I/O and DMA. */ +static int efx_init_io(struct efx_nic *efx) +{ + struct pci_dev *pci_dev = efx->pci_dev; + int rc; + + EFX_LOG(efx, "initialising I/O\n"); + + /* Generic device-enabling code */ + rc = pci_enable_device(pci_dev); + if (rc) { + EFX_ERR(efx, "failed to enable PCI device\n"); + goto fail1; + } + + pci_set_master(pci_dev); + + /* Set the PCI DMA mask. Try all possibilities from our + * genuine mask down to 32 bits, because some architectures + * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit + * masks event though they reject 46 bit masks. + */ + efx->dma_mask = efx->type->max_dma_mask; + while (efx->dma_mask > 0x7fffffffUL) { + if (pci_dma_supported(pci_dev, efx->dma_mask) && + ((rc = pci_set_dma_mask(pci_dev, efx->dma_mask)) == 0)) + break; + efx->dma_mask >>= 1; + } + if (rc) { + EFX_ERR(efx, "could not find a suitable DMA mask\n"); + goto fail2; + } + EFX_LOG(efx, "using DMA mask %llx\n", + (unsigned long long)efx->dma_mask); + rc = pci_set_consistent_dma_mask(pci_dev, efx->dma_mask); + if (rc) { + /* pci_set_consistent_dma_mask() is not *allowed* to + * fail with a mask that pci_set_dma_mask() accepted, + * but just in case... + */ + EFX_ERR(efx, "failed to set consistent DMA mask\n"); + goto fail2; + } + + /* Get memory base address */ + efx->membase_phys = pci_resource_start(efx->pci_dev, + efx->type->mem_bar); +#if !defined(EFX_HAVE_MSIX_TABLE_RESERVED) + rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc"); +#else + if (!request_mem_region(efx->membase_phys, efx->type->mem_map_size, + "sfc")) + rc = -EIO; +#endif + if (rc) { + EFX_ERR(efx, "request for memory BAR failed\n"); + rc = -EIO; + goto fail3; + } + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); + if (!efx->membase) { + EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n", + efx->type->mem_bar, efx->membase_phys, + efx->type->mem_map_size); + rc = -ENOMEM; + goto fail4; + } + EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n", + efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size, + efx->membase); + + return 0; + + fail4: + release_mem_region(efx->membase_phys, efx->type->mem_map_size); + fail3: + efx->membase_phys = 0UL; + /* fall-thru */ + fail2: + pci_disable_device(efx->pci_dev); + fail1: + return rc; +} + +static void efx_fini_io(struct efx_nic *efx) +{ + EFX_LOG(efx, "shutting down I/O\n"); + + if (efx->membase) { + iounmap(efx->membase); + efx->membase = NULL; + } + + if (efx->membase_phys) { +#if !defined(EFX_HAVE_MSIX_TABLE_RESERVED) + pci_release_region(efx->pci_dev, efx->type->mem_bar); +#else + release_mem_region(efx->membase_phys, efx->type->mem_map_size); +#endif + efx->membase_phys = 0UL; + } + + pci_disable_device(efx->pci_dev); +} + +/* Probe the number and type of interrupts we are able to obtain. */ +static int efx_probe_interrupts(struct efx_nic *efx) +{ + struct msix_entry xentries[EFX_MAX_CHANNELS]; + int rc, i; + + /* Select number of used RSS queues */ + /* TODO: Can we react to CPU hotplug? */ + if (rss_cpus == 0) + rss_cpus = num_online_cpus(); + + efx->rss_queues = 1; + if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { + unsigned int max_channel = efx->type->phys_addr_channels - 1; + + BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX)); + efx->rss_queues = min(max_channel + 1, rss_cpus); + efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS); + } + + /* Determine how many RSS queues we can use, and mark channels + * with the appropriate interrupt state */ + if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { + /* Build MSI request structure */ + for (i = 0; i < efx->rss_queues; i++) + xentries[i].entry = i; + + /* Request maximum number of MSI interrupts */ + rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues); + if (rc > 0) { + EFX_BUG_ON_PARANOID(rc >= efx->rss_queues); + efx->rss_queues = rc; + rc = pci_enable_msix(efx->pci_dev, xentries, + efx->rss_queues); + } + if (rc == 0) { + for (i = 0; i < efx->rss_queues; i++) { + efx->channel[i].has_interrupt = 1; + efx->channel[i].irq = xentries[i].vector; + } + } else { + /* Fall back to single channel MSI */ + efx->interrupt_mode = EFX_INT_MODE_MSI; + EFX_ERR(efx, "could not enable MSI-X\n"); + } + } + + /* Try single interrupt MSI */ + if (efx->interrupt_mode == EFX_INT_MODE_MSI) { + efx->rss_queues = 1; + rc = pci_enable_msi(efx->pci_dev); + if (rc == 0) { + efx->channel[0].irq = efx->pci_dev->irq; + efx->channel[0].has_interrupt = 1; + } else { + EFX_ERR(efx, "could not enable MSI\n"); + efx->interrupt_mode = EFX_INT_MODE_LEGACY; + } + } + + /* Assume legacy interrupts */ + if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { + /* Every channel is interruptible */ + for (i = 0; i < EFX_MAX_CHANNELS; i++) + efx->channel[i].has_interrupt = 1; + efx->legacy_irq = efx->pci_dev->irq; + } + + return 0; +} + +static void efx_remove_interrupts(struct efx_nic *efx) +{ + struct efx_channel *channel; + + /* Remove MSI/MSI-X interrupts */ + efx_for_each_channel_with_interrupt(channel, efx) + channel->irq = 0; + pci_disable_msi(efx->pci_dev); + pci_disable_msix(efx->pci_dev); + + /* Remove legacy interrupt */ + efx->legacy_irq = 0; +} + +/* Select number of used resources + * Should be called after probe_interrupts() + */ +static int efx_select_used(struct efx_nic *efx) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + int i; + + /* TX queues. One per port per channel with TX capability + * (more than one per port won't work on Linux, due to out + * of order issues... but will be fine on Solaris) + */ + tx_queue = &efx->tx_queue[0]; + + /* Perform this for each channel with TX capabilities. + * At the moment, we only support a single TX queue + */ + tx_queue->used = 1; + if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels) + tx_queue->channel = &efx->channel[1]; + else + tx_queue->channel = &efx->channel[0]; + tx_queue->channel->used_flags |= EFX_USED_BY_TX; + tx_queue++; + + /* RX queues. Each has a dedicated channel. */ + for (i = 0; i < EFX_MAX_RX_QUEUES; i++) { + rx_queue = &efx->rx_queue[i]; + + if (i < efx->rss_queues) { + rx_queue->used = 1; + /* If we allow multiple RX queues per channel + * we need to decide that here + */ + rx_queue->channel = &efx->channel[rx_queue->queue]; + rx_queue->channel->used_flags |= EFX_USED_BY_RX; + rx_queue++; + } + } + return 0; +} + +static int efx_probe_nic(struct efx_nic *efx) +{ + int rc; + + EFX_LOG(efx, "creating NIC\n"); + + /* Carry out hardware-type specific initialisation */ + rc = falcon_probe_nic(efx); + if (rc) + goto fail1; + + /* Determine the number of channels and RX queues by trying to hook + * in MSI-X interrupts. */ + rc = efx_probe_interrupts(efx); + if (rc) + goto fail2; + + /* Determine number of RX queues and TX queues */ + rc = efx_select_used(efx); + if (rc) + goto fail3; + + /* Register debugfs entries */ + rc = efx_init_debugfs_nic(efx); + if (rc) + goto fail4; + /* Initialise the interrupt moderation settings */ + efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec); + + return 0; + + fail4: + /* fall-thru */ + fail3: + efx_remove_interrupts(efx); + fail2: + falcon_remove_nic(efx); + fail1: + return rc; +} + +static void efx_remove_nic(struct efx_nic *efx) +{ + EFX_LOG(efx, "destroying NIC\n"); + + efx_remove_interrupts(efx); + falcon_remove_nic(efx); + + efx_fini_debugfs_nic(efx); +} + +/************************************************************************** + * + * NIC startup/shutdown + * + *************************************************************************/ + +static int efx_probe_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + int rc; + + /* Create NIC */ + rc = efx_probe_nic(efx); + if (rc) { + EFX_ERR(efx, "failed to create NIC\n"); + goto fail1; + } + + /* Create port */ + rc = efx_probe_port(efx); + if (rc) { + EFX_ERR(efx, "failed to create port\n"); + goto fail2; + } + + /* Create channels */ + efx_for_each_channel(channel, efx) { + rc = efx_probe_channel(channel); + if (rc) { + EFX_ERR(efx, "failed to create channel %d\n", + channel->channel); + goto fail3; + } + } + + return 0; + + fail3: + efx_for_each_channel(channel, efx) + efx_remove_channel(channel); + fail2: + efx_remove_port(efx); + fail1: + return rc; +} + +/* Called after previous invocation(s) of efx_stop_all, restarts the + * port, kernel transmit queue, NAPI processing and hardware interrupts. + * This function is safe to call multiple times when the NIC is in any + * state. */ +static void efx_start_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + + ASSERT_RTNL(); + + /* Check that it is appropriate to restart the interface. All + * of these flags are safe to read under just the rtnl lock */ + if (efx->port_enabled) + return; + if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT)) + return; + if (efx->net_dev_registered && !netif_running(efx->net_dev)) + return; + + /* Mark the port as enabled so port reconfigurations can start, then + * restart the transmit interface early so the watchdog timer stops */ + efx_start_port(efx); + efx_wake_queue(efx); + + efx_for_each_channel(channel, efx) + efx_start_channel(channel); + + falcon_enable_interrupts(efx); + + /* Start hardware monitor if we're in RUNNING */ + if (efx->state == STATE_RUNNING) + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); +} + +/* Flush all delayed work. Should only be called when no more delayed work + * will be scheduled. This doesn't flush pending online resets (efx_reset), + * since we're holding the rtnl_lock at this point. */ +static void efx_flush_all(struct efx_nic *efx) +{ +#if defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + struct efx_rx_queue *rx_queue; + + /* Make sure the hardware monitor is stopped */ + cancel_delayed_work_sync(&efx->monitor_work); + + /* Ensure that all RX slow refills are complete. */ + efx_for_each_rx_queue(rx_queue, efx) { + cancel_delayed_work_sync(&rx_queue->work); + } +#endif + +#if defined(EFX_USE_CANCEL_WORK_SYNC) + /* Stop scheduled port reconfigurations */ + cancel_work_sync(&efx->reconfigure_work); +#endif + +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + /* Ensure that the hardware monitor and asynchronous port + * reconfigurations are complete, which are the only two consumers + * of efx->workqueue. Since the hardware monitor runs on a long period, + * we put in some effort to cancel the delayed work safely rather + * than just flushing the queue twice (which is guaranteed to flush + * all the work since both efx_monitor and efx_reconfigure_work disarm + * if !efx->port_enabled. */ + if (timer_pending(&efx->monitor_work.timer)) + cancel_delayed_work(&efx->monitor_work); + flush_workqueue(efx->workqueue); + if (timer_pending(&efx->monitor_work.timer)) + cancel_delayed_work(&efx->monitor_work); + flush_workqueue(efx->workqueue); + + /* efx_rx_work will disarm if !channel->enabled, so we can just + * flush the refill workqueue twice as well. */ + flush_workqueue(efx->refill_workqueue); + flush_workqueue(efx->refill_workqueue); +#endif +} + +/* Quiesce hardware and software without bringing the link down. + * Safe to call multiple times, when the nic and interface is in any + * state. The caller is guaranteed to subsequently be in a position + * to modify any hardware and software state they see fit without + * taking locks. */ +static void efx_stop_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + + ASSERT_RTNL(); + + /* port_enabled can be read safely under the rtnl lock */ + if (!efx->port_enabled) + return; + + /* Disable interrupts and wait for ISR to complete */ + falcon_disable_interrupts(efx); + if (efx->legacy_irq) + synchronize_irq(efx->legacy_irq); + efx_for_each_channel_with_interrupt(channel, efx) + if (channel->irq) + synchronize_irq(channel->irq); + + /* Stop all synchronous port reconfigurations. */ + efx_stop_port(efx); + + /* Stop all NAPI processing and synchronous rx refills */ + efx_for_each_channel(channel, efx) + efx_stop_channel(channel); + + /* Flush reconfigure_work, refill_workqueue, monitor_work */ + efx_flush_all(efx); + + /* Stop the kernel transmit interface late, so the watchdog + * timer isn't ticking over the flush */ + efx_stop_queue(efx); + if (efx->net_dev_registered) { + netif_tx_lock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); + } +} + +static void efx_remove_all(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_remove_channel(channel); + efx_remove_port(efx); + efx_remove_nic(efx); +} + +static int efx_run_selftests(struct efx_nic *efx) +{ + struct efx_self_tests tests; + unsigned modes = efx->startup_loopbacks & efx->loopback_modes; + int rc; + + rc = efx_online_test(efx, &tests); + if (rc) { + EFX_ERR(efx, "failed self-tests with interrupt_mode of %s\n", + INT_MODE(efx)); + goto fail; + } + + if (onload_offline_selftest && modes) { + /* Run offline self test */ + EFX_LOG(efx, "performing on-load offline self-tests\n"); + rc = efx_offline_test(efx, &tests, modes); + EFX_LOG(efx, "%s on-load offline self-tests\n", + rc ? "FAILED" : "PASSED"); + if (rc) + goto fail; + } + + return 0; + + fail: + EFX_ERR(efx, "self-tests failed. Given up!\n"); + if (allow_load_on_failure) + rc = 0; + + return rc; +} + +int efx_flush_queues(struct efx_nic *efx) +{ + int rc; + + ASSERT_RTNL(); + + efx_stop_all(efx); + + /* We can't just flush the tx queues because the event queues + * may contain tx completions from that queue. Just flush everything */ + efx_fini_channels(efx); + rc = efx_init_channels(efx); + if (rc) { + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + return rc; + } + + efx_start_all(efx); + + return 0; +} + +/************************************************************************** + * + * Interrupt moderation + * + **************************************************************************/ + +/* Set interrupt moderation parameters */ +void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs) +{ + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + + ASSERT_RTNL(); + + efx_for_each_tx_queue(tx_queue, efx) + tx_queue->channel->irq_moderation = tx_usecs; + + efx_for_each_rx_queue(rx_queue, efx) + rx_queue->channel->irq_moderation = rx_usecs; +} + +/************************************************************************** + * + * Hardware monitor + * + **************************************************************************/ + +/* Run periodically off the general workqueue. Serialised against + * efx_reconfigure_port via the mac_lock */ +static void efx_monitor(struct work_struct *data) +{ +#if !defined(EFX_NEED_WORK_API_WRAPPERS) + struct efx_nic *efx = container_of(data, struct efx_nic, + monitor_work.work); +#else + struct efx_nic *efx = container_of(data, struct efx_nic, + monitor_work); +#endif + int rc = 0; + + EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", + raw_smp_processor_id()); + + +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + /* Without cancel_delayed_work_sync(), we have to make sure that + * we don't rearm when port_enabled == 0 */ + mutex_lock(&efx->mac_lock); + if (!efx->port_enabled) { + mutex_unlock(&efx->mac_lock); + return; + } + + rc = efx->mac_op->check_hw(efx); +#else + /* If the mac_lock is already held then it is likely a port + * reconfiguration is already in place, which will likely do + * most of the work of check_hw() anyway. */ + if (!mutex_trylock(&efx->mac_lock)) { + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); + return; + } + + if (efx->port_enabled) + rc = efx->mac_op->check_hw(efx); +#endif + mutex_unlock(&efx->mac_lock); + + if (rc) { + if (monitor_reset) { + EFX_ERR(efx, "hardware monitor detected a fault: " + "triggering reset\n"); + efx_schedule_reset(efx, RESET_TYPE_MONITOR); + } else { + EFX_ERR(efx, "hardware monitor detected a fault, " + "skipping reset\n"); + } + } + + queue_delayed_work(efx->workqueue, &efx->monitor_work, + efx_monitor_interval); +} + +/************************************************************************** + * + * ioctls + * + *************************************************************************/ + +/* Net device ioctl + * Context: process, rtnl_lock() held. + */ +static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) +{ + struct efx_nic *efx = net_dev->priv; + int rc; + + ASSERT_RTNL(); + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + rc = generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL); + break; + case SIOCSMIIREG: + rc = generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL); + efx_reconfigure_port(efx, 0); + break; + default: + rc = -EOPNOTSUPP; + } + + return rc; +} + +/************************************************************************** + * + * NAPI interface + * + **************************************************************************/ + +/* Allocate the NAPI dev's. + * Called after we know how many channels there are. + */ +static int efx_init_napi(struct efx_nic *efx) +{ + struct efx_channel *channel; + int rc; + + ASSERT_RTNL(); + + /* Allocate the NAPI dev for the port */ + efx->net_dev = alloc_etherdev(0); + if (!efx->net_dev) { + rc = -ENOMEM; + goto err; + } + efx->net_dev->priv = efx; + efx->mii.dev = efx->net_dev; + + /* Set features based on module parameters and DMA mask. + * Enable DMA to ZONE_HIGHMEM if the NIC can access all memory + * directly. This only has an effect on 32-bit systems and + * PAE on x86 limits memory to 64GB so 40 bits is plenty to + * address everything. If the device can't address 40 bits + * then it's safest to turn NETIF_F_HIGHDMA off because this + * might be a PAE system with more than 4G of RAM and a 32-bit + * NIC. The use of EFX_DMA_MASK is to eliminate compiler + * warnings on platforms where dma_addr_t is 32-bit. We + * assume that in those cases we can access all memory + * directly if our DMA mask is all ones. */ + efx->net_dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (efx->dma_mask >= EFX_DMA_MASK(DMA_40BIT_MASK)) + efx->net_dev->features |= NETIF_F_HIGHDMA; + + /* Copy MAC address */ + memcpy(&efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN); + + /* Allocate the per channel devs */ + efx_for_each_channel(channel, efx) { +#if !defined(EFX_HAVE_OLD_NAPI) + channel->napi_dev = efx->net_dev; +#else + channel->napi_dev = alloc_etherdev(0); + if (!channel->napi_dev) { + rc = -ENOMEM; + goto err; + } + channel->napi_dev->priv = channel; + atomic_set(&channel->napi_dev->refcnt, 1); +#endif + } + + return 0; + err: + efx_fini_napi(efx); + return rc; +} + +/* Free the NAPI state for the port and channels */ +static void efx_fini_napi(struct efx_nic *efx) +{ + struct efx_channel *channel; + + ASSERT_RTNL(); + + efx_for_each_channel(channel, efx) { + /* Finish per channel NAPI */ +#if defined(EFX_HAVE_OLD_NAPI) + if (channel->napi_dev) { + channel->napi_dev->priv = NULL; + free_netdev(channel->napi_dev); + } +#endif + channel->napi_dev = NULL; + } + + /* Finish port NAPI */ + if (efx->net_dev) { + efx->net_dev->priv = NULL; + free_netdev(efx->net_dev); + efx->net_dev = NULL; + } +} + +/************************************************************************** + * + * Kernel netpoll interface + * + *************************************************************************/ + +#ifdef CONFIG_NET_POLL_CONTROLLER + +/* Although in the common case interrupts will be disabled, this is not + * guaranteed. However, all our work happens inside the NAPI callback, + * so no locking is required. + */ +static void efx_netpoll(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + struct efx_channel *channel; + + efx_for_each_channel_with_interrupt(channel, efx) + efx_schedule_channel(channel); +} + +#endif + +/************************************************************************** + * + * Kernel net device interface + * + *************************************************************************/ + +/* Context: process, rtnl_lock() held. */ +static int efx_net_open(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + ASSERT_RTNL(); + + EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, + raw_smp_processor_id()); + efx_start_all(efx); + return 0; +} + +/* Context: process, rtnl_lock() held. + * Note that the kernel will ignore our return code; this method + * should really be a void. + */ +static int efx_net_stop(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + int rc; + + EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name, + raw_smp_processor_id()); + + /* Stop device and flush all the channels */ + efx_stop_all(efx); + efx_fini_channels(efx); + rc = efx_init_channels(efx); + if (rc) + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + + return 0; +} + +/* Context: process, dev_base_lock held, non-blocking. + * Statistics are taken directly from the MAC. + */ +static struct net_device_stats *efx_net_stats(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + struct efx_mac_stats *mac_stats = &efx->mac_stats; + struct net_device_stats *stats = &efx->stats; + + if (!spin_trylock(&efx->stats_lock)) + return stats; + if (efx->state == STATE_RUNNING) + efx->mac_op->update_stats(efx); + spin_unlock(&efx->stats_lock); + + stats->rx_packets = mac_stats->rx_packets; + stats->tx_packets = mac_stats->tx_packets; + stats->rx_bytes = mac_stats->rx_bytes; + stats->tx_bytes = mac_stats->tx_bytes; + stats->tx_errors = mac_stats->tx_bad; + stats->multicast = mac_stats->rx_multicast; + stats->collisions = mac_stats->tx_collision; + stats->rx_length_errors = mac_stats->rx_gtjumbo; + stats->rx_over_errors = mac_stats->rx_overflow; + stats->rx_crc_errors = mac_stats->rx_bad; + stats->rx_frame_errors = mac_stats->rx_align_error; + stats->rx_fifo_errors = 0; + stats->rx_missed_errors = mac_stats->rx_missed; + stats->rx_errors = (stats->rx_length_errors + + stats->rx_over_errors + + stats->rx_crc_errors + + stats->rx_frame_errors + + stats->rx_fifo_errors + + stats->rx_missed_errors + + mac_stats->rx_symbol_error); + stats->tx_aborted_errors = 0; + stats->tx_carrier_errors = 0; + stats->tx_fifo_errors = 0; + stats->tx_heartbeat_errors = 0; + stats->tx_window_errors = 0; + + return stats; +} + +/* Context: netif_tx_lock held, BHs disabled. */ +static void efx_watchdog(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n", + atomic_read(&efx->netif_stop_count), efx->port_enabled, + monitor_reset ? "resetting channels" : "skipping reset"); + + if (monitor_reset) + efx_schedule_reset(efx, RESET_TYPE_MONITOR); +} + + +/* Context: process, rtnl_lock() held. */ +static int efx_change_mtu(struct net_device *net_dev, int new_mtu) +{ + struct efx_nic *efx = net_dev->priv; + int rc = 0; + + ASSERT_RTNL(); + + if (new_mtu > EFX_MAX_MTU) + return -EINVAL; + + efx_stop_all(efx); + + /* Ask driverlink client if we can change MTU */ + rc = EFX_DL_CALLBACK(efx, request_mtu, new_mtu); + if (rc) { + EFX_ERR(efx, "MTU change vetoed by driverlink %s driver\n", + efx->dl_cb_dev.request_mtu->driver->name); + goto out; + } + + EFX_LOG(efx, "changing MTU to %d\n", new_mtu); + + efx_fini_channels(efx); + net_dev->mtu = new_mtu; + rc = efx_init_channels(efx); + if (rc) + goto fail; + + /* Reconfigure the MAC */ + efx_reconfigure_port(efx, 1); + + /* Notify driverlink client of new MTU */ + EFX_DL_CALLBACK(efx, mtu_changed, new_mtu); + + efx_start_all(efx); + + out: + return rc; + + fail: + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + return rc; +} + +static int efx_set_mac_address(struct net_device *net_dev, void *data) +{ + struct efx_nic *efx = net_dev->priv; + struct sockaddr *addr = data; + char *new_addr = addr->sa_data; + + ASSERT_RTNL(); + + if (!is_valid_ether_addr(new_addr)) { + DECLARE_MAC_BUF(mac); + EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n", + print_mac(mac, new_addr)); + return -EINVAL; + } + + memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); + + /* Reconfigure the MAC */ + efx_reconfigure_port(efx, 1); + + return 0; +} + +/* Context: netif_tx_lock held, BHs disabled. */ +static void efx_set_multicast_list(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + struct dev_mc_list *mc_list = net_dev->mc_list; + union efx_multicast_hash *mc_hash = &efx->multicast_hash; + unsigned long flags __attribute__ ((unused)); + int promiscuous; + u32 crc; + int bit; + int i; + + /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */ + promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0; + if (efx->promiscuous != promiscuous) { + if (efx->port_enabled) { + efx->promiscuous = promiscuous; + queue_work(efx->workqueue, &efx->reconfigure_work); + } + } + + /* Build multicast hash table */ + if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { + memset(mc_hash, 0xff, sizeof(*mc_hash)); + } else { + memset(mc_hash, 0x00, sizeof(*mc_hash)); + for (i = 0; i < net_dev->mc_count; i++) { + crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr); + bit = (crc & ((1 << EFX_MCAST_HASH_BITS) - 1)); + set_bit_le(bit, (void *)mc_hash); + mc_list = mc_list->next; + } + } + + /* Create and activate new global multicast hash table */ + falcon_set_multicast_hash(efx); +} + +/* Handle net device notifier events */ +static int efx_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *net_dev = (struct net_device *)ptr; + + if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) { + struct efx_nic *efx = net_dev->priv; + + strcpy(efx->name, net_dev->name); + efx_fini_debugfs_netdev(net_dev); + efx_init_debugfs_netdev(net_dev); + } + + return NOTIFY_DONE; +} + +static struct notifier_block efx_netdev_notifier = { + .notifier_call = efx_netdev_event, +}; + +static int efx_register_netdev(struct efx_nic *efx) +{ + struct net_device *net_dev = efx->net_dev; + int rc; + + net_dev->watchdog_timeo = 5 * HZ; + net_dev->irq = efx->pci_dev->irq; + net_dev->open = efx_net_open; + net_dev->stop = efx_net_stop; + net_dev->get_stats = efx_net_stats; + net_dev->tx_timeout = &efx_watchdog; + net_dev->hard_start_xmit = efx_hard_start_xmit; + net_dev->do_ioctl = efx_ioctl; + net_dev->change_mtu = efx_change_mtu; + net_dev->set_mac_address = efx_set_mac_address; + net_dev->set_multicast_list = efx_set_multicast_list; +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = efx_netpoll; +#endif + SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); + SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); + + /* Always start with carrier off; PHY events will detect the link */ + netif_carrier_off(efx->net_dev); + + BUG_ON(efx->net_dev_registered); + + /* Clear MAC statistics */ + efx->mac_op->update_stats(efx); + memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); + + rc = register_netdev(net_dev); + if (rc) { + EFX_ERR(efx, "could not register net dev\n"); + return rc; + } + strcpy(efx->name, net_dev->name); + + /* Create debugfs symlinks */ + rc = efx_init_debugfs_netdev(net_dev); + if (rc) { + EFX_ERR(efx, "failed to init net dev debugfs\n"); + unregister_netdev(efx->net_dev); + return rc; + } + + /* Allow link change notifications to be sent to the operating + * system. The must happen after register_netdev so that + * there are no outstanding link changes if that call fails. + * It must happen before efx_reconfigure_port so that the + * initial state of the link is reported. */ + mutex_lock(&efx->mac_lock); + efx->net_dev_registered = 1; + mutex_unlock(&efx->mac_lock); + + /* Safety net: in case we don't get a PHY event */ + rtnl_lock(); + efx_reconfigure_port(efx, 1); + rtnl_unlock(); + + EFX_LOG(efx, "registered\n"); + + return 0; +} + +static void efx_unregister_netdev(struct efx_nic *efx) +{ + int was_registered = efx->net_dev_registered; + struct efx_tx_queue *tx_queue; + + if (!efx->net_dev) + return; + + BUG_ON(efx->net_dev->priv != efx); + + /* SFC Bug 5356: Ensure that no more link status notifications get + * sent to the stack. Bad things happen if there's an + * outstanding notification after the net device is freed, but + * they only get flushed out by unregister_netdev, not by + * free_netdev. */ + mutex_lock(&efx->mac_lock); + efx->net_dev_registered = 0; + mutex_unlock(&efx->mac_lock); + + /* Free up any skbs still remaining. This has to happen before + * we try to unregister the netdev as running their destructors + * may be needed to get the device ref. count to 0. */ + efx_for_each_tx_queue(tx_queue, efx) + efx_release_tx_buffers(tx_queue); + + if (was_registered) { + strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); + efx_fini_debugfs_netdev(efx->net_dev); + unregister_netdev(efx->net_dev); + } +} + +/************************************************************************** + * + * Device reset and suspend + * + **************************************************************************/ + +/* This suspends the device (and acquires the suspend lock) without + * flushing the descriptor queues. It is included for the convenience + * of the driverlink layer. + */ +void efx_suspend(struct efx_nic *efx) +{ + EFX_LOG(efx, "suspending operations\n"); + + down(&efx->suspend_lock); + + rtnl_lock(); + efx_stop_all(efx); +} + +void efx_resume(struct efx_nic *efx) +{ + EFX_LOG(efx, "resuming operations\n"); + + efx_start_all(efx); + rtnl_unlock(); + + up(&efx->suspend_lock); +} + +/* The final hardware and software finalisation before reset. + * This function does not handle serialisation with the kernel, it + * assumes the caller has done this */ +static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int rc; + + ASSERT_RTNL(); + + rc = efx->mac_op->get_settings(efx, ecmd); + if (rc) { + EFX_ERR(efx, "could not back up PHY settings\n"); + goto fail; + } + + efx_fini_channels(efx); + return 0; + + fail: + return rc; +} + +/* The first part of software initialisation after a hardware reset + * This function does not handle serialisation with the kernel, it + * assumes the caller has done this */ +static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int rc; + + rc = efx_init_channels(efx); + if (rc) + goto fail1; + + /* In an INVISIBLE_RESET there might not be a link state transition, + * so we push the multicast list here. */ + falcon_set_multicast_hash(efx); + + /* Restore MAC and PHY settings. */ + rc = efx->mac_op->set_settings(efx, ecmd); + if (rc) { + EFX_ERR(efx, "could not restore PHY settings\n"); + goto fail2; + } + + return 0; + + fail2: + efx_fini_channels(efx); + fail1: + return rc; +} + +/* Reset the NIC as transparently as possible. Do not reset the PHY + * Note that the reset may fail, in which case the card will be left + * in a most-probably-unusable state. + * + * This function will sleep. You cannot reset from within an atomic + * state; use efx_schedule_reset() instead. + */ +static int efx_reset(struct efx_nic *efx) +{ + struct ethtool_cmd ecmd; + unsigned long flags __attribute__ ((unused)); + enum reset_type method = efx->reset_pending; + int rc; + + efx_dl_reset_lock(); + + rc = down_interruptible(&efx->suspend_lock); + if (rc) { + EFX_ERR(efx, "reset aborted by signal\n"); + goto unlock_dl_lock; + } + + /* We've got suspend_lock, which means we can only be in + * STATE_RUNNING or STATE_FINI. Don't clear + * efx->reset_pending, since this flag indicates that we + * should retry device initialisation. + */ + if (efx->state != STATE_RUNNING) { + EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); + goto unlock_suspend_lock; + } + + /* Notify driverlink clients of imminent reset. */ + efx_dl_reset_suspend(efx); + rtnl_lock(); + + efx->state = STATE_RESETTING; + EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); + + /* The net_dev->get_stats handler is quite slow, and will fail + * if a fetch is pending over reset. Serialise against it. */ + spin_lock(&efx->stats_lock); + spin_unlock(&efx->stats_lock); + + efx_stop_all(efx); + mutex_lock(&efx->mac_lock); + + rc = efx_reset_down(efx, &ecmd); + if (rc) + goto fail1; + falcon_fini_nic(efx); + + rc = falcon_reset_hw(efx, method); + if (rc) { + EFX_ERR(efx, "failed to reset hardware\n"); + goto fail2; + } + + /* Allow resets to be rescheduled. */ + efx->reset_pending = RESET_TYPE_NONE; + + /* Reinitialise bus-mastering, which may have been turned off before + * the reset was scheduled. This is still appropriate, even in the + * RESET_TYPE_DISABLE since this driver generally assumes the hardware + * can respond to requests. */ + pci_set_master(efx->pci_dev); + + /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE + * case so the driver can talk to external SRAM */ + rc = falcon_init_nic(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise NIC\n"); + goto fail3; + } + + /* Leave device stopped if necessary */ + if (method == RESET_TYPE_DISABLE) { + /* Reinitialise the device anyway so the driver unload sequence + * can talk to the external SRAM */ + (void) falcon_init_nic(efx); + rc = -EIO; + goto fail4; + } + + rc = efx_reset_up(efx, &ecmd); + if (rc) + goto fail5; + + mutex_unlock(&efx->mac_lock); + efx_reconfigure_port(efx, 1); + EFX_LOG(efx, "reset complete\n"); + + efx->state = STATE_RUNNING; + efx_start_all(efx); + + rtnl_unlock(); + + goto notify; + + fail5: + fail4: + fail3: + fail2: + fail1: + EFX_ERR(efx, "has been disabled\n"); + efx->state = STATE_DISABLED; + + /* Remove the net_dev */ + mutex_unlock(&efx->mac_lock); + rtnl_unlock(); + efx_unregister_netdev(efx); + efx_fini_port(efx); + + notify: + /* Notify driverlink clients of completed reset */ + efx_dl_reset_resume(efx, (rc == 0)); + + unlock_suspend_lock: + up(&efx->suspend_lock); + + unlock_dl_lock: + efx_dl_reset_unlock(); + + return rc; +} + +/* The worker thread exists so that code that cannot sleep can + * schedule a reset for later. + */ +static void efx_reset_work(struct work_struct *data) +{ + struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); + + efx_reset(nic); +} + +void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) +{ + enum reset_type method; + + if (efx->reset_pending != RESET_TYPE_NONE) { + EFX_INFO(efx, "quenching already scheduled reset\n"); + return; + } + + switch (type) { + case RESET_TYPE_INVISIBLE: + case RESET_TYPE_ALL: + case RESET_TYPE_WORLD: + case RESET_TYPE_DISABLE: + method = type; + break; + case RESET_TYPE_RX_RECOVERY: + case RESET_TYPE_RX_DESC_FETCH: + case RESET_TYPE_TX_DESC_FETCH: + method = RESET_TYPE_INVISIBLE; + break; + default: + method = RESET_TYPE_ALL; + break; + } + + if (method != type) + EFX_LOG(efx, "scheduling %s reset for %s\n", + RESET_TYPE(method), RESET_TYPE(type)); + else + EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method)); + + efx->reset_pending = method; + +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + queue_work(efx->reset_workqueue, &efx->reset_work); +#else + queue_work(efx->workqueue, &efx->reset_work); +#endif +} + +/************************************************************************** + * + * List of NICs we support + * + **************************************************************************/ + +enum efx_type_index { + EFX_TYPE_FALCON_A = 0, + EFX_TYPE_FALCON_B = 1, +}; + +static struct efx_nic_type *efx_nic_types[] = { + [EFX_TYPE_FALCON_A] = &falcon_a_nic_type, + [EFX_TYPE_FALCON_B] = &falcon_b_nic_type, +}; + + +/* PCI device ID table */ +static struct pci_device_id efx_pci_table[] __devinitdata = { + {EFX_VENDID_SFC, FALCON_A_P_DEVID, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, EFX_TYPE_FALCON_A}, + {EFX_VENDID_SFC, FALCON_B_P_DEVID, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, EFX_TYPE_FALCON_B}, + {0} /* end of list */ +}; + +/************************************************************************** + * + * Dummy PHY/MAC/Board operations + * + * Can be used where the MAC does not implement this operation + * Needed so all function pointers are valid and do not have to be tested + * before use + * + **************************************************************************/ +int efx_port_dummy_op_int(struct efx_nic *efx) +{ + return 0; +} +void efx_port_dummy_op_void(struct efx_nic *efx) {} +void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {} + +static struct efx_mac_operations efx_dummy_mac_operations = { + .init = efx_port_dummy_op_int, + .reconfigure = efx_port_dummy_op_void, + .fini = efx_port_dummy_op_void, +}; + +static struct efx_phy_operations efx_dummy_phy_operations = { + .init = efx_port_dummy_op_int, + .reconfigure = efx_port_dummy_op_void, + .check_hw = efx_port_dummy_op_int, + .fini = efx_port_dummy_op_void, + .clear_interrupt = efx_port_dummy_op_void, + .reset_xaui = efx_port_dummy_op_void, +}; + +/* Dummy board operations */ +static int efx_nic_dummy_op_int(struct efx_nic *nic) +{ + return 0; +} + +static void efx_nic_dummy_op_void(struct efx_nic *nic) {} + +static struct efx_board efx_dummy_board_info = { + .init = efx_nic_dummy_op_int, + .init_leds = efx_port_dummy_op_int, + .set_fault_led = efx_port_dummy_op_blink, + .monitor = efx_nic_dummy_op_int, + .blink = efx_port_dummy_op_blink, + .fini = efx_nic_dummy_op_void, +}; + +/************************************************************************** + * + * Data housekeeping + * + **************************************************************************/ + +/* This zeroes out and then fills in the invariants in a struct + * efx_nic (including all sub-structures). + */ +static int efx_init_struct(struct efx_nic *efx, enum efx_type_index type, + struct pci_dev *pci_dev) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + int i, rc; + + /* Initialise common structures */ + memset(efx, 0, sizeof(*efx)); + spin_lock_init(&efx->biu_lock); + spin_lock_init(&efx->phy_lock); + mutex_init(&efx->spi_lock); + sema_init(&efx->suspend_lock, 1); + INIT_WORK(&efx->reset_work, efx_reset_work); + INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); + efx->pci_dev = pci_dev; + efx->state = STATE_INIT; + efx->reset_pending = RESET_TYPE_NONE; + strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); + efx->board_info = efx_dummy_board_info; + + efx->rx_checksum_enabled = 1; + spin_lock_init(&efx->netif_stop_lock); + spin_lock_init(&efx->stats_lock); + mutex_init(&efx->mac_lock); + efx->mac_op = &efx_dummy_mac_operations; + efx->phy_op = &efx_dummy_phy_operations; + INIT_LIST_HEAD(&efx->dl_node); + INIT_LIST_HEAD(&efx->dl_device_list); + efx->dl_cb = efx_default_callbacks; + INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); + atomic_set(&efx->netif_stop_count, 1); + + for (i = 0; i < EFX_MAX_CHANNELS; i++) { + channel = &efx->channel[i]; + channel->efx = efx; + channel->channel = i; + channel->evqnum = i; + channel->work_pending = 0; + } + for (i = 0; i < EFX_MAX_TX_QUEUES; i++) { + tx_queue = &efx->tx_queue[i]; + tx_queue->efx = efx; + tx_queue->queue = i; + tx_queue->buffer = NULL; + tx_queue->channel = &efx->channel[0]; /* for safety */ + } + for (i = 0; i < EFX_MAX_RX_QUEUES; i++) { + rx_queue = &efx->rx_queue[i]; + rx_queue->efx = efx; + rx_queue->queue = i; + rx_queue->channel = &efx->channel[0]; /* for safety */ + rx_queue->buffer = NULL; + spin_lock_init(&rx_queue->add_lock); + INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work); + } + + efx->type = efx_nic_types[type]; + + /* Sanity-check NIC type */ + EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask & + (efx->type->txd_ring_mask + 1)); + EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask & + (efx->type->rxd_ring_mask + 1)); + EFX_BUG_ON_PARANOID(efx->type->evq_size & + (efx->type->evq_size - 1)); + /* As close as we can get to guaranteeing that we don't overflow */ + EFX_BUG_ON_PARANOID(efx->type->evq_size < + (efx->type->txd_ring_mask + 1 + + efx->type->rxd_ring_mask + 1)); + + EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); + + /* Higher numbered interrupt modes are less capable! */ + efx->interrupt_mode = max(efx->type->max_interrupt_mode, + interrupt_mode); +#if defined(EFX_NEED_DUMMY_MSIX) + if (efx->interrupt_mode == EFX_INT_MODE_MSIX) + efx->interrupt_mode = EFX_INT_MODE_MSI; +#endif + + /* Tasks that can fail are last */ + efx->refill_workqueue = create_workqueue("sfc_refill"); + if (!efx->refill_workqueue) { + rc = -ENOMEM; + goto fail1; + } + + efx->workqueue = create_singlethread_workqueue("sfc_work"); + if (!efx->workqueue) { + rc = -ENOMEM; + goto fail2; + } + +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + efx->reset_workqueue = create_singlethread_workqueue("sfc_reset"); + if (!efx->reset_workqueue) { + rc = -ENOMEM; + goto fail3; + } +#endif + + return 0; + +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + fail3: + destroy_workqueue(efx->workqueue); + efx->workqueue = NULL; +#endif + + fail2: + destroy_workqueue(efx->refill_workqueue); + efx->refill_workqueue = NULL; + fail1: + return rc; +} + +static void efx_fini_struct(struct efx_nic *efx) +{ +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + if (efx->reset_workqueue) { + destroy_workqueue(efx->reset_workqueue); + efx->reset_workqueue = NULL; + } +#endif + if (efx->workqueue) { + destroy_workqueue(efx->workqueue); + efx->workqueue = NULL; + } + if (efx->refill_workqueue) { + destroy_workqueue(efx->refill_workqueue); + efx->refill_workqueue = NULL; + } +} + +/************************************************************************** + * + * PCI interface + * + **************************************************************************/ + +/* Main body of final NIC shutdown code + * This is called only at module unload (or hotplug removal). + */ +static void efx_pci_remove_main(struct efx_nic *efx) +{ + ASSERT_RTNL(); + + /* Skip everything if we never obtained a valid membase */ + if (!efx->membase) + return; + + efx_fini_channels(efx); + efx_fini_port(efx); + + /* Shutdown the board, then the NIC and board state */ + efx->board_info.fini(efx); + falcon_fini_nic(efx); + falcon_fini_interrupt(efx); + efx->board_info.fini(efx); + + /* Tear down NAPI and LRO */ + efx_fini_napi(efx); + efx_remove_all(efx); +} + +/* Final NIC shutdown + * This is called only at module unload (or hotplug removal). + */ +static void efx_pci_remove(struct pci_dev *pci_dev) +{ + struct efx_nic *efx; + + efx = pci_get_drvdata(pci_dev); + if (!efx) + return; + + /* Unregister driver from driverlink layer */ + efx_dl_unregister_nic(efx); + + /* Mark the NIC as fini under both suspend_lock and + * rtnl_lock */ + down(&efx->suspend_lock); + rtnl_lock(); + efx->state = STATE_FINI; + up(&efx->suspend_lock); + + if (efx->membase) { + /* Stop the NIC. Since we're in STATE_FINI, this + * won't be reversed. */ + if (efx->net_dev_registered) + dev_close(efx->net_dev); + + /* Release the rtnl lock. Any queued efx_resets() + * can now return early [we're in STATE_FINI]. */ + rtnl_unlock(); + + efx_unregister_netdev(efx); + efx_fini_debugfs_channels(efx); + + /* Wait for any scheduled resets to complete. No more will be + * scheduled from this point because efx_stop_all() has been + * called, we are no longer registered with driverlink, and + * the net_device's have been removed. */ +#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC) + flush_workqueue(efx->reset_workqueue); +#else + flush_workqueue(efx->workqueue); +#endif + + /* Fini and remove all the software state */ + rtnl_lock(); + efx_pci_remove_main(efx); + } + + rtnl_unlock(); + + efx_fini_io(efx); + EFX_LOG(efx, "shutdown successful\n"); + + pci_set_drvdata(pci_dev, NULL); + efx_fini_struct(efx); + kfree(efx); +}; + +/* Main body of NIC initialisation + * This is called at module load (or hotplug insertion, theoretically). + */ +static int efx_pci_probe_main(struct efx_nic *efx) +{ + int rc; + + /* Do start-of-day initialisation */ + rc = efx_probe_all(efx); + if (rc) + goto fail1; + + /* Initialise port/channel net_dev's */ + rc = efx_init_napi(efx); + if (rc) + goto fail2; + + /* Initialise the board */ + rc = efx->board_info.init(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise board\n"); + goto fail3; + } + + /* Initialise device */ + rc = falcon_init_nic(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise NIC\n"); + goto fail4; + } + + /* Initialise port */ + rc = efx_init_port(efx); + if (rc) { + EFX_ERR(efx, "failed to initialise port\n"); + goto fail5; + } + + /* Initialise channels */ + rc = efx_init_channels(efx); + if (rc) + goto fail6; + + rc = falcon_init_interrupt(efx); + if (rc) + goto fail7; + + /* Start up device - interrupts can occur from this point */ + efx_start_all(efx); + + /* Check basic functionality and set interrupt mode */ + rc = efx_run_selftests(efx); + if (rc) + goto fail8; + + /* Stop the NIC */ + efx_stop_all(efx); + + return 0; + + fail8: + efx_stop_all(efx); + falcon_fini_interrupt(efx); + fail7: + efx_fini_channels(efx); + fail6: + efx_fini_port(efx); + fail5: + falcon_fini_nic(efx); + fail4: + efx->board_info.fini(efx); + fail3: + efx_fini_napi(efx); + fail2: + efx_remove_all(efx); + fail1: + return rc; +} + +/* NIC initialisation + * + * This is called at module load (or hotplug insertion, + * theoretically). It sets up PCI mappings, tests and resets the NIC, + * sets up and registers the network devices with the kernel and hooks + * the interrupt service routine. It does not prepare the device for + * transmission; this is left to the first time one of the network + * interfaces is brought up (i.e. efx_net_open). + */ +static int __devinit efx_pci_probe(struct pci_dev *pci_dev, + const struct pci_device_id *entry) +{ + struct efx_nic *efx; + enum efx_type_index type = entry->driver_data; + int i, rc; + + /* Allocate and initialise a struct efx_nic */ + efx = kmalloc(sizeof(*efx), GFP_KERNEL); + if (!efx) { + rc = -ENOMEM; + goto fail1; + } + pci_set_drvdata(pci_dev, efx); + rc = efx_init_struct(efx, type, pci_dev); + if (rc) + goto fail2; + + EFX_INFO(efx, "Solarflare Communications NIC detected\n"); + + /* Set up basic I/O (BAR mappings etc) */ + rc = efx_init_io(efx); + if (rc) + goto fail3; + + /* From this point on we begin to expose the driver to the OS + * to varying degrees, so lets grab the suspend_lock and + * rtnl_lock to serialise against efx_reset() and + * friends. efx->state is not STATE_RUNNING yet, but we don't + * want these tasks to fail, just to block until we drop the + * lock + */ + rc = down_interruptible(&efx->suspend_lock); + if (rc) { + EFX_ERR(efx, "suspend interrupted - aborting\n"); + goto fail4; + } + + rtnl_lock(); + + /* Probe, initialise and start everything. Run self-test */ + for (i = 0; i < 5; i++) { + rc = efx_pci_probe_main(efx); + if (rc == 0) + break; + + /* Retry if a recoverably reset event has been scheduled */ + if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && + (efx->reset_pending != RESET_TYPE_ALL)) + goto fail5; + + /* Serialise against efx_reset(). No more resets will be + * scheduled since efx_stop_all() has been called, and we + * have not and never have been registered with either + * the rtnetlink or driverlink layers. */ + rtnl_unlock(); + up(&efx->suspend_lock); + +#if defined(EFX_USE_CANCEL_WORK_SYNC) + cancel_work_sync(&efx->reset_work); +#else + flush_workqueue(efx->reset_workqueue); +#endif + + down(&efx->suspend_lock); + rtnl_lock(); + + efx->reset_pending = RESET_TYPE_NONE; + }; + if (rc) { + EFX_ERR(efx, "Could not reset NIC\n"); + goto fail5; + } + + /* Self-tests have all passed */ + rc = efx_init_debugfs_channels(efx); + if (rc) + goto fail6; + + /* Switch to the running state before we expose the device to + * the OS. This is to ensure that the initial gathering of + * MAC stats succeeds. */ + efx->state = STATE_RUNNING; + + rtnl_unlock(); + + rc = efx_register_netdev(efx); + if (rc) + goto fail7; + + up(&efx->suspend_lock); + + EFX_LOG(efx, "initialisation successful\n"); + + /* Register with driverlink layer */ + rc = efx_dl_register_nic(efx); + if (rc) + goto fail8; + + return 0; + + fail8: + down(&efx->suspend_lock); + efx_unregister_netdev(efx); + fail7: + /* Re-acquire the rtnl lock around pci_remove_main() */ + rtnl_lock(); + efx_fini_debugfs_channels(efx); + fail6: + efx_pci_remove_main(efx); + fail5: + /* Drop the locks before fini */ + rtnl_unlock(); + up(&efx->suspend_lock); + fail4: + efx_fini_io(efx); + fail3: + efx_fini_struct(efx); + fail2: + kfree(efx); + fail1: + EFX_LOG(efx, "initialisation failed. rc=%d\n", rc); + return rc; +} + +/* PCI driver definition */ +static struct pci_driver efx_pci_driver = { + .name = EFX_DRIVER_NAME, + .id_table = efx_pci_table, + .probe = efx_pci_probe, + .remove = efx_pci_remove, +}; + +/************************************************************************** + * + * Kernel module interface + * + *************************************************************************/ + +module_param(interrupt_mode, uint, 0444); +MODULE_PARM_DESC(interrupt_mode, + "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)"); + +module_param(onload_offline_selftest, uint, 0444); +MODULE_PARM_DESC(onload_offline_selftest, "Perform offline selftest on load"); + +static int __init efx_init_module(void) +{ + int rc; + + printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n"); + + rc = efx_init_debugfs(); + if (rc) + goto err_debugfs; + + rc = register_netdevice_notifier(&efx_netdev_notifier); + if (rc) + goto err_notifier; + + rc = pci_register_driver(&efx_pci_driver); + if (rc < 0) + goto err_pci; + + return 0; + + err_pci: + unregister_netdevice_notifier(&efx_netdev_notifier); + err_notifier: + efx_fini_debugfs(); + err_debugfs: + return rc; +} + +static void __exit efx_exit_module(void) +{ + printk(KERN_INFO "Solarflare NET driver unloading\n"); + + pci_unregister_driver(&efx_pci_driver); + unregister_netdevice_notifier(&efx_netdev_notifier); + efx_fini_debugfs(); + +} + +module_init(efx_init_module); +module_exit(efx_exit_module); + +MODULE_AUTHOR("Michael Brown <mbrown@xxxxxxxxxxxxxxxx> and " + "Solarflare Communications"); +MODULE_DESCRIPTION("Solarflare Communications network driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, efx_pci_table); diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/efx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/efx.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,103 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_EFX_H +#define EFX_EFX_H + +#include "net_driver.h" + +/* PCI IDs */ +#define EFX_VENDID_SFC 0x1924 +#define FALCON_A_P_DEVID 0x0703 +#define FALCON_A_S_DEVID 0x6703 +#define FALCON_B_P_DEVID 0x0710 + +/* TX */ +extern int efx_xmit(struct efx_nic *efx, + struct efx_tx_queue *tx_queue, struct sk_buff *skb); +extern void efx_stop_queue(struct efx_nic *efx); +extern void efx_wake_queue(struct efx_nic *efx); + +/* RX */ +#if defined(EFX_USE_FASTCALL) +extern void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue, + unsigned int index); +#else +extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); +#endif +#if defined(EFX_USE_FASTCALL) +extern void fastcall efx_rx_packet(struct efx_rx_queue *rx_queue, + unsigned int index, unsigned int len, + int checksummed, int discard); +#else +extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, + unsigned int len, int checksummed, int discard); +#endif +extern void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue, + struct efx_rx_buffer *rx_buf); + +/* Channels */ +extern void efx_process_channel_now(struct efx_channel *channel); +extern int efx_flush_queues(struct efx_nic *efx); + +/* Ports */ +extern void efx_reconfigure_port(struct efx_nic *efx, + int on_disabled); + +/* Global */ +extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); +extern void efx_suspend(struct efx_nic *efx); +extern void efx_resume(struct efx_nic *efx); +extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, + int rx_usecs); +extern int efx_request_power(struct efx_nic *efx, int mw, const char *name); +extern void efx_hex_dump(const u8 *, unsigned int, const char *); + +/* Dummy PHY ops for PHY drivers */ +extern int efx_port_dummy_op_int(struct efx_nic *efx); +extern void efx_port_dummy_op_void(struct efx_nic *efx); +extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink); + + +extern unsigned int efx_monitor_interval; + +static inline void efx_schedule_channel(struct efx_channel *channel) +{ + EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n", + channel->channel, raw_smp_processor_id()); + channel->work_pending = 1; + +#if defined(EFX_HAVE_OLD_NAPI) + if (!test_and_set_bit(__LINK_STATE_RX_SCHED, &channel->napi_dev->state)) + __netif_rx_schedule(channel->napi_dev); +#else + netif_rx_schedule(channel->napi_dev, &channel->napi_str); +#endif +} + + +#endif /* EFX_EFX_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/enum.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/enum.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,117 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2007: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Developed by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_ENUM_H +#define EFX_ENUM_H + +/** + * enum efx_loopback_mode - loopback modes + * @LOOPBACK_NONE: no loopback + * @LOOPBACK_NEAR: loopback nearest to bus + * @LOOPBACK_MAC: loopback within MAC unspecified level + * @LOOPBACK_XGMII: loopback within MAC at XGMII level + * @LOOPBACK_XGXS: loopback within MAC at XGXS level + * @LOOPBACK_XAUI: loopback within MAC at XAUI level + * @LOOPBACK_PHY: loopback within PHY unspecified level + * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level + * @LOOPBACK_PCS: loopback within PHY at PCS level + * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level + * @LOOPBACK_FAR: loopback furthest from bus + * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) + */ +/* Please keep in order and up-to-date w.r.t the following two #defines */ +enum efx_loopback_mode { + LOOPBACK_NONE = 0, + LOOPBACK_NEAR = 1, + LOOPBACK_MAC = 2, + LOOPBACK_XGMII = 3, + LOOPBACK_XGXS = 4, + LOOPBACK_XAUI = 5, + LOOPBACK_PHY = 6, + LOOPBACK_PHYXS = 7, + LOOPBACK_PCS = 8, + LOOPBACK_PMAPMD = 9, + LOOPBACK_FAR = 10, + LOOPBACK_NETWORK = 11, + LOOPBACK_MAX +}; +#define LOOPBACK_TEST_MAX LOOPBACK_FAR + +/* These loopbacks occur within the controller */ +#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI)) + +#define LOOPBACKS_1G_INTERNAL (1 << LOOPBACK_MAC) + +#define LOOPBACK_MASK(_efx) \ + (1 << (_efx)->loopback_mode) + +#define LOOPBACK_INTERNAL(_efx) \ + (((LOOPBACKS_10G_INTERNAL | LOOPBACKS_1G_INTERNAL) & \ + LOOPBACK_MASK(_efx)) ? 1 : 0) + +#define LOOPBACK_CHANGED(_from, _to, _mask) \ + ((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & \ + (_mask) ? 1 : 0) + +#define LOOPBACK_OUT_OF(_from, _to, _mask) \ + (((LOOPBACK_MASK(_from) & (_mask)) && \ + ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0) + +/*****************************************************************************/ + +/** + * enum reset_type - reset types + * + * %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and + * %RESET_TYPE_DISABLE specify the method/scope of the reset. The + * other valuesspecify reasons, which efx_schedule_reset() will choose + * a method for. + * + * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts + * @RESET_TYPE_ALL: reset everything but PCI core blocks + * @RESET_TYPE_WORLD: reset everything, save & restore PCI config + * @RESET_TYPE_DISABLE: disable NIC + * @RESET_TYPE_MONITOR: reset due to hardware monitor + * @RESET_TYPE_INT_ERROR: reset due to internal error + * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors + */ +enum reset_type { + RESET_TYPE_NONE = -1, + RESET_TYPE_INVISIBLE = 0, + RESET_TYPE_ALL = 1, + RESET_TYPE_WORLD = 2, + RESET_TYPE_DISABLE = 3, + RESET_TYPE_MAX_METHOD, + RESET_TYPE_MONITOR, + RESET_TYPE_INT_ERROR, + RESET_TYPE_RX_RECOVERY, + RESET_TYPE_RX_DESC_FETCH, + RESET_TYPE_TX_DESC_FETCH, + RESET_TYPE_MAX, +}; + +#endif /* EFX_ENUM_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/ethtool.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/ethtool.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,734 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include <linux/netdevice.h> +#include <linux/ethtool.h> +#include <linux/rtnetlink.h> +#include <asm/uaccess.h> +#include "net_driver.h" +#include "selftest.h" +#include "efx.h" +#include "ethtool.h" +#include "falcon.h" +#include "gmii.h" + +static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable); + +struct ethtool_string { + char name[ETH_GSTRING_LEN]; +}; + +struct efx_ethtool_stat { + const char *name; + enum { + EFX_ETHTOOL_STAT_SOURCE_mac_stats, + EFX_ETHTOOL_STAT_SOURCE_nic, + EFX_ETHTOOL_STAT_SOURCE_channel + } source; + unsigned offset; + u64(*get_stat) (void *field); /* Reader function */ +}; + +/* Initialiser for a struct #efx_ethtool_stat with type-checking */ +#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \ + get_stat_function) { \ + .name = #stat_name, \ + .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \ + .offset = ((((field_type *) 0) == \ + &((struct efx_##source_name *)0)->field) ? \ + offsetof(struct efx_##source_name, field) : \ + offsetof(struct efx_##source_name, field)), \ + .get_stat = get_stat_function, \ +} + +static u64 efx_get_uint_stat(void *field) +{ + return *(unsigned int *)field; +} + +static u64 efx_get_ulong_stat(void *field) +{ + return *(unsigned long *)field; +} + +static u64 efx_get_u64_stat(void *field) +{ + return *(u64 *) field; +} + +static u64 efx_get_atomic_stat(void *field) +{ + return atomic_read((atomic_t *) field); +} + +#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \ + EFX_ETHTOOL_STAT(field, mac_stats, field, \ + unsigned long, efx_get_ulong_stat) + +#define EFX_ETHTOOL_U64_MAC_STAT(field) \ + EFX_ETHTOOL_STAT(field, mac_stats, field, \ + u64, efx_get_u64_stat) + +#define EFX_ETHTOOL_UINT_NIC_STAT(name) \ + EFX_ETHTOOL_STAT(name, nic, n_##name, \ + unsigned int, efx_get_uint_stat) + +#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \ + EFX_ETHTOOL_STAT(field, nic, errors.field, \ + atomic_t, efx_get_atomic_stat) + +#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \ + EFX_ETHTOOL_STAT(field, channel, n_##field, \ + unsigned int, efx_get_uint_stat) + +static struct efx_ethtool_stat efx_ethtool_stats[] = { + EFX_ETHTOOL_U64_MAC_STAT(tx_bytes), + EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes), + EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_control), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_64), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error), + EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error), + EFX_ETHTOOL_U64_MAC_STAT(rx_bytes), + EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes), + EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_good), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_control), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_64), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error), + EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error), + EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt), + EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), +}; + +/* Number of ethtool statistics */ +#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) + +/************************************************************************** + * + * Ethtool operations + * + ************************************************************************** + */ + +/* Identify device by flashing LEDs */ +static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds) +{ + struct efx_nic *efx = net_dev->priv; + + efx->board_info.blink(efx, 1); + schedule_timeout_interruptible(seconds * HZ); + efx->board_info.blink(efx, 0); + return 0; +} + +/* This must be called with rtnl_lock held. */ +int efx_ethtool_get_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd) +{ + struct efx_nic *efx = net_dev->priv; + + return efx->mac_op->get_settings(efx, ecmd); +} + +/* This must be called with rtnl_lock held. */ +int efx_ethtool_set_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd) +{ + struct efx_nic *efx = net_dev->priv; + int rc; + + rc = efx->mac_op->set_settings(efx, ecmd); + if (rc) + return rc; + + /* Push the settings to the MAC */ + efx_reconfigure_port(efx, 0); + + return 0; +} + +static void efx_ethtool_get_drvinfo(struct net_device *net_dev, + struct ethtool_drvinfo *info) +{ + struct efx_nic *efx = net_dev->priv; + + strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); + strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); +} + +/** + * efx_fill_test - fill in an individual self-test entry + * @test_index: Index of the test + * @strings: Ethtool strings, or %NULL + * @data: Ethtool test results, or %NULL + * @test: Pointer to test result (used only if data != %NULL) + * @unit_format: Unit name format (e.g. "channel\%d") + * @unit_id: Unit id (e.g. 0 for "channel0") + * @test_format: Test name format (e.g. "loopback.\%s.tx.sent") + * @test_id: Test id (e.g. "PHY" for "loopback.PHY.tx_sent") + * + * Fill in an individual self-test entry. + */ +static void efx_fill_test(unsigned int test_index, + struct ethtool_string *strings, u64 *data, + int *test, const char *unit_format, int unit_id, + const char *test_format, const char *test_id) +{ + struct ethtool_string unit_str, test_str; + + /* Fill data value, if applicable */ + if (data) + data[test_index] = *test; + + /* Fill string, if applicable */ + if (strings) { + snprintf(unit_str.name, sizeof(unit_str.name), + unit_format, unit_id); + snprintf(test_str.name, sizeof(test_str.name), + test_format, test_id); + snprintf(strings[test_index].name, + sizeof(strings[test_index].name), + "%-9s%-17s", unit_str.name, test_str.name); + } +} + +#define EFX_PORT_NAME "port%d", 0 + +/** + * efx_fill_loopback_test - fill in a block of loopback self-test entries + * @efx: Efx NIC + * @lb_tests: Efx loopback self-test results structure + * @mode: Loopback test mode + * @test_index: Starting index of the test + * @strings: Ethtool strings, or %NULL + * @data: Ethtool test results, or %NULL + * + * Fill in a block of loopback self-test entries. Return new test + * index. + */ +static int efx_fill_loopback_test(struct efx_nic *efx, + struct efx_loopback_self_tests *lb_tests, + enum efx_loopback_mode mode, + unsigned int test_index, + struct ethtool_string *strings, u64 *data) +{ + struct efx_tx_queue *tx_queue; + + efx_for_each_tx_queue(tx_queue, efx) { + efx_fill_test(test_index++, strings, data, + &lb_tests->tx_sent[tx_queue->queue], + EFX_TX_QUEUE_NAME(tx_queue), + "loopback.%s.tx_sent", + efx_loopback_mode_names[mode]); + efx_fill_test(test_index++, strings, data, + &lb_tests->tx_done[tx_queue->queue], + EFX_TX_QUEUE_NAME(tx_queue), + "loopback.%s.tx_done", + efx_loopback_mode_names[mode]); + } + efx_fill_test(test_index++, strings, data, + &lb_tests->rx_good, + EFX_PORT_NAME, + "loopback.%s.rx_good", + efx_loopback_mode_names[mode]); + efx_fill_test(test_index++, strings, data, + &lb_tests->rx_bad, + EFX_PORT_NAME, + "loopback.%s.rx_bad", + efx_loopback_mode_names[mode]); + + return test_index; +} + +/** + * efx_ethtool_fill_self_tests - get self-test details + * @efx: Efx NIC + * @tests: Efx self-test results structure, or %NULL + * @strings: Ethtool strings, or %NULL + * @data: Ethtool test results, or %NULL + * + * Get self-test number of strings, strings, and/or test results. + * Return number of strings (== number of test results). + * + * The reason for merging these three functions is to make sure that + * they can never be inconsistent. + */ +static int efx_ethtool_fill_self_tests(struct efx_nic *efx, + struct efx_self_tests *tests, + struct ethtool_string *strings, + u64 *data) +{ + struct efx_channel *channel; + unsigned int n = 0; + enum efx_loopback_mode mode; + + /* Interrupt */ + efx_fill_test(n++, strings, data, &tests->interrupt, + "core", 0, "interrupt", NULL); + + /* Event queues */ + efx_for_each_channel(channel, efx) { + efx_fill_test(n++, strings, data, + &tests->eventq_dma[channel->channel], + EFX_CHANNEL_NAME(channel), + "eventq.dma", NULL); + efx_fill_test(n++, strings, data, + &tests->eventq_int[channel->channel], + EFX_CHANNEL_NAME(channel), + "eventq.int", NULL); + efx_fill_test(n++, strings, data, + &tests->eventq_poll[channel->channel], + EFX_CHANNEL_NAME(channel), + "eventq.poll", NULL); + } + + /* PHY presence */ + efx_fill_test(n++, strings, data, &tests->phy_ok, + EFX_PORT_NAME, "phy_ok", NULL); + + /* Loopback tests */ + efx_fill_test(n++, strings, data, &tests->loopback_speed, + EFX_PORT_NAME, "loopback.speed", NULL); + efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, + EFX_PORT_NAME, "loopback.full_duplex", NULL); + for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) { + if (!(efx->loopback_modes & (1 << mode))) + continue; + n = efx_fill_loopback_test(efx, + &tests->loopback[mode], mode, n, + strings, data); + } + + return n; +} + +static int efx_ethtool_get_stats_count(struct net_device *net_dev) +{ + return EFX_ETHTOOL_NUM_STATS; +} + +static int efx_ethtool_self_test_count(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL); +} + +static void efx_ethtool_get_strings(struct net_device *net_dev, + u32 string_set, u8 *strings) +{ + struct efx_nic *efx = net_dev->priv; + struct ethtool_string *ethtool_strings = + (struct ethtool_string *)strings; + int i; + + switch (string_set) { + case ETH_SS_STATS: + for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) + strncpy(ethtool_strings[i].name, + efx_ethtool_stats[i].name, + sizeof(ethtool_strings[i].name)); + break; + case ETH_SS_TEST: + efx_ethtool_fill_self_tests(efx, NULL, + ethtool_strings, NULL); + break; + default: + /* No other string sets */ + break; + } +} + +static void efx_ethtool_get_stats(struct net_device *net_dev, + struct ethtool_stats *stats + __attribute__ ((unused)), u64 *data) +{ + unsigned long flags __attribute__ ((unused)); + struct efx_nic *efx = net_dev->priv; + struct efx_mac_stats *mac_stats = &efx->mac_stats; + struct efx_ethtool_stat *stat; + struct efx_channel *channel; + int i; + + EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); + + /* Update MAC and NIC statistics */ + net_dev->get_stats(net_dev); + falcon_update_nic_stats(efx); + + /* Fill detailed statistics buffer */ + for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { + stat = &efx_ethtool_stats[i]; + switch (stat->source) { + case EFX_ETHTOOL_STAT_SOURCE_mac_stats: + data[i] = stat->get_stat((void *)mac_stats + + stat->offset); + break; + case EFX_ETHTOOL_STAT_SOURCE_nic: + data[i] = stat->get_stat((void *)efx + stat->offset); + break; + case EFX_ETHTOOL_STAT_SOURCE_channel: + data[i] = 0; + efx_for_each_channel(channel, efx) + data[i] += stat->get_stat((void *)channel + + stat->offset); + break; + } + } +} + +static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx = net_dev->priv; + int rc; + + rc = ethtool_op_set_tx_csum(net_dev, enable); + if (rc) + return rc; + + + efx_flush_queues(efx); + + return 0; +} + +static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx = net_dev->priv; + + /* No way to stop the hardware doing the checks; we just + * ignore the result. + */ + efx->rx_checksum_enabled = (enable ? 1 : 0); + + return 0; +} + +static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + return efx->rx_checksum_enabled; +} + +static void efx_ethtool_self_test(struct net_device *net_dev, + struct ethtool_test *test, u64 *data) +{ + struct efx_nic *efx = net_dev->priv; + struct efx_self_tests efx_tests; + int offline, already_up; + int rc; + + /* Make sure we've got rtnl lock since we're playing with + * interrupts, and calling efx_process_channel_now and others + */ + ASSERT_RTNL(); + + /* If the NIC isn't in the RUNNING state then exit */ + if (efx->state != STATE_RUNNING) { + rc = -EIO; + goto fail1; + } + + /* Make sure the interface is up. We need interrupts, NAPI + * and some RX buffers so this is helpful. NB. The caller has + * rtnl_lock so nobody else can call dev_open. */ + already_up = (efx->net_dev->flags & IFF_UP); + if (!already_up) { + rc = dev_open(efx->net_dev); + if (rc) { + EFX_ERR(efx, "failed opening device.\n"); + goto fail2; + } + } + + memset(&efx_tests, 0, sizeof(efx_tests)); + offline = (test->flags & ETH_TEST_FL_OFFLINE); + + /* Perform online self tests first */ + rc = efx_online_test(efx, &efx_tests); + if (rc) + goto out; + + /* Perform offline tests only if online tests passed */ + if (offline) { + /* Stop the kernel from sending packets during the test. The + * selftest will be consistently bringing the port up and down + * as it moves between loopback modes, so the watchdog timer + * probably won't run anyway */ + efx_stop_queue(efx); + + rc = efx_flush_queues(efx); + if (rc != 0) + goto out_offline; + + rc = efx_offline_test(efx, &efx_tests, + efx->loopback_modes); + out_offline: + efx_wake_queue(efx); + } + + /* fall-thru */ + out: + if (!already_up) + dev_close(efx->net_dev); + + EFX_LOG(efx, "%s all %sline self-tests\n", + rc == 0 ? "passed" : "failed", offline ? "off" : "on"); + + fail2: + fail1: + /* Fill ethtool results structures */ + efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data); + if (rc) + test->flags |= ETH_TEST_FL_FAILED; +} + +/* Restart autonegotiation */ +static int efx_ethtool_nway_reset(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + return mii_nway_restart(&efx->mii); +} + +static u32 efx_ethtool_get_link(struct net_device *net_dev) +{ + struct efx_nic *efx = net_dev->priv; + + return efx->link_up; +} + +static int efx_ethtool_get_coalesce(struct net_device *net_dev, + struct ethtool_coalesce *coalesce) +{ + struct efx_nic *efx = net_dev->priv; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + struct efx_channel *channel; + + memset(coalesce, 0, sizeof(*coalesce)); + + /* Find lowest IRQ moderation across all used TX queues */ + coalesce->tx_coalesce_usecs_irq = ~((u32) 0); + efx_for_each_tx_queue(tx_queue, efx) { + channel = tx_queue->channel; + if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) { + if (channel->used_flags != EFX_USED_BY_RX_TX) + coalesce->tx_coalesce_usecs_irq = + channel->irq_moderation; + else + coalesce->tx_coalesce_usecs_irq = 0; + } + } + + /* Find lowest IRQ moderation across all used RX queues */ + coalesce->rx_coalesce_usecs_irq = ~((u32) 0); + efx_for_each_rx_queue(rx_queue, efx) { + channel = rx_queue->channel; + if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq) + coalesce->rx_coalesce_usecs_irq = + channel->irq_moderation; + } + + return 0; +} + +/* Set coalescing parameters + * The difficulties occur for shared channels + */ +static int efx_ethtool_set_coalesce(struct net_device *net_dev, + struct ethtool_coalesce *coalesce) +{ + struct efx_nic *efx = net_dev->priv; + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + unsigned tx_usecs, rx_usecs; + + if (coalesce->use_adaptive_rx_coalesce || + coalesce->use_adaptive_tx_coalesce) + return -EOPNOTSUPP; + + if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) { + EFX_ERR(efx, "invalid coalescing setting. " + "Only rx/tx_coalesce_usecs_irq are supported\n"); + return -EOPNOTSUPP; + } + + rx_usecs = coalesce->rx_coalesce_usecs_irq; + tx_usecs = coalesce->tx_coalesce_usecs_irq; + + /* If the channel is shared only allow RX parameters to be set */ + efx_for_each_tx_queue(tx_queue, efx) { + if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) && + tx_usecs) { + EFX_ERR(efx, "Channel is shared. " + "Only RX coalescing may be set\n"); + return -EOPNOTSUPP; + } + } + + efx_init_irq_moderation(efx, tx_usecs, rx_usecs); + + /* Reset channel to pick up new moderation value. Note that + * this may change the value of the irq_moderation field + * (e.g. to allow for hardware timer granularity). + */ + efx_for_each_channel(channel, efx) + falcon_set_int_moderation(channel); + + return 0; +} + +static int efx_ethtool_set_pauseparam(struct net_device *net_dev, + struct ethtool_pauseparam *pause) +{ + struct efx_nic *efx = net_dev->priv; + enum efx_fc_type flow_control = efx->flow_control; + int rc; + + flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO); + flow_control |= pause->rx_pause ? EFX_FC_RX : 0; + flow_control |= pause->tx_pause ? EFX_FC_TX : 0; + flow_control |= pause->autoneg ? EFX_FC_AUTO : 0; + + /* Try to push the pause parameters */ + rc = efx->mac_op->set_pause(efx, flow_control); + if (rc) + return rc; + + /* Push the settings to the MAC */ + efx_reconfigure_port(efx, 0); + + return 0; +} + +static void efx_ethtool_get_pauseparam(struct net_device *net_dev, + struct ethtool_pauseparam *pause) +{ + struct efx_nic *efx = net_dev->priv; + + pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0; + pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0; + pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0; +} + + +#if defined(EFX_USE_ETHTOOL_GET_PERM_ADDR) +static int efx_ethtool_op_get_perm_addr(struct net_device *net_dev, + struct ethtool_perm_addr *addr, + u8 *data) +{ + struct efx_nic *efx = net_dev->priv; + + memcpy(data, efx->mac_address, ETH_ALEN); + + return 0; +} +#endif + +struct ethtool_ops efx_ethtool_ops = { + .get_settings = efx_ethtool_get_settings, + .set_settings = efx_ethtool_set_settings, + .get_drvinfo = efx_ethtool_get_drvinfo, + .nway_reset = efx_ethtool_nway_reset, + .get_link = efx_ethtool_get_link, + .get_coalesce = efx_ethtool_get_coalesce, + .set_coalesce = efx_ethtool_set_coalesce, + .get_pauseparam = efx_ethtool_get_pauseparam, + .set_pauseparam = efx_ethtool_set_pauseparam, + .get_rx_csum = efx_ethtool_get_rx_csum, + .set_rx_csum = efx_ethtool_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = efx_ethtool_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, +#if defined(EFX_USE_ETHTOOL_FLAGS) + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, +#endif + .self_test_count = efx_ethtool_self_test_count, + .self_test = efx_ethtool_self_test, + .get_strings = efx_ethtool_get_strings, + .phys_id = efx_ethtool_phys_id, + .get_stats_count = efx_ethtool_get_stats_count, + .get_ethtool_stats = efx_ethtool_get_stats, +#if defined(EFX_USE_ETHTOOL_GET_PERM_ADDR) + .get_perm_addr = efx_ethtool_op_get_perm_addr, +#endif +}; diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/ethtool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/ethtool.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,44 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005: Fen Systems Ltd. + * Copyright 2006: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#ifndef EFX_ETHTOOL_H +#define EFX_ETHTOOL_H + +#include "net_driver.h" + +/* + * Ethtool support + */ + +extern int efx_ethtool_get_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd); +extern int efx_ethtool_set_settings(struct net_device *net_dev, + struct ethtool_cmd *ecmd); + +extern struct ethtool_ops efx_ethtool_ops; + +#endif /* EFX_ETHTOOL_H */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/extraversion.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/extraversion.h Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,4 @@ +/* + * If compiling on kernels with backported features you may need to + * define EFX_DIST_KVER_ symbols here + */ diff -r 31d71546a644 -r 594bfb5cbe40 drivers/net/sfc/falcon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/net/sfc/falcon.c Tue Feb 19 11:15:05 2008 -0700 @@ -0,0 +1,3708 @@ +/**************************************************************************** + * Driver for Solarflare network controllers + * (including support for SFE4001 10GBT NIC) + * + * Copyright 2005-2006: Fen Systems Ltd. + * Copyright 2006-2008: Solarflare Communications Inc, + * 9501 Jeronimo Road, Suite 250, + * Irvine, CA 92618, USA + * + * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx> + * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + **************************************************************************** + */ + +#include <asm/io.h> +#include <asm/bitops.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/seq_file.h> +#include "net_driver.h" +#include "bitfield.h" +#include "efx.h" +#include "mac.h" +#include "gmii.h" +#include "spi.h" +#include "falcon.h" +#include "falcon_hwdefs.h" +#include "falcon_io.h" +#include "mdio_10g.h" +#include "phy.h" +#include "boards.h" +#include "driverlink.h" +#include "workarounds.h" + +/* Falcon hardware control. + * Falcon is the internal codename for the SFC4000 controller that is + * present in SFE400X evaluation boards + */ + +struct falcon_nic_data { + /* Number of entries in each TX queue descriptor cache. */ + unsigned tx_dc_entries; + /* Number of entries in each RX queue descriptor cache. */ + unsigned rx_dc_entries; + /* Base address in SRAM of TX queue descriptor caches. */ + unsigned tx_dc_base; + /* Base address in SRAM of RX queue descriptor caches. */ + unsigned rx_dc_base; + + /* Previous loopback mode used in deconfigure_mac_wrapper */ + enum efx_loopback_mode old_loopback_mode; + + /* Driverlink parameters */ + struct efx_dl_falcon_resources resources; +}; + +/************************************************************************** + * + * Configurable values + * + ************************************************************************** + */ + +static int disable_dma_stats; + +/* Specify the size of the RX descriptor cache */ +static int descriptor_cache_size = 64; + +/* + * Override EEPROM/flash type from non-volatile configuration or GPIO; + * may need to be specified if bootstrapping from blank flash. + */ +static unsigned int eeprom_type = -1; +static unsigned int flash_type = -1; + +/* RX FIFO XOFF watermark + * + * When the amount of the RX FIFO increases used increases past this + * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) + * This also has an effect on RX/TX arbitration + */ +static int rx_xoff_thresh_bytes = -1; +module_param(rx_xoff_thresh_bytes, int, 0644); +MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); + +/* RX FIFO XON watermark + * + * When the amount of the RX FIFO used decreases below this + * watermark send XON. Only used if TX flow control is enabled (ethtool -A) + * This also has an effect on RX/TX arbitration + */ +static int rx_xon_thresh_bytes = -1; +module_param(rx_xon_thresh_bytes, int, 0644); +MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); + +/* TX descriptor ring size - min 512 max 4k */ +#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K +#define FALCON_TXD_RING_SIZE 1024 +#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1) + +/* RX descriptor ring size - min 512 max 4k */ +#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K +#define FALCON_RXD_RING_SIZE 1024 +#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1) + +/* Event queue size - max 32k */ +#define FALCON_EVQ_ORDER EVQ_SIZE_4K +#define FALCON_EVQ_SIZE 4096 +#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1) + +/* Max number of internal errors. After this resets will not be performed */ +#define FALCON_MAX_INT_ERRORS 4 + +/* Maximum period that we wait for flush events. If the flush event + * doesn't arrive in this period of time then we check if the queue + * was disabled anyway. */ +#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */ + +/************************************************************************** + * + * Falcon constants + * + ************************************************************************** + */ + +/* DMA address mask (up to 46-bit, avoiding compiler warnings) + * + * Note that it is possible to have a platform with 64-bit longs and + * 32-bit DMA addresses, or vice versa. EFX_DMA_MASK takes care of the + * platform DMA mask. + */ +#if BITS_PER_LONG == 64 +#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL) +#else +#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL) +#endif + +/* TX DMA length mask (13-bit) */ +#define FALCON_TX_DMA_MASK (8192 - 1) + +/* Alignment of special buffers (4KB) */ +#define FALCON_BUF_ALIGN 4096 + +/* Dummy SRAM size code */ +#define SRM_NB_BSZ_ONCHIP_ONLY (-1) + +/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */ +#define PCI_EXP_DEVCAP_PWR_VAL_LBN (18) +/* This field takes up bits 26 and 27. */ +#define PCI_EXP_DEVCAP_PWR_SCL_LBN (26) +#define PCI_EXP_LNKSTA_LNK_WID (0x3f0) +#define PCI_EXP_LNKSTA_LNK_WID_LBN (4) + + +/************************************************************************** + * + * Falcon hardware access + * + **************************************************************************/ + +/* Read the current event from the event queue */ +static inline efx_qword_t *falcon_event(struct efx_channel *channel, + unsigned int index) +{ + return (((efx_qword_t *) (channel->eventq.addr)) + index); +} + +/* See if an event is present + * + * We check both the high and low dword of the event for all ones. We + * wrote all ones when we cleared the event, and no valid event can + * have all ones in either its high or low dwords. This approach is + * robust against reordering. + * + * Note that using a single 64-bit comparison is incorrect; even + * though the CPU read will be atomic, the DMA write may not be. + */ +static inline int falcon_event_present(efx_qword_t *event) +{ + return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | + EFX_DWORD_IS_ALL_ONES(event->dword[1]))); +} + +/* Read dword from a Falcon PCIE core register */ +static void falcon_pcie_core_read_reg(struct efx_nic *efx, int address, + efx_dword_t *result) +{ + efx_oword_t temp; + + BUG_ON(FALCON_REV(efx) < FALCON_REV_B0); + BUG_ON(address & 3 || address < 0); + + EFX_POPULATE_OWORD_1(temp, PCIE_CORE_ADDR, address); + + falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG); + falcon_read(efx, &temp, PCIE_CORE_INDIRECT_REG); + /* Extract PCIE_CORE_VALUE without byte-swapping */ + BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 || + PCIE_CORE_VALUE_WIDTH != 32); + result->u32[0] = temp.u32[1]; +} + +/* Write dword to a Falcon PCIE core register */ +static void falcon_pcie_core_write_reg(struct efx_nic *efx, int address, + efx_dword_t value) +{ + efx_oword_t temp; + + BUG_ON(FALCON_REV(efx) < FALCON_REV_B0); + BUG_ON(address & 0x3 || address < 0); + + EFX_POPULATE_OWORD_2(temp, + PCIE_CORE_ADDR, address, + PCIE_CORE_RW, 1); + /* Fill PCIE_CORE_VALUE without byte-swapping */ + BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 || + PCIE_CORE_VALUE_WIDTH != 32); + temp.u32[1] = value.u32[0]; + falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG); +} + +/************************************************************************** + * + * I2C bus - this is a bit-bashing interface using GPIO pins + * Note that it uses the output enables to tristate the outputs + * SDA is the data pin and SCL is the clock + * + ************************************************************************** + */ +static void falcon_setsdascl(struct efx_i2c_interface *i2c) +{ + efx_oword_t reg; + + falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1)); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1)); + falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER); +} + +static int falcon_getsda(struct efx_i2c_interface *i2c) +{ + efx_oword_t reg; + + falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); + return EFX_OWORD_FIELD(reg, GPIO3_IN); +} + +static int falcon_getscl(struct efx_i2c_interface *i2c) +{ + efx_oword_t reg; + + falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER); + return EFX_DWORD_FIELD(reg, GPIO0_IN); +} + +static struct efx_i2c_bit_operations falcon_i2c_bit_operations = { + .setsda = falcon_setsdascl, + .setscl = falcon_setsdascl, + .getsda = falcon_getsda, + .getscl = falcon_getscl, + .udelay = 100, + .mdelay = 10, +}; + +/************************************************************************** + * + * Falcon special buffer handling + * Special buffers are used for event queues and the TX and RX + * descriptor rings. + * + *************************************************************************/ + +/* Adds the relevant entries to the full-mode buffer table. */ +static int +falcon_pin_special_buffer_full(struct efx_nic *efx, + struct efx_special_buffer *buffer) +{ + efx_qword_t buf_desc; + int index; + dma_addr_t dma_addr; + int i; + + /* Write buffer descriptors to NIC */ + for (i = 0; i < buffer->entries; i++) { + index = buffer->index + i; + dma_addr = buffer->dma_addr + (i * 4096); + EFX_LOG(efx, "mapping special buffer %d at %llx\n", + index, (unsigned long long)dma_addr); + EFX_POPULATE_QWORD_4(buf_desc, + IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K, + BUF_ADR_REGION, 0, + BUF_ADR_FBUF, (dma_addr >> 12), + BUF_OWNER_ID_FBUF, 0); + falcon_write_sram(efx, &buf_desc, index); + } + + return 0; +} + +/* Clears the relevant entries from the buffer table */ +static void +falcon_clear_special_buffer_full(struct efx_nic *efx, + struct efx_special_buffer *buffer) +{ + efx_oword_t buf_tbl_upd; + unsigned int start = buffer->index; + unsigned int end = (buffer->index + buffer->entries - 1); + + EFX_LOG(efx, "unmapping special buffers %d-%d\n", + buffer->index, buffer->index + buffer->entries - 1); + + EFX_POPULATE_OWORD_4(buf_tbl_upd, + BUF_UPD_CMD, 0, + BUF_CLR_CMD, 1, + BUF_CLR_END_ID, end, + BUF_CLR_START_ID, start); + falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER); +} + +/* + * Allocate a new Falcon special buffer + * + * This allocates memory for a new buffer, clears it and allocates a + * new buffer ID range. It does not write into Falcon's buffer table. + * + * This call will allocate 4kB buffers, since Falcon can't use 8kB + * buffers for event queues and descriptor rings. It will always + * allocate an even number of 4kB buffers, since when we're in + * half-entry mode for the buffer table we can only deal with pairs of + * buffers. + */ +static int falcon_alloc_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer, + unsigned int len) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + + /* Round size up to an 8kB boundary (i.e. pairs of 4kB buffers) */ + len = (len + 8192 - 1) & ~(8192 - 1); + + /* Allocate buffer as consistent PCI DMA space */ + buffer->addr = pci_alloc_consistent(efx->pci_dev, len, + &buffer->dma_addr); + if (!buffer->addr) + return -ENOMEM; + buffer->len = len; + buffer->entries = len / 4096; + BUG_ON(buffer->dma_addr & (FALCON_BUF_ALIGN - 1)); + + /* All zeros is a potentially valid event so memset to 0xff */ + memset(buffer->addr, 0xff, len); + + /* Select new buffer ID */ + buffer->index = nic_data->resources.buffer_table_min; + nic_data->resources.buffer_table_min += buffer->entries; + + EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " + "(virt %p phys %lx)\n", buffer->index, + buffer->index + buffer->entries - 1, + (unsigned long long)buffer->dma_addr, len, + buffer->addr, virt_to_phys(buffer->addr)); + + return 0; +} + +/* + * Initialise a Falcon special buffer + * + * This will define a buffer (previously allocated via + * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing + * it to be used for event queues, descriptor rings etc. + */ +static int falcon_init_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer) +{ + EFX_BUG_ON_PARANOID(!buffer->addr); + + /* Write buffer descriptors to NIC */ + return falcon_pin_special_buffer_full(efx, buffer); +} + +/* Unmaps a buffer from Falcon and clears the buffer table + * entries */ +static void falcon_fini_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer) +{ + + if (!buffer->entries) + return; + + falcon_clear_special_buffer_full(efx, buffer); +} + +/* Release the buffer memory. */ +static void falcon_free_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer) +{ + if (!buffer->addr) + return; + + EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " + "(virt %p phys %lx)\n", buffer->index, + buffer->index + buffer->entries - 1, + (unsigned long long)buffer->dma_addr, buffer->len, + buffer->addr, virt_to_phys(buffer->addr)); + + pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, + buffer->dma_addr); + buffer->addr = NULL; + buffer->entries = 0; +} + +/************************************************************************** + * + * Falcon generic buffer handling + * These buffers are used for interrupt status and MAC stats + * + **************************************************************************/ + +static int falcon_alloc_buffer(struct efx_nic *efx, + struct efx_buffer *buffer, unsigned int len) +{ + buffer->addr = pci_alloc_consistent(efx->pci_dev, len, + &buffer->dma_addr); + if (!buffer->addr) + return -ENOMEM; + buffer->len = len; + memset(buffer->addr, 0, len); + return 0; +} + +static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) +{ + if (buffer->addr) { + pci_free_consistent(efx->pci_dev, buffer->len, + buffer->addr, buffer->dma_addr); + buffer->addr = NULL; + } +} + +/************************************************************************** + * + * Falcon TX path + * + **************************************************************************/ + +/* Returns a pointer to the specified transmit descriptor in the TX + * descriptor queue belonging to the specified channel. + */ +static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue, + unsigned int index) +{ + return (((efx_qword_t *) (tx_queue->txd.addr)) + index); +} + +/* Update TX descriptor write pointer + * This writes to the TX_DESC_WPTR register for the specified + * channel's transmit descriptor ring. + */ +static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) +{ + unsigned write_ptr; + efx_dword_t reg; + + write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; + EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr); + falcon_writel_page(tx_queue->efx, ®, + TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue); +} + + +/* For each entry inserted into the software descriptor ring, create a + * descriptor in the hardware TX descriptor ring (in host memory), and + * write a doorbell. + */ +#if defined(EFX_USE_FASTCALL) +void fastcall falcon_push_buffers(struct efx_tx_queue *tx_queue) +#else +void falcon_push_buffers(struct efx_tx_queue *tx_queue) +#endif +{ + + struct efx_tx_buffer *buffer; + efx_qword_t *txd; + unsigned write_ptr; + + BUG_ON(tx_queue->write_count == tx_queue->insert_count); + + do { + write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; + buffer = &tx_queue->buffer[write_ptr]; + txd = falcon_tx_desc(tx_queue, write_ptr); + ++tx_queue->write_count; + + /* Create TX descriptor ring entry */ + EFX_POPULATE_QWORD_5(*txd, + TX_KER_PORT, 0, + TX_KER_CONT, buffer->continuation, + TX_KER_BYTE_CNT, buffer->len, + TX_KER_BUF_REGION, 0, + TX_KER_BUF_ADR, buffer->dma_addr); + } while (tx_queue->write_count != tx_queue->insert_count); + + wmb(); /* Ensure descriptors are written before they are fetched */ + falcon_notify_tx_desc(tx_queue); +} + +/* Allocate hardware resources for a TX queue */ +int falcon_probe_tx(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + struct falcon_nic_data *nic_data = efx->nic_data; + int rc; + + rc = falcon_alloc_special_buffer(efx, &tx_queue->txd, + FALCON_TXD_RING_SIZE * + sizeof(efx_qword_t)); + if (rc) + return rc; + + nic_data->resources.txq_min = max(nic_data->resources.txq_min, + (unsigned)tx_queue->queue + 1); + + return 0; +} + +/* Prepare channel's TX datapath. */ +int falcon_init_tx(struct efx_tx_queue *tx_queue) +{ + efx_oword_t tx_desc_ptr; + struct efx_nic *efx = tx_queue->efx; + int rc; + + /* Pin TX descriptor ring */ + rc = falcon_init_special_buffer(efx, &tx_queue->txd); + if (rc) + return rc; + + /* Push TX descriptor ring to card */ + EFX_POPULATE_OWORD_10(tx_desc_ptr, + TX_DESCQ_EN, 1, + TX_ISCSI_DDIG_EN, 0, + TX_ISCSI_HDIG_EN, 0, + TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, + TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum, + TX_DESCQ_OWNER_ID, 0, + TX_DESCQ_LABEL, tx_queue->queue, + TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER, + TX_DESCQ_TYPE, 0, /* kernel queue */ + TX_NON_IP_DROP_DIS_B0, 1); + + if (FALCON_REV(efx) >= FALCON_REV_B0) { + int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM); + EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum); + EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum); + } + + falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, + tx_queue->queue); + + if (FALCON_REV(efx) < FALCON_REV_B0) { + efx_oword_t reg; + + /* Only 128 bits in this register */ + BUG_ON(tx_queue->queue >= 128); + + falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1); + if (efx->net_dev->features & NETIF_F_IP_CSUM) + clear_bit_le(tx_queue->queue, (void *)®); + else + set_bit_le(tx_queue->queue, (void *)®); + falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1); + } + + return 0; +} + +static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + struct efx_channel *channel = &efx->channel[0]; + efx_oword_t tx_flush_descq; + unsigned int read_ptr, i; + + /* Post a flush command */ + EFX_POPULATE_OWORD_2(tx_flush_descq, + TX_FLUSH_DESCQ_CMD, 1, + TX_FLUSH_DESCQ, tx_queue->queue); + falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER); + msleep(FALCON_FLUSH_TIMEOUT); + + /* If the NIC is resetting then don't bother checking */ + if (EFX_WORKAROUND_7803(efx) || (efx->state == STATE_RESETTING)) + return 0; + + /* Look for a flush completed event */ + read_ptr = channel->eventq_read_ptr; + for (i = 0; i < FALCON_EVQ_SIZE; ++i) { + efx_qword_t *event = falcon_event(channel, read_ptr); + int ev_code, ev_sub_code, ev_queue; + if (!falcon_event_present(event)) + break; + _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |