From 016a03d2d518388594d774d12b9e099df094c36f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:32:25 -0500 Subject: [PATCH] Import 2.3.50pre1 --- Documentation/Configure.help | 25 +- Documentation/networking/cs89x0.txt | 1301 +++++++++++----------- Makefile | 2 +- arch/i386/kernel/irq.c | 6 +- arch/i386/mm/init.c | 2 +- arch/ppc/configs/common_defconfig | 19 +- arch/ppc/defconfig | 19 +- arch/ppc/kernel/Makefile | 4 +- arch/ppc/kernel/feature.c | 3 + arch/ppc/kernel/head.S | 11 +- arch/ppc/kernel/irq.c | 159 +++ arch/ppc/kernel/pci.c | 50 - arch/ppc/kernel/pmac_pic.c | 1 + arch/ppc/kernel/pmac_setup.c | 17 +- arch/ppc/kernel/ppc_htab.c | 12 +- arch/ppc/kernel/prom.c | 80 +- arch/ppc/kernel/setup.c | 10 +- arch/ppc/mm/init.c | 5 +- arch/ppc/xmon/start.c | 26 +- arch/ppc/xmon/xmon.c | 32 +- arch/sparc64/kernel/setup.c | 10 +- arch/sparc64/lib/blockops.S | 38 +- arch/sparc64/mm/init.c | 86 +- arch/sparc64/mm/ultra.S | 56 +- drivers/block/Config.in | 6 +- drivers/block/ali14xx.c | 4 +- drivers/block/cpqarray.h | 1 - drivers/block/ide-cd.c | 6 +- drivers/block/ide-pmac.c | 2 +- drivers/block/ide-proc.c | 1 + drivers/block/nbd.c | 1 + drivers/cdrom/cdrom.c | 81 +- drivers/char/epca.c | 5 +- drivers/char/istallion.c | 4 +- drivers/char/stradis.c | 18 +- drivers/char/videodev.c | 3 - drivers/isdn/avmb1/b1dma.c | 2 +- drivers/isdn/avmb1/c4.c | 2 +- drivers/net/3c505.c | 1 - drivers/net/3c515.c | 1 + drivers/net/3c523.c | 5 +- drivers/net/Config.in | 26 +- drivers/net/Makefile | 14 +- drivers/net/acenic.c | 312 ++++-- drivers/net/acenic.h | 6 +- drivers/net/appletalk/Config.in | 20 + drivers/net/appletalk/Makefile | 30 + drivers/net/{ => appletalk}/cops.c | 0 drivers/net/{ => appletalk}/cops.h | 0 drivers/net/{ => appletalk}/cops_ffdrv.h | 0 drivers/net/{ => appletalk}/cops_ltdrv.h | 0 drivers/net/{ => appletalk}/ipddp.c | 0 drivers/net/{ => appletalk}/ipddp.h | 0 drivers/net/{ => appletalk}/ltpc.c | 3 + drivers/net/{ => appletalk}/ltpc.h | 0 drivers/net/cs89x0.c | 834 +++++++++++--- drivers/net/cs89x0.h | 1 + drivers/net/ncr885e.c | 6 - drivers/net/net_init.c | 16 +- drivers/net/tokenring/Config.in | 2 +- drivers/net/tokenring/Makefile | 80 +- drivers/net/via-rhine.c | 572 +++++----- drivers/net/yellowfin.c | 2 +- drivers/parport/Config.in | 5 + drivers/parport/parport_pc.c | 379 ++++++- drivers/pcmcia/yenta.c | 12 + drivers/scsi/sr.c | 6 +- drivers/sound/ac97_codec.c | 53 +- drivers/sound/trident.c | 837 +++++++------- drivers/sound/trident.h | 6 +- drivers/usb/Config.in | 2 +- drivers/usb/usb-ohci.c | 2 +- drivers/usb/usb-serial.c | 2 + drivers/video/riva/fbdev.c | 4 +- fs/block_dev.c | 2 +- fs/proc/proc_misc.c | 9 +- fs/proc/root.c | 3 - fs/udf/udfdecl.h | 1 + include/asm-ppc/types.h | 7 +- include/linux/ac97_codec.h | 10 +- include/linux/cdrom.h | 21 +- include/linux/ide.h | 3 +- ipc/shm.c | 4 +- net/Config.in | 2 +- net/netsyms.c | 2 + 85 files changed, 3387 insertions(+), 2026 deletions(-) create mode 100644 drivers/net/appletalk/Config.in create mode 100644 drivers/net/appletalk/Makefile rename drivers/net/{ => appletalk}/cops.c (100%) rename drivers/net/{ => appletalk}/cops.h (100%) rename drivers/net/{ => appletalk}/cops_ffdrv.h (100%) rename drivers/net/{ => appletalk}/cops_ltdrv.h (100%) rename drivers/net/{ => appletalk}/ipddp.c (100%) rename drivers/net/{ => appletalk}/ipddp.h (100%) rename drivers/net/{ => appletalk}/ltpc.c (99%) rename drivers/net/{ => appletalk}/ltpc.h (100%) diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 87688bfcb76e..908f120edc9d 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2268,10 +2268,11 @@ CONFIG_M386 UMC U5D or U5S. - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and - K6-3D. + - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5. - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and Intel Pentium II/Pentium Pro. + - "K6/II/III" for the AMD K6, K6-II and K6-III (aka K6-3D). + - "Athlon" for the AMD Athlon (aka K7) If you don't know what to do, choose "386". @@ -5990,7 +5991,8 @@ CONFIG_AIRONET4500 adhoc=1 there are no Access Points around master=1 Adhoc master (the one who creates network sync) slave=1 Adhoc slave(btw, it is still forming own net - sometimes) + sometimes, and has problems with firmware... + change IbssJoinNetTimeout from /proc...) channel=1..? meaningful in adhoc mode all other parameters can be set via /proc interface These parameters belong to .._card module, but alas, they are here @@ -8411,7 +8413,7 @@ CONFIG_USB_UHCI USB-UHCI High Bandwidth support CONFIG_USB_UHCI_HIGH_BANDWIDTH - This option enables the so called reclamation loop in usb-uhci, thus + This option enables the so-called reclamation loop in usb-uhci, thus allowing much higher transfer bandwidth for USB-bulk and control messages; isochronous transfers (audio, video etc.) are not affected. Due to a very simple design of the UHCI controller, this may cause @@ -8651,13 +8653,14 @@ CONFIG_USB_OV511 The module will be called ov511.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB ADMtek's Pegasus based ethernet devices support +USB ADMtek Pegasus-based ethernet device support CONFIG_USB_PEGASUS - Say Y if you want to use your usb ethernet device. Note that - the code is still experimental. If you have devices with other - vendor IDs than ADMtek's you should change/add them in the + Say Y if you want to use your USB ethernet device. Note that + the code is still experimental. If you have devices with vendor + IDs other than ADMtek's, you should change/add them in the driver code and send a message to me (petkan@spct.net) for update. + This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called ov511.o. If you want to compile it as a @@ -8742,9 +8745,9 @@ CONFIG_USB_DABUSB PLUSB driver CONFIG_USB_PLUSB - A driver for the Prolific PL-2302 USB to USB network device. This 'USB - cable' connects two hosts via a point to point network with bandwidth of - 5Mbit/s. Configure this driver after connecting the USB cable via + A driver for the Prolific PL-2302 USB-to-USB network device. This 'USB + cable' connects two hosts via a point-to-point network with bandwidth of + 5 Mbit/s. Configure this driver after connecting the USB cable via ifconfig plusb0 10.0.0.1 pointopoint 10.0.0.2 (and vice versa on the other host). diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt index f26fad4981f4..24f15cb71146 100644 --- a/Documentation/networking/cs89x0.txt +++ b/Documentation/networking/cs89x0.txt @@ -1,635 +1,666 @@ -CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS -Linux Network Interface Driver ver. 1.02 -=============================================================================== - - -TABLE OF CONTENTS - -1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS - 1.1 Product Overview - 1.2 Driver Description - 1.2.1 Driver Name - 1.2.2 File in the Driver Package - 1.3 System Requirements - 1.4 Licensing Information - -2.0 ADAPTER INSTALLATION and CONFIGURATION - 2.1 CS8900-based Adapter Configuration - 2.2 CS8920-based Adapter Configuration - -3.0 LOADING THE DRIVER AS A MODULE - -4.0 COMPILING THE DRIVER - 4.1 Compiling the Driver As a Loadable Module - 4.2 Compiling the Driver Into the Kernel - 4.3 Compiling the Driver for a Linux v1.2.13 Kernel - -5.0 TESTING AND TROUBLESHOOTING - 5.1 Known Defects and Limitations - 5.2 Testing the Adapter - 5.2.1 Diagnostic Self-Test - 5.2.2 Diagnostic Network Test - 5.3 Using the Adapter's LEDs - 5.4 Resolving I/O Conflicts - -6.0 TECHNICAL SUPPORT - 6.1 Contacting Crystal's Technical Support - 6.2 Information Required Before Contacting Technical Support - 6.3 Obtaining the Latest Driver Version - 6.3.1 Crystal's Web Site - 6.3.2 Crystal's Bulletin Board Service - - - -1.0 CRYSTAL LAN CS8900/CS8920 ETHERNET ADAPTERS -=============================================================================== - - -1.1 PRODUCT OVERVIEW - -The CS8900-based ISA Ethernet Adapters from Crystal Semiconductor follow -IEEE 802.3 standards and support half or full-duplex operation in ISA bus -computers on 10 Mbps Ethernet networks. The adapters are designed for -operation in 16-bit ISA or EISA bus expansion slots and are available in -10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 -or fiber networks). - -CS8920-based adapters are similar to the CS8900-based adapter with additional -features for Plug and Play (PnP) support and Wakeup Frame recognition. As -such, the configuration procedures differ somewhat between the two types of -adapters. Refer to the "Adapter Configuration" section for details on -configuring both types of adapters. - - -1.2 DRIVER DESCRIPTION - -The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux v1.2.13 -and v2.0 (or greater) kernels. It can be compiled directly into the kernel or -loaded at run-time as a device driver module. - -1.2.1 Driver Name: cs89x0 - -1.2.2 Files in the Driver Archive: - - readme.txt - this file - release.txt - known defects and modification log - cs89x0.c - driver C code - cs89x0.h - driver header file - cs89x0.o - pre-compiled module (for v2.0 kernel) - - - -1.3 SYSTEM REQUIREMENTS - -The following hardware is required: - - * Crystal LAN (CS8900/20-based) Ethernet ISA Adapter - - * IBM or IBM-compatible PC with: - * An 80386 or higher processor - * 16 bytes of contiguous IO space available between 210h - 370h - * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). - - * Appropriate cable (and connector for AUI, 10BASE-2) for your network - topology. - -The following software is required: - - * LINUX kernel version 1.2.13 or 2.X - - * CS8900/20 Setup Utility (DOS-based) - - * LINUX kernel sources for your kernel (if compiling into kernel) - - * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel - or a module) - - - -1.4 LICENSING INFORMATION - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, version 1. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -For a full copy of the GNU General Public License, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - - -2.0 ADAPTER INSTALLATION and CONFIGURATION -=============================================================================== - -Both the CS8900 and CS8920-based adapters can be configured using parameters -stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup -Utility if you want to change the adapter's configuration in EEPROM. - -When loading the driver as a module, you can specify many of the adapter's -configuration parameters on the command-line to override the EEPROM's settings -or for interface configuration when an EEPROM is not used. (CS8920-based -adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. - -Since the CS8900/20 Setup Utility is a DOS-based application, you must install -and configure the adapter in a DOS-based system using the CS8900/20 Setup -Utility before installation in the target LINUX system. (Not required if -installing a CS8900-based adapter and the default configuration is acceptable.) - - -2.1 CS8900-BASED ADAPTER CONFIGURATION - -CS8900-based adapters shipped from Crystal Semiconductor have been configured -with the following "default" settings: - - Operation Mode: Memory Mode - IRQ: 10 - Base I/O Address: 300 - Memory Base Address: D0000 - Optimization: DOS Client - Transmission Mode: Half-duplex - BootProm: None - Media Type: Autodetect (3-media cards) or - 10BASE-T (10BASE-T only adapter) - -You should only change the default configuration settings if conflicts with -another adapter exist. To change the adapter's configuration, run the -CS8900/20 Setup Utility. - - -2.2 CS8920-BASED ADAPTER CONFIGURATION - -CS8920-based adapters are shipped from Crystal Semiconductor configured as Plug -and Play (PnP) enabled. However, since Linux is not currently a PnP compatible -operating system, you must install the CS8920 adapter in a DOS-based PC and -run the CS8900/20 Setup Utility to disable PnP and configure the adapter before -installation in the target Linux system. Failure to do this will leave the -adapter inactive and the driver will be unable to communicate with the -adapter. - - - **************************************************************** - * CS8920-BASED ADAPTERS: * - * * - * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * - * SCO UNIX IS NOT A PnP OPERATING SYSTEM. THEREFORE, YOU MUST * - * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * - * TO ACTIVATE THE ADAPTER. * - **************************************************************** - - - - -3.0 LOADING THE DRIVER AS A MODULE -=============================================================================== - -If the driver is compiled as a loadable module, you can load the driver module -with the 'insmod' command. Many of the adapter's configuration parameters can -be specified as command-line arguments to the load command. This facility -provides a means to override the EEPROM's settings or for interface -configuration when an EEPROM is not used. - -Example: - - insmod cs89x0.o io=0x200 irq=0xA media=aui - -This example loads the module and configures the adapter to use an IO port base -address of 200h, interrupt 10, and use the AUI media connection. The following -configuration options are available on the command line: - -* io=### - specify IO address (200h-360h) -* irq=## - specify interrupt level -* mmode=##### - specify memory base address -* dma=# - specify DMA channel -* media=rj45 - specify media type - or media=2 - or media=aui - or medai=auto -* duplex=f - specify forced half/full/autonegotiate duplex - or duplex=h - or duplex=auto -* debug=# - debug level - -NOTES: -* If an EEPROM is present, any specified command-line parameter will override -the corresponding configuration value stored in EEPROM. - -* If no "io" or "mmode" parameter is specified on the command-line, the driver -will scan for the adapter. When scanning, the driver only reads I/O ports. -This sometimes is not sufficient, (e.g. after a warm boot). If you wish to -allow the driver to perform a more aggressive scan (one write to the IO base -addresses to reset the data port pointer) you can specify an I/O address with -an address value one greater than the configured address. Example, to scan for -an adapter located at IO base 0x300, specify an IO address of 0x301. Only -ports between 200h and 360h at 20h intervals are scanned. - -* The "duplex=auto" parameter is only supported for the CS8920. - -* The minimum command-line configuration required if an EEPROM is not present -is: - - * io or mmode base address - * irq - * media type (no autodetect) - -The following additional parameters are CS89XX defaults (values used with no -EEPROM or command-line argument). - - * DMA Burst = enabled - * IOCHRDY Enabled = enabled - * UseSA = enabled - * CS8900 defaults to half-duplex if not specified on command-line - * CS8920 defaults to autoneg if not specified on command-line - * Use reset defaults for other config parameters - -* You can use ifconfig to set the adapter's Ethernet address. - - - - -4.0 COMPILING THE DRIVER -=============================================================================== - -The cs89x0 driver can be compiled directly into the kernel or compiled into -a loadable device driver module. - -NOTE: This part of the description relates to adding the driver to a kernel -not containing the cs89x0 driver. This kernel already contains it. - -4.1 COMPILING THE DRIVER AS A LOADABLE MODULE - -To compile the driver into a loadable module, use the following command -(single command line, without quotes): - -"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall --Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS --c cs89x0.c" - - -4.2 COMPILING THE DRIVER INTO THE KERNEL - -To compile the driver directly into the kernel requires editing four -configuration files, copying the source file to the /linux/drivers/net -directory and then running the make utility to rebuild the kernel. - -1. Edit the following configuration files by adding the statements as -indicated. (When possible, try to locate the added text to the section of the -file containing similar statements). - -a.) In /usr/src/linux/drivers/net/CONFIG, add - -CS89x0_OPTS = - -Example: - - WD_OPTS = #-DWD_SHMEM=0xDD000 - EL2_OPTS = #-DEL2_AUI - CS89x0_OPTS = - NE_OPTS = - HP_OPTS = - PLIP_OPTS = - - -b.) In /usr/src/linux/drivers/net/Config.in, add: - -tristate 'CS89x0 support' CONFIG_CS89x0 - -Example: - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I - fi - - tristate 'CS89x0 support' CONFIG_CS89x0 - - tristate 'NE2000/NE1000 support' CONFIG_NE2000 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'NI5210 support' CONFIG_NI52 - - -c.) In /usr/src/linux/drivers/net/Makefile, add the following lines: - -ifeq ($(CONFIG_CS89x0),y) -L_OBJS += cs89x0.o -else - ifeq ($(CONFIG_CS89x0),m) - M_OBJS += cs89x0.o - endif -endif - - -d.) In /linux/drivers/net/Space.c file, add the line: - -extern int cs89x0_probe(struct net_device *dev); - - -Example: - - extern int ultra_probe(struct net_device *dev); - extern int wd_probe(struct net_device *dev); - extern int el2_probe(struct net_device *dev); - - extern int cs89x0_probe(struct net_device *dev); - - extern int ne_probe(struct net_device *dev); - extern int hp_probe(struct net_device *dev); - extern int hp_plus_probe(struct net_device *dev); - - -Also add: - - #ifdef CONFIG_CS89x0 - && cs89x0_probe(dev) - #endif - - -2.) Copy the driver source files (cs89x0.c and cs89x0.h) and this README file -into the /usr/src/linux/drivers/net directory. - - -3.) Run 'make config' followed by 'make dep' and finally 'make' to rebuild -the kernel. - - -4.3 COMPILING THE DRIVER FOR A LINUX v1.2.13 KERNEL - -To compile the driver for Linux v1.2.13 (into the kernel or as a module), -change the "SUPPORTS" define at the beginning of the cs89x0.c file. -Example: - -#define SUPPORTS_1_2_13 1 /* supports Linux kernel v1.2.13 */ - or -#define SUPPORTS_1_2_13 0 /* supports Linux kernel v2.0 (default) */ - - - -5.0 TESTING AND TROUBLESHOOTING -=============================================================================== - -5.1 KNOWN DEFECTS and LIMITATIONS - -Refer to the RELEASE.TXT file distributed as part of this archive for a list of -known defects, driver limitations, and work arounds. - - -5.2 TESTING THE ADAPTER - -Once the adapter has been installed and configured, the diagnostic option of -the CS8900/20 Setup Utility can be used to test the functionality of the -adapter and its network connection. Use the diagnostics 'Self Test' option to -test the functionality of the adapter with the hardware configuration you have -assigned. You can use the diagnostics 'Network Test' to test the ability of the -adapter to communicate across the Ethernet with another PC equipped with a -CS8900/20-based adapter card (it must also be running the CS8900/20 Setup -Utility). - - NOTE: The Setup Utility's diagnostics are designed to run in a - DOS-only operating system environment. DO NOT run the diagnostics - from a DOS or command prompt session under Windows 95, Windows NT, - OS/2, or other operating system. - - [AC - Question : Do they work in DOSEMU ?] - -To run the diagnostics tests on the CS8900/20 adapter: - - 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. - - 2.) The adapter's current configuration is displayed. Hit the ENTER key to - get to the main menu. - - 4.) Select 'Diagnostics' (ALT-G) from the main menu. - * Select 'Self-Test' to test the adapter's basic functionality. - * Select 'Network Test' to test the network connection and cabling. - - -5.2.1 DIAGNOSTIC SELF-TEST - -The diagnostic self-test checks the adapter's basic functionality as well as -its ability to communicate across the ISA bus based on the system resources -assigned during hardware configuration. The following tests are performed: - - * IO Register Read/Write Test - The IO Register Read/Write test ensures that the CS8900/20 can be - accessed in IO mode, and that the IO base address is correct. - - * Shared Memory Test - The Shared Memory test ensures the CS8900/20 can be accessed in memory - mode and that the range of memory addresses assigned does not conflict - with other devices in the system. - - * Interrupt Test - The Interrupt test ensures there are no conflicts with the assigned IRQ - signal. - - * EEPROM Test - The EEPROM test ensures the EEPROM can be read. - - * Chip RAM Test - The Chip RAM test ensures the 4 K of memory internal to the CS8900/20 is - working properly. - - * Internal Loop-back Test - The Internal Loop Back test ensures the adapter's transmitter and - receiver are operating properly. If this test fails, make sure the - adapter's cable is connected to the network (check for LED activity for - example). - - * Boot PROM Test - The Boot PROM test ensures the Boot PROM is present, and can be read. - Failure indicates the Boot PROM was not successfully read due to a - hardware problem or due to a conflicts on the Boot PROM address - assignment. (Test only applies if the adapter is configured to use the - Boot PROM option.) - -Failure of a test item indicates a possible system resource conflict with -another device on the ISA bus. In this case, you should use the Manual Setup -option to reconfigure the adapter by selecting a different value for the system -resource that failed. - - -5.2.2 DIAGNOSTIC NETWORK TEST - -The Diagnostic Network Test verifies a working network connection by -transferring data between two CS8900/20 adapters installed in different PCs -on the same network. (Note: the diagnostic network test should not be run -between two nodes across a router.) - -This test requires that each of the two PCs have a CS8900/20-based adapter -installed and have the CS8900/20 Setup Utility running. The first PC is -configured as a Responder and the other PC is configured as an Initiator. -Once the Initiator is started, it sends data frames to the Responder which -returns the frames to the Initiator. - -The total number of frames received and transmitted are displayed on the -Initiator's display, along with a count of the number of frames received and -transmitted OK or in error. The test can be terminated anytime by the user at -either PC. - -To setup the Diagnostic Network Test: - - 1.) Select a PC with a CS8900/20-based adapter and a known working network - connection to act as the Responder. Run the CS8900/20 Setup Utility - and select 'Diagnostics -> Network Test -> Responder' from the main - menu. Hit ENTER to start the Responder. - - 2.) Return to the PC with the CS8900/20-based adapter you want to test and - start the CS8900/20 Setup Utility. - - 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. - Hit ENTER to start the test. - -You may stop the test on the Initiator at any time while allowing the Responder -to continue running. In this manner, you can move to additional PCs and test -them by starting the Initiator on another PC without having to stop/start the -Responder. - - - -5.3 USING THE ADAPTER'S LEDs - -The 2 and 3-media adapters have two LEDs visible on the back end of the board -located near the 10Base-T connector. - -Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T -connection. (Only applies to 10Base-T. The green LED has no significance for -a 10Base-2 or AUI connection.) - -TX/RX LED: The yellow LED lights briefly each time the adapter transmits or -receives data. (The yellow LED will appear to "flicker" on a typical network.) - - -5.4 RESOLVING I/O CONFLICTS - -An IO conflict occurs when two or more adapter use the same ISA resource (IO -address, memory address or IRQ). You can usually detect an IO conflict in one -of four ways after installing and or configuring the CS8900/20-based adapter: - - 1.) The system does not boot properly (or at all). - - 2.) The driver can not communicate with the adapter, reporting an "Adapter - not found" error message. - - 3.) You cannot connect to the network or the driver will not load. - - 4.) If you have configured the adapter to run in memory mode but the driver - reports it is using IO mode when loading, this is an indication of a - memory address conflict. - -If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a -diagnostic self-test. Normally, the ISA resource in conflict will fail the -self-test. If so, reconfigure the adapter selecting another choice for the -resource in conflict. Run the diagnostics again to check for further IO -conflicts. - -In some cases, such as when the PC will not boot, it may be necessary to remove -the adapter and reconfigure it by installing it in another PC to run the -CS8900/20 Setup Utility. Once reinstalled in the target system, run the -diagnostics self-test to ensure the new configuration is free of conflicts -before loading the driver again. - -When manually configuring the adapter, keep in mind the typical ISA system -resource usage as indicated in the tables below. - -I/O Address Device IRQ Device ------------ -------- --- -------- - 200-20F Game I/O adapter 3 COM2, Bus Mouse - 230-23F Bus Mouse 4 COM1 - 270-27F LPT3: third parallel port 5 LPT2 - 2F0-2FF COM2: second serial port 6 Floppy Disk controller - 320-32F Fixed disk controller 7 LPT1 - 8 Real-time Clock - 9 EGA/VGA display adapter - 12 Mouse (PS/2) -Memory Address Device 13 Math Coprocessor --------------- --------------------- 14 Hard Disk controller -A000-BFFF EGA Graphics Adapter -A000-C7FF VGA Graphics Adapter -B000-BFFF Mono Graphics Adapter -B800-BFFF Color Graphics Adapter -E000-FFFF AT BIOS - - - - -6.0 TECHNICAL SUPPORT -=============================================================================== - -6.1 CONTACTING CRYSTAL'S TECHNICAL SUPPORT - -Crystal's CS89XX Technical Application Support can be reached at: - -Telephone :(800) 888-5016 (from inside U.S. and Canada) - :(512) 442-7555 (from outside the U.S. and Canada) -Fax :(512) 912-3871 -E-mail :ethernet@crystal.cirrus.com -WWW :http://www.crystal.com - - -6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT - -Before contacting Crystal for technical support, be prepared to provide as much -of the following information as possible. - -1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) - -2.) Adapter configuration - - * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel - * Plug and Play enabled/disabled (CS8920-based adapters only) - * Configured for media auto-detect or specific media type (which type). - -3.) PC System's Configuration - - * Plug and Play system (yes/no) - * BIOS (make and version) - * System make and model - * CPU (type and speed) - * System RAM - * SCSI Adapter - -4.) Software - - * CS89XX driver and version - * Your network operating system and version - * Your system's OS version - * Version of all protocol support files - -5.) Any Error Message displayed. - - - -6.3 OBTAINING THE LATEST DRIVER VERSION - -You can obtain the latest CS89XX drivers and support software from Crystal's -BBS or Web site. You can also contact Crystal's Technical Support (email: -ethernet@crystal.cirrus.com) and request that you be registered for automatic -software-update notification. - - -6.3.1 CRYSTAL'S WEB SITE - -Crystal Semiconductor maintains a web page at http://www.crystal.com with the -latest drivers and technical publications. - - -6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE - -Access to the BBS is available 24 hours a day, seven days a week. Baud -rates from 300K to 14.4K are supported as well as most common file transfer -protocols. - -To access the BBS, set your terminal software to use 8 data bits, 1 stop bit, -and no parity. Dial (512) 441-3265 and press after connection is made. -Login using your account name and password. (If you do not have an account, -you may login as "GUEST". No password is required for the Guest account.) - -From the main system menu, select the "Enter Public File Area" menu option. -From the Public File Area menu, select the "LAN (Local Area Network)" file -area. A list of the latest drivers and support utilities available for the -CS89XX ISA Ethernet adapter will be presented along with the option to download -the file(s) of your choice. - - + +NOTE +---- + +This document was contributed by Cirrus Logic for kernel 2.2.5. This version +has been updated for 2.3.48 by Andrew Morton + +Cirrus make a copy of this driver available at their website, as +described below. In general, you should use the driver version which +comes with your Linux distribution. + + + +CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +Linux Network Interface Driver ver. 2.00 +=============================================================================== + + +TABLE OF CONTENTS + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS + 1.1 Product Overview + 1.2 Driver Description + 1.2.1 Driver Name + 1.2.2 File in the Driver Package + 1.3 System Requirements + 1.4 Licensing Information + +2.0 ADAPTER INSTALLATION and CONFIGURATION + 2.1 CS8900-based Adapter Configuration + 2.2 CS8920-based Adapter Configuration + +3.0 LOADING THE DRIVER AS A MODULE + +4.0 COMPILING THE DRIVER + 4.1 Compiling the Driver as a Loadable Module + 4.2 Compiling the driver to support memory mode + 4.3 Compiling the driver to support Rx DMA + 4.4 Compiling the Driver into the Kernel + +5.0 TESTING AND TROUBLESHOOTING + 5.1 Known Defects and Limitations + 5.2 Testing the Adapter + 5.2.1 Diagnostic Self-Test + 5.2.2 Diagnostic Network Test + 5.3 Using the Adapter's LEDs + 5.4 Resolving I/O Conflicts + +6.0 TECHNICAL SUPPORT + 6.1 Contacting Cirrus Logic's Technical Support + 6.2 Information Required Before Contacting Technical Support + 6.3 Obtaining the Latest Driver Version + 6.4 Current maintainer + + + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +=============================================================================== + + +1.1 PRODUCT OVERVIEW + +The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow +IEEE 802.3 standards and support half or full-duplex operation in ISA bus +computers on 10 Mbps Ethernet networks. The adapters are designed for operation +in 16-bit ISA or EISA bus expansion slots and are available in +10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 +or fiber networks). + +CS8920-based adapters are similar to the CS8900-based adapter with additional +features for Plug and Play (PnP) support and Wakeup Frame recognition. As +such, the configuration procedures differ somewhat between the two types of +adapters. Refer to the "Adapter Configuration" section for details on +configuring both types of adapters. + + +1.2 DRIVER DESCRIPTION + +The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux +v2.3.48 or greater kernel. It can be compiled directly into the kernel +or loaded at run-time as a device driver module. + +1.2.1 Driver Name: cs89x0 + +1.2.2 Files in the Driver Archive: + +The files in the driver at Cirrus' website include: + + readme.txt - this file + build - batch file to compile cs89x0.c. + cs89x0.c - driver C code + cs89x0.h - driver header file + cs89x0.o - pre-compiled module (for v2.2.5 kernel) + config/Config.in - sample file to include cs89x0 driver in the kernel. + config/Makefile - sample file to include cs89x0 driver in the kernel. + config/Space.c - sample file to include cs89x0 driver in the kernel. + + + +1.3 SYSTEM REQUIREMENTS + +The following hardware is required: + + * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter + + * IBM or IBM-compatible PC with: + * An 80386 or higher processor + * 16 bytes of contiguous IO space available between 210h - 370h + * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). + + * Appropriate cable (and connector for AUI, 10BASE-2) for your network + topology. + +The following software is required: + +* LINUX kernel version 2.3.48 or higher + + * CS8900/20 Setup Utility (DOS-based) + + * LINUX kernel sources for your kernel (if compiling into kernel) + + * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel + or a module) + + + +1.4 LICENSING INFORMATION + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 1. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +For a full copy of the GNU General Public License, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + +2.0 ADAPTER INSTALLATION and CONFIGURATION +=============================================================================== + +Both the CS8900 and CS8920-based adapters can be configured using parameters +stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup +Utility if you want to change the adapter's configuration in EEPROM. + +When loading the driver as a module, you can specify many of the adapter's +configuration parameters on the command-line to override the EEPROM's settings +or for interface configuration when an EEPROM is not used. (CS8920-based +adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. + +Since the CS8900/20 Setup Utility is a DOS-based application, you must install +and configure the adapter in a DOS-based system using the CS8900/20 Setup +Utility before installation in the target LINUX system. (Not required if +installing a CS8900-based adapter and the default configuration is acceptable.) + + +2.1 CS8900-BASED ADAPTER CONFIGURATION + +CS8900-based adapters shipped from Cirrus Logic have been configured +with the following "default" settings: + + Operation Mode: Memory Mode + IRQ: 10 + Base I/O Address: 300 + Memory Base Address: D0000 + Optimization: DOS Client + Transmission Mode: Half-duplex + BootProm: None + Media Type: Autodetect (3-media cards) or + 10BASE-T (10BASE-T only adapter) + +You should only change the default configuration settings if conflicts with +another adapter exists. To change the adapter's configuration, run the +CS8900/20 Setup Utility. + + +2.2 CS8920-BASED ADAPTER CONFIGURATION + +CS8920-based adapters are shipped from Cirrus Logic configured as Plug +and Play (PnP) enabled. However, since the cs89x0 driver does NOT +support PnP, you must install the CS8920 adapter in a DOS-based PC and +run the CS8900/20 Setup Utility to disable PnP and configure the +adapter before installation in the target Linux system. Failure to do +this will leave the adapter inactive and the driver will be unable to +communicate with the adapter. + + + **************************************************************** + * CS8920-BASED ADAPTERS: * + * * + * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * + * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST * + * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * + * TO ACTIVATE THE ADAPTER. * + **************************************************************** + + + + +3.0 LOADING THE DRIVER AS A MODULE +=============================================================================== + +If the driver is compiled as a loadable module, you can load the driver module +with the 'modprobe' command. Many of the adapter's configuration parameters can +be specified as command-line arguments to the load command. This facility +provides a means to override the EEPROM's settings or for interface +configuration when an EEPROM is not used. + +Example: + + insmod cs89x0.o io=0x200 irq=0xA media=aui + +This exmaple loads the module and configures the adapter to use an IO port base +address of 200h, interrupt 10, and use the AUI media connection. The following +configuration options are available on the command line: + +* io=### - specify IO address (200h-360h) +* irq=## - specify interrupt level +* use_dma=1 - Enable DMA +* dma=# - specify dma channel (Driver is compiled to support + Rx DMA only) +* dmasize=# (16 or 64) - DMA size 16K or 64K. Default value is set to 16. +* media=rj45 - specify media type + or media=bnc + or media=aui + or medai=auto +* duplex=full - specify forced half/full/autonegotiate duplex + or duplex=half + or duplex=auto +* debug=# - debug level (only available if the driver was compiled + for debugging) + +NOTES: + +a) If an EEPROM is present, any specified command-line parameter + will override the corresponding configuration value stored in + EEPROM. + +b) The "io" parameter must be specified on the command-line. + +c) In case you can not re-load the driver because Linux system + returns the "device or resource busy" message, try to re-load it by + increment the IO port address by one. The driver will write + commands to the IO base addresses to reset the data port pointer. + You can specify an I/O address with an address value one greater + than the configured address. Example, to scan for an adapter + located at IO base 0x300, specify an IO address of 0x301. + +d) The "duplex=auto" parameter is only supported for the CS8920. + +e) The minimum command-line configuration required if an EEPROM is + not present is: + + io + irq + media type (no autodetect) + +f) The following addtional parameters are CS89XX defaults (values + used with no EEPROM or command-line argument). + + * DMA Burst = enabled + * IOCHRDY Enabled = enabled + * UseSA = enabled + * CS8900 defaults to half-duplex if not specified on command-line + * CS8920 defaults to autoneg if not specified on command-line + * Use reset defaults for other config parameters + * dma_mode = 0 + +g) You can use ifconfig to set the adapter's Ethernet address. + +h) Many Linux distributions use the 'modprobe' command to load + modules. This program uses the '/etc/conf.modules' file to + determine configuration information which is passed to a driver + module when it is loaded. All the configuration options which are + described above may be placed within /etc/conf.modules. + + For example: + + > cat /etc/conf.modules + ... + alias eth0 cs89x0 + options cs89x0 io=0x0200 dma=5 use_dma=1 + ... + + In this example we are telling the module system that the + ethernet driver for this machine should use the cs89x0 driver. We + are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma' + arguments to the driver when it is loaded. + +i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or + 7. You will probably find that other DMA channels will not work. + +j) The cs89x0 supports DMA for receiving only. DMA mode is + significantly more efficient. Flooding a 400 MHz Celeron machine + with large ping packets consumes 82% of its CPU capacity in non-DMA + mode. With DMA this is reduced to 45%. + +k) If your Linux kernel was compiled with inbuilt plug-and-play + support you will be able to find information about the cs89x0 card + with the command + + cat /proc/isapnp + +l) If during DMA operation you find erratic behavior or network data + corruption you should use your PC's BIOS to slow the EISA bus clock. + + +4.0 COMPILING THE DRIVER +=============================================================================== + +The cs89x0 driver can be compiled directly into the kernel or compiled into +a loadable device driver module. + + +4.1 COMPILING THE DRIVER AS A LOADABLE MODULE + +To compile the driver into a loadable module, use the following command +(single command line, without quotes): + +"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall +-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS +-c cs89x0.c" + +4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE + +Support for memory mode was not carried over into the 2.3 series kernels. + +4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA + +The compile-time optionality for DMA was removed in the 2.3 kernel +series. DMA support is now unconditionally part of the driver. It is +enabled by the 'use_dma=1' module option. + +4.4 COMPILING THE DRIVER INTO THE KERNEL + +If your Linux distribution already has support for the cs89x0 driver +then simply copy the source file to the /usr/src/linux/drivers/net +directory to replace the original ones and run the make utility to +rebuild the kernel. See Step 3 for rebuilding the kernel. + +If your Linux does not include the cs89x0 driver, you need to edit three +configuration files, copy the source file to the /usr/src/linux/drivers/net +directory, and then run the make utility to rebuild the kernel. + +1. Edit the following configuration files by adding the statements as +indicated. (When possible, try to locate the added text to the section of the +file containing similar statements). + + +a.) In /usr/src/linux/drivers/net/Config.in, add: + +tristate 'CS89x0 support' CONFIG_CS89x0 + +Example: + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I + fi + + tristate 'CS89x0 support' CONFIG_CS89x0 + + tristate 'NE2000/NE1000 support' CONFIG_NE2000 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'NI5210 support' CONFIG_NI52 + + +b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: + +ifeq ($(CONFIG_CS89x0),y) +L_OBJS += cs89x0.o +else + ifeq ($(CONFIG_CS89x0),m) + M_OBJS += cs89x0.o + endif +endif + + +c.) In /linux/drivers/net/Space.c file, add the line: + +extern int cs89x0_probe(struct device *dev); + + +Example: + + extern int ultra_probe(struct device *dev); + extern int wd_probe(struct device *dev); + extern int el2_probe(struct device *dev); + + extern int cs89x0_probe(struct device *dev); + + extern int ne_probe(struct device *dev); + extern int hp_probe(struct device *dev); + extern int hp_plus_probe(struct device *dev); + + +Also add: + + #ifdef CONFIG_CS89x0 + { cs89x0_probe,0 }, + #endif + + +2.) Copy the driver source files (cs89x0.c and cs89x0.h) +into the /usr/src/linux/drivers/net directory. + + +3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' +and finally 'make' (or make bzImage) to rebuild the kernel. + +4.) Use the DOS 'setup' utility to disable plug and play on the NIC. + + +5.0 TESTING AND TROUBLESHOOTING +=============================================================================== + +5.1 KNOWN DEFECTS and LIMITATIONS + +Refer to the RELEASE.TXT file distributed as part of this archive for a list of +known defects, driver limitations, and work arounds. + + +5.2 TESTING THE ADAPTER + +Once the adapter has been installed and configured, the diagnostic option of +the CS8900/20 Setup Utility can be used to test the functionality of the +adapter and its network connection. Use the diagnostics 'Self Test' option to +test the functionality of the adapter with the hardware configuration you have +assigned. You can use the diagnostics 'Network Test' to test the ability of the +adapter to communicate across the Ethernet with another PC equipped with a +CS8900/20-based adapter card (it must also be running the CS8900/20 Setup +Utility). + + NOTE: The Setup Utility's diagnostics are designed to run in a + DOS-only operating system environment. DO NOT run the diagnostics + from a DOS or command prompt session under Windows 95, Windows NT, + OS/2, or other operating system. + +To run the diagnostics tests on the CS8900/20 adapter: + + 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. + + 2.) The adapter's current configuration is displayed. Hit the ENTER key to + get to the main menu. + + 4.) Select 'Diagnostics' (ALT-G) from the main menu. + * Select 'Self-Test' to test the adapter's basic functionality. + * Select 'Network Test' to test the network connection and cabling. + + +5.2.1 DIAGNOSTIC SELF-TEST + +The diagnostic self-test checks the adapter's basic functionality as well as +its ability to communicate across the ISA bus based on the system resources +assigned during hardware configuration. The following tests are performed: + + * IO Register Read/Write Test + The IO Register Read/Write test insures that the CS8900/20 can be + accessed in IO mode, and that the IO base address is correct. + + * Shared Memory Test + The Shared Memory test insures the CS8900/20 can be accessed in memory + mode and that the range of memory addresses assigned does not conflict + with other devices in the system. + + * Interrupt Test + The Interrupt test insures there are no conflicts with the assigned IRQ + signal. + + * EEPROM Test + The EEPROM test insures the EEPROM can be read. + + * Chip RAM Test + The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + working properly. + + * Internal Loop-back Test + The Internal Loop Back test insures the adapter's transmitter and + receiver are operating properly. If this test fails, make sure the + adapter's cable is connected to the network (check for LED activity for + example). + + * Boot PROM Test + The Boot PROM test insures the Boot PROM is present, and can be read. + Failure indicates the Boot PROM was not successfully read due to a + hardware problem or due to a conflicts on the Boot PROM address + assignment. (Test only applies if the adapter is configured to use the + Boot PROM option.) + +Failure of a test item indicates a possible system resource conflict with +another device on the ISA bus. In this case, you should use the Manual Setup +option to reconfigure the adapter by selecting a different value for the system +resource that failed. + + +5.2.2 DIAGNOSTIC NETWORK TEST + +The Diagnostic Network Test verifies a working network connection by +transferring data between two CS8900/20 adapters installed in different PCs +on the same network. (Note: the diagnostic network test should not be run +between two nodes across a router.) + +This test requires that each of the two PCs have a CS8900/20-based adapter +installed and have the CS8900/20 Setup Utility running. The first PC is +configured as a Responder and the other PC is configured as an Initiator. +Once the Initiator is started, it sends data frames to the Responder which +returns the frames to the Initiator. + +The total number of frames received and transmitted are displayed on the +Initiator's display, along with a count of the number of frames received and +transmitted OK or in error. The test can be terminated anytime by the user at +either PC. + +To setup the Diagnostic Network Test: + + 1.) Select a PC with a CS8900/20-based adapter and a known working network + connection to act as the Responder. Run the CS8900/20 Setup Utility + and select 'Diagnostics -> Network Test -> Responder' from the main + menu. Hit ENTER to start the Responder. + + 2.) Return to the PC with the CS8900/20-based adapter you want to test and + start the CS8900/20 Setup Utility. + + 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. + Hit ENTER to start the test. + +You may stop the test on the Initiator at any time while allowing the Responder +to continue running. In this manner, you can move to additional PCs and test +them by starting the Initiator on another PC without having to stop/start the +Responder. + + + +5.3 USING THE ADAPTER'S LEDs + +The 2 and 3-media adapters have two LEDs visible on the back end of the board +located near the 10Base-T connector. + +Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T +connection. (Only applies to 10Base-T. The green LED has no significance for +a 10Base-2 or AUI connection.) + +TX/RX LED: The yellow LED lights briefly each time the adapter transmits or +receives data. (The yellow LED will appear to "flicker" on a typical network.) + + +5.4 RESOLVING I/O CONFLICTS + +An IO conflict occurs when two or more adapter use the same ISA resource (IO +address, memory address or IRQ). You can usually detect an IO conflict in one +of four ways after installing and or configuring the CS8900/20-based adapter: + + 1.) The system does not boot properly (or at all). + + 2.) The driver can not communicate with the adapter, reporting an "Adapter + not found" error message. + + 3.) You cannot connect to the network or the driver will not load. + + 4.) If you have configured the adapter to run in memory mode but the driver + reports it is using IO mode when loading, this is an indication of a + memory address conflict. + +If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a +diagnostic self-test. Normally, the ISA resource in conflict will fail the +self-test. If so, reconfigure the adapter selecting another choice for the +resource in conflict. Run the diagnostics again to check for further IO +conflicts. + +In some cases, such as when the PC will not boot, it may be necessary to remove +the adapter and reconfigure it by installing it in another PC to run the +CS8900/20 Setup Utility. Once reinstalled in the target system, run the +diagnostics self-test to ensure the new configuration is free of conflicts +before loading the driver again. + +When manually configuring the adapter, keep in mind the typical ISA system +resource usage as indicated in the tables below. + +I/O Address Device IRQ Device +----------- -------- --- -------- + 200-20F Game I/O adapter 3 COM2, Bus Mouse + 230-23F Bus Mouse 4 COM1 + 270-27F LPT3: third parallel port 5 LPT2 + 2F0-2FF COM2: second serial port 6 Floppy Disk controller + 320-32F Fixed disk controller 7 LPT1 + 8 Real-time Clock + 9 EGA/VGA display adapter + 12 Mouse (PS/2) +Memory Address Device 13 Math Coprocessor +-------------- --------------------- 14 Hard Disk controller +A000-BFFF EGA Graphics Adpater +A000-C7FF VGA Graphics Adpater +B000-BFFF Mono Graphics Adapter +B800-BFFF Color Graphics Adapter +E000-FFFF AT BIOS + + + + +6.0 TECHNICAL SUPPORT +=============================================================================== + +6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT + +Cirrus Logic's CS89XX Technical Application Support can be reached at: + +Telephone :(800) 888-5016 (from inside U.S. and Canada) + :(512) 442-7555 (from outside the U.S. and Canada) +Fax :(512) 912-3871 +Email :ethernet@crystal.cirrus.com +WWW :http://www.cirrus.com + + +6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT + +Before contacting Cirrus Logic for technical support, be prepared to provide as +Much of the following information as possible. + +1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) + +2.) Adapter configuration + + * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel + * Plug and Play enabled/disabled (CS8920-based adapters only) + * Configured for media auto-detect or specific media type (which type). + +3.) PC System's Configuration + + * Plug and Play system (yes/no) + * BIOS (make and version) + * System make and model + * CPU (type and speed) + * System RAM + * SCSI Adapter + +4.) Software + + * CS89XX driver and version + * Your network operating system and version + * Your system's OS version + * Version of all protocol support files + +5.) Any Error Message displayed. + + + +6.3 OBTAINING THE LATEST DRIVER VERSION + +You can obtain the latest CS89XX drivers and support software from Cirrus Logic's +Web site. You can also contact Cirrus Logic's Technical Support (email: +ethernet@crystal.cirrus.com) and request that you be registered for automatic +software-update notification. + +Cirrus Logic maintains a web page at http://www.cirrus.com with the +the latest drivers and technical publications. + + +6.4 Current maintainer + +In February 2000 the maintenance of this driver was assumed by Andrew +Morton + + diff --git a/Makefile b/Makefile index 21436a4cb2e4..155997f18c50 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 49 +SUBLEVEL = 50 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 4163626f4208..120c861e7997 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -199,13 +199,13 @@ static void show(char * str) printk(" %d",local_bh_count(i)); printk(" ]\nStack dumps:"); - for(i=0;i< smp_num_cpus;i++) { + for(i = 0; i < smp_num_cpus; i++) { unsigned long esp; - if(i==cpu) + if (i == cpu) continue; printk("\nCPU %d:",i); esp = init_tss[i].esp0; - if(esp==NULL) { + if (!esp) { /* tss->esp0 is set to NULL in cpu_init(), * it's initialized when the cpu returns to user * space. -- manfreds diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index b9e535a71979..c801285eb180 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -320,7 +320,7 @@ static void __init pagetable_init(void) if (vaddr >= end) break; #if CONFIG_X86_PAE - pmd = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE); + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); #else pmd = (pmd_t *)pgd; diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index 4ba96bde9851..c849bac82993 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -92,7 +92,14 @@ CONFIG_BLK_DEV_IDESCSI=y # # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -194,6 +201,7 @@ CONFIG_SCSI_CONSTANTS=y # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -249,7 +257,6 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -266,6 +273,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -389,7 +397,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y -CONFIG_FB_ATY128=y +# CONFIG_FB_ATY128 is not set CONFIG_FB_3DFX=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set @@ -448,6 +456,7 @@ CONFIG_PSMOUSE=y # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux @@ -496,6 +505,8 @@ CONFIG_USB_OHCI=y # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set # # USB HID @@ -503,7 +514,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y -# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_WMFORCE is not set CONFIG_INPUT_KEYBDEV=y CONFIG_INPUT_MOUSEDEV=y diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 4ba96bde9851..c849bac82993 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -92,7 +92,14 @@ CONFIG_BLK_DEV_IDESCSI=y # # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_IDEDMA_PCI is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_AEC6210 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_OPTI621 is not set CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y @@ -194,6 +201,7 @@ CONFIG_SCSI_CONSTANTS=y # # SCSI low-level drivers # +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set @@ -249,7 +257,6 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -266,6 +273,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -389,7 +397,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set CONFIG_FB_ATY=y -CONFIG_FB_ATY128=y +# CONFIG_FB_ATY128 is not set CONFIG_FB_3DFX=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set @@ -448,6 +456,7 @@ CONFIG_PSMOUSE=y # CONFIG_WATCHDOG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux @@ -496,6 +505,8 @@ CONFIG_USB_OHCI=y # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set # # USB HID @@ -503,7 +514,7 @@ CONFIG_USB_OHCI=y # CONFIG_USB_HID is not set CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y -# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WACOM is not set # CONFIG_USB_WMFORCE is not set CONFIG_INPUT_KEYBDEV=y CONFIG_INPUT_MOUSEDEV=y diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0f71676225f3..73db2269e9d7 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -98,7 +98,7 @@ ifeq ($(CONFIG_ALL_PPC),y) OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) - O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o + O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o open_pic.o endif all: $(KHEAD) kernel.o @@ -114,6 +114,8 @@ ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/ptrace.h $(CC) $(CFLAGS) -S mk_defs.c cp ppc_defs.head ppc_defs.h +# for bk, this way we can write to the file even if it's not checked out + chmod u+w ppc_defs.h grep '^#define' mk_defs.s >> ppc_defs.h rm mk_defs.s diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 156eb187e32c..d14c7380acc1 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -154,6 +154,9 @@ feature_init(void) { struct device_node *np; + if (_machine != _MACH_Pmac) + return; + np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index b6d44ecb300c..dab413c15c5e 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -222,7 +222,7 @@ __after_prom_start: mtspr IBAT0L,r8 mtspr IBAT0U,r11 #if 0 /* Useful debug code, please leave in for now so I don't have to - * look at docs when I need to setup a BAT ; + * look at docs when I need to setup a BAT ... */ bl setup_screen_bat #endif @@ -256,6 +256,8 @@ __after_prom_start: * prep needs the mmu to be turned on here, but pmac already has it on. * this shouldn't bother the pmac since it just gets turned on again * as we jump to our code at KERNELBASE. -- Cort + * Actually no, pmac doesn't have it on any more. BootX enters with MMU + * off, and in other cases, we now turn it off before changing BATs above. */ turn_on_mmu: mfmsr r0 @@ -1423,6 +1425,7 @@ start_here: li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) mtspr SRR0,r4 mtspr SRR1,r3 + SYNC rfi /* Load up the kernel context */ 2: @@ -1433,6 +1436,7 @@ start_here: tlbsync /* ... on all CPUs */ sync #endif + bl load_up_mmu /* Set up for using our exception vectors */ @@ -1448,6 +1452,7 @@ start_here: ori r3,r3,start_kernel@l mtspr SRR0,r3 mtspr SRR1,r4 + SYNC rfi /* enable MMU and jump to start_kernel */ /* @@ -1530,11 +1535,11 @@ setup_screen_bat: li r3,0 mtspr DBAT1U,r3 mtspr IBAT1U,r3 - lis r3, 0x9100 + lis r3, 0x8200 ori r4,r3,0x2a mtspr DBAT1L,r4 mtspr IBAT1L,r4 - ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */ + ori r3,r3,(BL_16M<<2)|0x2 /* set up BAT registers for 604 */ mtspr DBAT1U,r3 mtspr IBAT1U,r3 blr diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index ffac1871a18d..f8e11ecc033b 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -45,7 +45,9 @@ #include #include #include +#include +#include #include #include #include @@ -611,3 +613,160 @@ void __global_restore_flags(unsigned long flags) } #endif /* __SMP__ */ +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", irq_affinity[(int)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (int) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == NULL)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == NULL) + continue; + register_irq_proc(i); + } +} diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 8326bc369cfb..773c99b5ccc8 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -131,11 +131,6 @@ char __init *pcibios_setup(char *str) return str; } -int pcibios_assign_resource(struct pci_dev *pdev, int resource) -{ - return 0; -} - /* the next two are stolen from the alpha port... */ void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, @@ -189,48 +184,3 @@ int pcibios_enable_device(struct pci_dev *dev) } return 0; } - -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. We don't re-assign resources unless we are - * forced to do so. - * - * Expects start=0, end=size-1, flags=resource type. - */ - -int pci_assign_resource(struct pci_dev *dev, int i) -{ - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; - u32 new, check; - - if (!pr) { - printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) { - if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) { - printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } - } else { - if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) { - printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); - return -EBUSY; - } - } - if (i < 6) { - int reg = PCI_BASE_ADDRESS_0 + 4*i; - new = r->start | (r->flags & PCI_REGION_FLAG_MASK); - pci_write_config_dword(dev, reg, new); - pci_read_config_dword(dev, reg, &check); - if (new != check) - printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check); - } else if (i == PCI_ROM_RESOURCE) { - r->flags |= PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK)); - } - printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i); - return 0; -} diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index b0276ca2c20d..f2794ae5a4eb 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "pmac_pic.h" /* pmac */struct pmac_irq_hw { diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 5fef07e89e8f..c2c4cbbf496f 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -283,8 +283,6 @@ pmac_setup_arch(void) ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000) ? "enabled" : "disabled"); - feature_init(); - #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -325,14 +323,15 @@ static void __init init_p2pbridge(void) || p2pbridge->parent == NULL || strcmp(p2pbridge->parent->name, "pci") != 0) return; - if (pci_device_loc(p2pbridge, &bus, &devfn) < 0) return; - - pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); + if (ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) { + printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); + return; + } val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; - pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val); - pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); + ppc_md.pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val); + ppc_md.pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val); } static void __init ohare_init(void) @@ -703,8 +702,8 @@ pmac_progress(char *s, unsigned short hex) { if (disp_bi == 0) return; - drawstring(s); - drawchar('\n'); + prom_drawstring(s); + prom_drawchar('\n'); } #endif CONFIG_BOOTX_TEXT diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index da46f3c1ce64..441310e687c7 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -44,12 +44,6 @@ extern unsigned long htab_evicts; extern unsigned long pte_misses; extern unsigned long pte_errors; -struct file_operations ppc_htab_operations = { - llseek: ppc_htab_lseek, - read: ppc_htab_read, - write: ppc_htab_write, -}; - /* these will go into processor.h when I'm done debugging -- Cort */ #define MMCR0 952 #define MMCR0_PMC1_CYCLES (0x1<<7) @@ -63,6 +57,12 @@ struct file_operations ppc_htab_operations = { #define PMC1 953 #define PMC2 954 +struct file_operations ppc_htab_operations = { + llseek: ppc_htab_lseek, + read: ppc_htab_read, + write: ppc_htab_write, +}; + char *pmc1_lookup(unsigned long mmcr0) { switch ( mmcr0 & (0x7f<<7) ) diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 4ee638f62827..310e301e64a0 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -114,9 +114,9 @@ static struct device_node *allnodes = 0; static void clearscreen(void); static void flushscreen(void); -void drawchar(char c); -void drawstring(const char *c); -static void drawhex(unsigned long v); +void prom_drawchar(char c); +void prom_drawstring(const char *c); +void prom_drawhex(unsigned long v); static void scrollscreen(void); static void draw_byte(unsigned char c, long locX, long locY); @@ -134,6 +134,8 @@ static long g_max_loc_Y = 0; static unsigned char vga_font[cmapsz]; +int bootx_text_mapped = 1; + #endif /* CONFIG_BOOTX_TEXT */ @@ -257,7 +259,7 @@ prom_print(const char *msg) { #ifdef CONFIG_BOOTX_TEXT if (RELOC(disp_bi) != 0) - drawstring(msg); + prom_drawstring(msg); #endif return; } @@ -385,6 +387,7 @@ prom_init(int r3, int r4, prom_entry pp) #ifdef CONFIG_BOOTX_TEXT prom_print(RELOC("booting...\n")); flushscreen(); + RELOC(bootx_text_mapped) = 0; #endif return phys; } @@ -633,6 +636,7 @@ prom_init(int r3, int r4, prom_entry pp) prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); prom_print(RELOC("booting...\n")); } + RELOC(bootx_text_mapped) = 0; #endif return phys; @@ -648,28 +652,30 @@ prom_welcome(boot_infos_t* bi, unsigned long phys) prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); prom_print(RELOC("\nstarted at : 0x")); - drawhex(phys); + prom_drawhex(phys); prom_print(RELOC("\nlinked at : 0x")); - drawhex(KERNELBASE); + prom_drawhex(KERNELBASE); prom_print(RELOC("\nframe buffer at : 0x")); - drawhex((unsigned long)bi->dispDeviceBase); + prom_drawhex((unsigned long)bi->dispDeviceBase); prom_print(RELOC(" (phys), 0x")); - drawhex((unsigned long)bi->logicalDisplayBase); + prom_drawhex((unsigned long)bi->logicalDisplayBase); prom_print(RELOC(" (log)")); + prom_print(RELOC("\nklimit : 0x")); + prom_drawhex(RELOC(klimit)); prom_print(RELOC("\nMSR : 0x")); __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); pvr >>= 16; if (pvr > 1) { prom_print(RELOC("\nHID0 : 0x")); __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); } if (pvr == 8 || pvr == 12) { prom_print(RELOC("\nICTC : 0x")); __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); - drawhex(flags); + prom_drawhex(flags); } prom_print(RELOC("\n\n")); } @@ -807,13 +813,18 @@ setup_disp_fake_bi(ihandle dp) prom_print(RELOC("Initializing fake screen\n")); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), + &width, sizeof(width)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), + &height, sizeof(height)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), + &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), + &pitch, sizeof(pitch)); address = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), + &address, sizeof(address)); if (address == 0) { prom_print(RELOC("Failed to get address\n")); return; @@ -837,7 +848,6 @@ setup_disp_fake_bi(ihandle dp) bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; bi->dispDeviceRect[2] = width; bi->dispDeviceRect[3] = height; - RELOC(disp_bi) = 0; } #endif @@ -1844,6 +1854,7 @@ map_bootx_text(void) disp_bi->logicalDisplayBase = ioremap((unsigned long) disp_bi->dispDeviceBase, disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); + bootx_text_mapped = 1; } /* Calc the base address of a given point (x,y) */ @@ -1940,11 +1951,14 @@ scrollscreen(void) __pmac void -drawchar(char c) +prom_drawchar(char c) { unsigned long offset = reloc_offset(); int cline = 0, x; + if (!RELOC(bootx_text_mapped)) + return; + switch (c) { case '\b': if (RELOC(g_loc_X) > 0) @@ -1988,27 +2002,33 @@ drawchar(char c) __pmac void -drawstring(const char *c) +prom_drawstring(const char *c) { + unsigned long offset = reloc_offset(); + + if (!RELOC(bootx_text_mapped)) + return; while (*c) - drawchar(*c++); + prom_drawchar(*c++); } __pmac -static void -drawhex(unsigned long v) +void +prom_drawhex(unsigned long v) { static char hex_table[] = "0123456789abcdef"; unsigned long offset = reloc_offset(); - drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); - drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); + if (!RELOC(bootx_text_mapped)) + return; + prom_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]); + prom_drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]); } diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 5a57ba8a24dd..73a6c2bf7ae0 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -29,6 +29,7 @@ #endif #include #include +#include #ifdef CONFIG_OAK #include "oak_setup.h" #endif /* CONFIG_OAK */ @@ -417,7 +418,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { parse_bootinfo(); - + if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) @@ -687,6 +688,7 @@ void __init setup_arch(char **cmdline_p) ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); + paging_init(); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) @@ -733,12 +735,12 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); id->eide_pio = __le16_to_cpu(id->eide_pio); id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); - for (i=0; i<2 i++) + for (i=0; i<2; i++) id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); - for (i=0; i<4 i++) + for (i=0; i<4; i++) id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); id->queue_depth = __le16_to_cpu(id->queue_depth); - for (i=0; i<4 i++) + for (i=0; i<4; i++) id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); id->major_rev_num = __le16_to_cpu(id->major_rev_num); id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 2faccd0420ab..eaa5924a2047 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -961,8 +961,9 @@ void __init MMU_init(void) } #endif #if 0 - setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE); - disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase; +// This is bogus, BAT must be aligned. +// setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE); +// disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase; #endif ioremap_base = 0xf0000000; break; diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 8e924699fa83..95b19ba475fb 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -17,12 +17,12 @@ static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); -extern void drawchar(char); -extern void drawstring(const char *str); +extern void prom_drawchar(char); +extern void prom_drawstring(const char *str); static int xmon_expect(const char *str, unsigned int timeout); static int console = 0; -static int use_screen = 0; +static int use_screen = 1; /* default */ static int via_modem = 0; static int xmon_use_sccb = 0; static struct device_node *macio_node; @@ -48,6 +48,8 @@ xmon_map_scc(void) { volatile unsigned char *base; + use_screen = 0; + if ( _machine == _MACH_Pmac ) { struct device_node *np; @@ -58,7 +60,7 @@ xmon_map_scc(void) /* needs to be hacked if xmon_printk is to be used from within find_via_pmu() */ if (!via_modem && disp_bi && find_via_pmu()) { - drawstring("xmon uses screen and keyboard\n"); + prom_drawstring("xmon uses screen and keyboard\n"); use_screen = 1; return; } @@ -122,7 +124,7 @@ xmon_write(void *handle, void *ptr, int nb) if (use_screen) { /* write it on the screen */ for (i = 0; i < nb; ++i) - drawchar(*p++); + prom_drawchar(*p++); return nb; } #endif @@ -142,6 +144,7 @@ xmon_write(void *handle, void *ptr, int nb) ct = 1; --i; } else { + prom_drawchar(c); if (console) printk("%c", c); ct = 0; @@ -187,15 +190,15 @@ xmon_get_pmu_key(void) do { if (--t < 0) { on = 1 - on; - drawchar(on? 0xdb: 0x20); - drawchar('\b'); + prom_drawchar(on? 0xdb: 0x20); + prom_drawchar('\b'); t = 200000; } pmu_poll(); } while (xmon_pmu_keycode == -1); k = xmon_pmu_keycode; if (on) - drawstring(" \b"); + prom_drawstring(" \b"); /* test for shift keys */ if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { @@ -284,6 +287,8 @@ xmon_init_scc() { int i, x; + if (macio_node != 0) + feature_set(macio_node, FEATURE_Serial_enable); if (via_modem && macio_node != 0) { unsigned int t0; @@ -399,15 +404,12 @@ int xmon_expect(const char *str, unsigned int timeout) for (;;) { c = xmon_read_poll(); if (c == -1) { - if (readtb() - t0 > timeout) { - printk("timeout\n"); + if (readtb() - t0 > timeout) return 0; - } continue; } if (c == '\n') break; - printk("%c", c); if (c != '\r' && lineptr < &line[sizeof(line) - 1]) *lineptr++ = c; } diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index d18d74dfda9c..620df9aea28a 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -119,7 +119,8 @@ void xmon(struct pt_regs *excp) { struct pt_regs regs; - int msr, cmd; + int msr, cmd, i; + unsigned *sp; if (excp == NULL) { asm volatile ("stw 0,0(%0)\n\ @@ -135,6 +136,29 @@ xmon(struct pt_regs *excp) excp = ®s; } + prom_drawstring("xmon pc="); prom_drawhex(excp->nip); + prom_drawstring(" lr="); prom_drawhex(excp->link); + prom_drawstring(" msr="); prom_drawhex(excp->msr); + prom_drawstring(" trap="); prom_drawhex(excp->trap); + prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]); + sp = &excp->gpr[0]; + for (i = 0; i < 32; ++i) { + if ((i & 7) == 0) + prom_drawstring("\n"); + prom_drawstring(" "); + prom_drawhex(sp[i]); + } + sp = (unsigned *) excp->gpr[1]; + for (i = 0; i < 64; ++i) { + if ((i & 7) == 0) { + prom_drawstring("\n"); + prom_drawhex(sp); + prom_drawstring(" "); + } + prom_drawstring(" "); + prom_drawhex(sp[i]); + } + prom_drawstring("\n"); msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ remove_bpts(); @@ -521,7 +545,7 @@ void excprint(struct pt_regs *fp) { printf("vector: %x at pc = %x %s", - fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/""); + fp->trap, fp->nip, pretty_lookup_name(fp->nip)); printf(", msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); if (fp->trap == 0x300 || fp->trap == 0x600) @@ -1390,6 +1414,10 @@ static char *lookup_name(unsigned long addr) if ( !sysmap || !sysmap_size ) return NULL; + /* adjust if addr is relative to kernelbase */ + if ( addr < PAGE_OFFSET ) + addr += PAGE_OFFSET; + cmp = simple_strtoul(c, &c, 8); strcpy( last, strsep( &c, "\n")); while ( c < (sysmap+sysmap_size) ) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index ed2e8bd812f7..0d1b968fa3a4 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $ +/* $Id: setup.c,v 1.52 2000/03/03 23:48:41 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -164,9 +164,17 @@ int prom_callback(long *args) } if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) { + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + /* * Locked down tlb entry 63. */ + tte = spitfire_get_dtlb_data(63); res = PROM_TRUE; goto done; diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index 1aa48643ce48..1cdbf09da44e 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.19 1999/11/19 05:52:45 davem Exp $ +/* $Id: blockops.S,v 1.20 2000/03/03 23:48:38 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -46,13 +46,37 @@ copy_page: /* %o0=dest, %o1=src */ sethi %hi(TLBTEMP_ENT1), %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate + + /* Spitfire Errata #32 workaround */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %o4 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %o5 + stxa %g0, [%o5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS membar #Sync add %o3, (TLBTEMP_ENTSZ), %o3 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g5 + stxa %g0, [%g5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g7 + stxa %g0, [%g7] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o1, [%o2] ASI_DMMU stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS @@ -120,7 +144,19 @@ clear_page: /* %o0=dest */ sethi %hi(TLBTEMP_ENT2), %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g5 + stxa %g0, [%g5] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + + /* Spitfire Errata #32 workaround */ + mov 0x8, %g7 + stxa %g0, [%g7] ASI_DMMU + flush %g6 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o0, [%o2] ASI_DMMU stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 58dc224f9245..68147d4d4107 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.146 2000/02/09 21:11:09 davem Exp $ +/* $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -230,6 +230,14 @@ static void inherit_prom_mappings(void) /* Now fixup OBP's idea about where we really are mapped. */ prom_printf("Remapping the kernel... "); + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR; phys_page += ((unsigned long)&prom_boot_page - (unsigned long)&empty_zero_page); @@ -252,11 +260,27 @@ static void inherit_prom_mappings(void) : "memory"); tte_vaddr = (unsigned long) &empty_zero_page; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63); remap_func = (void *) ((unsigned long) &prom_remap - (unsigned long) &prom_boot_page); + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR, (unsigned long) &empty_zero_page, prom_get_mmu_ihandle()); @@ -319,8 +343,16 @@ static void __flush_nucleus_vptes(void) /* Only DTLB must be checked for VPTE entries. */ for(i = 0; i < 63; i++) { - unsigned long tag = spitfire_get_dtlb_tag(i); + unsigned long tag; + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + tag = spitfire_get_dtlb_tag(i); if(((tag & ~(PAGE_MASK)) == 0) && ((tag & (PAGE_MASK)) >= prom_reserved_base)) { __asm__ __volatile__("stxa %%g0, [%0] %1" @@ -436,10 +468,26 @@ void inherit_locked_prom_mappings(int save_p) for(i = 0; i < 63; i++) { unsigned long data; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + data = spitfire_get_dtlb_data(i); if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag = spitfire_get_dtlb_tag(i); + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + tag = spitfire_get_dtlb_tag(i); if(save_p) { prom_dtlb[dtlb_seen].tlb_ent = i; prom_dtlb[dtlb_seen].tlb_tag = tag; @@ -459,10 +507,25 @@ void inherit_locked_prom_mappings(int save_p) for(i = 0; i < 63; i++) { unsigned long data; + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + data = spitfire_get_itlb_data(i); if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag = spitfire_get_itlb_tag(i); + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + tag = spitfire_get_itlb_tag(i); if(save_p) { prom_itlb[itlb_seen].tlb_ent = i; prom_itlb[itlb_seen].tlb_tag = tag; @@ -544,6 +607,13 @@ void __flush_tlb_all(void) : "=r" (pstate) : "i" (PSTATE_IE)); for(i = 0; i < 64; i++) { + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) { __asm__ __volatile__("stxa %%g0, [%0] %1" : /* no outputs */ @@ -552,6 +622,14 @@ void __flush_tlb_all(void) spitfire_put_dtlb_data(i, 0x0UL); membar("#Sync"); } + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + if(!(spitfire_get_itlb_data(i) & _PAGE_L)) { __asm__ __volatile__("stxa %%g0, [%0] %1" : /* no outputs */ diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 0825b058585d..210db79e69d7 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.37 2000/02/14 02:52:04 davem Exp $ +/* $Id: ultra.S,v 1.38 2000/03/03 23:48:44 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -35,7 +35,7 @@ __flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */ __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT, * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start) */ -#define TLB_MAGIC 206 /* Students, do you know how I calculated this? -DaveM */ +#define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */ /*IC3*/ cmp %o5, %o4 be,pt %xcc, __flush_tlb_page srlx %o5, 13, %g5 @@ -58,6 +58,12 @@ __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ wrpr %g1, PSTATE_IE, %pstate mov TLB_TAG_ACCESS, %g3 mov (62 << 3), %g2 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + 1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 @@ -83,12 +89,27 @@ __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ wrpr %g1, 0x0, %pstate 4: stxa %g0, [%g3] ASI_IMMU stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS + flush %g6 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ba,pt %xcc, 2b - flush %g6 + nop + 5: stxa %g0, [%g3] ASI_DMMU /*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS + flush %g6 + + /* Spitfire Errata #32 workaround. */ + mov 0x8, %o4 + stxa %g0, [%o4] ASI_DMMU + flush %g6 + ba,pt %xcc, 3b - flush %g6 + nop .align 32 __flush_tlb_mm_slow: @@ -293,28 +314,51 @@ xcall_receive_signal: clr %l6 99: retry + .data + +errata32_hwbug: + .xword 0 + + .text + /* These two are not performance critical... */ .globl xcall_flush_tlb_all xcall_flush_tlb_all: + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + clr %g2 clr %g3 1: ldxa [%g3] ASI_DTLB_DATA_ACCESS, %g4 and %g4, _PAGE_L, %g5 brnz,pn %g5, 2f mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_DMMU membar #Sync - stxa %g0, [%g3] ASI_DTLB_DATA_ACCESS membar #Sync + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + 2: ldxa [%g3] ASI_ITLB_DATA_ACCESS, %g4 and %g4, _PAGE_L, %g5 brnz,pn %g5, 2f mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_IMMU membar #Sync - stxa %g0, [%g3] ASI_ITLB_DATA_ACCESS + membar #Sync + + /* Spitfire Errata #32 workaround. */ + sethi %hi(errata32_hwbug), %g4 + stx %g0, [%g4 + %lo(errata32_hwbug)] + 2: add %g2, 1, %g2 cmp %g2, 63 ble,pt %icc, 1b diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 64432480bc77..0e29e3a2e15b 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -213,9 +213,9 @@ if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then # tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING # tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT -fi +#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then +# bool ' Boot support (linear, striped)' CONFIG_MD_BOOT +#fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c index e7fd203b44df..b3ffaa529ea6 100644 --- a/drivers/block/ali14xx.c +++ b/drivers/block/ali14xx.c @@ -55,12 +55,12 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; +static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4}; /* register initialization data */ typedef struct { byte reg, data; } RegInitializer; -static RegInitializer __init initData[] = { +static RegInitializer initData[] __initdata = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, diff --git a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h index fedbb46acef0..31e9786f3fa2 100644 --- a/drivers/block/cpqarray.h +++ b/drivers/block/cpqarray.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #endif diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 0f032ac8c072..641783e9c526 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -1883,7 +1883,7 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi, char buffer[16]; int stat; - init_cdrom_command(&cgc, buffer, sizeof(buffer)); + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN); /* These will be moved into the Uniform layer shortly... */ switch (cmd) { @@ -2075,7 +2075,7 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) if ((stat = cdrom_select_speed (drive, speed)) < 0) return stat; - init_cdrom_command(&cgc, &buf, sizeof(buf)); + init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); #ifndef __ACER50__ /* Now with that done, update the speed fields */ @@ -2303,7 +2303,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) return nslots; } - init_cdrom_command(&cgc, &buf, sizeof(buf)); + init_cdrom_command(&cgc, &buf, sizeof(buf), CGC_DATA_UNKNOWN); /* we have to cheat a little here. the packet will eventually * be queued with ide_cdrom_packet(), which extracts the * drive from cdi->handle. Since this device hasn't been diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index 28eb789c2aeb..e0803e6fa29a 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -420,7 +420,7 @@ pmac_ide_probe(void) hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->chipset = ide_generic; + hwif->chipset = ide_pmac; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 90977c959742..debba3207c19 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -405,6 +405,7 @@ static int proc_ide_read_imodel case ide_cmd646: name = "cmd646"; break; case ide_cy82c693: name = "cy82c693"; break; case ide_4drives: name = "4drives"; break; + case ide_pmac: name = "mac-io"; break; default: name = "(unknown)"; break; } len = sprintf(page, "%s\n", name); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index abecb27c409f..65e7bfdc48e2 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -77,6 +77,7 @@ static int nbd_open(struct inode *inode, struct file *file) nbd_dev[dev].refcnt++; if (!(nbdev->flags & NBD_INITIALISED)) { init_MUTEX(&nbdev->queue_lock); + INIT_LIST_HEAD(&nbdev->queue_head); nbdev->flags |= NBD_INITIALISED; } MOD_INC_USE_COUNT; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index c20ce1b93982..c66efc8c7f96 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -187,14 +187,23 @@ -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8. - 3.05 Dec 13, 1999 - Jens Axboe + 3.06 Dec 13, 1999 - Jens Axboe -- Added support for changing the region of DVD drives. -- Added sense data to generic command. + + 3.07 Feb 2, 2000 - Jens Axboe + -- Do same "read header length" trick in cdrom_get_disc_info() as + we do in cdrom_get_track_info() -- some drive don't obbey specs and + fail if they can't supply the full Mt Fuji size table. + -- Deleted stuff related to setting up write modes. It has a different + home now. + -- Clear header length in mode_select unconditionally. + -- Removed the register_disk() that was added, not needed here. -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.06" -#define VERSION "Id: cdrom.c 3.06 1999/12/13" +#define REVISION "Revision: 3.07" +#define VERSION "Id: cdrom.c 3.07 2000/02/02" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -415,7 +424,6 @@ int unregister_cdrom(struct cdrom_device_info *unreg) return 0; } -static struct cdrom_device_info *cdrom_find_device(kdev_t dev) { struct cdrom_device_info *cdi; @@ -682,7 +690,7 @@ static int cdrom_read_mech_status(struct cdrom_device_info *cdi, length = sizeof(struct cdrom_mechstat_header) + cdi->capacity * sizeof(struct cdrom_slot); - init_cdrom_command(&cgc, buf, length); + init_cdrom_command(&cgc, buf, length, CGC_DATA_READ); cgc.cmd[0] = GPCMD_MECHANISM_STATUS; cgc.cmd[8] = (length >> 8) & 0xff; cgc.cmd[9] = length & 0xff; @@ -737,7 +745,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) if (cdi->sanyo_slot && slot < 0) return 0; - init_cdrom_command(&cgc, NULL, 0); + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); cgc.cmd[0] = GPCMD_LOAD_UNLOAD; cgc.cmd[4] = 2 + (slot >= 0); cgc.cmd[8] = slot; @@ -921,12 +929,15 @@ void sanitize_format(union cdrom_addr *addr, *curr = requested; } -void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len) +void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len, + int type) { memset(cgc, 0, sizeof(struct cdrom_generic_command)); - memset(buf, 0, len); + if (buf) + memset(buf, 0, len); cgc->buffer = (char *) buf; cgc->buflen = len; + cgc->data_direction = type; } /* DVD handling */ @@ -953,6 +964,7 @@ static void setup_report_key(struct cdrom_generic_command *cgc, unsigned agid, u } } cgc->cmd[9] = cgc->buflen; + cgc->data_direction = CGC_DATA_WRITE; } static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type) @@ -974,6 +986,7 @@ static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, uns } } cgc->cmd[9] = cgc->buflen; + cgc->data_direction = CGC_DATA_READ; } static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) @@ -983,7 +996,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, 0); + init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); switch (ai->type) { /* LU data send */ @@ -1124,7 +1137,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->physical.layer_num; cgc.cmd[7] = s->type; @@ -1165,7 +1178,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; @@ -1193,7 +1206,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; - init_cdrom_command(&cgc, buf, size); + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = size >> 8; @@ -1214,7 +1227,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf)); + init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen = 0xff; @@ -1244,7 +1257,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) return -ENOMEM; - init_cdrom_command(&cgc, buf, size); + init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[8] = size >> 8; @@ -1305,6 +1318,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi, cgc->cmd[2] = page_code | (page_control << 6); cgc->cmd[7] = cgc->buflen >> 8; cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_READ; return cdo->generic_packet(cdi, cgc); } @@ -1314,11 +1328,12 @@ int cdrom_mode_select(struct cdrom_device_info *cdi, struct cdrom_device_ops *cdo = cdi->ops; memset(cgc->cmd, 0, sizeof(cgc->cmd)); - + memset(cgc->buffer, 0, 2); cgc->cmd[0] = GPCMD_MODE_SELECT_10; cgc->cmd[1] = 0x10; /* PF */ cgc->cmd[7] = cgc->buflen >> 8; cgc->cmd[8] = cgc->buflen & 0xff; + cgc->data_direction = CGC_DATA_WRITE; return cdo->generic_packet(cdi, cgc); } @@ -1330,7 +1345,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, char buffer[32]; int ret; - init_cdrom_command(&cgc, buffer, 16); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; cgc.cmd[1] = 2; /* MSF addressing */ cgc.cmd[2] = 0x40; /* request subQ data */ @@ -1812,6 +1827,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); if (cgc.buffer == NULL) return -ENOMEM; + cgc.data_direction = CGC_DATA_READ; ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); if (!ret) if (copy_to_user((char *)arg, cgc.buffer, blocksize)) @@ -1849,7 +1865,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, kfree(cgc.buffer); return -EFAULT; } - + cgc.data_direction = CGC_DATA_READ; while (ra.nframes > 0) { ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW); @@ -1913,6 +1929,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cgc.cmd[7] = entry.cdte_addr.msf.second; cgc.cmd[8] = entry.cdte_addr.msf.frame; cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYMSF: { @@ -1926,6 +1943,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cgc.cmd[6] = msf.cdmsf_min1; cgc.cmd[7] = msf.cdmsf_sec1; cgc.cmd[8] = msf.cdmsf_frame1; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMPLAYBLK: { @@ -1939,6 +1957,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cgc.cmd[5] = blk.from & 0xff; cgc.cmd[7] = (blk.len >> 8) & 0xff; cgc.cmd[8] = blk.len & 0xff; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } case CDROMVOLCTRL: @@ -1989,9 +2008,6 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, buffer[offset+13] = volctrl.channel2 & mask[offset+13]; buffer[offset+15] = volctrl.channel3 & mask[offset+15]; - /* clear the first three */ - memset(buffer, 0, 3); - /* set volume */ cgc.buffer = buffer; return cdrom_mode_select(cdi, &cgc); @@ -2003,6 +2019,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cgc.cmd[0] = GPCMD_START_STOP_UNIT; cgc.cmd[1] = 1; cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } @@ -2011,6 +2028,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cgc.cmd[0] = GPCMD_PAUSE_RESUME; cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; + cgc.data_direction = CGC_DATA_NONE; return cdo->generic_packet(cdi, &cgc); } @@ -2090,7 +2108,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, if (copy && !ret) __copy_to_user(userbuf, cgc.buffer, cgc.buflen); /* copy back sense data */ - if (ret && sense != NULL) + if (sense != NULL) if (copy_to_user(sense, cgc.sense, sizeof(struct request_sense))) ret = -EFAULT; kfree(cgc.buffer); @@ -2125,7 +2143,7 @@ int cdrom_get_track_info(kdev_t dev, __u16 track, __u8 type, struct cdrom_generic_command cgc; int ret; - init_cdrom_command(&cgc, ti, 8); + init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; cgc.cmd[1] = type & 3; cgc.cmd[4] = (track & 0xff00) >> 8; @@ -2145,12 +2163,26 @@ int cdrom_get_disc_info(kdev_t dev, disc_information *di) struct cdrom_device_info *cdi = cdrom_find_device(dev); struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_generic_command cgc; + int ret; /* set up command and get the disc info */ - init_cdrom_command(&cgc, di, sizeof(*di)); + init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DISC_INFO; - cgc.cmd[8] = cgc.buflen; + cgc.cmd[8] = cgc.buflen = 2; + if ((ret = cdo->generic_packet(cdi, &cgc))) + return ret; + + /* not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply + */ + cgc.buflen = be16_to_cpu(di->disc_information_length) + + sizeof(di->disc_information_length); + + if (cgc.buflen > sizeof(disc_information)) + cgc.buflen = sizeof(disc_information); + + cgc.cmd[8] = cgc.buflen; return cdo->generic_packet(cdi, &cgc); } @@ -2265,6 +2297,7 @@ EXPORT_SYMBOL(cdrom_select_disc); EXPORT_SYMBOL(cdrom_mode_select); EXPORT_SYMBOL(cdrom_mode_sense); EXPORT_SYMBOL(init_cdrom_command); +EXPORT_SYMBOL(cdrom_find_device); #ifdef CONFIG_SYSCTL diff --git a/drivers/char/epca.c b/drivers/char/epca.c index e8de397bfce0..31cd5546c258 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1545,13 +1545,14 @@ int __init init_module() } /* End init_module */ #endif -#ifdef MODULE -/* -------------------- Begin cleanup_module ---------------------- */ #ifdef ENABLE_PCI static struct pci_driver epca_driver; #endif +#ifdef MODULE +/* -------------------- Begin cleanup_module ---------------------- */ + void cleanup_module() { /* Begin cleanup_module */ diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 0b1ab10e1f98..ad945239027b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -142,6 +142,8 @@ static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t); */ #define STLI_EISAPROBE 0 +static devfs_handle_t devfs_handle = NULL; + /*****************************************************************************/ /* @@ -830,8 +832,6 @@ int init_module() /*****************************************************************************/ -static devfs_handle_t devfs_handle = NULL; - void cleanup_module() { stlibrd_t *brdp; diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c index b63f35436409..6d98f9323025 100644 --- a/drivers/char/stradis.c +++ b/drivers/char/stradis.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -2236,13 +2237,9 @@ static void release_saa(void) } } -#ifdef MODULE -int init_module(void) -{ -#else -int init_stradis_cards(struct video_init *unused) + +static int __init stradis_init (void) { -#endif struct pci_dev *dev = NULL; int result = 0, i; @@ -2269,11 +2266,14 @@ int init_stradis_cards(struct video_init *unused) return 0; } -#ifdef MODULE -void cleanup_module(void) + +static void __exit stradis_exit (void) { release_saa(); printk(KERN_INFO "stradis: module cleanup complete\n"); } -#endif + +module_init(stradis_init); +module_exit(stradis_exit); + diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index cfcdbfcdeaa9..f0b1aaf4dd0b 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -60,9 +60,6 @@ static struct video_init video_init_list[]={ {"i2c-tuner", i2c_tuner_init}, {"bttv", init_bttv_cards}, #endif -#ifdef CONFIG_VIDEO_STRADIS - {"stradis", init_stradis_cards}, -#endif #ifdef CONFIG_VIDEO_BWQCAM {"bw-qcam", init_bw_qcams}, #endif diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c index d61b883752a0..1785e1740212 100644 --- a/drivers/isdn/avmb1/b1dma.c +++ b/drivers/isdn/avmb1/b1dma.c @@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.3 $"; MODULE_AUTHOR("Carsten Paeth "); -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_PARM(suppress_pollack, "0-1i"); /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c index 7483370cf269..76f34569dafd 100644 --- a/drivers/isdn/avmb1/c4.c +++ b/drivers/isdn/avmb1/c4.c @@ -65,7 +65,7 @@ static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ -int suppress_pollack = 0; +static int suppress_pollack = 0; MODULE_AUTHOR("Carsten Paeth "); diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index 5e948c7e7e30..b333ad08c6c0 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -1049,7 +1049,6 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb) static void elp_timeout(struct net_device *dev) { - unsigned long flags; elp_device *adapter = dev->priv; int stat; diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 80f56adf7603..d8a5e12af9e5 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -46,6 +46,7 @@ static int max_interrupt_work = 20; #define RX_RING_SIZE 16 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#include #include #include #include diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 9e3f72b3367c..7a14db1ce427 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -85,10 +85,7 @@ $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ */ -#ifdef MODULE #include -#endif - #include #include #include @@ -902,7 +899,7 @@ static void elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) #ifndef NO_NOPCOMMANDS if (stat & STAT_CNA) { /* CU went 'not ready' */ - if (netif_running(dev->state)) { + if (netif_running(dev)) { printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); } } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 64edb30c1afa..b264def307a4 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -3,6 +3,7 @@ # source drivers/net/arcnet/Config.in +source drivers/net/appletalk/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING @@ -131,9 +132,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then fi tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT - if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' CS89x0 support' CONFIG_CS89x0 - fi + tristate ' CS89x0 support' CONFIG_CS89x0 tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS @@ -209,27 +208,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then fi fi -# -# AppleTalk -# - -if [ "$CONFIG_ATALK" != "n" ]; then - mainmenu_option next_comment - comment 'Appletalk devices' - dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK - dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK - if [ "$CONFIG_COPS" != "n" ]; then - bool ' Dayna firmware support' CONFIG_COPS_DAYNA - bool ' Tangent firmware support' CONFIG_COPS_TANGENT - fi - dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK - if [ "$CONFIG_IPDDP" != "n" ]; then - bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP - bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP - fi - endmenu -fi - if [ ! "$CONFIG_PARPORT" = "n" ]; then dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT fi diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6a7b1f06abb9..3231ad4b96f2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -18,7 +18,7 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ - arcnet skfp tulip + arcnet skfp tulip appletalk O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -104,6 +104,15 @@ else endif endif +ifeq ($(CONFIG_ATALK),y) +SUB_DIRS += appletalk +MOD_IN_SUB_DIRS += appletalk +else + ifeq ($(CONFIG_ATALK),m) + MOD_IN_SUB_DIRS += appletalk + endif +endif + # # link order important here # @@ -280,9 +289,6 @@ obj-$(CONFIG_A2065) += a2065.o obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o -obj-$(CONFIG_LTPC) += ltpc.o -obj-$(CONFIG_COPS) += cops.o -obj-$(CONFIG_IPDDP) += ipddp.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 3587dfe16a67..9969bcbde342 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -83,13 +83,13 @@ * They used the DEC vendor ID by mistake */ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX -#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a +#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a #endif #ifndef PCI_VENDOR_ID_SGI -#define PCI_VENDOR_ID_SGI 0x10a9 +#define PCI_VENDOR_ID_SGI 0x10a9 #endif #ifndef PCI_DEVICE_ID_SGI_ACENIC -#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 +#define PCI_DEVICE_ID_SGI_ACENIC 0x0009 #endif #ifndef wmb @@ -100,6 +100,11 @@ #define __exit #endif +#ifndef SMP_CACHE_BYTES +#define SMP_CACHE_BYTES L1_CACHE_BYTES +#endif + + #if (LINUX_VERSION_CODE < 0x02030e) #define net_device device #endif @@ -121,7 +126,7 @@ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, return virt_ptr; } #define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) -#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) #define pci_unmap_single(cookie, address, size, dir) #endif @@ -140,18 +145,22 @@ static inline void netif_start_queue(struct net_device *dev) dev->start = 1; } -#define ace_mark_net_bh(foo) mark_bh(foo) -#define ace_if_busy(dev) dev->tbusy -#define ace_if_running(dev) dev->start -#define ace_if_down(dev) {do{dev->start = 0;}while (0);} +#define ace_mark_net_bh(foo) mark_bh(foo) +#define netif_queue_stopped(dev) dev->tbusy +#define netif_running(dev) dev->start +#define ace_if_down(dev) {do{dev->start = 0;}while (0);} #else #define NET_BH 0 #define ace_mark_net_bh(foo) {do{} while(0);} -#define ace_if_busy(dev) netif_queue_stopped(dev) -#define ace_if_running(dev) netif_running(dev) #define ace_if_down(dev) {do{} while(0);} #endif + +#define ACE_MAX_MOD_PARMS 8 +#define BOARD_IDX_STATIC 0 +#define BOARD_IDX_OVERFLOW -1 + + #include "acenic.h" /* @@ -336,30 +345,41 @@ static inline void netif_start_queue(struct net_device *dev) #define ACE_STD_BUFSIZE (ACE_STD_MTU + ETH_HLEN + 2+4+16) #define ACE_JUMBO_BUFSIZE (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16) -#define DEF_TX_RATIO 24 /* * There seems to be a magic difference in the effect between 995 and 996 * but little difference between 900 and 995 ... no idea why. + * + * There is now a default set of tuning parameters which is set, depending + * on whether or not the user enables Jumbo frames. It's assumed that if + * Jumbo frames are enabled, the user wants optimal tuning for that case. */ -#define DEF_TX_COAL 996 +#define DEF_TX_COAL 400 /* 996 */ #define DEF_TX_MAX_DESC 40 -#define DEF_RX_COAL 1000 +#define DEF_RX_COAL 120 /* 1000 */ #define DEF_RX_MAX_DESC 25 +#define DEF_TX_RATIO 21 /* 24 */ + +#define DEF_JUMBO_TX_COAL 20 +#define DEF_JUMBO_TX_MAX_DESC 60 +#define DEF_JUMBO_RX_COAL 30 +#define DEF_JUMBO_RX_MAX_DESC 6 +#define DEF_JUMBO_TX_RATIO 21 + #define TX_COAL_INTS_ONLY 0 /* seems not worth it */ #define DEF_TRACE 0 -#define DEF_STAT 2 * TICKS_PER_SEC +#define DEF_STAT (2 * TICKS_PER_SEC) -static int link[8] = {0, }; -static int trace[8] = {0, }; -static int tx_coal_tick[8] = {0, }; -static int rx_coal_tick[8] = {0, }; -static int max_tx_desc[8] = {0, }; -static int max_rx_desc[8] = {0, }; -static int tx_ratio[8] = {0, }; -static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1}; +static int link[ACE_MAX_MOD_PARMS] = {0, }; +static int trace[ACE_MAX_MOD_PARMS] = {0, }; +static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; +static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; +static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, }; +static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, }; +static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, }; +static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; static const char __initdata *version = - "acenic.c: v0.41 02/16/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" + "acenic.c: v0.42 03/02/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev = NULL; @@ -469,11 +489,6 @@ int __init acenic_probe (struct net_device *dev) pci_set_master(pdev); -#ifdef __sparc__ - /* NOTE: Cache line size is in 32-bit word units. */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); -#endif - /* * Remap the regs into kernel space - this is abuse of * dev->base_addr since it was means for I/O port @@ -484,7 +499,6 @@ int __init acenic_probe (struct net_device *dev) #else dev->base_addr = pdev->resource[0].start; #endif - ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); if (!ap->regs) { printk(KERN_ERR "%s: Unable to map I/O register, " @@ -540,8 +554,7 @@ int __init acenic_probe (struct net_device *dev) if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { printk(KERN_ERR "%s: Driver compiled without Tigon I" " support - NIC disabled\n", dev->name); - iounmap(ap->regs); - unregister_netdev(dev); + ace_init_cleanup(dev); continue; } #endif @@ -550,13 +563,17 @@ int __init acenic_probe (struct net_device *dev) continue; #ifdef MODULE - if (ace_init(dev, boards_found)) - continue; + if (boards_found >= ACE_MAX_MOD_PARMS) + ap->board_idx = BOARD_IDX_OVERFLOW; + else + ap->board_idx = boards_found; #else - if (ace_init(dev, -1)) - continue; + ap->board_idx = BOARD_IDX_STATIC; #endif + if (ace_init(dev)) + continue; + boards_found++; } @@ -566,20 +583,16 @@ int __init acenic_probe (struct net_device *dev) * or more boards. Otherwise, return failure (-ENODEV). */ -#ifdef MODULE - return boards_found; -#else if (boards_found > 0) return 0; else return -ENODEV; -#endif } #ifdef MODULE MODULE_AUTHOR("Jes Sorensen "); -MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver"); +MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver"); MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); @@ -597,7 +610,7 @@ void __exit ace_module_cleanup(void) while (root_dev) { next = ((struct ace_private *)root_dev->priv)->next; - ap = (struct ace_private *)root_dev->priv; + ap = root_dev->priv; regs = ap->regs; @@ -670,38 +683,26 @@ void __exit ace_module_cleanup(void) } } - ace_free_descriptors(root_dev); - - if (ap->trace_buf) - kfree(ap->trace_buf); - if (ap->info) - pci_free_consistent(ap->pdev, sizeof(struct ace_info), - ap->info, ap->info_dma); - if (ap->skb) - kfree(ap->skb); - if (root_dev->irq) - free_irq(root_dev->irq, root_dev); - unregister_netdev(root_dev); - iounmap(regs); + ace_init_cleanup(root_dev); kfree(root_dev); - root_dev = next; } } +#endif int __init ace_module_init(void) { - int cards; + int status; root_dev = NULL; #ifdef NEW_NETINIT - cards = acenic_probe(); + status = acenic_probe(); #else - cards = acenic_probe(NULL); + status = acenic_probe(NULL); #endif - return cards ? 0 : -ENODEV; + return status; } @@ -717,7 +718,6 @@ void cleanup_module(void) ace_module_cleanup(); } #endif -#endif #if (LINUX_VERSION_CODE >= 0x02032a) @@ -817,10 +817,36 @@ static int ace_allocate_descriptors(struct net_device *dev) fail: /* Clean up. */ + ace_init_cleanup(dev); + return 1; +} + + +/* + * Generic cleanup handling data allocated during init. Used when the + * module is unloaded or if an error occurs during initialization + */ +static void ace_init_cleanup(struct net_device *dev) +{ + struct ace_private *ap; + + ap = dev->priv; + ace_free_descriptors(dev); - iounmap(ap->regs); + + if (ap->info) + pci_free_consistent(ap->pdev, sizeof(struct ace_info), + ap->info, ap->info_dma); + if (ap->skb) + kfree(ap->skb); + if (ap->trace_buf) + kfree(ap->trace_buf); + + if (dev->irq) + free_irq(dev->irq, dev); + unregister_netdev(dev); - return 1; + iounmap(ap->regs); } @@ -840,19 +866,22 @@ static inline void ace_issue_cmd(struct ace_regs *regs, struct cmd *cmd) } -static int __init ace_init(struct net_device *dev, int board_idx) +static int __init ace_init(struct net_device *dev) { struct ace_private *ap; struct ace_regs *regs; struct ace_info *info = NULL; unsigned long tmp_ptr, myjif; u32 tig_ver, mac1, mac2, tmp, pci_state; - int ecode = 0; + int board_idx, ecode = 0; short i; + unsigned char cache; ap = dev->priv; regs = ap->regs; + board_idx = ap->board_idx; + /* * aman@sgi.com - its useful to do a NIC reset here to * address the `Firmware not running' problem subsequent @@ -968,6 +997,21 @@ static int __init ace_init(struct net_device *dev, int board_idx) dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; + /* + * Looks like this is necessary to deal with on all architectures, + * even this %$#%$# N440BX Intel based thing doesn't get it right. + * Ie. having two NICs in the machine, one will have the cache + * line set at boot time, the other will not. + */ + pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache); + if ((cache << 2) != SMP_CACHE_BYTES) { + printk(KERN_INFO " PCI cache line size set incorrectly " + "(%i bytes) by BIOS/FW, correcting to %i\n", + (cache << 2), SMP_CACHE_BYTES); + pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, + SMP_CACHE_BYTES >> 2); + } + pci_state = readl(®s->PciState); printk(KERN_INFO " PCI bus width: %i bits, speed: %iMHz, " "latency: %i clks\n", @@ -991,19 +1035,20 @@ static int __init ace_init(struct net_device *dev, int board_idx) /* * Tuning parameters only supported for 8 cards */ - if (board_idx > 7 || dis_pci_mem_inval[board_idx]) { + if (board_idx == BOARD_IDX_OVERFLOW || + dis_pci_mem_inval[board_idx]) { if (ap->pci_command & PCI_COMMAND_INVALIDATE) { ap->pci_command &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); - printk(KERN_INFO "%s: disabling PCI memory " - "write and invalidate\n", dev->name); + printk(KERN_INFO " Disabling PCI memory " + "write and invalidate\n"); } } else if (ap->pci_command & PCI_COMMAND_INVALIDATE) { - printk(KERN_INFO "%s: PCI memory write & invalidate " - "enabled by BIOS, enabling counter " - "measures\n", dev->name); - switch(L1_CACHE_BYTES) { + printk(KERN_INFO " PCI memory write & invalidate " + "enabled by BIOS, enabling counter measures\n"); + + switch(SMP_CACHE_BYTES) { case 16: tmp |= DMA_WRITE_MAX_16; break; @@ -1023,8 +1068,10 @@ static int __init ace_init(struct net_device *dev, int board_idx) } } } + #ifdef __sparc__ - /* On this platform, we know what the best dma settings + /* + * On this platform, we know what the best dma settings * are. We use 64-byte maximum bursts, because if we * burst larger than the cache line size (or even cross * a 64byte boundry in a single burst) the UltraSparc @@ -1034,12 +1081,18 @@ static int __init ace_init(struct net_device *dev, int board_idx) * set will give the PCI controller proper hints about * prefetching. */ - tmp = (tmp & ~(0xfc)); + tmp = tmp & ~DMA_READ_WRITE_MASK; tmp |= DMA_READ_MAX_64; tmp |= DMA_WRITE_MAX_64; #endif writel(tmp, ®s->PciState); + if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) { + printk(KERN_INFO " Enabling PCI Fast Back to Back\n"); + ap->pci_command |= PCI_COMMAND_FAST_BACK; + pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command); + } + /* * Initialize the generic info block and the command+event rings * and the control blocks for the transmit and receive rings @@ -1213,21 +1266,15 @@ static int __init ace_init(struct net_device *dev, int board_idx) writel(1, ®s->AssistState); writel(DEF_STAT, ®s->TuneStatTicks); - - writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); - writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); - writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); - writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); writel(DEF_TRACE, ®s->TuneTrace); - writel(DEF_TX_RATIO, ®s->TxBufRat); - if (board_idx >= 8) { - printk(KERN_WARNING "%s: more then 8 NICs detected, " - "ignoring module parameters!\n", dev->name); - board_idx = -1; - } + ace_set_rxtx_parms(dev, 0); - if (board_idx >= 0) { + if (board_idx == BOARD_IDX_OVERFLOW) { + printk(KERN_WARNING "%s: more then %i NICs detected, " + "ignoring module parameters!\n", + dev->name, ACE_MAX_MOD_PARMS); + } else if (board_idx >= 0) { if (tx_coal_tick[board_idx]) writel(tx_coal_tick[board_idx], ®s->TuneTxCoalTicks); @@ -1352,8 +1399,6 @@ static int __init ace_init(struct net_device *dev, int board_idx) writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); writel(0, ®s->Mb0Lo); - free_irq(dev->irq, dev); - dev->irq = 0; ecode = -EBUSY; goto init_error; @@ -1376,27 +1421,63 @@ static int __init ace_init(struct net_device *dev, int board_idx) "the RX mini ring\n", dev->name); } return 0; + init_error: - iounmap(ap->regs); - unregister_netdev(dev); - if (ap->skb) { - kfree(ap->skb); - ap->skb = NULL; - } - if (ap->info) - pci_free_consistent(ap->pdev, sizeof(struct ace_info), - info, ap->info_dma); + ace_init_cleanup(dev); return ecode; } +static void ace_set_rxtx_parms(struct net_device *dev, int jumbo) +{ + struct ace_private *ap; + struct ace_regs *regs; + int board_idx; + + ap = dev->priv; + regs = ap->regs; + + board_idx = ap->board_idx; + + if (board_idx >= 0) { + if (!jumbo) { + if (!tx_coal_tick[board_idx]) + writel(DEF_TX_COAL, ®s->TuneTxCoalTicks); + if (!max_tx_desc[board_idx]) + writel(DEF_TX_MAX_DESC, ®s->TuneMaxTxDesc); + if (!rx_coal_tick[board_idx]) + writel(DEF_RX_COAL, ®s->TuneRxCoalTicks); + if (!max_rx_desc[board_idx]) + writel(DEF_RX_MAX_DESC, ®s->TuneMaxRxDesc); + if (!tx_ratio[board_idx]) + writel(DEF_TX_RATIO, ®s->TxBufRat); + } else { + if (!tx_coal_tick[board_idx]) + writel(DEF_JUMBO_TX_COAL, + ®s->TuneTxCoalTicks); + if (!max_tx_desc[board_idx]) + writel(DEF_JUMBO_TX_MAX_DESC, + ®s->TuneMaxTxDesc); + if (!rx_coal_tick[board_idx]) + writel(DEF_JUMBO_RX_COAL, + ®s->TuneRxCoalTicks); + if (!max_rx_desc[board_idx]) + writel(DEF_JUMBO_RX_MAX_DESC, + ®s->TuneMaxRxDesc); + if (!tx_ratio[board_idx]) + writel(DEF_JUMBO_TX_RATIO, ®s->TxBufRat); + } + } +} + + /* * Monitor the card to detect hangs. */ static void ace_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; /* @@ -1459,7 +1540,7 @@ static void ace_dump_trace(struct ace_private *ap) { #if 0 if (!ap->trace_buf) - if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))); + if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL))) return; #endif } @@ -1664,7 +1745,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) { struct ace_private *ap; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; while (evtcsm != evtprd) { switch (ap->evt_ring[evtcsm].evt) { @@ -1742,7 +1823,7 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd) static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) { - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; u32 idx; int mini_count = 0, std_count = 0; @@ -1795,7 +1876,8 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) skb = rip->skb; rip->skb = NULL; - pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE); + pci_unmap_single(ap->pdev, rip->mapping, mapsize, + PCI_DMA_FROMDEVICE); skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -1860,7 +1942,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) u32 txcsm, rxretcsm, rxretprd; u32 evtcsm, evtprd; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; /* @@ -1902,7 +1984,8 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) ap->stats.tx_packets++; ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(ap->pdev, mapping, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); ap->skb->tx_skbuff[idx].skb = NULL; @@ -1928,7 +2011,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) * Ie. skip the comparison of the tx producer vs. the * consumer. */ - if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) { + if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) { /* * This does not need to be atomic (and expensive), * I've seen cases where it would fail otherwise ;-( @@ -1959,7 +2042,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) * This has to go last in the interrupt handler and run with * the spin lock released ... what lock? */ - if (ace_if_running(dev)) { + if (netif_running(dev)) { int cur_size; int run_bh = 0; @@ -2108,7 +2191,7 @@ static int ace_close(struct net_device *dev) ace_if_down(dev); netif_stop_queue(dev); - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; del_timer(&ap->timer); @@ -2143,7 +2226,8 @@ static int ace_close(struct net_device *dev) writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); - pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(ap->pdev, mapping, skb->len, + PCI_DMA_TODEVICE); dev_kfree_skb(skb); ap->skb->tx_skbuff[i].skb = NULL; } @@ -2165,7 +2249,7 @@ static int ace_close(struct net_device *dev) static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ace_private *ap = (struct ace_private *)dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; unsigned long addr; u32 idx, flagsize; @@ -2193,7 +2277,8 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev) ap->skb->tx_skbuff[idx].skb = skb; ap->skb->tx_skbuff[idx].mapping = - pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + pci_map_single(ap->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; #if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); @@ -2264,12 +2349,13 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu) ap->jumbo = 1; if (!test_and_set_bit(0, &ap->jumbo_refill_busy)) ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE); - ap->jumbo = 1; + ace_set_rxtx_parms(dev, 1); } } else { netif_stop_queue(dev); while (test_and_set_bit(0, &ap->jumbo_refill_busy)); synchronize_irq(); + ace_set_rxtx_parms(dev, 0); if (ap->jumbo){ struct cmd cmd; @@ -2287,7 +2373,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu) static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { #ifdef ETHTOOL - struct ace_private *ap = (struct ace_private *) dev->priv; + struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; struct ethtool_cmd ecmd; u32 link, speed; @@ -2429,7 +2515,7 @@ static int ace_set_mac_addr(struct net_device *dev, void *p) u16 *da; struct cmd cmd; - if(ace_if_running(dev)) + if(netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); @@ -2587,7 +2673,7 @@ int __init ace_load_firmware(struct net_device *dev) struct ace_private *ap; struct ace_regs *regs; - ap = (struct ace_private *)dev->priv; + ap = dev->priv; regs = ap->regs; if (!(readl(®s->CpuCtrl) & CPU_HALTED)) { diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index 7719338ab577..958561a690b6 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -233,6 +233,7 @@ typedef struct { #define DMA_WRITE_MAX_128 0xa0 #define DMA_WRITE_MAX_256 0xc0 #define DMA_WRITE_MAX_1K 0xe0 +#define DMA_READ_WRITE_MASK 0xfc #define MEM_READ_MULTIPLE 0x00020000 #define PCI_66MHZ 0x00080000 #define PCI_32BIT 0x00100000 @@ -635,6 +636,7 @@ struct ace_private unsigned char *trace_buf; struct pci_dev *pdev; struct net_device *next; + int board_idx; u16 pci_command; u8 pci_latency; char name[48]; @@ -698,7 +700,7 @@ static inline void ace_set_txprd(struct ace_regs *regs, /* * Prototypes */ -static int ace_init(struct net_device *dev, int board_idx); +static int ace_init(struct net_device *dev); static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs); static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs); @@ -717,8 +719,10 @@ extern int ace_recycle(struct sk_buff *skb); #endif static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int ace_set_mac_addr(struct net_device *dev, void *p); +static void ace_set_rxtx_parms(struct net_device *dev, int jumbo); static int ace_allocate_descriptors(struct net_device *dev); static void ace_free_descriptors(struct net_device *dev); +static void ace_init_cleanup(struct net_device *dev); static struct net_device_stats *ace_get_stats(struct net_device *dev); static int read_eeprom_byte(struct net_device *dev, unsigned long offset); diff --git a/drivers/net/appletalk/Config.in b/drivers/net/appletalk/Config.in new file mode 100644 index 000000000000..951cf498d98c --- /dev/null +++ b/drivers/net/appletalk/Config.in @@ -0,0 +1,20 @@ +# +# Appletalk driver configuration +# + +if [ "$CONFIG_ATALK" != "n" ]; then + mainmenu_option next_comment + comment 'Appletalk devices' + dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK + dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK + if [ "$CONFIG_COPS" != "n" ]; then + bool ' Dayna firmware support' CONFIG_COPS_DAYNA + bool ' Tangent firmware support' CONFIG_COPS_TANGENT + fi + dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK + if [ "$CONFIG_IPDDP" != "n" ]; then + bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP + bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP + fi + endmenu +fi diff --git a/drivers/net/appletalk/Makefile b/drivers/net/appletalk/Makefile new file mode 100644 index 000000000000..a59443c6128a --- /dev/null +++ b/drivers/net/appletalk/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for drivers/net/appletalk +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +obj-y := +obj-n := +obj-m := +obj- := +export-objs := + +obj-$(CONFIG_LTPC) += ltpc.o +obj-$(CONFIG_COPS) += cops.o +obj-$(CONFIG_IPDDP) += ipddp.o + +L_TARGET := appletalk.a +L_OBJS := $(filter-out $(export-objs), $(obj-y)) +LX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make + diff --git a/drivers/net/cops.c b/drivers/net/appletalk/cops.c similarity index 100% rename from drivers/net/cops.c rename to drivers/net/appletalk/cops.c diff --git a/drivers/net/cops.h b/drivers/net/appletalk/cops.h similarity index 100% rename from drivers/net/cops.h rename to drivers/net/appletalk/cops.h diff --git a/drivers/net/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h similarity index 100% rename from drivers/net/cops_ffdrv.h rename to drivers/net/appletalk/cops_ffdrv.h diff --git a/drivers/net/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h similarity index 100% rename from drivers/net/cops_ltdrv.h rename to drivers/net/appletalk/cops_ltdrv.h diff --git a/drivers/net/ipddp.c b/drivers/net/appletalk/ipddp.c similarity index 100% rename from drivers/net/ipddp.c rename to drivers/net/appletalk/ipddp.c diff --git a/drivers/net/ipddp.h b/drivers/net/appletalk/ipddp.h similarity index 100% rename from drivers/net/ipddp.h rename to drivers/net/appletalk/ipddp.h diff --git a/drivers/net/ltpc.c b/drivers/net/appletalk/ltpc.c similarity index 99% rename from drivers/net/ltpc.c rename to drivers/net/appletalk/ltpc.c index e461f8807137..2728d63c0bf8 100644 --- a/drivers/net/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -62,6 +62,9 @@ /*** * * $Log: ltpc.c,v $ + * Revision 1.1.2.1 2000/03/01 05:35:07 jgarzik + * at and tr cleanup + * * Revision 1.8 1997/01/28 05:44:54 bradford * Clean up for non-module a little. * Hacked about a bit to clean things up - Alan Cox diff --git a/drivers/net/ltpc.h b/drivers/net/appletalk/ltpc.h similarity index 100% rename from drivers/net/ltpc.h rename to drivers/net/appletalk/ltpc.h diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 01dd799b3810..5ef42cf9c62a 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1,4 +1,7 @@ -/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 + * driver for linux. + */ + /* Written 1996 by Russell Nelson, with reference to skeleton.c written 1993-1994 by Donald Becker. @@ -6,8 +9,8 @@ This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. - The author may be reached at nelson@crynwr.com, Crynwr - Software, 11 Grant St., Potsdam, NY 13676 + The author may be reached at nelson@crynwr.com, Crynwr + Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 Changelog: @@ -25,19 +28,30 @@ : as an example. Disabled autoprobing in init_module(), : not a good thing to do to other devices while Linux : is running from all accounts. - + + Russ Nelson : Jul 13 1998. Added RxOnly DMA support. + + Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility. + : email: ethernet@crystal.cirrus.com + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + Andrew Morton : andrewm@uow.edu.au + : Kernel 2.3.48 + : Handle kmalloc() failures + : Other resource allocation fixes + : Add SMP locks + : Integrate Russ Nelson's ALLOW_DMA functionality back in. + : If ALLOW_DMA is true, make DMA runtime selectable + : Folded in changes from Cirrus (Melody Lee + : ) + : Don't call netif_wake_queue() in net_send_packet() + : Fixed an out-of-mem bug in dma_rx() + : Updated Documentation/cs89x0.txt */ static char *version = -"cs89x0.c:v1.03 11/26/96 Russell Nelson \n"; - -/* ======================= configure the driver here ======================= */ - -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 2 -#endif +"cs89x0.c: (kernel 2.3.48) Russell Nelson , Andrew Morton \n"; /* ======================= end of configuration ======================= */ @@ -52,7 +66,19 @@ static char *version = #define MOD_DEC_USE_COUNT #endif -#define PRINTK(x) printk x +/* + * Set this to zero to disable DMA code + * + * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' + * module options so we don't break any startup scripts. + */ +#define ALLOW_DMA 1 + +/* + * Set this to zero to remove all the debug statements via + * dead code elimination + */ +#define DEBUGGING 0 /* Sources: @@ -76,39 +102,66 @@ static char *version = #include #include #include +#if ALLOW_DMA +#include +#endif #include #include +#include #include #include #include + #include "cs89x0.h" /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ static unsigned int netcard_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; + { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; -static unsigned int net_debug = NET_DEBUG; +#if DEBUGGING +static unsigned int net_debug = 5; +#else +#define net_debug 0 /* gcc will remove all the debug code for us */ +#endif /* The number of low I/O ports used by the ethercard. */ #define NETCARD_IO_EXTENT 16 +/* we allow the user to override various values normally set in the EEPROM */ +#define FORCE_RJ45 0x0001 /* pick one of these three */ +#define FORCE_AUI 0x0002 +#define FORCE_BNC 0x0004 + +#define FORCE_AUTO 0x0010 /* pick one of these three */ +#define FORCE_HALF 0x0020 +#define FORCE_FULL 0x0030 + /* Information that need to be kept for each board. */ struct net_local { struct net_device_stats stats; int chip_type; /* one of: CS8900, CS8920, CS8920M */ char chip_revision; /* revision letter of the chip ('A'...) */ - int send_cmd; /* the propercommand used to send a packet. */ - int auto_neg_cnf; - int adapter_cnf; - int isa_config; - int irq_map; - int rx_mode; - int curr_rx_cfg; - int linectl; - int send_underrun; /* keep track of how many underruns in a row we get */ - struct sk_buff *skb; + int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */ + int auto_neg_cnf; /* auto-negotiation word from EEPROM */ + int adapter_cnf; /* adapter configuration from EEPROM */ + int isa_config; /* ISA configuration from EEPROM */ + int irq_map; /* IRQ map from EEPROM */ + int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */ + int curr_rx_cfg; /* a copy of PP_RxCFG */ + int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. */ + int send_underrun; /* keep track of how many underruns in a row we get */ + int force; /* force various values; see FORCE* above. */ + spinlock_t lock; +#if ALLOW_DMA + int use_dma; /* Flag: we're using dma */ + int dma; /* DMA channel */ + int dmasize; /* 16 or 64 */ + unsigned char *dma_buff; /* points to the beginning of the buffer */ + unsigned char *end_dma_buff; /* points to the end of the buffer */ + unsigned char *rx_dma_ptr; /* points to the next packet */ +#endif }; /* Index to functions, as function prototypes. */ @@ -117,7 +170,7 @@ extern int cs89x0_probe(struct net_device *dev); static int cs89x0_probe1(struct net_device *dev, int ioaddr); static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void set_multicast_list(struct net_device *dev); static void net_timeout(struct net_device *dev); @@ -128,7 +181,11 @@ static void reset_chip(struct net_device *dev); static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer); static int get_eeprom_cksum(int off, int len, int *buffer); static int set_mac_address(struct net_device *dev, void *addr); - +static void count_rx_errors(int status, struct net_local *lp); +#if ALLOW_DMA +static void get_dma_channel(struct net_device *dev); +static void release_dma_buff(struct net_local *lp); +#endif /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -139,6 +196,7 @@ static int set_mac_address(struct net_device *dev, void *addr); If dev->base_addr == 1, always return failure. If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). + Return 0 on success. */ int __init cs89x0_probe(struct net_device *dev) @@ -146,6 +204,9 @@ int __init cs89x0_probe(struct net_device *dev) int i; int base_addr = dev ? dev->base_addr : 0; + if (net_debug) + printk("cs89x0:cs89x0_probe()\n"); + if (base_addr > 0x1ff) /* Check a single specified location. */ return cs89x0_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -158,34 +219,38 @@ int __init cs89x0_probe(struct net_device *dev) if (cs89x0_probe1(dev, ioaddr) == 0) return 0; } - printk("cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); + printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); return ENODEV; } -extern int inline readreg(struct net_device *dev, int portno) +extern int inline +readreg(struct net_device *dev, int portno) { outw(portno, dev->base_addr + ADD_PORT); return inw(dev->base_addr + DATA_PORT); } -extern void inline writereg(struct net_device *dev, int portno, int value) +extern void inline +writereg(struct net_device *dev, int portno, int value) { outw(portno, dev->base_addr + ADD_PORT); outw(value, dev->base_addr + DATA_PORT); } - -extern int inline readword(struct net_device *dev, int portno) +extern int inline +readword(struct net_device *dev, int portno) { return inw(dev->base_addr + portno); } -extern void inline writeword(struct net_device *dev, int portno, int value) +extern void inline +writeword(struct net_device *dev, int portno, int value) { outw(value, dev->base_addr + portno); } -static int __init wait_eeprom_ready(struct net_device *dev) +static int __init +wait_eeprom_ready(struct net_device *dev) { int timeout = jiffies; /* check to see if the EEPROM is ready, a timeout is used - @@ -197,7 +262,8 @@ static int __init wait_eeprom_ready(struct net_device *dev) return 0; } -static int __init get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) +static int __init +get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) { int i; @@ -214,7 +280,8 @@ static int __init get_eeprom_data(struct net_device *dev, int off, int len, int return 0; } -static int __init get_eeprom_cksum(int off, int len, int *buffer) +static int __init +get_eeprom_cksum(int off, int len, int *buffer) { int i, cksum; @@ -229,19 +296,28 @@ static int __init get_eeprom_cksum(int off, int len, int *buffer) /* This is the real probe routine. Linux has a history of friendly device probes on the ISA bus. A good device probes avoids doing writes, and - verifies that the correct device exists and functions. */ + verifies that the correct device exists and functions. + Return 0 on success. + */ -static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) +static int __init +cs89x0_probe1(struct net_device *dev, int ioaddr) { struct net_local *lp; static unsigned version_printed = 0; int i; unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; + int retval; /* Initialize the device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == 0) + { + retval = ENOMEM; + goto out; + } memset(dev->priv, 0, sizeof(struct net_local)); } lp = (struct net_local *)dev->priv; @@ -257,7 +333,10 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) } if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) - return ENODEV; + { + retval = ENODEV; + goto out1; + } /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; @@ -278,7 +357,7 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) if (net_debug && version_printed++ == 0) printk(version); - printk("%s: cs89%c0%s rev %c found at %#3lx", + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ", dev->name, lp->chip_type==CS8900?'0':'2', lp->chip_type==CS8920M?"M":"", @@ -289,11 +368,11 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) /* First check to see if an EEPROM is attached*/ if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) - printk("\ncs89x0: No EEPROM, relying on command line....\n"); + printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n"); else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM read failed, relying on command line.\n"); + printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n"); } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk("\ncs89x0: EEPROM checksum bad, relying on command line\n"); + printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n"); } else { /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; @@ -301,16 +380,36 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2]; /* Store ISA configuration */ lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2]; - /* store the initial memory base address */ dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8; + + /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ + /* store the initial memory base address */ for (i = 0; i < ETH_ALEN/2; i++) { dev->dev_addr[i*2] = eeprom_buff[i]; dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; } } + /* allow them to force multiple transceivers. If they force multiple, autosense */ + { + int count = 0; + if (lp->force & FORCE_RJ45) {lp->adapter_cnf |= A_CNF_10B_T; count++; } + if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_AUI; count++; } + if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_10B_2; count++; } + if (count > 1) {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; } + else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; } + else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; } + else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; } + } + + /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ - printk(" media %s%s%s", + /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ + + /* FIXME: we don't set the Ethernet address on the command line. Use + ifconfig IFACE hw ether AABBCCDDEEFF */ + + printk(KERN_INFO "cs89x0 media %s%s%s", (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"", (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"", (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":""); @@ -353,14 +452,33 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) dev->irq = i; } - printk(" IRQ %d", dev->irq); + printk(", IRQ %d", dev->irq); +#if ALLOW_DMA + if (lp->use_dma) + { + get_dma_channel(dev); + printk(", DMA %d", dev->dma); + } + else +#endif + { + printk(", programmed I/O"); + } /* print the ethernet address. */ + printk(", MAC "); for (i = 0; i < ETH_ALEN; i++) - printk(" %2.2x", dev->dev_addr[i]); + { + printk("%s%02x", i ? ":" : "", dev->dev_addr[i]); + } /* Grab the region so we can find another board if autoIRQ fails. */ + + /* + * FIXME: we should check this, but really the isapnp stuff should have given + * us a free region. Sort this out when the isapnp is sorted out + */ request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0"); dev->open = net_open; @@ -376,11 +494,188 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr) ether_setup(dev); printk("\n"); + if (net_debug) + printk("cs89x0_probe1() successful\n"); return 0; +out1: + kfree(dev->priv); + dev->priv = 0; +out: + return retval; +} + + +/********************************* + * This page contains DMA routines +**********************************/ + +#if ALLOW_DMA + +#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) + +static void +get_dma_channel(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->dma) { + dev->dma = lp->dma; + lp->isa_config |= ISA_RxDMA; + } else { + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + dev->dma = lp->isa_config & DMA_NO_MASK; + if (lp->chip_type == CS8900) + dev->dma += 5; + if (dev->dma < 5 || dev->dma > 7) { + lp->isa_config &= ~ANY_ISA_DMA; + return; + } + } + return; +} + +static void +write_dma(struct net_device *dev, int chip_type, int dma) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + if (chip_type == CS8900) { + writereg(dev, PP_CS8900_ISADMA, dma-5); + } else { + writereg(dev, PP_CS8920_ISADMA, dma); + } +} + +static void +set_dma_cfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->use_dma) + { + if ((lp->isa_config & ANY_ISA_DMA) == 0) + { + if (net_debug > 3) + printk("set_dma_cfg(): no DMA\n"); + return; + } + if (lp->isa_config & ISA_RxDMA) + { + lp->curr_rx_cfg |= RX_DMA_ONLY; + if (net_debug > 3) + printk("set_dma_cfg(): RX_DMA_ONLY\n"); + } + else + { + lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */ + if (net_debug > 3) + printk("set_dma_cfg(): AUTO_RX_DMA\n"); + } + } +} + +static int +dma_bufcfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) + return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0; + else + return 0; +} + +static int +dma_busctl(struct net_device *dev) +{ + int retval = 0; + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) + { + if (lp->isa_config & ANY_ISA_DMA) + retval |= RESET_RX_DMA; /* Reset the DMA pointer */ + if (lp->isa_config & DMA_BURST) + retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */ + if (lp->dmasize == 64) + retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */ + retval |= MEMORY_ON; /* we need memory enabled to use DMA. */ + } + return retval; +} + +static void +dma_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + unsigned char *bp = lp->rx_dma_ptr; + + { + int i; + for (i = 0; i < 1000; i++) + ; + } + + status = bp[0] + (bp[1]<<8); + length = bp[2] + (bp[3]<<8); + bp += 4; + if (net_debug > 5) + { + printk( "%s: receiving DMA packet at %lx, status %x, length %x\n", + dev->name, (unsigned long)bp, status, length); + } + if ((status & RX_OK) == 0) { + count_rx_errors(status, lp); + goto skip_this_frame; + } + + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + if (net_debug) /* I don't think we want to do this to a stressed system */ + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + + /* AKPM: advance bp to the next frame */ +skip_this_frame: + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + return; + } + + skb->len = length; + skb->dev = dev; + + if (bp + length > lp->end_dma_buff) { + int semi_cnt = lp->end_dma_buff - bp; + memcpy(skb_put(skb,semi_cnt), bp, semi_cnt); + memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff, + length - semi_cnt); + } else { + memcpy(skb_put(skb,length), bp, length); + } + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + + if (net_debug > 3) + { + printk( "%s: received %d byte DMA packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + return; } -void __init -reset_chip(struct net_device *dev) +#endif /* ALLOW_DMA */ + +void __init reset_chip(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; @@ -399,8 +694,8 @@ reset_chip(struct net_device *dev) outb(0, ioaddr + DATA_PORT + 1); outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); - outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT); - outb((dev->mem_start >> 24) & 0xff, ioaddr + DATA_PORT + 1); + outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); + outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); } /* Wait until the chip is reset */ reset_start_time = jiffies; @@ -430,11 +725,18 @@ control_dc_dc(struct net_device *dev, int on_not_off) } +#define DETECTED_NONE 0 +#define DETECTED_RJ45H 1 +#define DETECTED_RJ45F 2 +#define DETECTED_AUI 3 +#define DETECTED_BNC 4 + static int detect_tp(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int timenow = jiffies; + int fdx; if (net_debug > 1) printk("%s: Attempting TP\n", dev->name); @@ -450,35 +752,63 @@ detect_tp(struct net_device *dev) for (timenow = jiffies; jiffies - timenow < 15; ) ; if ((readreg(dev, PP_LineST) & LINK_OK) == 0) - return 0; - - if (lp->chip_type != CS8900) { + return DETECTED_NONE; + + if (lp->chip_type == CS8900) { + switch (lp->force & 0xf0) { +#if 0 + case FORCE_AUTO: + printk("%s: cs8900 doesn't autonegotiate\n",dev->name); + return DETECTED_NONE; +#endif + /* CS8900 doesn't support AUTO, change to HALF*/ + case FORCE_AUTO: + lp->force &= ~FORCE_AUTO; + lp->force |= FORCE_HALF; + break; + case FORCE_HALF: + break; + case FORCE_FULL: + writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900); + break; + } + fdx = readreg(dev, PP_TestCTL) & FDX_8900; + } else { + switch (lp->force & 0xf0) { + case FORCE_AUTO: + lp->auto_neg_cnf = AUTO_NEG_ENABLE; + break; + case FORCE_HALF: + lp->auto_neg_cnf = 0; + break; + case FORCE_FULL: + lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX; + break; + } writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { - printk("%s: negotiating duplex...\n",dev->name); + printk(KERN_INFO "%s: negotiating duplex...\n",dev->name); while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { if (jiffies - timenow > 4000) { - printk("**** Full / half duplex auto-negotiation timed out ****\n"); + printk(KERN_ERR "**** Full / half duplex auto-negotiation timed out ****\n"); break; } } } - if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE) - printk("%s: using full duplex\n", dev->name); - else - printk("%s: using half duplex\n", dev->name); + fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE; } - - return A_CNF_MEDIA_10B_T; + if (fdx) + return DETECTED_RJ45F; + else + return DETECTED_RJ45H; } /* send a test packet - return true if carrier bits are ok */ static int send_test_pkt(struct net_device *dev) { - int ioaddr = dev->base_addr; char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 0, 46, /* A 46 in network order */ 0, 0, /* DSAP=0 & SSAP=0 fields */ @@ -490,8 +820,8 @@ send_test_pkt(struct net_device *dev) memcpy(test_packet, dev->dev_addr, ETH_ALEN); memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); - outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT); - outw(ETH_ZLEN, ioaddr + TX_LEN_PORT); + writeword(dev, TX_CMD_PORT, TX_AFTER_ALL); + writeword(dev, TX_LEN_PORT, ETH_ZLEN); /* Test to see if the chip has allocated memory for the packet */ while (jiffies - timenow < 5) @@ -501,11 +831,7 @@ send_test_pkt(struct net_device *dev) return 0; /* this shouldn't happen */ /* Write the contents of the packet */ - if (dev->mem_start) { - memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN); - } else { - outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); - } + outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); if (net_debug > 1) printk("Sending test packet "); /* wait a couple of jiffies for packet to be received */ @@ -531,9 +857,9 @@ detect_aui(struct net_device *dev) writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) - return A_CNF_MEDIA_AUI; + return DETECTED_AUI; else - return 0; + return DETECTED_NONE; } static int @@ -547,9 +873,9 @@ detect_bnc(struct net_device *dev) writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) - return A_CNF_MEDIA_10B_2; + return DETECTED_BNC; else - return 0; + return DETECTED_NONE; } @@ -579,6 +905,9 @@ write_irq(struct net_device *dev, int chip_type, int irq) registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. */ + +/* AKPM: do we need to do any locking here? */ + static int net_open(struct net_device *dev) { @@ -588,9 +917,15 @@ net_open(struct net_device *dev) if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ +/* Cirrus' release had this: */ +#if 0 + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); +#endif +/* And 2.3.47 had this: */ writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) { - if (request_irq (i, NULL, 0, "cs8920", dev) != -EBUSY) { + if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) { write_irq(dev, lp->chip_type, i); writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0) @@ -601,21 +936,74 @@ net_open(struct net_device *dev) if (i >= CS8920_NO_INTS) { writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ + if (net_debug) + printk("cs89x0: can't get an interrupt\n"); return -EAGAIN; } } else { if (((1 << dev->irq) & lp->irq_map) == 0) { - printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", + printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); return -EAGAIN; } +/* FIXME: Cirrus' release had this: */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ ); +/* And 2.3.47 had this: */ +#if 0 writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); +#endif write_irq(dev, lp->chip_type, dev->irq); if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) { + if (net_debug) + printk("cs89x0: request_irq(%d) failed\n", dev->irq); return -EAGAIN; } } +#if ALLOW_DMA + if (lp->use_dma) + { + if (lp->isa_config & ANY_ISA_DMA) { + unsigned long flags; + lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, + (lp->dmasize * 1024) / PAGE_SIZE); + + if (!lp->dma_buff) { + printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize); + goto release_irq; + } + if (net_debug > 1) + { + printk( "%s: dma %lx %lx\n", + dev->name, + (unsigned long)lp->dma_buff, + (unsigned long)virt_to_bus(lp->dma_buff)); + } + if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS || + !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) { + printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name); + goto release_irq; + } + memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */ + if (request_dma(dev->dma, "cs89x0")) { + printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma); + goto release_irq; + } + write_dma(dev, lp->chip_type, dev->dma); + lp->rx_dma_ptr = lp->dma_buff; + lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024; + spin_lock_irqsave(&lp->lock, flags); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff)); + set_dma_count(dev->dma, lp->dmasize*1024); + enable_dma(dev->dma); + spin_unlock_irqrestore(&lp->lock, flags); + } + } +#endif /* ALLOW_DMA */ + /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); @@ -637,8 +1025,11 @@ net_open(struct net_device *dev) default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); } if (!result) { - printk("%s: EEPROM is configured for unavailable media\n", dev->name); + printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name); release_irq: +#if ALLOW_DMA + release_dma_buff(lp); +#endif writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); free_irq(dev->irq, dev); return -EAGAIN; @@ -648,43 +1039,58 @@ net_open(struct net_device *dev) switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { case A_CNF_MEDIA_10B_T: result = detect_tp(dev); - if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */ + } break; case A_CNF_MEDIA_AUI: result = detect_aui(dev); - if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */ + } break; case A_CNF_MEDIA_10B_2: result = detect_bnc(dev); - if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name); - if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ - result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */ + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */ + } break; case A_CNF_MEDIA_AUTO: writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); if (lp->adapter_cnf & A_CNF_10B_T) - if ((result = detect_tp(dev)) != 0) + if ((result = detect_tp(dev)) != DETECTED_NONE) break; if (lp->adapter_cnf & A_CNF_AUI) - if ((result = detect_aui(dev)) != 0) + if ((result = detect_aui(dev)) != DETECTED_NONE) break; if (lp->adapter_cnf & A_CNF_10B_2) - if ((result = detect_bnc(dev)) != 0) + if ((result = detect_bnc(dev)) != DETECTED_NONE) break; - printk("%s: no media detected\n", dev->name); + printk(KERN_ERR "%s: no media detected\n", dev->name); goto release_irq; } switch(result) { - case 0: printk("%s: no network cable attached to configured media\n", dev->name); + case DETECTED_NONE: + printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name); goto release_irq; - case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break; - case A_CNF_MEDIA_AUI: printk("%s: using 10Base-5 (AUI)\n", dev->name);break; - case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break; - default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq; + case DETECTED_RJ45H: + printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_RJ45F: + printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_AUI: + printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name); + break; + case DETECTED_BNC: + printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name); + break; } /* Turn on both receive and transmit operations */ @@ -695,22 +1101,34 @@ net_open(struct net_device *dev) writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + if (lp->isa_config & STREAM_TRANSFER) lp->curr_rx_cfg |= RX_STREAM_ENBL; - +#if ALLOW_DMA + set_dma_cfg(dev); +#endif writereg(dev, PP_RxCFG, lp->curr_rx_cfg); writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | - TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | - TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); +#if ALLOW_DMA + dma_bufcfg(dev) | +#endif + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); /* now that we've got our act together, enable everything */ writereg(dev, PP_BusCTL, ENABLE_IRQ + | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */ +#if ALLOW_DMA + | dma_busctl(dev) +#endif ); MOD_INC_USE_COUNT; netif_start_queue(dev); + if (net_debug) + printk("cs89x0: net_open() succeeded\n"); return 0; } @@ -727,39 +1145,54 @@ static void net_timeout(struct net_device *dev) static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - short ioaddr = dev->base_addr; - unsigned long flags; if (net_debug > 3) - printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + { + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ - save_flags(flags); - cli(); + spin_lock_irq(&lp->lock); netif_stop_queue(dev); - + /* initiate a transmit sequence */ - outw(lp->send_cmd, ioaddr + TX_CMD_PORT); - outw(skb->len, ioaddr + TX_LEN_PORT); + writeword(dev, TX_CMD_PORT, lp->send_cmd); + writeword(dev, TX_LEN_PORT, skb->len); /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { - /* Gasp! It hasn't. But that shouldn't happen since - we're waiting for TxOk, so return 1 and requeue this packet. */ - restore_flags(flags); + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) + { + /* + * Gasp! It hasn't. But that shouldn't happen since + * we're waiting for TxOk, so return 1 and requeue this packet. + */ + + spin_unlock_irq(&lp->lock); + if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return 1; } /* Write the contents of the packet */ - outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); - - restore_flags(flags); + outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); + spin_unlock_irq(&lp->lock); dev->trans_start = jiffies; dev_kfree_skb (skb); - netif_wake_queue(dev); - + + /* + * We DO NOT call netif_wake_queue() here. + * We also DO NOT call netif_start_queue(). + * + * Either of these would cause another bottom half run through + * net_send_packet() before this packet has fully gone out. That causes + * us to hit the "Gasp!" above and the send is rescheduled. it runs like + * a dog. We just return and wait for the Tx completion interrupt handler + * to restart the netdevice layer + */ + return 0; } @@ -771,7 +1204,7 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status; - + ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -792,11 +1225,18 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) case ISQ_TRANSMITTER_EVENT: lp->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ - if ((status & TX_OK) == 0) lp->stats.tx_errors++; - if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; - if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; - if (status & TX_LATE_COL) lp->stats.tx_window_errors++; - if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + if ((status & ( TX_OK | + TX_LOST_CRS | + TX_SQE_ERROR | + TX_LATE_COL | + TX_16_COL)) != TX_OK) + { + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + } break; case ISQ_BUFFER_EVENT: if (status & READY_FOR_TX) { @@ -819,6 +1259,22 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) event of a tx underrun */ netif_wake_queue(dev); /* Inform upper layers. */ } +#if ALLOW_DMA + if (lp->use_dma && (status & RX_DMA)) { + int count = readreg(dev, PP_DmaFrameCnt); + while(count) { + if (net_debug > 5) + printk("%s: receiving %d DMA frames\n", dev->name, count); + if (net_debug > 2 && count >1) + printk("%s: receiving %d DMA frames\n", dev->name, count); + dma_rx(dev); + if (--count == 0) + count = readreg(dev, PP_DmaFrameCnt); + if (net_debug > 2 && count > 0) + printk("%s: continuing with %d DMA frames\n", dev->name, count); + } + } +#endif break; case ISQ_RX_MISS_EVENT: lp->stats.rx_missed_errors += (status >>6); @@ -830,45 +1286,58 @@ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) } } +static void +count_rx_errors(int status, struct net_local *lp) +{ + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; +} + /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; struct sk_buff *skb; int status, length; + int ioaddr = dev->base_addr; status = inw(ioaddr + RX_FRAME_PORT); length = inw(ioaddr + RX_FRAME_PORT); + if ((status & RX_OK) == 0) { - lp->stats.rx_errors++; - if (status & RX_RUNT) lp->stats.rx_length_errors++; - if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; - if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) - /* per str 172 */ - lp->stats.rx_crc_errors++; - if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + count_rx_errors(status, lp); return; } /* Malloc up new buffer. */ skb = alloc_skb(length, GFP_ATOMIC); if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); +#if 0 /* Again, this seems a cruel thing to do */ + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); +#endif lp->stats.rx_dropped++; return; } skb->len = length; skb->dev = dev; - insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1); + insw(ioaddr + RX_FRAME_PORT, skb->data, length >> 1); if (length & 1) skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); - if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", - dev->name, length, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + if (net_debug > 3) + { + printk( "%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); @@ -877,10 +1346,23 @@ net_rx(struct net_device *dev) return; } +#if ALLOW_DMA +static void release_dma_buff(struct net_local *lp) +{ + if (lp->dma_buff) + { + free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE); + lp->dma_buff = 0; + } +} +#endif + /* The inverse routine to net_open(). */ static int net_close(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; + netif_stop_queue(dev); writereg(dev, PP_RxCFG, 0); @@ -890,11 +1372,16 @@ net_close(struct net_device *dev) free_irq(dev->irq, dev); - /* Update the statistics here. */ +#if ALLOW_DMA + if (lp->use_dma && lp->dma) { + free_dma(dev->dma); + release_dma_buff(lp); + } +#endif + /* Update the statistics here. */ MOD_DEC_USE_COUNT; return 0; - } /* Get the current statistics. This may be called with the card open or @@ -903,12 +1390,13 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; - cli(); + spin_lock_irqsave(&lp->lock, flags); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - sti(); + spin_unlock_irqrestore(&lp->lock, flags); return &lp->stats; } @@ -916,7 +1404,9 @@ net_get_stats(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); if(dev->flags&IFF_PROMISC) { lp->rx_mode = RX_ALL_ACCEPT; @@ -935,18 +1425,23 @@ static void set_multicast_list(struct net_device *dev) /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ writereg(dev, PP_RxCFG, lp->curr_rx_cfg | (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); + spin_unlock_irqrestore(&lp->lock, flags); } static int set_mac_address(struct net_device *dev, void *addr) { int i; + if (netif_running(dev)) return -EBUSY; - printk("%s: Setting MAC address to ", dev->name); - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); - printk(".\n"); + if (net_debug) + { + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + } /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); @@ -963,17 +1458,31 @@ static struct net_device dev_cs89x0 = { 0, 0, 0, 0, 0, NULL, NULL }; +/* + * Support the 'debug' module parm even if we're compiled for non-debug to + * avoid breaking someone's startup scripts + */ + static int io=0; static int irq=0; static int debug=0; static char media[8]; static int duplex=-1; +static int use_dma = 0; /* These generate unused var warnings if ALLOW_DMA = 0 */ +static int dma=0; +static int dmasize=16; /* or 64 */ + MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(media, "s"); MODULE_PARM(duplex, "i"); +MODULE_PARM(dma , "i"); +MODULE_PARM(dmasize , "i"); +MODULE_PARM(use_dma , "i"); + +MODULE_AUTHOR("Mike Cruse, Russwll Nelson , Andrew Morton "); EXPORT_NO_SYMBOLS; @@ -1008,15 +1517,34 @@ init_module(void) { struct net_local *lp; +#if DEBUGGING net_debug = debug; +#endif dev_cs89x0.name = namespace; dev_cs89x0.irq = irq; dev_cs89x0.base_addr = io; + dev_cs89x0.init = cs89x0_probe; dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev_cs89x0.priv == 0) + { + printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + return -ENOMEM; + } memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); lp = (struct net_local *)dev_cs89x0.priv; +#if ALLOW_DMA + if (use_dma) + { + lp->use_dma = use_dma; + lp->dma = dma; + lp->dmasize = dmasize; + } +#endif + + spin_lock_init(&lp->lock); + /* boy, they'd better get these right */ if (!strcmp(media, "rj45")) lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; @@ -1031,12 +1559,20 @@ init_module(void) lp->auto_neg_cnf = AUTO_NEG_ENABLE; if (io == 0) { - printk(KERN_NOTICE "cs89x0.c: Module autoprobing not allowed.\n"); - printk(KERN_NOTICE "cs89x0.c: Append io=0xNNN\n"); + printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n"); + printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); return -EPERM; } + +#if ALLOW_DMA + if (use_dma && dmasize != 16 && dmasize != 64) { + printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize); + return -EPERM; + } +#endif + if (register_netdev(&dev_cs89x0) != 0) { - printk(KERN_WARNING "cs89x0.c: No card found at 0x%x\n", io); + printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); return -ENXIO; } return 0; @@ -1045,13 +1581,7 @@ init_module(void) void cleanup_module(void) { - -#endif -#ifdef MODULE - outw(0, dev_cs89x0.base_addr + ADD_PORT); -#endif -#ifdef MODULE - + outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ unregister_netdev(&dev_cs89x0); diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h index 7e78805af80f..d05ca7a42c50 100644 --- a/drivers/net/cs89x0.h +++ b/drivers/net/cs89x0.h @@ -217,6 +217,7 @@ #define ENDEC_LOOPBACK 0x0200 #define AUI_LOOPBACK 0x0400 #define BACKOFF_OFF 0x0800 +#define FDX_8900 0x4000 #define FAST_TEST 0x8000 /* PP_RxEvent - Receive Event Bit definition - Read-only */ diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c index 6a8c8b4129a6..f91796d313c0 100644 --- a/drivers/net/ncr885e.c +++ b/drivers/net/ncr885e.c @@ -1210,9 +1210,6 @@ static int __init ncr885e_probe(void) unsigned short cmd; unsigned char irq, latency; - if ( debug >= 0) - ncr885e_debug = debug; - while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, pdev )) != NULL ) { @@ -1399,9 +1396,6 @@ write_mii( unsigned long ioaddr, int reg, int data ) int init_module(void) { - if ( debug >= 0) - ncr885e_debug = debug; - return ncr885e_probe(); } diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index b4fc3e0a8824..96959300f83c 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -69,18 +69,24 @@ static struct net_device *init_alloc_dev(int sizeof_priv) { struct net_device *dev; - int alloc_size = sizeof(struct net_device) + IFNAMSIZ - + sizeof_priv + 3; - alloc_size &= ~3; /* Round to dword boundary. */ - dev = (struct net_device *)kmalloc(alloc_size, GFP_KERNEL); - if(dev==NULL) + int alloc_size; + + /* 32-byte alignment */ + alloc_size = sizeof (*dev) + IFNAMSIZ + sizeof_priv + 31; + alloc_size &= ~31; + + dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); + if (dev == NULL) { printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); return NULL; } + memset(dev, 0, alloc_size); + if (sizeof_priv) dev->priv = (void *) (dev + 1); + dev->name = sizeof_priv + (char *)(dev + 1); return dev; } diff --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in index b7e67fbad134..31688f34d3de 100644 --- a/drivers/net/tokenring/Config.in +++ b/drivers/net/tokenring/Config.in @@ -3,7 +3,7 @@ # mainmenu_option next_comment -comment 'Token Ring driver support' +comment 'Token Ring devices' bool 'Token Ring driver support' CONFIG_TR if [ "$CONFIG_TR" != "n" ]; then diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile index 65dfefc702f6..bf48c15e4de0 100644 --- a/drivers/net/tokenring/Makefile +++ b/drivers/net/tokenring/Makefile @@ -5,73 +5,29 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # -# Note 2! The CFLAGS definition is now inherited from the -# parent makefile. -# -# -# Note : at this point, these files are compiled on all systems. -# In the future, some of these should be built conditionally. -# - -SUB_DIRS := +SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) +obj-y := +obj-n := +obj-m := +obj- := +export-objs := -L_TARGET := tr.a -L_OBJS := -M_OBJS := - -ifeq ($(CONFIG_IBMTR),y) - L_OBJS += ibmtr.o -else - ifeq ($(CONFIG_IBMTR),m) - M_OBJS += ibmtr.o - endif -endif - -ifeq ($(CONFIG_IBMOL),y) - L_OBJS += olympic.o -else - ifeq ($(CONFIG_IBMOL),m) - M_OBJS += olympic.o - endif -endif - -ifeq ($(CONFIG_TMS380TR),y) - L_OBJS += tms380tr.o - ifeq ($(CONFIG_ABYSS),y) - L_OBJS += abyss.o - endif - ifeq ($(CONFIG_MADGEMC),y) - L_OBJS += madgemc.o - endif - ifeq ($(CONFIG_TMSPCI),y) - L_OBJS += tmspci.o - endif -else - ifeq ($(CONFIG_TMS380TR),m) - M_OBJS += tms380tr.o - ifeq ($(CONFIG_ABYSS),m) - M_OBJS += abyss.o - endif - ifeq ($(CONFIG_MADGEMC),m) - M_OBJS += madgemc.o - endif - ifeq ($(CONFIG_TMSPCI),m) - M_OBJS += tmspci.o - endif - endif -endif +obj-$(CONFIG_IBMTR) += ibmtr.o +obj-$(CONFIG_IBMOL) += olympic.o +obj-$(CONFIG_TMS380TR) += tms380tr.o +obj-$(CONFIG_ABYSS) += abyss.o +obj-$(CONFIG_MADGEMC) += madgemc.o +obj-$(CONFIG_TMSPCI) += tmspci.o +obj-$(CONFIG_SMCTR) += smctr.o -ifeq ($(CONFIG_SMCTR),y) - L_OBJS += smctr.o -else - ifeq ($(CONFIG_SMCTR),m) - M_OBJS += smctr.o - endif -endif +L_TARGET := tr.a +L_OBJS := $(filter-out $(export-objs), $(obj-y)) +LX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make - diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index abfde3e8a5e4..bbca052e750d 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -17,10 +17,21 @@ Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html + + + Linux kernel version history: + + LK1.1.0: + - Jeff Garzik: softnet 'n stuff + + LK1.1.1: + - Justin Guyett: softnet and locking fixes + - Jeff Garzik: use PCI interface + */ static const char *versionA = -"via-rhine.c:v1.01 2/27/99 Written by Donald Becker\n"; +"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n"; static const char *versionB = " http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n"; @@ -29,7 +40,6 @@ static const char *versionB = static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ static int max_interrupt_work = 20; -static int min_pci_latency = 64; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ @@ -112,7 +122,6 @@ static const int multicast_filter_limit = 32; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(min_pci_latency, "i"); MODULE_PARM(debug, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); @@ -157,7 +166,7 @@ buffers. When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is copied to the new skbuff. When the incoming frame is larger, the skbuff is passed directly up the protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in the last phase of netdev_rx(). +skbuffs in the last phase of via_rhine_rx(). The RX_COPYBREAK value is chosen to trade-off the memory wasted by using a full-sized skbuff for small frames vs. the copying costs of larger @@ -208,34 +217,50 @@ The chip does not pad to minimum transmit length. */ - + /* This table drives the PCI probe routines. It's mostly boilerplate in all of the drivers, and will likely be provided by some future kernel. Note the matching code -- the first table entry matchs all 56** cards but second only the 1234 card. */ + enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { + +enum via_rhine_chips { + vt86c100a = 0, + vt3043, +}; + +struct via_rhine_chip_info { const char *name; - u16 vendor_id, device_id, device_id_mask, flags; + u16 flags; int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; -static struct net_device *via_probe1(struct pci_dev *pdev, long ioaddr, int irq, - int chp_idx, int fnd_cnt); -static struct pci_id_info pci_tbl[] = { - { "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff, - PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, - { "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff, - PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1}, - {0,}, /* 0 terminated list. */ +/* directly indexed by enum via_rhine_chips, above */ +static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = +{ + {"VIA VT86C100A Rhine-II", + PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, + 128,}, + {"VIA VT3043 Rhine", + PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER, + 128,}, +}; + +static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = +{ + {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a}, + {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043}, + {0,}, /* terminate list */ }; +MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); + /* A chip capabilities table, matching the entries in pci_tbl[] above. */ @@ -315,16 +340,14 @@ struct netdev_private { struct sk_buff* tx_skbuff[TX_RING_SIZE]; unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ - struct net_device *next_module; /* Link for devices of this type. */ struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; - long in_interrupt; /* Word-long for SMP locks. */ struct rx_desc *rx_head_desc; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int cur_tx, dirty_tx; + unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned short int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ u16 chip_cmd; /* Current setting for ChipCmd */ unsigned int tx_full:1; /* The Tx queue is full. */ @@ -342,136 +365,94 @@ struct netdev_private { static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int netdev_open(struct net_device *dev); -static void check_duplex(struct net_device *dev); -static void netdev_timer(unsigned long data); -static void tx_timeout(struct net_device *dev); -static void init_ring(struct net_device *dev); -static int start_tx(struct sk_buff *skb, struct net_device *dev); -static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); -static int netdev_rx(struct net_device *dev); -static void netdev_error(struct net_device *dev, int intr_status); -static void set_rx_mode(struct net_device *dev); -static struct net_device_stats *get_stats(struct net_device *dev); +static int via_rhine_open(struct net_device *dev); +static void via_rhine_check_duplex(struct net_device *dev); +static void via_rhine_timer(unsigned long data); +static void via_rhine_tx_timeout(struct net_device *dev); +static void via_rhine_init_ring(struct net_device *dev); +static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev); +static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static void via_rhine_tx(struct net_device *dev); +static void via_rhine_rx(struct net_device *dev); +static void via_rhine_error(struct net_device *dev, int intr_status); +static void via_rhine_set_rx_mode(struct net_device *dev); +static struct net_device_stats *via_rhine_get_stats(struct net_device *dev); static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int netdev_close(struct net_device *dev); - - +static int via_rhine_close(struct net_device *dev); -/* A list of our installed devices, for removing the driver module. */ -static struct net_device *root_net_dev = NULL; -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - cards we know about in slot order. */ - -static int pci_etherdev_probe(struct pci_id_info pci_tbl[]) +static int __devinit via_rhine_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; struct net_device *dev; + struct netdev_private *np; + int i, option; + int chip_id = (int) ent->driver_data; + int irq = pdev->irq; + static int card_idx = -1; + static int did_version = 0; + long ioaddr; + int io_size; + + /* print version once and once only */ + if (! did_version++) { + printk (KERN_INFO "%s", versionA); + printk (KERN_INFO "%s", versionB); + } + + card_idx++; + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + io_size = via_rhine_chip_info[chip_id].io_size; - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long pciaddr; - long ioaddr; - struct pci_dev *pdev; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - - pdev = pci_find_slot (pci_bus, pci_device_fn); - if (!pdev) continue; - vendor = pdev->vendor; - device = pdev->device; - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; #ifdef VIA_USE_IO - pciaddr = pdev->resource[0].start; + ioaddr = pci_resource_start (pdev, 0); #else - pciaddr = pdev->resource[1].start; + ioaddr = pci_resource_start (pdev, 1); #endif - irq = pdev->irq; - - if (debug > 2) - printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", - pci_tbl[chip_idx].name, pciaddr, irq); - - if (pci_tbl[chip_idx].flags & PCI_USES_IO) { - ioaddr = pciaddr & ~3; - if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, - pci_tbl[chip_idx].io_size)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - pciaddr); - continue; - } - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pdev->bus->number, pdev->devfn, pci_command, new_command); - pci_write_config_word(pdev, PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, ioaddr, irq, chip_idx, cards_found); - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < min_pci_latency) { - printk(KERN_INFO " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to %d clocks.\n", - pci_latency, min_pci_latency); - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); - } - } - dev = 0; - cards_found++; + if (pci_enable_device (pdev)) { + printk (KERN_ERR "unable to init PCI device (card #%d)\n", + card_idx); + goto err_out; + } + + if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER) + pci_set_master (pdev); + + dev = init_etherdev(NULL, sizeof (*np)); + if (dev == NULL) { + printk (KERN_ERR "init_ethernet failed for card #%d\n", + card_idx); + goto err_out; + } + + if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) { + printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n", + dev->name, io_size, + pci_resource_start (pdev, 0)); + goto err_out_free_netdev; + } + if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) { + printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n", + dev->name, io_size, + pci_resource_start (pdev, 1)); + goto err_out_free_pio; } - return cards_found ? 0 : -ENODEV; -} - - -static struct net_device *via_probe1(struct pci_dev *pdev, - long ioaddr, int irq, - int chip_id, int card_idx) -{ - struct net_device *dev; - struct netdev_private *np; - int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - - dev = init_etherdev(NULL, 0); - if(dev==NULL) - return NULL; - - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, pci_tbl[chip_id].name, ioaddr); - -#ifdef VIA_USE_IO - if (!request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name)) { - unregister_netdev (dev); - kfree (dev); - return NULL; +#ifndef VIA_USE_IO + ioaddr = (long) ioremap (ioaddr, io_size); + if (!ioaddr) { + printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", + dev->name, io_size, + pci_resource_start (pdev, 1)); + goto err_out_free_mmio; } #endif + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + /* Ideally we would be read the EEPROM but access may be locked. */ for (i = 0; i <6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); @@ -485,16 +466,8 @@ static struct net_device *via_probe1(struct pci_dev *pdev, dev->base_addr = ioaddr; dev->irq = irq; - /* Make certain the descriptor lists are cache-aligned. */ - np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31); - /* FIXME! check return !!! */ - memset(np, 0, sizeof(*np)); - dev->priv = np; - - np->next_module = root_net_dev; - root_net_dev = dev; - - np->lock = SPIN_LOCK_UNLOCKED; + np = dev->priv; + spin_lock_init (&np->lock); np->chip_id = chip_id; if (dev->mem_start) @@ -515,14 +488,16 @@ static struct net_device *via_probe1(struct pci_dev *pdev, np->duplex_lock = 1; /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - dev->tx_timeout = tx_timeout; + dev->open = via_rhine_open; + dev->hard_start_xmit = via_rhine_start_tx; + dev->stop = via_rhine_close; + dev->get_stats = via_rhine_get_stats; + dev->set_multicast_list = via_rhine_set_rx_mode; + dev->do_ioctl = mii_ioctl; + dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + + pdev->driver_data = dev; if (cap_tbl[np->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; @@ -541,10 +516,25 @@ static struct net_device *via_probe1(struct pci_dev *pdev, np->mii_cnt = phy_idx; } - return dev; + return 0; + +#ifndef VIA_USE_IO +/* note this is ifdef'd because the ioremap is ifdef'd... + * so additional exit conditions above this must move + * release_mem_region outside of the ifdef */ +err_out_free_mmio: + release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)); +#endif +err_out_free_pio: + release_region(pci_resource_start (pdev, 0), io_size); +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); +err_out: + return -ENODEV; } - + /* Read and write over the MII Management Data I/O (MDIO) interface. */ static int mdio_read(struct net_device *dev, int phy_id, int regnum) @@ -581,8 +571,8 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value return; } - -static int netdev_open(struct net_device *dev) + +static int via_rhine_open(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -591,16 +581,16 @@ static int netdev_open(struct net_device *dev) /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) return -EAGAIN; if (debug > 1) - printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", dev->name, dev->irq); MOD_INC_USE_COUNT; - init_ring(dev); + via_rhine_init_ring(dev); writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); @@ -613,15 +603,14 @@ static int netdev_open(struct net_device *dev) /* Configure the FIFO thresholds. */ writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in set_rx_mode(). */ + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ if (dev->if_port == 0) dev->if_port = np->default_port; netif_start_queue(dev); - np->in_interrupt = 0; - set_rx_mode(dev); + via_rhine_set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| @@ -634,10 +623,10 @@ static int netdev_open(struct net_device *dev) np->chip_cmd |= CmdFDuplex; writew(np->chip_cmd, ioaddr + ChipCmd); - check_duplex(dev); + via_rhine_check_duplex(dev); if (debug > 2) - printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x " + printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), mdio_read(dev, np->phys[0], 1)); @@ -646,22 +635,23 @@ static int netdev_open(struct net_device *dev) init_timer(&np->timer); np->timer.expires = RUN_AT(1); np->timer.data = (unsigned long)dev; - np->timer.function = &netdev_timer; /* timer handler */ + np->timer.function = &via_rhine_timer; /* timer handler */ add_timer(&np->timer); return 0; } -static void check_duplex(struct net_device *dev) +static void via_rhine_check_duplex(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; int duplex; if (np->duplex_lock || mii_reg5 == 0xffff) return; - duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; if (np->full_duplex != duplex) { np->full_duplex = duplex; if (debug) @@ -676,7 +666,7 @@ static void check_duplex(struct net_device *dev) } } -static void netdev_timer(unsigned long data) +static void via_rhine_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -687,41 +677,41 @@ static void netdev_timer(unsigned long data) printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); } - check_duplex(dev); + via_rhine_check_duplex(dev); np->timer.expires = RUN_AT(next_tick); add_timer(&np->timer); } -static void tx_timeout(struct net_device *dev) +static void via_rhine_tx_timeout (struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = (struct netdev_private *) dev->priv; long ioaddr = dev->base_addr; - printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " - "%4.4x, resetting...\n", - dev->name, readw(ioaddr + IntrStatus), - mdio_read(dev, np->phys[0], 1)); + printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " + "%4.4x, resetting...\n", + dev->name, readw (ioaddr + IntrStatus), + mdio_read (dev, np->phys[0], 1)); - /* Perhaps we should reinitialize the hardware here. */ - dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ - /* Trigger an immediate transmit demand. */ + /* Trigger an immediate transmit demand. */ - dev->trans_start = jiffies; - np->stats.tx_errors++; - return; + dev->trans_start = jiffies; + np->stats.tx_errors++; + + netif_start_queue (dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void init_ring(struct net_device *dev) +static void via_rhine_init_ring(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; int i; - np->tx_full = 0; np->cur_rx = np->cur_tx = 0; np->dirty_rx = np->dirty_tx = 0; @@ -749,7 +739,6 @@ static void init_ring(struct net_device *dev) np->rx_ring[i].rx_status = 0; np->rx_ring[i].rx_length = DescOwn; } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); for (i = 0; i < TX_RING_SIZE; i++) { np->tx_skbuff[i] = 0; @@ -763,14 +752,18 @@ static void init_ring(struct net_device *dev) return; } -static int start_tx(struct sk_buff *skb, struct net_device *dev) +static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; + unsigned long flags; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ + /* lock eth irq */ + spin_lock_irqsave (&np->lock, flags); + /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; @@ -796,12 +789,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* Wake the potentially-idle transmit channel. */ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1) - netif_start_queue(dev); /* Typical path */ - else - np->tx_full = 1; + if (np->cur_tx == np->dirty_tx + TX_RING_SIZE) + netif_stop_queue(dev); + dev->trans_start = jiffies; + spin_unlock_irqrestore (&np->lock, flags); + if (debug > 4) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", dev->name, np->cur_tx, entry); @@ -811,20 +805,15 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *)dev_instance; - struct netdev_private *np; long ioaddr, boguscnt = max_interrupt_work; + u32 intr_status; ioaddr = dev->base_addr; - np = (struct netdev_private *)dev->priv; - spin_lock (&np->lock); - - do { - u32 intr_status = readw(ioaddr + IntrStatus); - + while ((intr_status = readw(ioaddr + IntrStatus))) { /* Acknowledge all of the current interrupt sources ASAP. */ writew(intr_status & 0xffff, ioaddr + IntrStatus); @@ -832,54 +821,18 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", dev->name, intr_status); - if (intr_status == 0) - break; - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) - netdev_rx(dev); - - for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { - int entry = np->dirty_tx % TX_RING_SIZE; - int txstatus; - if (np->tx_ring[entry].tx_own) - break; - txstatus = np->tx_ring[entry].tx_status; - if (debug > 6) - printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", - entry, txstatus); - if (txstatus & 0x8000) { - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", - dev->name, txstatus); - np->stats.tx_errors++; - if (txstatus & 0x0400) np->stats.tx_carrier_errors++; - if (txstatus & 0x0200) np->stats.tx_window_errors++; - if (txstatus & 0x0100) np->stats.tx_aborted_errors++; - if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; - if (txstatus & 0x0002) np->stats.tx_fifo_errors++; - /* Transmitter restarted in 'abnormal' handler. */ - } else { - np->stats.collisions += (txstatus >> 3) & 15; - np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; - np->stats.tx_packets++; - } - /* Free the original skb. */ - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = 0; - } - if (np->tx_full && - netif_queue_stopped(dev) && - np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { - /* The ring is no longer full, clear tbusy. */ - np->tx_full = 0; - netif_wake_queue (dev); - } + via_rhine_rx(dev); + + if (intr_status & (IntrTxDone | IntrTxAbort | IntrTxUnderrun | + IntrTxAborted)) + via_rhine_tx(dev); /* Abnormal error summary/uncommon events handlers. */ if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange | IntrStatsMax | IntrTxAbort | IntrTxUnderrun)) - netdev_error(dev, intr_status); + via_rhine_error(dev, intr_status); if (--boguscnt < 0) { printk(KERN_WARNING "%s: Too much work at interrupt, " @@ -887,25 +840,67 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) dev->name, intr_status); break; } - } while (1); + } if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); +} + +/* This routine is logically part of the interrupt handler, but isolated + for clarity and better register allocation. */ +static void via_rhine_tx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE; + + spin_lock (&np->lock); + + /* if tx_full is set, they're all dirty, not clean */ + while (np->dirty_tx != np->cur_tx) { + if (np->tx_ring[entry].tx_own) /* transmit request pending */ + break; + txstatus = np->tx_ring[entry].tx_status; + if (debug > 6) + printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n", + entry, txstatus); + if (txstatus & 0x8000) { + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n", + dev->name, txstatus); + np->stats.tx_errors++; + if (txstatus & 0x0400) np->stats.tx_carrier_errors++; + if (txstatus & 0x0200) np->stats.tx_window_errors++; + if (txstatus & 0x0100) np->stats.tx_aborted_errors++; + if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; + if (txstatus & 0x0002) np->stats.tx_fifo_errors++; + /* Transmitter restarted in 'abnormal' handler. */ + } else { + np->stats.collisions += (txstatus >> 3) & 15; + np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; + np->stats.tx_packets++; + } + /* Free the original skb. */ + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = NULL; + entry = (++np->dirty_tx) % TX_RING_SIZE; + } + if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2) + netif_wake_queue (dev); spin_unlock (&np->lock); } /* This routine is logically part of the interrupt handler, but isolated for clarity and better register allocation. */ -static int netdev_rx(struct net_device *dev) +static void via_rhine_rx(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; - int entry = np->cur_rx % RX_RING_SIZE; - int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE; + int boguscnt = RX_RING_SIZE; if (debug > 4) { - printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", + printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n", entry, np->rx_head_desc->rx_length); } @@ -916,7 +911,7 @@ static int netdev_rx(struct net_device *dev) u16 desc_status = desc->rx_status; if (debug > 4) - printk(KERN_DEBUG " netdev_rx() status is %4.4x.\n", + printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n", desc_status); if (--boguscnt < 0) break; @@ -924,15 +919,15 @@ static int netdev_rx(struct net_device *dev) if ((desc_status & RxWholePkt) != RxWholePkt) { printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " "multiple buffers, entry %#x length %d status %4.4x!\n", - dev->name, np->cur_rx, data_size, desc_status); + dev->name, entry, data_size, desc_status); printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", dev->name, np->rx_head_desc, - &np->rx_ring[np->cur_rx % RX_RING_SIZE]); + &np->rx_ring[entry]); np->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ if (debug > 2) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + printk(KERN_DEBUG " via_rhine_rx() Rx error was %8.8x.\n", desc_status); np->stats.rx_errors++; if (desc_status & 0x0030) np->stats.rx_length_errors++; @@ -973,9 +968,9 @@ static int netdev_rx(struct net_device *dev) } /* Refill the Rx ring buffers. */ - for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + while (np->dirty_rx != np->cur_rx) { struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; + entry = np->dirty_rx++ % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; @@ -990,10 +985,9 @@ static int netdev_rx(struct net_device *dev) /* Pre-emptively restart Rx engine. */ writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd); - return 0; } -static void netdev_error(struct net_device *dev, int intr_status) +static void via_rhine_error(struct net_device *dev, int intr_status) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1003,7 +997,7 @@ static void netdev_error(struct net_device *dev, int intr_status) /* Link failed, restart autonegotiation. */ mdio_write(dev, np->phys[0], 0, 0x3300); else - check_duplex(dev); + via_rhine_check_duplex(dev); if (debug) printk(KERN_ERR "%s: MII status changed: Autonegotiation " "advertising %4.4x partner %4.4x.\n", dev->name, @@ -1026,7 +1020,7 @@ static void netdev_error(struct net_device *dev, int intr_status) printk(KERN_INFO "%s: Transmitter underrun, increasing Tx " "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } - if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) { + if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) { printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ @@ -1034,7 +1028,7 @@ static void netdev_error(struct net_device *dev, int intr_status) } } -static struct enet_statistics *get_stats(struct net_device *dev) +static struct net_device_stats *via_rhine_get_stats(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1068,7 +1062,7 @@ static inline u32 ether_crc(int length, unsigned char *data) return crc; } -static void set_rx_mode(struct net_device *dev) +static void via_rhine_set_rx_mode(struct net_device *dev) { struct netdev_private *np = (struct netdev_private *)dev->priv; long ioaddr = dev->base_addr; @@ -1120,7 +1114,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } } -static int netdev_close(struct net_device *dev) +static int via_rhine_close(struct net_device *dev) { long ioaddr = dev->base_addr; struct netdev_private *np = (struct netdev_private *)dev->priv; @@ -1162,45 +1156,49 @@ static int netdev_close(struct net_device *dev) return 0; } -static int __init via_rhine_init_module (void) + +static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); -#ifdef CARDBUS - register_driver(ðerdev_ops); - return 0; -#else - return pci_etherdev_probe(pci_tbl); + struct net_device *dev = pdev->driver_data; + struct netdev_private *np = (struct netdev_private *)(dev->priv); + + unregister_netdev(dev); + + release_region(pci_resource_start (pdev, 0), + via_rhine_chip_info[np->chip_id].io_size); + release_mem_region(pci_resource_start (pdev, 1), + via_rhine_chip_info[np->chip_id].io_size); + +#ifndef VIA_USE_IO + iounmap((char *)(dev->base_addr)); #endif + + kfree(dev); } -static void __exit via_rhine_cleanup_module (void) + +static struct pci_driver via_rhine_driver = { + name: "via-rhine", + id_table: via_rhine_pci_tbl, + probe: via_rhine_init_one, + remove: via_rhine_remove_one, +}; + + +static int __init via_rhine_init (void) { + return pci_module_init (&via_rhine_driver); +} -#ifdef CARDBUS - unregister_driver(ðerdev_ops); -#endif - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_net_dev) { - struct netdev_private *np = - (struct netdev_private *)(root_net_dev->priv); - unregister_netdev(root_net_dev); -#ifdef VIA_USE_IO - release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size); -#else - iounmap((char *)(root_net_dev->base_addr)); -#endif - kfree(root_net_dev); - root_net_dev = np->next_module; -#if 0 - kfree(np); /* Assumption: no struct realignment. */ -#endif - } +static void __exit via_rhine_cleanup (void) +{ + pci_unregister_driver (&via_rhine_driver); } -module_init(via_rhine_init_module); -module_exit(via_rhine_cleanup_module); + +module_init(via_rhine_init); +module_exit(via_rhine_cleanup); /* diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 7eb759b94de2..85febe47dc91 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1263,7 +1263,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, real_ioaddr = ioaddr = pci_resource_start (pdev, 0); #else real_ioaddr = ioaddr = pci_resource_start (pdev, 1); - ioaddr = ioremap(ioaddr, YELLOWFIN_SIZE); + ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); #endif irq = pdev->irq; diff --git a/drivers/parport/Config.in b/drivers/parport/Config.in index d2af7d8f6756..d4222f353f17 100644 --- a/drivers/parport/Config.in +++ b/drivers/parport/Config.in @@ -5,6 +5,9 @@ # Parport configuration. # +mainmenu_option next_comment +comment 'Parallel port support' + tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT @@ -47,3 +50,5 @@ if [ "$CONFIG_PARPORT" != "n" ]; then bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284 fi + +endmenu diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 49e530ace82a..9cfa53b0d02b 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -70,20 +70,40 @@ #define ECR_TST 06 #define ECR_CNF 07 +#undef DEBUG + +#ifdef DEBUG +#define DPRINTK printk +#else +#define DPRINTK(stuff...) +#endif + + +#define NR_SUPERIOS 3 +static struct superio_struct { /* For Super-IO chips autodetection */ + int io; + int irq; + int dma; +} superios[NR_SUPERIOS]= { {0,},}; + /* frob_control, but for ECR */ static void frob_econtrol (struct parport *pb, unsigned char m, unsigned char v) { unsigned char ectr = inb (ECONTROL (pb)); -#ifdef DEBUG_PARPORT - printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", + DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, (ectr & ~m) ^ v); -#endif + outb ((ectr & ~m) ^ v, ECONTROL (pb)); } #ifdef CONFIG_PARPORT_PC_FIFO -/* Safely change the mode bits in the ECR */ +/* Safely change the mode bits in the ECR + Returns: + 0 : Success + -EBUSY: Could not drain FIFO in some finite amount of time, + mode not changed! + */ static int change_mode(struct parport *p, int m) { const struct parport_pc_private *priv = p->physport->private_data; @@ -91,6 +111,8 @@ static int change_mode(struct parport *p, int m) unsigned char oecr; int mode; + DPRINTK("parport change_mode ECP-ISA to mode 0x%02x\n",m); + if (!priv->ecr) { printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); return 0; @@ -993,6 +1015,305 @@ struct parport_operations parport_pc_ops = parport_ieee1284_read_byte, }; +/* Super-IO chipset detection, Winbond, SMSC */ + +static void show_parconfig_smsc37c669(int io, int key) +{ + int cr1,cr4,cra,cr23,cr26,cr27,i=0; + char *modes[]={ "SPP and Bidirectional (PS/2)", + "EPP and SPP", + "ECP", + "ECP and EPP"}; + + outb(key,io); + outb(key,io); + outb(1,io); + cr1=inb(io+1); + outb(4,io); + cr4=inb(io+1); + outb(0x0a,io); + cra=inb(io+1); + outb(0x23,io); + cr23=inb(io+1); + outb(0x26,io); + cr26=inb(io+1); + outb(0x27,io); + cr27=inb(io+1); + outb(0xaa,io); + + printk ("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, " + "A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n", + cr1,cr4,cra,cr23,cr26,cr27); + + /* The documentation calls DMA and IRQ-Lines by letters, so + the board maker can/will wire them + appropriately/randomly... G=reserved H=IDE-irq, */ + printk ("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, " + "fifo threshold=%d\n", cr23*4, + (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-', + (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cra & 0x0f); + printk("SMSC LPT Config: enabled=%s power=%s\n", + (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no"); + printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n", + (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03], + (cr4 & 40) ? "1.7" : "1.9"); + + /* Heuristics ! BIOS setup for this mainboard device limits + the choices to standard settings, i.e. io-address and IRQ + are related, however DMA can be 1 or 3, assume DMA_A=DMA1, + DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */ + if(cr23*4 >=0x100) { /* if active */ + while((superios[i].io!= 0) && (i 3) + printk("dma=none\n"); + else + printk("dma=%d\n",cr74 & 0x07); + printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", + irqtypes[crf0>>7], (crf0>>3)&0x0f); + printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]); + + if(cr30 & 0x01) { /* the settings can be interrogated later ... */ + while((superios[i].io!= 0) && (i 3) ? + PARPORT_DMA_NONE : (cr74 & 0x07)); + } + } +} + +static void decode_winbond(int efer, int key, int devid, int devrev, int oldid) +{ + char *type=NULL; + int id,progif=2; + + if (devid == devrev) + /* simple heuristics, we happened to read some + non-winbond register */ + return; + + printk("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x " + "oldid=%02x\n", efer,key,devid,devrev,oldid); + id=(devid<<8) | devrev; + + /* Values are from public data sheets pdf files, I can just + confirm 83977TF is correct :-) */ + if (id == 0x9773) type="83977TF"; + else if (id == 0x9774) type="83977ATF"; + else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x"; + else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97x35x"; + else if ((id & ~0x0f) == 0x5210) type="83627"; + else if ((id & ~0x0f) == 0x6010) type="83697HF"; + else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;} + else if ((oldid &0x0f ) == 0x0c) { type="83877ATF"; progif=1;} + else progif=0; + + if(type==NULL) + printk("Winbond unkown chip type\n"); + else + printk("Winbond chip type %s\n",type); + + if(progif==2) + show_parconfig_winbond(efer,key); + return; +} + +static void decode_smsc(int efer, int key, int devid, int devrev) +{ + char *type=NULL; + void (*func)(int io, int key); + int id; + + if (devid == devrev) + /* simple heuristics, we happened to read some + non-winbond register */ + return; + + func=NULL; + printk("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x\n", + efer,key,devid,devrev); + id=(devid<<8) | devrev; + + if (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;} + else if (id==0x6582) type="37c665IR"; + else if ((id==0x6502) && (key==0x44)) type="37c665GT"; + else if ((id==0x6502) && (key==0x55)) type="37c666GT"; + + if(type==NULL) + printk("SMSC unknown chip type\n"); + else + printk("SMSC chip type %s\n",type); + + if(func) (func)(efer,key); + return; +} + + +static void winbond_check(int io, int key) +{ + int devid,devrev,oldid; + + outb(key,io); + outb(key,io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x20,io); /* Write EFIR, extended function index register */ + devid=inb(io+1); /* Read EFDR, extended function data register */ + outb(0x21,io); + devrev=inb(io+1); + outb(0x09,io); + oldid=inb(io+1); + outb(0xaa,io); /* Magic Seal */ + + decode_winbond(io,key,devid,devrev,oldid); +} + +static void winbond_check2(int io,int key) +{ + int devid,devrev,oldid; + + outb(key,io); /* Write Magic Byte to EFER, extended + funtion enable register */ + outb(0x20,io+2); /* Write EFIR, extended function index register */ + devid=inb(io+2); /* Read EFDR, extended function data register */ + outb(0x21,io+1); + devrev=inb(io+2); + outb(0x09,io+1); + oldid=inb(io+2); + outb(0xaa,io); /* Magic Seal */ + + decode_winbond(io,key,devid,devrev,oldid); +} + +static void smsc_check(int io, int key) +{ + int devid,devrev; + + outb(key,io); + outb(key,io); /* Write Magic Sequence to EFER, extended + funtion enable register */ + outb(0x0d,io); /* Write EFIR, extended function index register */ + devid=inb(io+1); /* Read EFDR, extended function data register */ + outb(0x0e,io); + devrev=inb(io+1); + outb(0xaa,io); /* Magic Seal */ + + decode_smsc(io,key,devid,devrev); +} + + +static void detect_and_report_winbond (void) +{ + printk("Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n"); + + winbond_check(0x3f0,0x87); + winbond_check(0x370,0x87); + winbond_check(0x2e ,0x87); + winbond_check(0x4e ,0x87); + winbond_check(0x3f0,0x86); + winbond_check2(0x250,0x88); + winbond_check2(0x250,0x89); +} + +static void detect_and_report_smsc (void) +{ + printk("SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n"); + smsc_check(0x3f0,0x55); + smsc_check(0x370,0x55); + smsc_check(0x3f0,0x44); + smsc_check(0x370,0x44); +} + +static int get_superio_dma (struct parport *p) +{ + int i=0; + while( (superios[i].io != p->base) && (ibase) && (iprivate_data; + int intrline[]={0,7,9,10,11,14,15,5}; /* Translate ECP + intrLine to ISA irq + value */ /* If there is no ECR, we have no hope of supporting ECP. */ if (!priv->ecr) @@ -1253,11 +1577,23 @@ static int __devinit parport_ECP_supported(struct parport *pb) printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base, config & 0x80 ? "Level" : "Pulses"); - config = inb (CONFIGB (pb)); - if (!(config & 0x40)) { + configb = inb (CONFIGB (pb)); + if (!(configb & 0x40)) { printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base); pb->irq = PARPORT_IRQ_NONE; } + printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", + pb->base, config, configb); + printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); + if ((configb >>3) & 0x07) + printk("%d",intrline[(configb >>3) & 0x07]); + else + printk(""); + printk ( " dma="); + if( (configb & 0x03 ) == 0x00) + printk("\n"); + else + printk("%d\n",configb & 0x07); /* Go back to mode 000 */ frob_econtrol (pb, 0xe0, ECR_SPP << 5); @@ -1476,8 +1812,6 @@ static int __devinit parport_irq_probe(struct parport *pb) if (priv->ecr) { pb->irq = programmable_irq_support(pb); - if (pb->irq != PARPORT_IRQ_NONE) - goto out; } if (pb->modes & PARPORT_MODE_ECP) @@ -1497,7 +1831,9 @@ static int __devinit parport_irq_probe(struct parport *pb) if (pb->irq == PARPORT_IRQ_NONE) pb->irq = irq_probe_SPP(pb); -out: + if (pb->irq == PARPORT_IRQ_NONE) + pb->irq = get_superio_irq(pb); + return pb->irq; } @@ -1525,7 +1861,12 @@ static int __devinit parport_dma_probe (struct parport *p) { const struct parport_pc_private *priv = p->private_data; if (priv->ecr) - p->dma = programmable_dma_support(p); + p->dma = programmable_dma_support(p); /* ask ECP chipset first */ + if (p->dma == PARPORT_DMA_NONE) + /* ask known Super-IO chips proper, although these + claim ECP compatible, some don't report their DMA + conforming to ECP standards */ + p->dma = get_superio_dma(p); return p->dma; } @@ -1533,9 +1874,9 @@ static int __devinit parport_dma_probe (struct parport *p) /* --- Initialisation code -------------------------------- */ struct parport *__devinit parport_pc_probe_port (unsigned long int base, - unsigned long int base_hi, - int irq, int dma, - struct pci_dev *dev) + unsigned long int base_hi, + int irq, int dma, + struct pci_dev *dev) { struct parport_pc_private *priv; struct parport_operations *ops; @@ -1625,7 +1966,8 @@ struct parport *__devinit parport_pc_probe_port (unsigned long int base, parport_dma_probe(p); } } - if (p->dma == PARPORT_DMA_AUTO) + if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq + is mandatory (see above) */ p->dma = PARPORT_DMA_NONE; #ifdef CONFIG_PARPORT_PC_FIFO @@ -2040,6 +2382,7 @@ static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PAR static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; +static int superio = 0; MODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); MODULE_DESCRIPTION("PC-style parallel port driver"); @@ -2051,12 +2394,18 @@ MODULE_PARM_DESC(irq, "IRQ line"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); +MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe"); +MODULE_PARM(superio, "i"); int init_module(void) { /* Work out how many ports we have, then get parport_share to parse the irq values. */ unsigned int i; + if (superio) { + detect_and_report_winbond (); + detect_and_report_smsc (); + } for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); if (i) { if (parport_parse_irqs(i, irq, irqval)) return 1; diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index fc971cc7428c..abb46572a507 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -602,7 +602,19 @@ static int yenta_init(pci_socket_t *socket) static int yenta_suspend(pci_socket_t *socket) { yenta_set_socket(socket, &dead_socket); + + /* + * This does not work currently. The controller + * loses too much informationduring D3 to come up + * cleanly. We should probably fix yenta_init() + * to update all the critical registers, notably + * the IO and MEM bridging region data.. That is + * something that pci_set_power_state() should + * probably know about bridges anyway. + * pci_set_power_state(socket->dev, 3); + */ + return 0; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 35f18a53c427..781cde85af84 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -666,11 +666,7 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command /* scsi_wait_cmd sets the command length */ SRpnt->sr_cmd_len = 0; - /* - * FIXME(eric) - need to set the data direction here. - */ - SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; - + SRpnt->sr_data_direction = cgc->data_direction; scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen, SR_TIMEOUT, MAX_RETRIES); diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index 95bafcf20df2..32a3380e9ae4 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -20,6 +20,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.3 Feb 22 2000 Ollie Lho + * bug fix for record mask setting * v0.2 Feb 10 2000 Ollie Lho * add ac97_read_proc for /proc/driver/vnedor/ac97 * v0.1 Jan 14 2000 Ollie Lho @@ -40,7 +42,9 @@ static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, uns static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask); static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg); -#define arraysize(x) (sizeof(x)/sizeof((x)[0])) +static int sigmatel_init(struct ac97_codec * codec); + +#define arraysize(x) (sizeof(x)/sizeof((x)[0])) static struct { unsigned int id; @@ -50,14 +54,16 @@ static struct { {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, {0x43525900, "Cirrus Logic CS4297" , NULL}, + {0x43525903, "Cirrus Logic CS4297" , NULL}, {0x43525913, "Cirrus Logic CS4297A" , NULL}, + {0x43525923, "Cirrus Logic CS4298" , NULL}, {0x43525931, "Cirrus Logic CS4299" , NULL}, - {0x4e534331, "National Semiconductor LM4549", NULL}, + {0x4e534331, "National Semiconductor LM4549" , NULL}, {0x83847600, "SigmaTel STAC????" , NULL}, {0x83847604, "SigmaTel STAC9701/3/4/5", NULL}, {0x83847605, "SigmaTel STAC9704" , NULL}, {0x83847608, "SigmaTel STAC9708" , NULL}, - {0x83847609, "SigmaTel STAC9721/23" , NULL}, + {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init}, {0x54524108, "TriTech TR28028" , NULL}, {0x574D4C00, "Wolfson WM9704" , NULL}, {0x00000000, NULL, NULL} @@ -156,11 +162,12 @@ enum ac97_recsettings { }; static unsigned int ac97_rm2oss[] = { - [AC97_REC_MIC] = SOUND_MIXER_MIC, - [AC97_REC_CD] = SOUND_MIXER_CD, - [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, - [AC97_REC_AUX] = SOUND_MIXER_LINE1, - [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_MIC] = SOUND_MIXER_MIC, + [AC97_REC_CD] = SOUND_MIXER_CD, + [AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, + [AC97_REC_AUX] = SOUND_MIXER_LINE1, + [AC97_REC_LINE] = SOUND_MIXER_LINE, + [AC97_REC_STEREO]= SOUND_MIXER_IGAIN, [AC97_REC_PHONE] = SOUND_MIXER_PHONEIN }; @@ -171,6 +178,7 @@ static unsigned int ac97_oss_rm[] = { [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO, [SOUND_MIXER_LINE1] = AC97_REC_AUX, [SOUND_MIXER_LINE] = AC97_REC_LINE, + [SOUND_MIXER_IGAIN] = AC97_REC_STEREO, [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE }; @@ -216,8 +224,10 @@ static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) } #ifdef DEBUG - printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), " - "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret); + printk("ac97_codec: read OSS mixer %2d (%s ac97 register 0x%02x), " + "0x%04x -> 0x%04x\n", + oss_channel, codec->id ? "Secondary" : "Primary", + mh->offset, val, ret); #endif return ret; @@ -269,6 +279,7 @@ static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, #ifdef DEBUG printk(" 0x%04x", val); #endif + codec->codec_write(codec, mh->offset, val); #ifdef DEBUG @@ -303,8 +314,11 @@ static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) if (rw) { /* read it from the card */ - val = codec->codec_read(codec, 0x1a) & 0x7; - return ac97_rm2oss[val]; + val = codec->codec_read(codec, AC97_RECORD_SELECT); +#ifdef DEBUG + printk("ac97_codec: ac97 recmask to set to 0x%04x\n", val); +#endif + return (1 << ac97_rm2oss[val & 0x07]); } /* else, write the first set in the mask as the @@ -315,10 +329,10 @@ static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) val |= val << 8; /* set both channels */ #ifdef DEBUG - printk("ac97_codec: setting ac97 recmask to 0x%x\n", val); + printk("ac97_codec: setting ac97 recmask to 0x%04x\n", val); #endif - codec->codec_write(codec, 0x1a, val); + codec->codec_write(codec, AC97_RECORD_SELECT, val); return 0; }; @@ -384,9 +398,9 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned return -EINVAL; /* do we ever want to touch the hardware? */ - val = codec->read_mixer(codec, i); - /* val = codec->mixer_state[i]; */ - break; + /* val = codec->read_mixer(codec, i); */ + val = codec->mixer_state[i]; + break; } return put_user(val, (int *)arg); } @@ -497,9 +511,10 @@ int ac97_probe_codec(struct ac97_codec *codec) codec->codec_write(codec, AC97_RESET, 0L); if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000) return 0; - + codec->name = NULL; codec->codec_init = NULL; + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); for (i = 0; i < arraysize(ac97_codec_ids); i++) { @@ -520,6 +535,8 @@ int ac97_probe_codec(struct ac97_codec *codec) codec->record_sources = AC97_RECORD_MASK; if (!(cap & 0x04)) codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE); + if (!(cap & 0x10)) + codec->supported_mixers &= ~SOUND_MASK_ALTPCM; /* generic OSS to AC97 wrapper */ codec->read_mixer = ac97_read_mixer; diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index de01c6cbe02f..b3a9f750402a 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -29,6 +29,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.13 Mar 03 2000 Ollie Lho + * new pci_* for 2.4 kernel, back ported to 2.2 + * v0.12 Feb 23 2000 Ollie Lho + * Preliminary Recording support + * v0.11.2 Feb 19 2000 Ollie Lho + * removed incomplete full-dulplex support * v0.11.1 Jan 28 2000 Ollie Lho * small bug in setting sample rate for 4d-nx (reported by Aaron) * v0.11 Jan 27 2000 Ollie Lho @@ -58,9 +64,10 @@ * Clean up of low level channel register access code. (done) * Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done) * Dual AC97 codecs support (done partially, need channel binding to test) - * Recording support + * Recording support (done) * Mmap support * "Channel Binding" ioctl extension + * new pci device driver interface for 2.4 kernel */ #include @@ -85,27 +92,15 @@ #include "trident.h" -#undef DEBUG - -#define DRIVER_VERSION "0.11.1" +#define DRIVER_VERSION "0.13" /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ #define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */ -/* The first 32 channels are called Bank A. They are (should be) reserved - for MIDI synthesizer. But since that is not supported yet, we can (ab)use - them to play PCM samples */ -#undef ABUSE_BANK_A - -/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ? - NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW - channels */ -#ifdef ABUSE_BANK_A -#define NR_HW_CH 64 -#else +#define TRIDENT_DMA_MASK 0x3fffffff /* DMA buffer mask for pci_alloc_consist */ + #define NR_HW_CH 32 -#endif /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only have 2 SDATA_IN lines (currently) */ @@ -119,18 +114,29 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n"; -struct pci_audio_info { - u16 vendor; - u16 device; - char *name; +enum { + TRIDENT_4D_DX = 0, + TRIDENT_4D_NX, + SIS_7018 }; -static struct pci_audio_info pci_audio_devices[] = { - {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"}, - {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"} +static char * card_names[] = { + "Trident 4DWave DX", + "Trident 4DWave NX", + "SiS 7018 PCI Audio" }; +static struct pci_device_id trident_pci_tbl [] __devinitdata = { + {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX}, + {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_NX}, + {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7018}, +}; + +MODULE_DEVICE_TABLE (pci, trident_pci_tbl); + /* "software" or virtual channel, an instance of opened /dev/dsp */ struct trident_state { unsigned int magic; @@ -156,14 +162,15 @@ struct trident_state { /* OSS buffer manangemeent stuff */ void *rawbuf; + dma_addr_t dma_handle; unsigned buforder; unsigned numfrag; unsigned fragshift; /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started, update by update_ptr */ + unsigned hwptr; /* where dma last started, updated by update_ptr */ unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be comsumed by dma machine */ + int count; /* bytes to be comsumed or been generated by dma machine */ unsigned total_bytes; /* total bytes dmaed by hardware */ unsigned error; /* number of over/underruns */ @@ -177,22 +184,21 @@ struct trident_state { /* OSS stuff */ unsigned mapped:1; unsigned ready:1; - unsigned endcleared:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; - } dma_dac, dma_adc; + } dmabuf; }; /* hardware channels */ struct trident_channel { int num; /* channel number */ - u32 lba; /* reg 0xe4 */ - u32 eso; /* reg 0xe8 */ - u32 delta; - u16 attribute; /* reg 0xec */ + u32 lba; /* Loop Begine Address, where dma buffer starts */ + u32 eso; /* End Sample Offset, wehre dma buffer ends (in the unit of samples) */ + u32 delta; /* delta value, sample rate / 48k for playback, 48k/sample rate for recording */ + u16 attribute; /* control where PCM data go and come */ u16 fm_vol; - u32 control; /* reg 0xf0 */ + u32 control; /* signed/unsigned, 8/16 bits, mono/stereo */ }; struct trident_pcm_bank_address { @@ -234,7 +240,6 @@ struct trident_card { spinlock_t lock; /* PCI device stuff */ - struct pci_audio_info *pci_info; struct pci_dev * pci_dev; u16 pci_id; @@ -422,9 +427,6 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c if (bank->bitmap == ~0UL) { /* no more free channels avaliable */ printk(KERN_ERR "trident: no more channels available on Bank B.\n"); -#ifdef ABUSE_BANK_A - goto bank_a; -#endif return NULL; } for (idx = 31; idx >= 0; idx--) { @@ -435,26 +437,6 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c return channel; } } - -#ifdef ABUSE_BANK_A - /* channels in Bank A should be reserved for synthesizer - not for normal use (channels in Bank A can't record) */ - bank_a: - bank = &card->banks[BANK_A]; - if (bank->bitmap == ~0UL) { - /* no more free channels avaliable */ - printk(KERN_ERR "trident: no more channels available on Bank A.\n"); - return NULL; - } - for (idx = 31; idx >= 0; idx--) { - if (!(bank->bitmap & (1 << idx))) { - struct trident_channel *channel = &bank->channels[idx]; - banks->bitmap |= 1 << idx; - channel->num = idx; - return channels; - } - } -#endif return NULL; } @@ -462,13 +444,8 @@ static void trident_free_pcm_channel(struct trident_card *card, int channel) { int bank; -#ifdef ABUSE_BANK_A - if (channel < 0 || channel > 63) - return; -#else if (channel < 31 || channel > 63) return; -#endif bank = channel >> 5; channel = channel & 0x1f; @@ -497,15 +474,12 @@ static int trident_load_channel_registers(struct trident_card *card, u32 *data, } /* called with spin lock held */ -static int trident_write_voice_regs(struct trident_state *state, unsigned int rec) +static int trident_write_voice_regs(struct trident_state *state) { unsigned int data[CHANNEL_REGS + 1]; struct trident_channel *channel; - if (rec) - channel = state->dma_adc.channel; - else - channel = state->dma_dac.channel; + channel = state->dmabuf.channel; data[1] = channel->lba; data[4] = channel->control; @@ -534,7 +508,7 @@ static int trident_write_voice_regs(struct trident_state *state, unsigned int re return trident_load_channel_registers(state->card, data, channel->num); } -static int compute_rate(u32 rate) +static int compute_rate_play(u32 rate) { int delta; /* We special case 44100 and 8000 since rounding with the equation @@ -552,10 +526,25 @@ static int compute_rate(u32 rate) return delta; } +static int compute_rate_rec(u32 rate) +{ + int delta; + + if (rate == 44100) + delta = 0x116a; + else if (rate == 8000) + delta = 0x6000; + else if (rate == 48000) + delta = 0x1000; + else + delta = ((48000 << 12) / rate) & 0x0000ffff; + + return delta; +} /* set playback sample rate */ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; if (rate > 48000) rate = 48000; @@ -563,9 +552,9 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned rate = 4000; dmabuf->rate = rate; - dmabuf->channel->delta = compute_rate(rate); + dmabuf->channel->delta = compute_rate_play(rate); - trident_write_voice_regs(state, 0); + trident_write_voice_regs(state); #ifdef DEBUG printk("trident: called trident_set_dac_rate : rate = %d\n", rate); @@ -577,16 +566,17 @@ static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned /* set recording sample rate */ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; + if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; dmabuf->rate = rate; - dmabuf->channel->delta = compute_rate(rate); + dmabuf->channel->delta = compute_rate_rec(rate); - trident_write_voice_regs(state, 1); + trident_write_voice_regs(state); #ifdef DEBUG printk("trident: called trident_set_adc_rate : rate = %d\n", rate); @@ -597,18 +587,18 @@ static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned /* prepare channel attributes for playback */ static void trident_play_setup(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; channel->lba = virt_to_bus(dmabuf->rawbuf); - channel->delta = compute_rate(dmabuf->rate); + channel->delta = compute_rate_play(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { - /* FIXME: channel attributes are configured by ioctls, but it is not implemented - so just set to ZERO for the moment */ + /* FIXME: channel attributes are configured by ioctls, but it is not + implemented so just set to ZERO for the moment */ channel->attribute = 0; } else { channel->attribute = 0; @@ -631,7 +621,7 @@ static void trident_play_setup(struct trident_state *state) "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", channel->lba, channel->delta, channel->eso, channel->control); #endif - trident_write_voice_regs(state, 0); + trident_write_voice_regs(state); } /* prepare channel attributes for recording */ @@ -639,7 +629,7 @@ static void trident_rec_setup(struct trident_state *state) { u16 w; struct trident_card *card = state->card; - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; /* Enable AC-97 ADC (capture) */ @@ -651,25 +641,30 @@ static void trident_rec_setup(struct trident_state *state) case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT)); outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT)); + /* enable and set record channel */ + outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH)); break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: w = inw(TRID_REG(card, T4D_MISCINT)); outw(w | 0x1000, TRID_REG(card, T4D_MISCINT)); + /* enable and set record channel */ + outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH)); break; default: return; } channel->lba = virt_to_bus(dmabuf->rawbuf); - channel->delta = compute_rate(dmabuf->rate); + channel->delta = compute_rate_rec(dmabuf->rate); channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) { - /* FIXME: channel attributes are configured by ioctls, but it is not implemented - so just set to ZERO for the moment */ - channel->attribute = 0; + /* FIXME: channel attributes are configured by ioctls, but it is not + implemented so just set to 0x8a80 for the moment, record from PCM L/R + input and mono = (left + right + 1)/2*/ + channel->attribute = 0x8A80; } else { channel->attribute = 0; } @@ -691,21 +686,16 @@ static void trident_rec_setup(struct trident_state *state) "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n", channel->lba, channel->delta, channel->eso, channel->control); #endif - trident_write_voice_regs(state, 1); + trident_write_voice_regs(state); } /* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ -extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec) +extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; u32 cso; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - if (!dmabuf->enable) return 0; @@ -727,7 +717,8 @@ extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, uns } #ifdef DEBUG - printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n", + printk("trident: trident_get_dma_addr: chip reported channel: %d, " + "cso = 0x%04x\n", dmabuf->channel->num, cso); #endif /* ESO and CSO are in units of Samples, convert to byte offset */ @@ -739,11 +730,11 @@ extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, uns /* Stop recording (lock held) */ extern __inline__ void __stop_adc(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; - dmabuf->enable &= ~DMA_RUNNING; + dmabuf->enable &= ~ADC_RUNNING; trident_stop_voice(card, chan_num); trident_disable_voice_irq(card, chan_num); } @@ -760,16 +751,14 @@ static void stop_adc(struct trident_state *state) static void start_adc(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_adc; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); - if ((dmabuf->mapped || - dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize)) - && dmabuf->ready) { - dmabuf->enable |= DMA_RUNNING; + if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) { + dmabuf->enable |= ADC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); } @@ -779,11 +768,11 @@ static void start_adc(struct trident_state *state) /* stop playback (lock held) */ extern __inline__ void __stop_dac(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; - dmabuf->enable &= ~DMA_RUNNING; + dmabuf->enable &= ~DAC_RUNNING; trident_stop_voice(card, chan_num); trident_disable_voice_irq(card, chan_num); } @@ -800,14 +789,14 @@ static void stop_dac(struct trident_state *state) static void start_dac(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned int chan_num = dmabuf->channel->num; struct trident_card *card = state->card; unsigned long flags; spin_lock_irqsave(&card->lock, flags); if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { - dmabuf->enable |= DMA_RUNNING; + dmabuf->enable |= DAC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); } @@ -818,39 +807,27 @@ static void start_dac(struct trident_state *state) #define DMABUF_MINORDER 1 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */ -static int alloc_dmabuf(struct trident_state *state, unsigned rec) +static int alloc_dmabuf(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf; int order; unsigned long map, mapend; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - /* alloc as big a chunk as we can, FIXME: is this necessary ?? */ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) + if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, + PAGE_SIZE << order, + &dmabuf->dma_handle))) break; if (!rawbuf) return -ENOMEM; + #ifdef DEBUG printk("trident: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf); #endif - /* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address - (LBA) which limits the address space to 1 (2) GB, bad T^2 design */ - if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) { - printk(KERN_ERR "trident: DMA buffer beyond 1 GB; " - "bus address = 0x%lx, size = %ld\n", - virt_to_bus(rawbuf), PAGE_SIZE << order); - free_pages((unsigned long)rawbuf, order); - return -ENOMEM; - } - dmabuf->ready = dmabuf->mapped = 0; dmabuf->rawbuf = rawbuf; dmabuf->buforder = order; @@ -864,16 +841,18 @@ static int alloc_dmabuf(struct trident_state *state, unsigned rec) } /* free DMA buffer */ -static void dealloc_dmabuf(struct dmabuf *dmabuf) +static void dealloc_dmabuf(struct trident_state *state) { + struct dmabuf *dmabuf = &state->dmabuf; unsigned long map, mapend; if (dmabuf->rawbuf) { /* undo marking the pages as reserved */ mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++) - clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder); + clear_bit(PG_reserved, &mem_map[map].flags); + pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, + dmabuf->rawbuf, dmabuf->dma_handle); } dmabuf->rawbuf = NULL; dmabuf->mapped = dmabuf->ready = 0; @@ -881,25 +860,20 @@ static void dealloc_dmabuf(struct dmabuf *dmabuf) static int prog_dmabuf(struct trident_state *state, unsigned rec) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; unsigned bytepersec; unsigned bufsize; unsigned long flags; int ret; - if (rec) - dmabuf = &state->dma_adc; - else - dmabuf = &state->dma_dac; - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = dmabuf->endcleared = 0; + dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; spin_unlock_irqrestore(&state->card->lock, flags); /* allocate DMA buffer if not allocated yet */ if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state, rec))) + if ((ret = alloc_dmabuf(state))) return ret; /* FIXME: figure out all this OSS fragment stuff */ @@ -958,7 +932,7 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) */ static void trident_clear_tail(struct trident_state *state) { - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned swptr; unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80; unsigned int len; @@ -971,7 +945,6 @@ static void trident_clear_tail(struct trident_state *state) if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize) return; - if (swptr < dmabuf->dmasize/2) len = dmabuf->dmasize/2 - swptr; else @@ -979,7 +952,7 @@ static void trident_clear_tail(struct trident_state *state) memset(dmabuf->rawbuf + swptr, silence, len); - spin_lock_irqsave(&state->card->lock, flags); + spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr += len; dmabuf->count += len; spin_unlock_irqrestore(&state->card->lock, flags); @@ -991,7 +964,7 @@ static void trident_clear_tail(struct trident_state *state) static int drain_dac(struct trident_state *state, int nonblock) { DECLARE_WAITQUEUE(wait, current); - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned long tmo; int count; @@ -1038,49 +1011,49 @@ static int drain_dac(struct trident_state *state, int nonblock) return 0; } -/* call with spinlock held! */ +/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ static void trident_update_ptr(struct trident_state *state) { - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; unsigned hwptr; int diff; - /* update ADC pointer */ - if (state->dma_adc.ready) { - dmabuf = &state->dma_adc; - hwptr = trident_get_dma_addr(state, 1); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + /* update hardware pointer */ + hwptr = trident_get_dma_addr(state); + diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; + dmabuf->hwptr = hwptr; + dmabuf->total_bytes += diff; - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count += diff; + /* error handling and process wake up for DAC */ + if (dmabuf->enable == ADC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count -= diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - if (!dmabuf->mapped) { - if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) { - __stop_adc(state); + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_adc(state); dmabuf->error++; } + /* since dma machine only interrupts at ESO and ESO/2, we sure have at + least half of dma buffer free, so wake up the process unconditionally */ + wake_up(&dmabuf->wait); } } - - /* update DAC pointer */ - if (state->dma_dac.ready) { - dmabuf = &state->dma_dac; - hwptr = trident_get_dma_addr(state, 0); - diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; - - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { if (dmabuf->mapped) { dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) + if (dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); - } - else { + } else { dmabuf->count -= diff; + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { /* buffer underrun or buffer overrun, we have no way to recover it here, just stop the machine and let the process force hwptr @@ -1088,7 +1061,7 @@ static void trident_update_ptr(struct trident_state *state) __stop_dac(state); dmabuf->error++; } - /* since dma machine only interrupts at ESO and ESO/2, we sure have at + /* since dma machine only interrupts at ESO and ESO/2, we sure have at least half of dma buffer free, so wake up the process unconditionally */ wake_up(&dmabuf->wait); } @@ -1120,17 +1093,13 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else { printk("trident: spurious channel irq %d.\n", 63 - i); - trident_stop_voice(card, i); - trident_disable_voice_irq(card, i); + trident_stop_voice(card, 63 - i); + trident_disable_voice_irq(card, 63 - i); } } } } - if (event & SB_IRQ){ - /* Midi - TODO */ - } - /* manually clear interrupt status, bad hardware design, blame T^2 */ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(card, T4D_MISCINT)); @@ -1142,18 +1111,21 @@ static loff_t trident_llseek(struct file *file, loff_t offset, int origin) return -ESPIPE; } -/* in this loop, dma_adc.count signifies the amount of data thats waiting - to be copied to the user's buffer. it is filled by the interrupt - handler and drained by this loop. */ +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to + the user's buffer. it is filled by the dma machine and drained by this loop. */ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned swptr; int cnt; +#ifdef DEBUG + printk("trident: trident_read called, count = %d\n", count); +#endif + VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; @@ -1167,6 +1139,12 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); + if (dmabuf->count > (signed) dmabuf->dmasize) { + /* buffer overrun, we are recovering from sleep_on_timeout, + resync hwptr and swptr, make process flush the buffer */ + dmabuf->count = dmabuf->dmasize; + dmabuf->swptr = dmabuf->hwptr; + } swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count < cnt) @@ -1175,25 +1153,35 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ if (cnt > count) cnt = count; - if (cnt <= 0) { + unsigned long tmo; + /* buffer is empty, start the dma machine and wait for data to be + recorded */ start_adc(state); if (file->f_flags & O_NONBLOCK) { - ret = ret ? ret : -EAGAIN; + if (!ret) ret = -EAGAIN; return ret; } - if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) { - printk(KERN_ERR - "(trident) read: chip lockup? " + /* No matter how much space left in the buffer, we have to wait untill + CSO == ESO/2 or CSO == ESO when address engine interrupts */ + tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); + tmo >>= sample_shift[dmabuf->fmt]; + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer overrun. And worse, there is + NOTHING we can do to prevent it. */ + if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { +#ifdef DEBUG + printk(KERN_ERR "trident: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); - stop_adc(state); - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->count = 0; - dmabuf->hwptr = 0; - dmabuf->swptr = 0; - spin_unlock_irqrestore(&state->card->lock, flags); +#endif + /* a buffer overrun, we delay the recovery untill next time the + while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { ret = ret ? ret : -ERESTARTSYS; @@ -1203,7 +1191,7 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - ret = ret ? ret : -EFAULT; + if (!ret) ret = -EFAULT; return ret; } @@ -1219,14 +1207,15 @@ static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_ ret += cnt; start_adc(state); } - return ret; } +/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to + the soundcard. it is drained by the dma machine and filled by this loop. */ static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf = &state->dma_dac; + struct dmabuf *dmabuf = &state->dmabuf; ssize_t ret; unsigned long flags; unsigned swptr; @@ -1234,7 +1223,7 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count #ifdef DEBUG printk("trident: trident_write called, count = %d\n", count); -#endif +#endif VALIDATE_STATE(state); if (ppos != &file->f_pos) @@ -1265,7 +1254,8 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count cnt = count; if (cnt <= 0) { unsigned long tmo; - /* buffer is full, start the dma machine and wait for data to be played */ + /* buffer is full, start the dma machine and wait for data to be + played */ start_dac(state); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; @@ -1275,15 +1265,16 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count CSO == ESO/2 or CSO == ESO when address engine interrupts */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= sample_shift[dmabuf->fmt]; - /* There are two situations when sleep_on_timeout returns, one is when the - interrupt is serviced correctly and the process is waked up by ISR ON TIME. - Another is when timeout is expired, which means that either interrupt is NOT - serviced correctly (pending interrupt) or it is TOO LATE for the process to - be scheduled to run (scheduler latency) which results in a (potential) buffer - underrun. And worse, there is NOTHING we can do to prevent it. */ + /* There are two situations when sleep_on_timeout returns, one is when + the interrupt is serviced correctly and the process is waked up by + ISR ON TIME. Another is when timeout is expired, which means that + either interrupt is NOT serviced correctly (pending interrupt) or it + is TOO LATE for the process to be scheduled to run (scheduler latency) + which results in a (potential) buffer underrun. And worse, there is + NOTHING we can do to prevent it. */ if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) { #ifdef DEBUG - printk(KERN_ERR "trident: schedule timeout, " + printk(KERN_ERR "trident: playback schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); @@ -1307,7 +1298,6 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count spin_lock_irqsave(&state->card->lock, flags); dmabuf->swptr = swptr; dmabuf->count += cnt; - dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; @@ -1320,32 +1310,33 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait) { - struct trident_state *s = (struct trident_state *)file->private_data; + struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned int mask = 0; - VALIDATE_STATE(s); + VALIDATE_STATE(state); if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->dma_dac.wait, wait); + poll_wait(file, &dmabuf->wait, wait); if (file->f_mode & FMODE_READ) - poll_wait(file, &s->dma_adc.wait, wait); + poll_wait(file, &dmabuf->wait, wait); - spin_lock_irqsave(&s->card->lock, flags); - trident_update_ptr(s); + spin_lock_irqsave(&state->card->lock, flags); + trident_update_ptr(state); if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac.mapped) { - if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + if (dmabuf->mapped) { + if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize) + if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } } - spin_unlock_irqrestore(&s->card->lock, flags); + spin_unlock_irqrestore(&state->card->lock, flags); return mask; } @@ -1353,7 +1344,7 @@ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wa static int trident_mmap(struct file *file, struct vm_area_struct *vma) { struct trident_state *state = (struct trident_state *)file->private_data; - struct dmabuf *dmabuf; + struct dmabuf *dmabuf = &state->dmabuf; int ret; unsigned long size; @@ -1361,11 +1352,9 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) return ret; - dmabuf = &state->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(state, 1)) != 0) return ret; - dmabuf = &state->dma_adc; } else return -EINVAL; @@ -1385,14 +1374,15 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma) static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret; VALIDATE_STATE(state); - mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) || - ((file->f_mode & FMODE_READ) && state->dma_adc.mapped); + mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || + ((file->f_mode & FMODE_READ) && dmabuf->mapped); #ifdef DEBUG printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n", _IOC_NR(cmd), arg ? *(int *)arg : 0); @@ -1404,19 +1394,20 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm return put_user(SOUND_VERSION, (int *)arg); case SNDCTL_DSP_RESET: + /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { stop_dac(state); synchronize_irq(); - state->dma_dac.ready = 0; - state->dma_dac.swptr = state->dma_dac.hwptr = 0; - state->dma_dac.count = state->dma_dac.total_bytes = 0; + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(state); synchronize_irq(); - state->dma_adc.ready = 0; - state->dma_adc.swptr = state->dma_adc.hwptr = 0; - state->dma_adc.count = state->dma_adc.total_bytes = 0; + dmabuf->ready = 0; + dmabuf->swptr = dmabuf->hwptr = 0; + dmabuf->count = dmabuf->total_bytes = 0; } return 0; @@ -1430,40 +1421,38 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_dac_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; spin_lock_irqsave(&state->card->lock, flags); trident_set_adc_rate(state, val); spin_unlock_irqrestore(&state->card->lock, flags); } } - return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : - state->dma_dac.rate, - (int *)arg); + return put_user(dmabuf->rate, (int *)arg); case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val) - state->dma_dac.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val) - state->dma_adc.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } return 0; @@ -1471,12 +1460,12 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) return val; - return put_user(state->dma_dac.fragsize, (int *)arg); + return put_user(dmabuf->fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf(state, 1))) return val; - return put_user(state->dma_adc.fragsize, (int *)arg); + return put_user(dmabuf->fragsize, (int *)arg); } case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ @@ -1487,120 +1476,99 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val == AFMT_S16_LE) - state->dma_dac.fmt |= TRIDENT_FMT_16BIT; + dmabuf->fmt |= TRIDENT_FMT_16BIT; else - state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT; + dmabuf->fmt &= ~TRIDENT_FMT_16BIT; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val == AFMT_S16_LE) - state->dma_adc.fmt |= TRIDENT_FMT_16BIT; + dmabuf->fmt |= TRIDENT_FMT_16BIT; else - state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT; + dmabuf->fmt &= ~TRIDENT_FMT_16BIT; } } - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); case SNDCTL_DSP_CHANNELS: get_user_ret(val, (int *)arg, -EFAULT); if (val != 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); - state->dma_dac.ready = 0; + dmabuf->ready = 0; if (val >= 2) - state->dma_dac.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); - state->dma_adc.ready = 0; + dmabuf->ready = 0; if (val >= 2) - state->dma_adc.fmt |= TRIDENT_FMT_STEREO; + dmabuf->fmt |= TRIDENT_FMT_STEREO; else - state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO; + dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } } - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + case SNDCTL_DSP_POST: /* FIXME: the same as RESET ?? */ return 0; case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision)) + if (dmabuf->subdivision) return -EINVAL; get_user_ret(val, (int *)arg, -EFAULT); if (val != 1 && val != 2 && val != 4) return -EINVAL; - if (file->f_mode & FMODE_READ) - state->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - state->dma_dac.subdivision = val; + dmabuf->subdivision = val; return 0; case SNDCTL_DSP_SETFRAGMENT: get_user_ret(val, (int *)arg, -EFAULT); - if (file->f_mode & FMODE_READ) { - state->dma_adc.ossfragshift = val & 0xffff; - state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (state->dma_adc.ossfragshift < 4) - state->dma_adc.ossfragshift = 4; - if (state->dma_adc.ossfragshift > 15) - state->dma_adc.ossfragshift = 15; - if (state->dma_adc.ossmaxfrags < 4) - state->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - state->dma_dac.ossfragshift = val & 0xffff; - state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; - if (state->dma_dac.ossfragshift < 4) - state->dma_dac.ossfragshift = 4; - if (state->dma_dac.ossfragshift > 15) - state->dma_dac.ossfragshift = 15; - if (state->dma_dac.ossmaxfrags < 4) - state->dma_dac.ossmaxfrags = 4; - } + + dmabuf->ossfragshift = val & 0xffff; + dmabuf->ossmaxfrags = (val >> 16) & 0xffff; + if (dmabuf->ossfragshift < 4) + dmabuf->ossfragshift = 4; + if (dmabuf->ossfragshift > 15) + dmabuf->ossfragshift = 15; + if (dmabuf->ossmaxfrags < 4) + dmabuf->ossmaxfrags = 4; + return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0) + if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - abinfo.fragsize = state->dma_dac.fragsize; - abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count; - abinfo.fragstotal = state->dma_dac.numfrag; - abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift; + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->dmasize - dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0) + if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - abinfo.fragsize = state->dma_adc.fragsize; - abinfo.bytes = state->dma_adc.count; - abinfo.fragstotal = state->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift; + abinfo.fragsize = dmabuf->fragsize; + abinfo.bytes = dmabuf->count; + abinfo.fragstotal = dmabuf->numfrag; + abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; @@ -1609,14 +1577,13 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm return 0; case SNDCTL_DSP_GETCAPS: - return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, - (int *)arg); + return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg); case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && state->dma_adc.enable) + if (file->f_mode & FMODE_READ && dmabuf->enable) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) + if (file->f_mode & FMODE_WRITE && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); @@ -1624,20 +1591,18 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm get_user_ret(val, (int *)arg, -EFAULT); if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { - if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; start_adc(state); - } - else + } else stop_adc(state); } if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { - if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0))) + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; start_dac(state); - } - else + } else stop_dac(state); } return 0; @@ -1647,59 +1612,50 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - cinfo.bytes = state->dma_adc.total_bytes; - cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift; - cinfo.ptr = state->dma_adc.hwptr; - if (state->dma_adc.mapped) - state->dma_adc.count &= state->dma_adc.fragsize-1; + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); - + case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - cinfo.bytes = state->dma_dac.total_bytes; - cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift; - cinfo.ptr = state->dma_dac.hwptr; - if (state->dma_dac.mapped) - state->dma_dac.count &= state->dma_dac.fragsize-1; + cinfo.bytes = dmabuf->total_bytes; + cinfo.blocks = dmabuf->count >> dmabuf->fragshift; + cinfo.ptr = dmabuf->hwptr; + if (dmabuf->mapped) + dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->card->lock, flags); return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_SETDUPLEX: - /* XXX fix */ - return 0; + return -EINVAL; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); - val = state->dma_dac.count; + val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); return put_user(val, (int *)arg); case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate : - state->dma_dac.rate, (int *)arg); + return put_user(dmabuf->rate, (int *)arg); case SOUND_PCM_READ_CHANNELS: - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); - + return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + (int *)arg); + case SOUND_PCM_READ_BITS: - if (file->f_mode & FMODE_WRITE) - return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); - else - return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ? - AFMT_S16_LE : AFMT_U8, (int *)arg); + return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + AFMT_S16_LE : AFMT_U8, (int *)arg); + case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: case SNDCTL_DSP_SETSYNCRO: @@ -1738,70 +1694,61 @@ static int trident_open(struct inode *inode, struct file *file) found_virt: /* found a free virtual channel, allocate hardware channels */ - if (file->f_mode & FMODE_READ) - if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) { - kfree (card->states[i]); - card->states[i] = NULL;; - return -ENODEV; - } - if (file->f_mode & FMODE_WRITE) - if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) { - kfree (card->states[i]); - card->states[i] = NULL; - if (file->f_mode & FMODE_READ) - /* free previously allocated hardware channel */ - trident_free_pcm_channel(card, state->dma_adc.channel->num); - return -ENODEV; - } + if ((state->dmabuf.channel = trident_alloc_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } /* initialize the virtual channel */ state->virt = i; state->card = card; state->magic = TRIDENT_STATE_MAGIC; - init_waitqueue_head(&state->dma_adc.wait); - init_waitqueue_head(&state->dma_dac.wait); + init_waitqueue_head(&state->dmabuf.wait); init_MUTEX(&state->open_sem); file->private_data = state; down(&state->open_sem); - /* set default sample format, Refer to OSS Programmer's Guide */ - if (file->f_mode & FMODE_READ) { - /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */ - state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT; - state->dma_adc.ossfragshift = 0; - state->dma_adc.ossmaxfrags = 0; - state->dma_adc.subdivision = 0; - trident_set_adc_rate(state, 48000); - } - - /* according to OSS document, /dev/dsp should be default to unsigned 8-bits, - mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */ + /* set default sample format. According to OSS Programmer's Guide /dev/dsp + should be default to unsigned 8-bits, mono, with sample rate 8kHz and + /dev/dspW will accept 16-bits sample */ if (file->f_mode & FMODE_WRITE) { - state->dma_dac.fmt &= ~TRIDENT_FMT_MASK; + state->dmabuf.fmt &= ~TRIDENT_FMT_MASK; if ((minor & 0xf) == SND_DEV_DSP16) - state->dma_dac.fmt |= TRIDENT_FMT_16BIT; - state->dma_dac.ossfragshift = 0; - state->dma_dac.ossmaxfrags = 0; - state->dma_dac.subdivision = 0; + state->dmabuf.fmt |= TRIDENT_FMT_16BIT; + state->dmabuf.ossfragshift = 0; + state->dmabuf.ossmaxfrags = 0; + state->dmabuf.subdivision = 0; trident_set_dac_rate(state, 8000); } + if (file->f_mode & FMODE_READ) { + /* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample, + to be dealed with in trident_set_adc_rate() ?? */ + state->dmabuf.fmt &= ~TRIDENT_FMT_MASK; + if ((minor & 0xf) == SND_DEV_DSP16) + state->dmabuf.fmt |= TRIDENT_FMT_16BIT; + state->dmabuf.ossfragshift = 0; + state->dmabuf.ossmaxfrags = 0; + state->dmabuf.subdivision = 0; + trident_set_adc_rate(state, 8000); + } + state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&state->open_sem); - //FIXME put back in - //MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; return 0; } static int trident_release(struct inode *inode, struct file *file) { struct trident_state *state = (struct trident_state *)file->private_data; + struct dmabuf *dmabuf = &state->dmabuf; VALIDATE_STATE(state); - if (file->f_mode & FMODE_WRITE) { trident_clear_tail(state); drain_dac(state, file->f_flags & O_NONBLOCK); @@ -1812,13 +1759,13 @@ static int trident_release(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) { stop_dac(state); - dealloc_dmabuf(&state->dma_dac); - trident_free_pcm_channel(state->card, state->dma_dac.channel->num); + dealloc_dmabuf(state); + trident_free_pcm_channel(state->card, dmabuf->channel->num); } if (file->f_mode & FMODE_READ) { stop_adc(state); - dealloc_dmabuf(&state->dma_adc); - trident_free_pcm_channel(state->card, state->dma_adc.channel->num); + dealloc_dmabuf(state); + trident_free_pcm_channel(state->card, dmabuf->channel->num); } kfree(state->card->states[state->virt]); @@ -1828,8 +1775,7 @@ static int trident_release(struct inode *inode, struct file *file) /* we're covered by the open_sem */ up(&state->open_sem); - //FIXME put back in - //MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return 0; } @@ -1845,7 +1791,7 @@ static /*const*/ struct file_operations trident_audio_fops = { }; /* trident specific AC97 functions */ -/* Write AC97 mixer registers */ +/* Write AC97 codec registers */ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) { struct trident_card *card = (struct trident_card *)codec->private_data; @@ -1863,7 +1809,7 @@ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) address = SI_AC97_WRITE; mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY; if (codec->id) - mask |= SI_AC97_SECONDARY; + mask |= SI_AC97_SECONDARY; busy = SI_AC97_BUSY_WRITE; break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX: @@ -1874,7 +1820,7 @@ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) address = NX_ACR1_AC97_W; mask = NX_AC97_BUSY_WRITE; if (codec->id) - mask |= NX_AC97_WRITE_SECONDARY; + mask |= NX_AC97_WRITE_SECONDARY; busy = NX_AC97_BUSY_WRITE; break; } @@ -1968,17 +1914,13 @@ static int trident_open_mixdev(struct inode *inode, struct file *file) match: file->private_data = card->ac97_codec[i]; - //FIXME put back in - //MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; return 0; } static int trident_release_mixdev(struct inode *inode, struct file *file) { - //struct ac97_codec *codec = (struct ac97_codec *)file->private_data; - - //FIXME put back in - //MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return 0; } @@ -2061,36 +2003,35 @@ static int __init trident_ac97_init(struct trident_card *card) } /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */ -static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info) + untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ +static int __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { - u16 w; unsigned long iobase; struct trident_card *card; - iobase = pcidev->resource[0].start; + if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) { + printk(KERN_ERR "trident: architecture does not support" + " 30bit PCI busmaster DMA\n"); + return -1; + } + + iobase = pci_dev->resource[0].start; if (check_region(iobase, 256)) { printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n", iobase); - return 0; + return -1; } - /* just to be sure that IO space and bus master is on */ - pci_set_master(pcidev); - pci_read_config_word(pcidev, PCI_COMMAND, &w); - w |= PCI_COMMAND_IO|PCI_COMMAND_MASTER; - pci_write_config_word(pcidev, PCI_COMMAND, w); - if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "trident: out of memory\n"); - return 0; + return -1; } memset(card, 0, sizeof(*card)); card->iobase = iobase; - card->pci_info = pci_info; - card->pci_id = pci_info->device; - card->irq = pcidev->irq; + card->pci_dev = pci_dev; + card->pci_id = pci_id->device; + card->irq = pci_dev->irq; card->next = devs; card->magic = TRIDENT_CARD_MAGIC; card->banks[BANK_A].addresses = &bank_a_addrs; @@ -2098,14 +2039,18 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info card->banks[BANK_B].addresses = &bank_b_addrs; card->banks[BANK_B].bitmap = 0UL; spin_lock_init(&card->lock); - devs = card; + devs = card; + + pci_set_master(pci_dev); + pci_enable_device(pci_dev); printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n", - card->pci_info->name, card->iobase, card->irq); + card_names[pci_id->driver_data], card->iobase, card->irq); /* claim our iospace and irq */ - request_region(card->iobase, 256, card->pci_info->name); - if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) { + request_region(card->iobase, 256, card_names[pci_id->driver_data]); + if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, + card_names[pci_id->driver_data], card)) { printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq); release_region(card->iobase, 256); kfree(card); @@ -2117,7 +2062,7 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info release_region(iobase, 256); free_irq(card->irq, card); kfree(card); - return 0; + return -1; } /* initilize AC97 codec and register /dev/mixer */ if (trident_ac97_init(card) <= 0) { @@ -2125,68 +2070,66 @@ static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info release_region(iobase, 256); free_irq(card->irq, card); kfree(card); - return 0; + return -1; } outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); + pci_dev->driver_data = card; + pci_dev->dma_mask = TRIDENT_DMA_MASK; + /* Enable Address Engine Interrupts */ trident_enable_loop_interrupts(card); - return 1; + return 0; } -static int __init init_trident(void) +static void __devexit trident_remove(struct pci_dev *pci_dev) { - struct pci_dev *pcidev = NULL; - int foundone = 0; int i; + struct trident_card *card = pci_dev->driver_data; - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; + /* Kill interrupts, and SP/DIF */ + trident_disable_loop_interrupts(card); - printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version " - DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); + /* free hardware resources */ + free_irq(card->irq, devs); + release_region(card->iobase, 256); - for (i = 0; i < sizeof (pci_audio_devices); i++) { - pcidev = NULL; - while ((pcidev = pci_find_device(pci_audio_devices[i].vendor, - pci_audio_devices[i].device, - pcidev)) != NULL) { - foundone += trident_install(pcidev, pci_audio_devices + i); + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) + if (devs->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); } - } + unregister_sound_dsp(card->dev_audio); - if (!foundone) - return -ENODEV; - return 0; + kfree(card); } MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho"); MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver"); -static void __exit cleanup_trident(void) -{ - while (devs != NULL) { - int i; - /* Kill interrupts, and SP/DIF */ - trident_disable_loop_interrupts(devs); +#define TRIDENT_MODULE_NAME "trident" - /* free hardware resources */ - free_irq(devs->irq, devs); - release_region(devs->iobase, 256); +static struct pci_driver trident_pci_driver = { + name: TRIDENT_MODULE_NAME, + id_table: trident_pci_tbl, + probe: trident_probe, + remove: trident_remove, +}; - /* unregister audio devices */ - for (i = 0; i < NR_AC97; i++) - if (devs->ac97_codec[i] != NULL) { - unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer); - kfree (devs->ac97_codec[i]); - } - unregister_sound_dsp(devs->dev_audio); +static int __init trident_init_module (void) +{ + printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version " + DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - kfree(devs); - devs = devs->next; - } + return pci_module_init (&trident_pci_driver); +} + +static void __exit trident_cleanup_module (void) +{ + pci_unregister_driver (&trident_pci_driver); } -module_init(init_trident); -module_exit(cleanup_trident); +module_init(trident_init_module); +module_exit(trident_cleanup_module); diff --git a/drivers/sound/trident.h b/drivers/sound/trident.h index 4504cb30390a..6bbb25bd1594 100644 --- a/drivers/sound/trident.h +++ b/drivers/sound/trident.h @@ -60,13 +60,13 @@ #define TRIDENT_FMT_16BIT 0x02 #define TRIDENT_FMT_MASK 0x03 -#define DMA_ENABLE 0x01 -#define DMA_RUNNING 0x02 - +#define DAC_RUNNING 0x01 +#define ADC_RUNNING 0x02 /* Register Addresses */ /* operational registers common to DX, NX, 7018 */ enum trident_op_registers { + T4D_REC_CH = 0x70, T4D_START_A = 0x80, T4D_STOP_A = 0x84, T4D_DLY_A = 0x88, T4D_SIGN_CSO_A = 0x8c, T4D_CSPF_A = 0x90, T4D_CEBC_A = 0x94, diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index bf6c23b53aba..39659ca553c3 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -45,7 +45,7 @@ comment 'USB Devices' dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB dep_tristate ' PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB - dep_tristate ' USB ADMteks Pegasus based devices support' CONFIG_USB_PEGASUS $CONFIG_USB + dep_tristate ' USB ADMtek Pegasus-based device support' CONFIG_USB_PEGASUS $CONFIG_USB dep_tristate ' USB Diamond Rio500 support' CONFIG_USB_RIO500 $CONFIG_USB comment 'USB HID' diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index bb017e60c6bb..9bc13642063e 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -1264,7 +1264,7 @@ static int rh_submit_urb (urb_t * urb) int status = TD_CC_NOERROR; __u32 datab[4]; - __u8 * data_buf = datab; + __u8 * data_buf = (__u8 *) datab; __u16 bmRType_bReq; __u16 wValue; diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index 6b9615e72b61..40c935ce930b 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -1347,6 +1347,8 @@ static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned urb_value , 0, buf, 0, HZ * 5)); } + + return -ENOIOCTLCMD; } #endif /* CONFIG_USB_SERIAL_FTDI_SIO */ diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 4e8c4e9d4650..82c916d8a499 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -517,8 +517,8 @@ static int __devinit rivafb_init_one (struct pci_dev *pd, rinfo->riva.Architecture = rci->arch_rev; rinfo->pd = pd; - rinfo->base0_region_size = pci_resource_start (pd, 0); - rinfo->base1_region_size = pci_resource_start (pd, 1); + rinfo->base0_region_size = pci_resource_len (pd, 0); + rinfo->base1_region_size = pci_resource_len (pd, 1); assert (rinfo->base0_region_size >= 0x00800000); /* from GGI */ assert (rinfo->base0_region_size >= 0x01000000); /* from GGI */ diff --git a/fs/block_dev.c b/fs/block_dev.c index 5a202c7e1d4d..c455a735d769 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -630,7 +630,7 @@ int blkdev_put(struct block_device *bdev, int kind) /* syncing will go here */ if (kind == BDEV_FILE || kind == BDEV_FS) fsync_dev(rdev); - if (atomic_dec_and_test(&bdev->bd_openers) && MAJOR(rdev) != RAMDISK_MAJOR) { + if (atomic_dec_and_test(&bdev->bd_openers)) { /* invalidating buffers will go here */ invalidate_buffers(rdev); } diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index db58636722fe..1a6eddc87ee6 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -664,8 +664,11 @@ void __init proc_misc_init(void) } } #ifdef __powerpc__ - entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_htab_operations; + { + extern struct file_operations ppc_htab_operations; + entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL); + if (entry) + entry->proc_fops = &ppc_htab_operations; + } #endif } diff --git a/fs/proc/root.c b/fs/proc/root.c index 6cdb2ad19d13..cce48d845b07 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -70,9 +70,6 @@ void __init proc_root_init(void) proc_mkdir("openprom", 0); #endif proc_tty_init(); -#ifdef __powerpc__ - proc_register(&proc_root, &proc_root_ppc_htab); -#endif #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index b2d7f1ab4d94..b92eed7db895 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -9,6 +9,7 @@ #ifdef __KERNEL__ +#include #include #ifndef LINUX_VERSION_CODE diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h index 4cbcd785079d..ca2fb0529793 100644 --- a/include/asm-ppc/types.h +++ b/include/asm-ppc/types.h @@ -2,10 +2,7 @@ #define _PPC_TYPES_H #ifndef __ASSEMBLY__ -/* - * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the - * header files exported to user space - */ +#ifdef __KERNEL__ typedef unsigned short umode_t; @@ -42,8 +39,6 @@ typedef struct { u32 u[4]; } __attribute((aligned(16))) vector128; -#ifdef __KERNEL__ - #define BITS_PER_LONG 32 /* DMA addresses are 32-bits wide */ diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h index 7090e062577c..50c75c3a846b 100644 --- a/include/linux/ac97_codec.h +++ b/include/linux/ac97_codec.h @@ -54,14 +54,13 @@ /* record mux defines */ #define AC97_RECMUX_MIC 0x0000 #define AC97_RECMUX_CD 0x0101 -#define AC97_RECMUX_VIDEO 0x0202 /* not used */ -#define AC97_RECMUX_AUX 0x0303 -#define AC97_RECMUX_LINE 0x0404 +#define AC97_RECMUX_VIDEO 0x0202 +#define AC97_RECMUX_AUX 0x0303 +#define AC97_RECMUX_LINE 0x0404 #define AC97_RECMUX_STEREO_MIX 0x0505 #define AC97_RECMUX_MONO_MIX 0x0606 #define AC97_RECMUX_PHONE 0x0707 - /* general purpose register bit defines */ #define AC97_GP_LPBK 0x0080 /* Loopback mode */ #define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */ @@ -73,7 +72,6 @@ #define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */ #define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ - /* powerdown control and status bit defines */ /* status */ @@ -116,7 +114,7 @@ SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT) #define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD|SOUND_MASK_VIDEO|\ + SOUND_MASK_CD|SOUND_MASK_IGAIN|SOUND_MASK_VIDEO|\ SOUND_MASK_LINE1| SOUND_MASK_LINE|\ SOUND_MASK_PHONEIN) diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 3f15c3063b5e..a1d9b293943a 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -5,13 +5,12 @@ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998, 1999 Jens Axboe, axboe@image.dk + * 1998-2000 Jens Axboe, axboe@suse.de */ #ifndef _LINUX_CDROM_H #define _LINUX_CDROM_H -#include #include /******************************************************* @@ -225,7 +224,7 @@ struct cdrom_tocentry struct cdrom_read { int cdread_lba; - caddr_t cdread_bufaddr; + char *cdread_bufaddr; int cdread_buflen; }; @@ -267,6 +266,11 @@ struct cdrom_blk #define CDROM_PACKET_SIZE 12 +#define CGC_DATA_UNKNOWN 0 +#define CGC_DATA_WRITE 1 +#define CGC_DATA_READ 2 +#define CGC_DATA_NONE 3 + /* for CDROM_PACKET_COMMAND ioctl */ struct cdrom_generic_command { @@ -275,6 +279,7 @@ struct cdrom_generic_command unsigned int buflen; int stat; struct request_sense *sense; + unsigned char data_direction; void *reserved[3]; }; @@ -790,7 +795,8 @@ extern int cdrom_mode_sense(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc, int page_code, int page_control); extern void init_cdrom_command(struct cdrom_generic_command *cgc, - void *buffer, int len); + void *buffer, int len, int type); +extern struct cdrom_device_info *cdrom_find_device(kdev_t dev); typedef struct { __u16 disc_information_length; @@ -798,9 +804,9 @@ typedef struct { __u8 reserved1 : 3; __u8 erasable : 1; __u8 border_status : 2; - __u8 disc_border : 2; + __u8 disc_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 disc_border : 2; + __u8 disc_status : 2; __u8 border_status : 2; __u8 erasable : 1; __u8 reserved1 : 3; @@ -938,7 +944,6 @@ struct mode_page_header { }; typedef struct { - struct mode_page_header header; #if defined(__BIG_ENDIAN_BITFIELD) __u8 ps : 1; __u8 reserved1 : 1; @@ -991,7 +996,7 @@ typedef struct { __u8 subhdr1; __u8 subhdr2; __u8 subhdr3; -} write_param_page __attribute__((packed)); +} __attribute__((packed)) write_param_page; #endif /* End of kernel only stuff */ diff --git a/include/linux/ide.h b/include/linux/ide.h index 3672f2789f79..64136c7327d7 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -358,7 +358,8 @@ typedef enum { ide_unknown, ide_generic, ide_pci, ide_cmd640, ide_dtc2278, ide_ali14xx, ide_qd6580, ide_umc8672, ide_ht6560b, ide_pdc4030, ide_rz1000, ide_trm290, - ide_cmd646, ide_cy82c693, ide_4drives + ide_cmd646, ide_cy82c693, ide_4drives, + ide_pmac } hwif_chipset_t; #ifdef CONFIG_BLK_DEV_IDEPCI diff --git a/ipc/shm.c b/ipc/shm.c index 9c326c799706..6c6fc31d65c3 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -925,9 +925,9 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr swap_free(entry); if ((shp != shm_lock(shp->id)) && (is_shmzero == 0)) BUG(); - if (is_shmzero) shm_swp--; + if (is_shmzero == 0) shm_swp--; } - if (is_shmzero) shm_rss++; + if (is_shmzero == 0) shm_rss++; pte = pte_mkdirty(mk_pte(page, PAGE_SHARED)); SHM_ENTRY(shp, idx) = pte; } else diff --git a/net/Config.in b/net/Config.in index 45f1b1168977..833846406b20 100644 --- a/net/Config.in +++ b/net/Config.in @@ -53,7 +53,7 @@ tristate 'The IPX protocol' CONFIG_IPX if [ "$CONFIG_IPX" != "n" ]; then source net/ipx/Config.in fi -tristate 'Appletalk DDP' CONFIG_ATALK +tristate 'Appletalk protocol support' CONFIG_ATALK if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'DECnet Support (EXPERIMENTAL)' CONFIG_DECNET if [ "$CONFIG_DECNET" != "n" ]; then diff --git a/net/netsyms.c b/net/netsyms.c index 16ff31dd0023..d99e539579ce 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -586,6 +586,8 @@ EXPORT_SYMBOL(nf_register_queue_handler); EXPORT_SYMBOL(nf_unregister_queue_handler); EXPORT_SYMBOL(nf_hook_slow); EXPORT_SYMBOL(nf_hooks); +EXPORT_SYMBOL(nf_setsockopt); +EXPORT_SYMBOL(nf_getsockopt); #endif EXPORT_SYMBOL(register_gifconf); -- 2.39.5