Merge HEAD from master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 29 Aug 2005 17:36:48 +0000 (10:36 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 29 Aug 2005 17:36:48 +0000 (10:36 -0700)
154 files changed:
Documentation/networking/phy.txt [new file with mode: 0644]
Makefile
arch/alpha/kernel/signal.c
arch/arm/Kconfig
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/gic.c [new file with mode: 0644]
arch/arm/kernel/signal.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/generic.h
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm26/kernel/signal.c
arch/cris/arch-v10/kernel/signal.c
arch/cris/arch-v32/kernel/signal.c
arch/frv/kernel/signal.c
arch/h8300/kernel/signal.c
arch/i386/kernel/signal.c
arch/ia64/kernel/signal.c
arch/m32r/kernel/signal.c
arch/m68knommu/kernel/signal.c
arch/mips/kernel/irixsig.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/parisc/kernel/signal.c
arch/ppc/kernel/signal.c
arch/ppc64/kernel/signal.c
arch/ppc64/kernel/signal32.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/signal.c
arch/sh/kernel/signal.c
arch/sh64/kernel/signal.c
arch/sparc/kernel/signal.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/um/drivers/mmapper_kern.c
arch/um/kernel/signal_kern.c
arch/v850/kernel/signal.c
arch/x86_64/kernel/signal.c
arch/xtensa/kernel/signal.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/sleep/poweroff.c
drivers/char/vt.c
drivers/isdn/capi/capifs.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
drivers/mfd/Kconfig [new file with mode: 0644]
drivers/mfd/Makefile [new file with mode: 0644]
drivers/mfd/mcp-core.c [new file with mode: 0644]
drivers/mfd/mcp-sa11x0.c [new file with mode: 0644]
drivers/mfd/mcp.h [new file with mode: 0644]
drivers/mmc/mmc.c
drivers/mmc/mmc.h
drivers/mmc/mmc_sysfs.c
drivers/mmc/mmci.c
drivers/mmc/wbsd.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/Space.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/e1000/e1000_main.c
drivers/net/eepro100.c
drivers/net/forcedeth.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/Kconfig
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/baycom_par.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/hamradio/mkiss.c
drivers/net/ixgb/ixgb.h
drivers/net/ixgb/ixgb_ee.c
drivers/net/ixgb/ixgb_ethtool.c
drivers/net/ixgb/ixgb_hw.h
drivers/net/ixgb/ixgb_main.c
drivers/net/jazzsonic.c
drivers/net/loopback.c
drivers/net/macsonic.c
drivers/net/mv643xx_eth.c
drivers/net/mv643xx_eth.h
drivers/net/pci-skeleton.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/phy/Kconfig [new file with mode: 0644]
drivers/net/phy/Makefile [new file with mode: 0644]
drivers/net/phy/cicada.c [new file with mode: 0644]
drivers/net/phy/davicom.c [new file with mode: 0644]
drivers/net/phy/lxt.c [new file with mode: 0644]
drivers/net/phy/marvell.c [new file with mode: 0644]
drivers/net/phy/mdio_bus.c [new file with mode: 0644]
drivers/net/phy/phy.c [new file with mode: 0644]
drivers/net/phy/phy_device.c [new file with mode: 0644]
drivers/net/phy/qsemi.c [new file with mode: 0644]
drivers/net/r8169.c
drivers/net/s2io-regs.h
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/skge.c
drivers/net/skge.h
drivers/net/sonic.c
drivers/net/sonic.h
drivers/net/tokenring/Kconfig
drivers/net/tokenring/abyss.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/proteon.c
drivers/net/tokenring/skisa.c
drivers/net/tokenring/tms380tr.c
drivers/net/tokenring/tms380tr.h
drivers/net/tokenring/tmspci.c
drivers/net/wan/cycx_drv.c
drivers/net/wireless/orinoco.c
drivers/parport/parport_serial.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_port.c
drivers/scsi/ahci.c
drivers/scsi/ata_piix.c
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
drivers/scsi/libata.h
drivers/scsi/sata_nv.c
drivers/scsi/sata_promise.c
drivers/scsi/sata_qstor.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sis.c
drivers/scsi/sata_svw.c
drivers/scsi/sata_sx4.c
drivers/scsi/sata_uli.c
drivers/scsi/sata_via.c
drivers/scsi/sata_vsc.c
drivers/scsi/sg.c
drivers/serial/8250_pci.c
fs/adfs/adfs.h
include/asm-arm/arch-sa1100/mcp.h [new file with mode: 0644]
include/asm-arm/hardware/gic.h [new file with mode: 0644]
include/linux/8250_pci.h
include/linux/ata.h
include/linux/ethtool.h
include/linux/libata.h
include/linux/mii.h
include/linux/mmc/host.h
include/linux/pci_ids.h
include/linux/phy.h [new file with mode: 0644]
include/linux/serialP.h

diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
new file mode 100644 (file)
index 0000000..29ccae4
--- /dev/null
@@ -0,0 +1,288 @@
+
+-------
+PHY Abstraction Layer
+(Updated 2005-07-21)
+
+Purpose
+
+ Most network devices consist of set of registers which provide an interface
+ to a MAC layer, which communicates with the physical connection through a
+ PHY.  The PHY concerns itself with negotiating link parameters with the link
+ partner on the other side of the network connection (typically, an ethernet
+ cable), and provides a register interface to allow drivers to determine what
+ settings were chosen, and to configure what settings are allowed.
+
+ While these devices are distinct from the network devices, and conform to a
+ standard layout for the registers, it has been common practice to integrate
+ the PHY management code with the network driver.  This has resulted in large
+ amounts of redundant code.  Also, on embedded systems with multiple (and
+ sometimes quite different) ethernet controllers connected to the same 
+ management bus, it is difficult to ensure safe use of the bus.
+
+ Since the PHYs are devices, and the management busses through which they are
+ accessed are, in fact, busses, the PHY Abstraction Layer treats them as such.
+ In doing so, it has these goals:
+
+   1) Increase code-reuse
+   2) Increase overall code-maintainability
+   3) Speed development time for new network drivers, and for new systems
+ Basically, this layer is meant to provide an interface to PHY devices which
+ allows network driver writers to write as little code as possible, while
+ still providing a full feature set.
+
+The MDIO bus
+
+ Most network devices are connected to a PHY by means of a management bus.
+ Different devices use different busses (though some share common interfaces).
+ In order to take advantage of the PAL, each bus interface needs to be
+ registered as a distinct device.
+
+ 1) read and write functions must be implemented.  Their prototypes are:
+
+     int write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+     int read(struct mii_bus *bus, int mii_id, int regnum);
+
+   mii_id is the address on the bus for the PHY, and regnum is the register
+   number.  These functions are guaranteed not to be called from interrupt
+   time, so it is safe for them to block, waiting for an interrupt to signal
+   the operation is complete
+ 2) A reset function is necessary.  This is used to return the bus to an
+   initialized state.
+
+ 3) A probe function is needed.  This function should set up anything the bus
+   driver needs, setup the mii_bus structure, and register with the PAL using
+   mdiobus_register.  Similarly, there's a remove function to undo all of
+   that (use mdiobus_unregister).
+ 4) Like any driver, the device_driver structure must be configured, and init
+   exit functions are used to register the driver.
+
+ 5) The bus must also be declared somewhere as a device, and registered.
+
+ As an example for how one driver implemented an mdio bus driver, see
+ drivers/net/gianfar_mii.c and arch/ppc/syslib/mpc85xx_devices.c
+
+Connecting to a PHY
+
+ Sometime during startup, the network driver needs to establish a connection
+ between the PHY device, and the network device.  At this time, the PHY's bus
+ and drivers need to all have been loaded, so it is ready for the connection.
+ At this point, there are several ways to connect to the PHY:
+
+ 1) The PAL handles everything, and only calls the network driver when
+   the link state changes, so it can react.
+
+ 2) The PAL handles everything except interrupts (usually because the
+   controller has the interrupt registers).
+
+ 3) The PAL handles everything, but checks in with the driver every second,
+   allowing the network driver to react first to any changes before the PAL
+   does.
+ 4) The PAL serves only as a library of functions, with the network device
+   manually calling functions to update status, and configure the PHY
+
+
+Letting the PHY Abstraction Layer do Everything
+
+ If you choose option 1 (The hope is that every driver can, but to still be
+ useful to drivers that can't), connecting to the PHY is simple:
+
+ First, you need a function to react to changes in the link state.  This
+ function follows this protocol:
+
+   static void adjust_link(struct net_device *dev);
+ Next, you need to know the device name of the PHY connected to this device. 
+ The name will look something like, "phy0:0", where the first number is the
+ bus id, and the second is the PHY's address on that bus.
+ Now, to connect, just call this function:
+   phydev = phy_connect(dev, phy_name, &adjust_link, flags);
+
+ phydev is a pointer to the phy_device structure which represents the PHY.  If
+ phy_connect is successful, it will return the pointer.  dev, here, is the
+ pointer to your net_device.  Once done, this function will have started the
+ PHY's software state machine, and registered for the PHY's interrupt, if it
+ has one.  The phydev structure will be populated with information about the
+ current state, though the PHY will not yet be truly operational at this
+ point.
+
+ flags is a u32 which can optionally contain phy-specific flags.
+ This is useful if the system has put hardware restrictions on
+ the PHY/controller, of which the PHY needs to be aware.
+
+ Now just make sure that phydev->supported and phydev->advertising have any
+ values pruned from them which don't make sense for your controller (a 10/100
+ controller may be connected to a gigabit capable PHY, so you would need to
+ mask off SUPPORTED_1000baseT*).  See include/linux/ethtool.h for definitions
+ for these bitfields. Note that you should not SET any bits, or the PHY may
+ get put into an unsupported state.
+
+ Lastly, once the controller is ready to handle network traffic, you call
+ phy_start(phydev).  This tells the PAL that you are ready, and configures the
+ PHY to connect to the network.  If you want to handle your own interrupts,
+ just set phydev->irq to PHY_IGNORE_INTERRUPT before you call phy_start.
+ Similarly, if you don't want to use interrupts, set phydev->irq to PHY_POLL.
+
+ When you want to disconnect from the network (even if just briefly), you call
+ phy_stop(phydev).
+
+Keeping Close Tabs on the PAL
+
+ It is possible that the PAL's built-in state machine needs a little help to
+ keep your network device and the PHY properly in sync.  If so, you can
+ register a helper function when connecting to the PHY, which will be called
+ every second before the state machine reacts to any changes.  To do this, you
+ need to manually call phy_attach() and phy_prepare_link(), and then call
+ phy_start_machine() with the second argument set to point to your special
+ handler.
+
+ Currently there are no examples of how to use this functionality, and testing
+ on it has been limited because the author does not have any drivers which use
+ it (they all use option 1).  So Caveat Emptor.
+
+Doing it all yourself
+
+ There's a remote chance that the PAL's built-in state machine cannot track
+ the complex interactions between the PHY and your network device.  If this is
+ so, you can simply call phy_attach(), and not call phy_start_machine or
+ phy_prepare_link().  This will mean that phydev->state is entirely yours to
+ handle (phy_start and phy_stop toggle between some of the states, so you
+ might need to avoid them).
+
+ An effort has been made to make sure that useful functionality can be
+ accessed without the state-machine running, and most of these functions are
+ descended from functions which did not interact with a complex state-machine.
+ However, again, no effort has been made so far to test running without the
+ state machine, so tryer beware.
+
+ Here is a brief rundown of the functions:
+
+ int phy_read(struct phy_device *phydev, u16 regnum);
+ int phy_write(struct phy_device *phydev, u16 regnum, u16 val);
+
+   Simple read/write primitives.  They invoke the bus's read/write function
+   pointers.
+
+ void phy_print_status(struct phy_device *phydev);
+   A convenience function to print out the PHY status neatly.
+
+ int phy_clear_interrupt(struct phy_device *phydev);
+ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
+   
+   Clear the PHY's interrupt, and configure which ones are allowed,
+   respectively.  Currently only supports all on, or all off.
+ int phy_enable_interrupts(struct phy_device *phydev);
+ int phy_disable_interrupts(struct phy_device *phydev);
+
+   Functions which enable/disable PHY interrupts, clearing them
+   before and after, respectively.
+
+ int phy_start_interrupts(struct phy_device *phydev);
+ int phy_stop_interrupts(struct phy_device *phydev);
+
+   Requests the IRQ for the PHY interrupts, then enables them for
+   start, or disables then frees them for stop.
+
+ struct phy_device * phy_attach(struct net_device *dev, const char *phy_id,
+                u32 flags);
+
+   Attaches a network device to a particular PHY, binding the PHY to a generic
+   driver if none was found during bus initialization.  Passes in
+   any phy-specific flags as needed.
+
+ int phy_start_aneg(struct phy_device *phydev);
+   
+   Using variables inside the phydev structure, either configures advertising
+   and resets autonegotiation, or disables autonegotiation, and configures
+   forced settings.
+
+ static inline int phy_read_status(struct phy_device *phydev);
+
+   Fills the phydev structure with up-to-date information about the current
+   settings in the PHY.
+
+ void phy_sanitize_settings(struct phy_device *phydev)
+   
+   Resolves differences between currently desired settings, and
+   supported settings for the given PHY device.  Does not make
+   the changes in the hardware, though.
+
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+
+   Ethtool convenience functions.
+
+ int phy_mii_ioctl(struct phy_device *phydev,
+                 struct mii_ioctl_data *mii_data, int cmd);
+
+   The MII ioctl.  Note that this function will completely screw up the state
+   machine if you write registers like BMCR, BMSR, ADVERTISE, etc.  Best to
+   use this only to write registers which are not standard, and don't set off
+   a renegotiation.
+
+
+PHY Device Drivers
+
+ With the PHY Abstraction Layer, adding support for new PHYs is
+ quite easy.  In some cases, no work is required at all!  However,
+ many PHYs require a little hand-holding to get up-and-running.
+
+Generic PHY driver
+
+ If the desired PHY doesn't have any errata, quirks, or special
+ features you want to support, then it may be best to not add
+ support, and let the PHY Abstraction Layer's Generic PHY Driver
+ do all of the work.  
+
+Writing a PHY driver
+
+ If you do need to write a PHY driver, the first thing to do is
+ make sure it can be matched with an appropriate PHY device.
+ This is done during bus initialization by reading the device's
+ UID (stored in registers 2 and 3), then comparing it to each
+ driver's phy_id field by ANDing it with each driver's
+ phy_id_mask field.  Also, it needs a name.  Here's an example:
+
+   static struct phy_driver dm9161_driver = {
+         .phy_id         = 0x0181b880,
+        .name           = "Davicom DM9161E",
+        .phy_id_mask    = 0x0ffffff0,
+        ...
+   }
+
+ Next, you need to specify what features (speed, duplex, autoneg,
+ etc) your PHY device and driver support.  Most PHYs support
+ PHY_BASIC_FEATURES, but you can look in include/mii.h for other
+ features.
+
+ Each driver consists of a number of function pointers:
+
+   config_init: configures PHY into a sane state after a reset.
+     For instance, a Davicom PHY requires descrambling disabled.
+   probe: Does any setup needed by the driver
+   suspend/resume: power management
+   config_aneg: Changes the speed/duplex/negotiation settings
+   read_status: Reads the current speed/duplex/negotiation settings
+   ack_interrupt: Clear a pending interrupt
+   config_intr: Enable or disable interrupts
+   remove: Does any driver take-down
+
+ Of these, only config_aneg and read_status are required to be
+ assigned by the driver code.  The rest are optional.  Also, it is
+ preferred to use the generic phy driver's versions of these two
+ functions if at all possible: genphy_read_status and
+ genphy_config_aneg.  If this is not possible, it is likely that
+ you only need to perform some actions before and after invoking
+ these functions, and so your functions will wrap the generic
+ ones.
+
+ Feel free to look at the Marvell, Cicada, and Davicom drivers in
+ drivers/net/phy/ for examples (the lxt and qsemi drivers have
+ not been tested as of this writing)
index 300f61f6f6a25f52d44c5bee024f8cf57e8f3d66..5acd1fc68d173000c1d3de42e4c3788d48c3fb10 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 13
-EXTRAVERSION =-rc7
+EXTRAVERSION =
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
index 08fe8071a7f8fde380e1fa7338fef07ab8925ef5..2e45e8604e325454e87681321c862e57b19b1355 100644 (file)
@@ -566,13 +566,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_RESETHAND)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER)) 
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void
index c65c6eb9810d84b05267470cadfbf2efc9b0e682..4bf0e8737e1fd514477ec4009ba4e908f189b9a9 100644 (file)
@@ -635,10 +635,6 @@ config PM
          and the Battery Powered Linux mini-HOWTO, available from
          <http://www.tldp.org/docs.html#howto>.
 
-         Note that, even if you say N here, Linux on the x86 architecture
-         will issue the hlt instruction if nothing is to be done, thereby
-         sending the processor to sleep and saving power.
-
 config APM
        tristate "Advanced Power Management Emulation"
        depends on PM
@@ -650,12 +646,6 @@ config APM
          battery status information, and user-space programs will receive
          notification of APM "events" (e.g. battery status change).
 
-         If you select "Y" here, you can disable actual use of the APM
-         BIOS by passing the "apm=off" option to the kernel at boot time.
-
-         Note that the APM support is almost completely disabled for
-         machines with more than one CPU.
-
          In order to use APM, you will need supporting software. For location
          and more information, read <file:Documentation/pm.txt> and the
          Battery Powered Linux mini-HOWTO, available from
@@ -665,39 +655,12 @@ config APM
          manpage ("man 8 hdparm") for that), and it doesn't turn off
          VESA-compliant "green" monitors.
 
-         This driver does not support the TI 4000M TravelMate and the ACER
-         486/DX4/75 because they don't have compliant BIOSes. Many "green"
-         desktop machines also don't have compliant BIOSes, and this driver
-         may cause those machines to panic during the boot phase.
-
          Generally, if you don't have a battery in your machine, there isn't
          much point in using this driver and you should say N. If you get
          random kernel OOPSes or reboots that don't seem to be related to
          anything, try disabling/enabling this option (or disabling/enabling
          APM in your BIOS).
 
-         Some other things you should try when experiencing seemingly random,
-         "weird" problems:
-
-         1) make sure that you have enough swap space and that it is
-         enabled.
-         2) pass the "no-hlt" option to the kernel
-         3) switch on floating point emulation in the kernel and pass
-         the "no387" option to the kernel
-         4) pass the "floppy=nodma" option to the kernel
-         5) pass the "mem=4M" option to the kernel (thereby disabling
-         all but the first 4 MB of RAM)
-         6) make sure that the CPU is not over clocked.
-         7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/>
-         8) disable the cache from your BIOS settings
-         9) install a fan for the video card or exchange video RAM
-         10) install a better fan for the CPU
-         11) exchange RAM chips
-         12) exchange the motherboard.
-
-         To compile this driver as a module, choose M here: the
-         module will be called apm.
-
 endmenu
 
 source "net/Kconfig"
@@ -752,6 +715,8 @@ source "drivers/hwmon/Kconfig"
 
 source "drivers/misc/Kconfig"
 
+source "drivers/mfd/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
index 692af6b5e8ff259d1455e816edf92ec186229a7a..666ba393575b8d7800b5b8a14d4e5ce1466932bc 100644 (file)
@@ -1,6 +1,9 @@
 config ICST525
        bool
 
+config ARM_GIC
+       bool
+
 config ICST307
        bool
 
index 11f20a43ee3aa81c8c605512b2d5398361478026..a87886564b19e0b9c33798cdae6947114e0e5947 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-y                          += rtctime.o
 obj-$(CONFIG_ARM_AMBA)         += amba.o
+obj-$(CONFIG_ARM_GIC)          += gic.o
 obj-$(CONFIG_ICST525)          += icst525.o
 obj-$(CONFIG_ICST307)          += icst307.o
 obj-$(CONFIG_SA1111)           += sa1111.o
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
new file mode 100644 (file)
index 0000000..51dbf54
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *  linux/arch/arm/common/gic.c
+ *
+ *  Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Interrupt architecture for the GIC:
+ *
+ * o There is one Interrupt Distributor, which receives interrupts
+ *   from system devices and sends them to the Interrupt Controllers.
+ *
+ * o There is one CPU Interface per CPU, which sends interrupts sent
+ *   by the Distributor, and interrupts generated locally, to the
+ *   associated CPU.
+ *
+ * Note that IRQs 0-31 are special - they are local to each CPU.
+ * As such, the enable set/clear, pending set/clear and active bit
+ * registers are banked per-cpu for these sources.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/gic.h>
+
+static void __iomem *gic_dist_base;
+static void __iomem *gic_cpu_base;
+
+/*
+ * Routines to acknowledge, disable and enable interrupts
+ *
+ * Linux assumes that when we're done with an interrupt we need to
+ * unmask it, in the same way we need to unmask an interrupt when
+ * we first enable it.
+ *
+ * The GIC has a seperate notion of "end of interrupt" to re-enable
+ * an interrupt after handling, in order to support hardware
+ * prioritisation.
+ *
+ * We can make the GIC behave in the way that Linux expects by making
+ * our "acknowledge" routine disable the interrupt, then mark it as
+ * complete.
+ */
+static void gic_ack_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
+       writel(irq, gic_cpu_base + GIC_CPU_EOI);
+}
+
+static void gic_mask_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
+}
+
+static void gic_unmask_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq % 32);
+       writel(mask, gic_dist_base + GIC_DIST_ENABLE_SET + (irq / 32) * 4);
+}
+
+static void gic_set_cpu(struct irqdesc *desc, unsigned int irq, unsigned int cpu)
+{
+       void __iomem *reg = gic_dist_base + GIC_DIST_TARGET + (irq & ~3);
+       unsigned int shift = (irq % 4) * 8;
+       u32 val;
+
+       val = readl(reg) & ~(0xff << shift);
+       val |= 1 << (cpu + shift);
+       writel(val, reg);
+}
+
+static struct irqchip gic_chip = {
+       .ack            = gic_ack_irq,
+       .mask           = gic_mask_irq,
+       .unmask         = gic_unmask_irq,
+#ifdef CONFIG_SMP
+       .set_cpu        = gic_set_cpu,
+#endif
+};
+
+void __init gic_dist_init(void __iomem *base)
+{
+       unsigned int max_irq, i;
+       u32 cpumask = 1 << smp_processor_id();
+
+       cpumask |= cpumask << 8;
+       cpumask |= cpumask << 16;
+
+       gic_dist_base = base;
+
+       writel(0, base + GIC_DIST_CTRL);
+
+       /*
+        * Find out how many interrupts are supported.
+        */
+       max_irq = readl(base + GIC_DIST_CTR) & 0x1f;
+       max_irq = (max_irq + 1) * 32;
+
+       /*
+        * The GIC only supports up to 1020 interrupt sources.
+        * Limit this to either the architected maximum, or the
+        * platform maximum.
+        */
+       if (max_irq > max(1020, NR_IRQS))
+               max_irq = max(1020, NR_IRQS);
+
+       /*
+        * Set all global interrupts to be level triggered, active low.
+        */
+       for (i = 32; i < max_irq; i += 16)
+               writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);
+
+       /*
+        * Set all global interrupts to this CPU only.
+        */
+       for (i = 32; i < max_irq; i += 4)
+               writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
+
+       /*
+        * Set priority on all interrupts.
+        */
+       for (i = 0; i < max_irq; i += 4)
+               writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+
+       /*
+        * Disable all interrupts.
+        */
+       for (i = 0; i < max_irq; i += 32)
+               writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+
+       /*
+        * Setup the Linux IRQ subsystem.
+        */
+       for (i = 29; i < max_irq; i++) {
+               set_irq_chip(i, &gic_chip);
+               set_irq_handler(i, do_level_IRQ);
+               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+       }
+
+       writel(1, base + GIC_DIST_CTRL);
+}
+
+void __cpuinit gic_cpu_init(void __iomem *base)
+{
+       gic_cpu_base = base;
+       writel(0xf0, base + GIC_CPU_PRIMASK);
+       writel(1, base + GIC_CPU_CTRL);
+}
+
+#ifdef CONFIG_SMP
+void gic_raise_softirq(cpumask_t cpumask, unsigned int irq)
+{
+       unsigned long map = *cpus_addr(cpumask);
+
+       writel(map << 16 | irq, gic_dist_base + GIC_DIST_SOFTINT);
+}
+#endif
index 5e435e42dacdef45d87173527d60759aa7af083f..a94d75fef598b90bc1a65d32dc017bfa184c0059 100644 (file)
@@ -658,11 +658,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        /*
         * Block the signal if we were unsuccessful.
         */
-       if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret != 0) {
                spin_lock_irq(&tsk->sighand->siglock);
                sigorsets(&tsk->blocked, &tsk->blocked,
                          &ka->sa.sa_mask);
-               sigaddset(&tsk->blocked, sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&tsk->blocked, sig);
                recalc_sigpending();
                spin_unlock_irq(&tsk->sighand->siglock);
        }
index 4d4d303ee3a8003bdbd4e5f48a8a04480fadfd1e..24687f511bf53c9bf74ee4d55a332a61a690f162 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 #include <asm/arch/assabet.h>
+#include <asm/arch/mcp.h>
 
 #include "generic.h"
 
@@ -198,6 +199,11 @@ static struct irda_platform_data assabet_irda_data = {
        .set_speed      = assabet_irda_set_speed,
 };
 
+static struct mcp_plat_data assabet_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init assabet_init(void)
 {
        /*
@@ -246,6 +252,7 @@ static void __init assabet_init(void)
        sa11x0_set_flash_data(&assabet_flash_data, assabet_flash_resources,
                              ARRAY_SIZE(assabet_flash_resources));
        sa11x0_set_irda_data(&assabet_irda_data);
+       sa11x0_set_mcp_data(&assabet_mcp_data);
 }
 
 /*
index 0aa918e24c3123c26caa928a7683aa4e5d45bf9d..9484be7dc671a0ada6bb834ea480b48b73ff6863 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include <asm/arch/cerf.h>
+#include <asm/arch/mcp.h>
 #include "generic.h"
 
 static struct resource cerfuart2_resources[] = {
@@ -116,10 +117,16 @@ static void __init cerf_map_io(void)
        GPDR |= CERF_GPIO_CF_RESET;
 }
 
+static struct mcp_plat_data cerf_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init cerf_init(void)
 {
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_set_flash_data(&cerf_flash_data, &cerf_flash_resource, 1);
+       sa11x0_set_mcp_data(&cerf_mcp_data);
 }
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
index 95ae217be1bc06a485d29764c1507f6d50eac9a9..3f1e358455e51578ca01f16d6cde1a3141fbfb50 100644 (file)
@@ -221,6 +221,11 @@ static struct platform_device sa11x0mcp_device = {
        .resource       = sa11x0mcp_resources,
 };
 
+void sa11x0_set_mcp_data(struct mcp_plat_data *data)
+{
+       sa11x0mcp_device.dev.platform_data = data;
+}
+
 static struct resource sa11x0ssp_resources[] = {
        [0] = {
                .start  = 0x80070000,
index bfe41da9923e35b0b427058485e05749c454f2a1..279e3afa3c393bd8b25b4f01c47abd00ffb40d57 100644 (file)
@@ -34,5 +34,8 @@ struct resource;
 extern void sa11x0_set_flash_data(struct flash_platform_data *flash,
                                  struct resource *res, int nr);
 
+struct sa11x0_ssp_plat_ops;
+extern void sa11x0_set_ssp_data(struct sa11x0_ssp_plat_ops *ops);
+
 struct irda_platform_data;
 void sa11x0_set_irda_data(struct irda_platform_data *irda);
index 870b488aeda44323172400c76bfd2e1274fbf9a8..ed6744d480aff0f04e2b1bd6a1f742b1e01d3b23 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 
 #include "generic.h"
 
 
 #warning "include/asm/arch-sa1100/ide.h needs fixing for lart"
 
+static struct mcp_plat_data lart_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
+static void __init lart_init(void)
+{
+       sa11x0_set_mcp_data(&lart_mcp_data);
+}
+
 static struct map_desc lart_io_desc[] __initdata = {
  /* virtual     physical    length      type */
   { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */
@@ -47,5 +58,6 @@ MACHINE_START(LART, "LART")
        .boot_params    = 0xc0000100,
        .map_io         = lart_map_io,
        .init_irq       = sa1100_init_irq,
+       .init_machine   = lart_init,
        .timer          = &sa1100_timer,
 MACHINE_END
index 43a00359fcdddf9e8d0186702112ae98659f9921..7482288278d96acf17323a5612aa2791ab771d4c 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 #include <asm/arch/shannon.h>
 
 #include "generic.h"
@@ -52,9 +53,15 @@ static struct resource shannon_flash_resource = {
        .flags          = IORESOURCE_MEM,
 };
 
+static struct mcp_plat_data shannon_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 static void __init shannon_init(void)
 {
        sa11x0_set_flash_data(&shannon_flash_data, &shannon_flash_resource, 1);
+       sa11x0_set_mcp_data(&shannon_mcp_data);
 }
 
 static void __init shannon_map_io(void)
index 77978586b1268d955e2fa58fdaab475a2408ee0c..07f6d5fd7bb0a0108f149d8323073012dfe0a9d2 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
+#include <asm/arch/mcp.h>
 #include <asm/arch/simpad.h>
 
 #include <linux/serial_core.h>
@@ -123,6 +124,11 @@ static struct resource simpad_flash_resources [] = {
        }
 };
 
+static struct mcp_plat_data simpad_mcp_data = {
+       .mccr0          = MCCR0_ADM,
+       .sclk_rate      = 11981000,
+};
+
 
 
 static void __init simpad_map_io(void)
@@ -157,6 +163,7 @@ static void __init simpad_map_io(void)
 
        sa11x0_set_flash_data(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
+       sa11x0_set_mcp_data(&simpad_mcp_data);
 }
 
 static void simpad_power_off(void)
index 356d9809cc0bb5ad4ba011025889061a92d711ea..ce2055bdc9ee82c342e35f63ca98835d66c9715b 100644 (file)
@@ -454,14 +454,13 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
                if (ka->sa.sa_flags & SA_ONESHOT)
                        ka->sa.sa_handler = SIG_DFL;
 
-               if (!(ka->sa.sa_flags & SA_NODEFER)) {
-                       spin_lock_irq(&tsk->sighand->siglock);
-                       sigorsets(&tsk->blocked, &tsk->blocked,
-                                 &ka->sa.sa_mask);
+               spin_lock_irq(&tsk->sighand->siglock);
+               sigorsets(&tsk->blocked, &tsk->blocked,
+                         &ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
                        sigaddset(&tsk->blocked, sig);
-                       recalc_sigpending();
-                       spin_unlock_irq(&tsk->sighand->siglock);
-               }
+               recalc_sigpending();
+               spin_unlock_irq(&tsk->sighand->siglock);
                return;
        }
 
index 85e0032e664ffcf93e489841d4ba19ee3746e42a..693771961f859f788c4eec80bbea21df85ecf1e7 100644 (file)
@@ -517,13 +517,12 @@ handle_signal(int canrestart, unsigned long sig,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index fb4c79d5b76b028840c5cf665e6807b27a86f475..0a3614dab88701b2827e26ce5858c94bf824852e 100644 (file)
@@ -568,13 +568,12 @@ handle_signal(int canrestart, unsigned long sig,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 36a2dffc8ebd953618a70a4f365b23ce3349ea3f..d4ccc0728dfe4b97ac7065f4b0fe344e72320873 100644 (file)
@@ -506,13 +506,12 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 } /* end handle_signal() */
 
 /*****************************************************************************/
index 5aab87eae1f941f8373d8ea1db5882ced9b447d0..f13d5e82d4b977065727d88ce45be4f0904c7dbb 100644 (file)
@@ -488,13 +488,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 89ef7adc63a4be19611f57b580fddf46259dbd73..140e340569c67711fc83f3f54cf4139d64c701aa 100644 (file)
@@ -577,10 +577,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                ret = setup_frame(sig, ka, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index b8a0a7d257a9b3f427561faadb6d98eaf7b4648f..774f34b675cfdb3c688e2831b4fb599d1081b2ae 100644 (file)
@@ -467,15 +467,12 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
                if (!setup_frame(sig, ka, info, oldset, scr))
                        return 0;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               {
-                       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-                       sigaddset(&current->blocked, sig);
-                       recalc_sigpending();
-               }
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked, sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
 
index 5aef7e406ef5f2a0a74e90a334ee4a5ad2817ffd..71763f7a1d1989eb0cda8196694e07043a47ce52 100644 (file)
@@ -341,13 +341,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up the stack frame */
        setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 30dceb59a462078b6c09b3616dee2ef9ca46c75a..43a2726c0d0a4931070a55c1af124650ed872e58 100644 (file)
@@ -732,13 +732,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 40244782a8e54185d263de24729f83b135150096..4c114ae21793eb8a4fde93da5b8ba529c2222395 100644 (file)
@@ -155,13 +155,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_irix_frame(ka, regs, sig, oldset);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
index 65ee15396ffdefc52782ab24bd983baf08e90f30..0209c1dd1429a1c87a1da11a2f2ce1f14f705a30 100644 (file)
@@ -425,13 +425,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
                setup_frame(ka, regs, sig, oldset);
 #endif
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
index c1a69cf232f937e68cac85eaa8c47aec58d6650b..f6875f023a29fdc34ef22bedbb292f9ccf3db9bc 100644 (file)
@@ -751,13 +751,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info,
        else
                setup_frame(ka, regs, sig, oldset);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 int do_signal32(sigset_t *oldset, struct pt_regs *regs)
index 9421bb98ea6398a369bc01e2811f55491ef065fc..55d71c15e1f7cebc25b68c9e9facb4c7fdfb69e4 100644 (file)
@@ -517,13 +517,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
                return 0;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
 
index 8aaeb6f4e750249026e257b3e416604eb09c075f..2244bf91e593b1fd1ec13b596b4515e6c829987e 100644 (file)
@@ -759,13 +759,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        else
                handle_signal(signr, &ka, &info, oldset, regs, newsp);
 
-       if (!(ka.sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka.sa.sa_mask);
+       if (!(ka.sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 
        return 1;
 }
index bf782276984c69147411c7aa5f513ab4cc545cda..49a79a55c32de7d5ab73191dbe78047a6dcf848e 100644 (file)
@@ -481,10 +481,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
        /* Set up Signal Frame */
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index 3c2fa5c284c04ef223c468c2df53f6c7676dc20a..46f4d6cc7fc9591ce7240887a05edadcd711c6f6 100644 (file)
@@ -976,11 +976,12 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
        else
                ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp);
 
-       if (ret && !(ka.sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked,
                          &ka.sa.sa_mask);
-               sigaddset(&current->blocked, signr);
+               if (!(ka.sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index d05d65ac96940832776685c0f8b537269bc95231..7358cdb8441fbf960a1f1bb5371780f3f5e798c6 100644 (file)
@@ -637,12 +637,11 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,
        else
                setup_frame32(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
index 610c1d03e975701b152df903f399de25b4954ff2..6a3f5b7473a91b7c1a5ad08238430966f839e9f1 100644 (file)
@@ -429,13 +429,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 8022243f017828a44875f6f79b86ff487388b0ec..b475c4d2405f3e81795dfb39dfdd8aa2c350e94d 100644 (file)
@@ -546,13 +546,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index c6a14a87c59b4a887664a34c6604c96515c31417..3ea8929e483b5fea4f99fc6b6ebe2144ed61eb77 100644 (file)
@@ -664,13 +664,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 011ff35057a5149f332f2b928bb7e052b20d4292..5f34d7dc2b898672a4a8bfccd40940a647af0170 100644 (file)
@@ -1034,13 +1034,12 @@ handle_signal(unsigned long signr, struct k_sigaction *ka,
                else
                        setup_frame(&ka->sa, regs, signr, oldset, info);
        }
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
index b27934671c35324b713d355b6119541b3c8e69df..60f5dfabb1e173bcc08064c54cd64addf16c5030 100644 (file)
@@ -574,13 +574,12 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
 {
        setup_rt_frame(ka, regs, signr, oldset,
                       (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked,signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
index f28428f4170e67449259ce79e6a6ab1b0da6b2ca..b1ed23091fbb9c4ec6961de6dfd1c3e2857b8262 100644 (file)
@@ -1325,13 +1325,12 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
                else
                        setup_frame32(&ka->sa, regs, signr, oldset, info);
        }
-       if (!(ka->sa.sa_flags & SA_NOMASK)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NOMASK))
                sigaddset(&current->blocked,signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
index a37a5ac13c22b8fb709d0ced7ec5db0a2629ce63..022f67bb687364f2934b388fca57f703f53c2bfe 100644 (file)
@@ -9,19 +9,11 @@
  *
  */
 
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/time.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/init.h> 
 #include <linux/module.h>
 #include <linux/mm.h> 
-#include <linux/slab.h>
-#include <linux/init.h> 
-#include <linux/smp_lock.h>
 #include <linux/miscdevice.h>
 #include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
 #include "mem_user.h"
 #include "user_util.h"
  
@@ -31,35 +23,22 @@ static unsigned long p_buf = 0;
 static char *v_buf = NULL;
 
 static ssize_t
-mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+mmapper_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-       if(*ppos > mmapper_size)
-               return -EINVAL;
-
-       if(count + *ppos > mmapper_size)
-               count = count + *ppos - mmapper_size;
-
-       if(count < 0)
-               return -EINVAL;
-       copy_to_user(buf,&v_buf[*ppos],count);
-       
-       return count;
+       return simple_read_from_buffer(buf, count, ppos, v_buf, mmapper_size);
 }
 
 static ssize_t
-mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+mmapper_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
-       if(*ppos > mmapper_size)
+       if (*ppos > mmapper_size)
                return -EINVAL;
 
-       if(count + *ppos > mmapper_size)
-               count = count + *ppos - mmapper_size;
-
-       if(count < 0)
-               return -EINVAL;
+       if (count > mmapper_size - *ppos)
+               count = mmapper_size - *ppos;
 
-       copy_from_user(&v_buf[*ppos],buf,count);
+       if (copy_from_user(&v_buf[*ppos], buf, count))
+               return -EFAULT;
        
        return count;
 }
@@ -77,7 +56,6 @@ mmapper_mmap(struct file *file, struct vm_area_struct * vma)
        int ret = -EINVAL;
        int size;
 
-       lock_kernel();
        if (vma->vm_pgoff != 0)
                goto out;
        
@@ -92,7 +70,6 @@ mmapper_mmap(struct file *file, struct vm_area_struct * vma)
                goto out;
        ret = 0;
 out:
-       unlock_kernel();
        return ret;
 }
 
index 7807a3e8c426e362233c797a563f89523c2b7439..03618bd13d55f1521fb59a9b29224dd7fd0fd9f3 100644 (file)
@@ -87,12 +87,12 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
                force_sigsegv(signr, current);
-       }
-       else if(!(ka->sa.sa_flags & SA_NODEFER)){
+       } else {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked, &current->blocked, 
                          &ka->sa.sa_mask);
-               sigaddset(&current->blocked, signr);
+                if(!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, signr);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index 37061e32e1a42d3878a8108ebb340af11ab066e2..633e4e1b825f875daa32f2759ab3f6b94d555209 100644 (file)
@@ -462,13 +462,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        else
                setup_frame(sig, ka, oldset, regs);
 
-       if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked,sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 }
 
 /*
index 98590a989f3d759311935f6142191761bd42c376..d642fbf3da29d7823cd2a22f4329858aad7d76f3 100644 (file)
@@ -394,10 +394,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 #endif
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret && !(ka->sa.sa_flags & SA_NODEFER)) {
+       if (ret) {
                spin_lock_irq(&current->sighand->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-               sigaddset(&current->blocked,sig);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
        }
index df6e1e17b096ddc6093978f8c313c91dc7e1c5d2..dc42cede939462986a0acba34e756ee0614d4e3a 100644 (file)
@@ -702,12 +702,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (ka.sa.sa_flags & SA_ONESHOT)
                ka.sa.sa_handler = SIG_DFL;
 
-       if (!(ka.sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+       if (!(ka.sa.sa_flags & SA_NODEFER))
                sigaddset(&current->blocked, signr);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
-       }
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
        return 1;
 }
index cecab0acc3fe6baf22311c574abdc96ede313b74..46d655fab1159c54768d08d226ac3bc36a393b2a 100644 (file)
@@ -48,6 +48,8 @@ source "drivers/hwmon/Kconfig"
 
 source "drivers/misc/Kconfig"
 
+source "drivers/mfd/Kconfig"
+
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
index 126a851d56538f8c336da54d3091d0491f470094..9663132ed82547d3584a280b19c14a26c0895a0a 100644 (file)
@@ -26,7 +26,7 @@ obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 obj-$(CONFIG_SERIO)            += input/serio/
 obj-y                          += serial/
 obj-$(CONFIG_PARPORT)          += parport/
-obj-y                          += base/ block/ misc/ net/ media/
+obj-y                          += base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_PPC_PMAC)         += macintosh/
index 186b182c582522810c22fd44cecf88afd87c97f1..f93d2ee54800517590d28f2d77767124962eb89f 100644 (file)
@@ -55,7 +55,11 @@ void acpi_power_off(void)
 
 static int acpi_shutdown(struct sys_device *x)
 {
-       return acpi_sleep_prepare(ACPI_STATE_S5);
+       if (system_state == SYSTEM_POWER_OFF) {
+               /* Prepare if we are going to power off the system */
+               return acpi_sleep_prepare(ACPI_STATE_S5);
+       }
+       return 0;
 }
 
 static struct sysdev_class acpi_sysclass = {
index 30d96739fb2379b1f73d5d6dbbabb899eaf09456..665103ccaee83b69b6ca30a7fda0f40eec8983f7 100644 (file)
@@ -2433,7 +2433,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
        int ret = 0;
 
        acquire_console_sem();
-       if (tty->count == 1) {
+       if (tty->driver_data == NULL) {
                ret = vc_allocate(currcons);
                if (ret == 0) {
                        struct vc_data *vc = vc_cons[currcons].d;
index f8570fd9d2abb6ec707d007a4080d91cd5b2fceb..3abd7fc6e5ef3e0331cc080a61a214b2be27066f 100644 (file)
@@ -191,8 +191,10 @@ static int __init capifs_init(void)
        err = register_filesystem(&capifs_fs_type);
        if (!err) {
                capifs_mnt = kern_mount(&capifs_fs_type);
-               if (IS_ERR(capifs_mnt))
+               if (IS_ERR(capifs_mnt)) {
                        err = PTR_ERR(capifs_mnt);
+                       unregister_filesystem(&capifs_fs_type);
+               }
        }
        if (!err)
                printk(KERN_NOTICE "capifs: Rev %s\n", rev);
index 63b626f70c81e1fc2769d91c3141e26d6c89d2d7..9b9d6f8ee74eb768d919297c82a9818cbeac8987 100644 (file)
@@ -70,13 +70,22 @@ EXPORT_SYMBOL(dibusb_power_ctrl);
 
 int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
 {
-       u8 b[2];
-       b[0] = DIBUSB_REQ_SET_IOCTL;
-       b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+       u8 b[3] = { 0 };
+       int ret;
+
+       if ((ret = dibusb_streaming_ctrl(d,onoff)) < 0)
+               return ret;
 
-       dvb_usb_generic_write(d,b,3);
+       if (onoff) {
+               b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
+               b[1] = 0x00;
+               if ((ret = dvb_usb_generic_write(d,b,2)) < 0)
+                       return ret;
+       }
 
-       return dibusb_streaming_ctrl(d,onoff);
+       b[0] = DIBUSB_REQ_SET_IOCTL;
+       b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+       return dvb_usb_generic_write(d,b,3);
 }
 EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
 
index 3491ff40885c0f4ff7c0d550196a477f240b05a3..6fa92100248b8291b7353b070dc7347bfea67d38 100644 (file)
@@ -23,12 +23,12 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
         */
        if (newfeedcount == 0) {
                deb_ts("stop feeding\n");
+               dvb_usb_urb_kill(d);
 
                if (d->props.streaming_ctrl != NULL)
                        if ((ret = d->props.streaming_ctrl(d,0)))
                                err("error while stopping stream.");
 
-               dvb_usb_urb_kill(d);
        }
 
        d->feedcount = newfeedcount;
@@ -44,6 +44,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
         * for reception.
         */
        if (d->feedcount == onoff && d->feedcount > 0) {
+               deb_ts("submitting all URBs\n");
+               dvb_usb_urb_submit(d);
 
                deb_ts("controlling pid parser\n");
                if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
@@ -59,7 +61,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
                                return -ENODEV;
                        }
 
-               dvb_usb_urb_submit(d);
        }
        return 0;
 }
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
new file mode 100644 (file)
index 0000000..1588a59
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Multifunction miscellaneous devices
+#
+
+menu "Multimedia Capabilities Port drivers"
+
+config MCP
+       tristate
+
+# Interface drivers
+config MCP_SA11X0
+       tristate "Support SA11x0 MCP interface"
+       depends on ARCH_SA1100
+       select MCP
+
+endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
new file mode 100644 (file)
index 0000000..98bdd6a
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for multifunction miscellaneous devices
+#
+
+obj-$(CONFIG_MCP)              += mcp-core.o
+obj-$(CONFIG_MCP_SA11X0)       += mcp-sa11x0.o
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
new file mode 100644 (file)
index 0000000..c75d713
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  linux/drivers/mfd/mcp-core.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ *  Generic MCP (Multimedia Communications Port) layer.  All MCP locking
+ *  is solely held within this file.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/device.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+
+#include "mcp.h"
+
+#define to_mcp(d)              container_of(d, struct mcp, attached_device)
+#define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
+
+static int mcp_bus_match(struct device *dev, struct device_driver *drv)
+{
+       return 1;
+}
+
+static int mcp_bus_probe(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+       return drv->probe(mcp);
+}
+
+static int mcp_bus_remove(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+       drv->remove(mcp);
+       return 0;
+}
+
+static int mcp_bus_suspend(struct device *dev, pm_message_t state)
+{
+       struct mcp *mcp = to_mcp(dev);
+       int ret = 0;
+
+       if (dev->driver) {
+               struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+               ret = drv->suspend(mcp, state);
+       }
+       return ret;
+}
+
+static int mcp_bus_resume(struct device *dev)
+{
+       struct mcp *mcp = to_mcp(dev);
+       int ret = 0;
+
+       if (dev->driver) {
+               struct mcp_driver *drv = to_mcp_driver(dev->driver);
+
+               ret = drv->resume(mcp);
+       }
+       return ret;
+}
+
+static struct bus_type mcp_bus_type = {
+       .name           = "mcp",
+       .match          = mcp_bus_match,
+       .suspend        = mcp_bus_suspend,
+       .resume         = mcp_bus_resume,
+};
+
+/**
+ *     mcp_set_telecom_divisor - set the telecom divisor
+ *     @mcp: MCP interface structure
+ *     @div: SIB clock divisor
+ *
+ *     Set the telecom divisor on the MCP interface.  The resulting
+ *     sample rate is SIBCLOCK/div.
+ */
+void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
+{
+       spin_lock_irq(&mcp->lock);
+       mcp->ops->set_telecom_divisor(mcp, div);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_set_telecom_divisor);
+
+/**
+ *     mcp_set_audio_divisor - set the audio divisor
+ *     @mcp: MCP interface structure
+ *     @div: SIB clock divisor
+ *
+ *     Set the audio divisor on the MCP interface.
+ */
+void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
+{
+       spin_lock_irq(&mcp->lock);
+       mcp->ops->set_audio_divisor(mcp, div);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_set_audio_divisor);
+
+/**
+ *     mcp_reg_write - write a device register
+ *     @mcp: MCP interface structure
+ *     @reg: 4-bit register index
+ *     @val: 16-bit data value
+ *
+ *     Write a device register.  The MCP interface must be enabled
+ *     to prevent this function hanging.
+ */
+void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       mcp->ops->reg_write(mcp, reg, val);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+}
+EXPORT_SYMBOL(mcp_reg_write);
+
+/**
+ *     mcp_reg_read - read a device register
+ *     @mcp: MCP interface structure
+ *     @reg: 4-bit register index
+ *
+ *     Read a device register and return its value.  The MCP interface
+ *     must be enabled to prevent this function hanging.
+ */
+unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
+{
+       unsigned long flags;
+       unsigned int val;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       val = mcp->ops->reg_read(mcp, reg);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+
+       return val;
+}
+EXPORT_SYMBOL(mcp_reg_read);
+
+/**
+ *     mcp_enable - enable the MCP interface
+ *     @mcp: MCP interface to enable
+ *
+ *     Enable the MCP interface.  Each call to mcp_enable will need
+ *     a corresponding call to mcp_disable to disable the interface.
+ */
+void mcp_enable(struct mcp *mcp)
+{
+       spin_lock_irq(&mcp->lock);
+       if (mcp->use_count++ == 0)
+               mcp->ops->enable(mcp);
+       spin_unlock_irq(&mcp->lock);
+}
+EXPORT_SYMBOL(mcp_enable);
+
+/**
+ *     mcp_disable - disable the MCP interface
+ *     @mcp: MCP interface to disable
+ *
+ *     Disable the MCP interface.  The MCP interface will only be
+ *     disabled once the number of calls to mcp_enable matches the
+ *     number of calls to mcp_disable.
+ */
+void mcp_disable(struct mcp *mcp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcp->lock, flags);
+       if (--mcp->use_count == 0)
+               mcp->ops->disable(mcp);
+       spin_unlock_irqrestore(&mcp->lock, flags);
+}
+EXPORT_SYMBOL(mcp_disable);
+
+static void mcp_release(struct device *dev)
+{
+       struct mcp *mcp = container_of(dev, struct mcp, attached_device);
+
+       kfree(mcp);
+}
+
+struct mcp *mcp_host_alloc(struct device *parent, size_t size)
+{
+       struct mcp *mcp;
+
+       mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+       if (mcp) {
+               memset(mcp, 0, sizeof(struct mcp) + size);
+               spin_lock_init(&mcp->lock);
+               mcp->attached_device.parent = parent;
+               mcp->attached_device.bus = &mcp_bus_type;
+               mcp->attached_device.dma_mask = parent->dma_mask;
+               mcp->attached_device.release = mcp_release;
+       }
+       return mcp;
+}
+EXPORT_SYMBOL(mcp_host_alloc);
+
+int mcp_host_register(struct mcp *mcp)
+{
+       strcpy(mcp->attached_device.bus_id, "mcp0");
+       return device_register(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_register);
+
+void mcp_host_unregister(struct mcp *mcp)
+{
+       device_unregister(&mcp->attached_device);
+}
+EXPORT_SYMBOL(mcp_host_unregister);
+
+int mcp_driver_register(struct mcp_driver *mcpdrv)
+{
+       mcpdrv->drv.bus = &mcp_bus_type;
+       mcpdrv->drv.probe = mcp_bus_probe;
+       mcpdrv->drv.remove = mcp_bus_remove;
+       return driver_register(&mcpdrv->drv);
+}
+EXPORT_SYMBOL(mcp_driver_register);
+
+void mcp_driver_unregister(struct mcp_driver *mcpdrv)
+{
+       driver_unregister(&mcpdrv->drv);
+}
+EXPORT_SYMBOL(mcp_driver_unregister);
+
+static int __init mcp_init(void)
+{
+       return bus_register(&mcp_bus_type);
+}
+
+static void __exit mcp_exit(void)
+{
+       bus_unregister(&mcp_bus_type);
+}
+
+module_init(mcp_init);
+module_exit(mcp_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Core multimedia communications port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
new file mode 100644 (file)
index 0000000..e9806fb
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  linux/drivers/mfd/mcp-sa11x0.c
+ *
+ *  Copyright (C) 2001-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ *  SA11x0 MCP (Multimedia Communications Port) driver.
+ *
+ *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/system.h>
+#include <asm/arch/mcp.h>
+
+#include <asm/arch/assabet.h>
+
+#include "mcp.h"
+
+struct mcp_sa11x0 {
+       u32     mccr0;
+       u32     mccr1;
+};
+
+#define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
+
+static void
+mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
+{
+       unsigned int mccr0;
+
+       divisor /= 32;
+
+       mccr0 = Ser4MCCR0 & ~0x00007f00;
+       mccr0 |= divisor << 8;
+       Ser4MCCR0 = mccr0;
+}
+
+static void
+mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
+{
+       unsigned int mccr0;
+
+       divisor /= 32;
+
+       mccr0 = Ser4MCCR0 & ~0x0000007f;
+       mccr0 |= divisor;
+       Ser4MCCR0 = mccr0;
+}
+
+/*
+ * Write data to the device.  The bit should be set after 3 subframe
+ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
+ * We really should try doing something more productive while we
+ * wait.
+ */
+static void
+mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
+{
+       int ret = -ETIME;
+       int i;
+
+       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+
+       for (i = 0; i < 2; i++) {
+               udelay(mcp->rw_timeout);
+               if (Ser4MCSR & MCSR_CWC) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               printk(KERN_WARNING "mcp: write timed out\n");
+}
+
+/*
+ * Read data from the device.  The bit should be set after 3 subframe
+ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
+ * We really should try doing something more productive while we
+ * wait.
+ */
+static unsigned int
+mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
+{
+       int ret = -ETIME;
+       int i;
+
+       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+
+       for (i = 0; i < 2; i++) {
+               udelay(mcp->rw_timeout);
+               if (Ser4MCSR & MCSR_CRC) {
+                       ret = Ser4MCDR2 & 0xffff;
+                       break;
+               }
+       }
+
+       if (ret < 0)
+               printk(KERN_WARNING "mcp: read timed out\n");
+
+       return ret;
+}
+
+static void mcp_sa11x0_enable(struct mcp *mcp)
+{
+       Ser4MCSR = -1;
+       Ser4MCCR0 |= MCCR0_MCE;
+}
+
+static void mcp_sa11x0_disable(struct mcp *mcp)
+{
+       Ser4MCCR0 &= ~MCCR0_MCE;
+}
+
+/*
+ * Our methods.
+ */
+static struct mcp_ops mcp_sa11x0 = {
+       .set_telecom_divisor    = mcp_sa11x0_set_telecom_divisor,
+       .set_audio_divisor      = mcp_sa11x0_set_audio_divisor,
+       .reg_write              = mcp_sa11x0_write,
+       .reg_read               = mcp_sa11x0_read,
+       .enable                 = mcp_sa11x0_enable,
+       .disable                = mcp_sa11x0_disable,
+};
+
+static int mcp_sa11x0_probe(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct mcp_plat_data *data = pdev->dev.platform_data;
+       struct mcp *mcp;
+       int ret;
+
+       if (!data)
+               return -ENODEV;
+
+       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
+               return -EBUSY;
+
+       mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
+       if (!mcp) {
+               ret = -ENOMEM;
+               goto release;
+       }
+
+       mcp->owner              = THIS_MODULE;
+       mcp->ops                = &mcp_sa11x0;
+       mcp->sclk_rate          = data->sclk_rate;
+       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
+       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
+       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
+       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
+
+       dev_set_drvdata(dev, mcp);
+
+       if (machine_is_assabet()) {
+               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+       }
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+       /*
+        * Initialise device.  Note that we initially
+        * set the sampling rate to minimum.
+        */
+       Ser4MCSR = -1;
+       Ser4MCCR1 = data->mccr1;
+       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+
+       /*
+        * Calculate the read/write timeout (us) from the bit clock
+        * rate.  This is the period for 3 64-bit frames.  Always
+        * round this time up.
+        */
+       mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
+                         mcp->sclk_rate;
+
+       ret = mcp_host_register(mcp);
+       if (ret == 0)
+               goto out;
+
+ release:
+       release_mem_region(0x80060000, 0x60);
+       dev_set_drvdata(dev, NULL);
+
+ out:
+       return ret;
+}
+
+static int mcp_sa11x0_remove(struct device *dev)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       dev_set_drvdata(dev, NULL);
+       mcp_host_unregister(mcp);
+       release_mem_region(0x80060000, 0x60);
+
+       return 0;
+}
+
+static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state, u32 level)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       if (level == SUSPEND_DISABLE) {
+               priv(mcp)->mccr0 = Ser4MCCR0;
+               priv(mcp)->mccr1 = Ser4MCCR1;
+               Ser4MCCR0 &= ~MCCR0_MCE;
+       }
+       return 0;
+}
+
+static int mcp_sa11x0_resume(struct device *dev, u32 level)
+{
+       struct mcp *mcp = dev_get_drvdata(dev);
+
+       if (level == RESUME_RESTORE_STATE) {
+               Ser4MCCR1 = priv(mcp)->mccr1;
+               Ser4MCCR0 = priv(mcp)->mccr0;
+       }
+       return 0;
+}
+
+/*
+ * The driver for the SA11x0 MCP port.
+ */
+static struct device_driver mcp_sa11x0_driver = {
+       .name           = "sa11x0-mcp",
+       .bus            = &platform_bus_type,
+       .probe          = mcp_sa11x0_probe,
+       .remove         = mcp_sa11x0_remove,
+       .suspend        = mcp_sa11x0_suspend,
+       .resume         = mcp_sa11x0_resume,
+};
+
+/*
+ * This needs re-working
+ */
+static int __init mcp_sa11x0_init(void)
+{
+       return driver_register(&mcp_sa11x0_driver);
+}
+
+static void __exit mcp_sa11x0_exit(void)
+{
+       driver_unregister(&mcp_sa11x0_driver);
+}
+
+module_init(mcp_sa11x0_init);
+module_exit(mcp_sa11x0_exit);
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h
new file mode 100644 (file)
index 0000000..c093a93
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  linux/drivers/mfd/mcp.h
+ *
+ *  Copyright (C) 2001 Russell King, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#ifndef MCP_H
+#define MCP_H
+
+struct mcp_ops;
+
+struct mcp {
+       struct module   *owner;
+       struct mcp_ops  *ops;
+       spinlock_t      lock;
+       int             use_count;
+       unsigned int    sclk_rate;
+       unsigned int    rw_timeout;
+       dma_device_t    dma_audio_rd;
+       dma_device_t    dma_audio_wr;
+       dma_device_t    dma_telco_rd;
+       dma_device_t    dma_telco_wr;
+       struct device   attached_device;
+};
+
+struct mcp_ops {
+       void            (*set_telecom_divisor)(struct mcp *, unsigned int);
+       void            (*set_audio_divisor)(struct mcp *, unsigned int);
+       void            (*reg_write)(struct mcp *, unsigned int, unsigned int);
+       unsigned int    (*reg_read)(struct mcp *, unsigned int);
+       void            (*enable)(struct mcp *);
+       void            (*disable)(struct mcp *);
+};
+
+void mcp_set_telecom_divisor(struct mcp *, unsigned int);
+void mcp_set_audio_divisor(struct mcp *, unsigned int);
+void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
+unsigned int mcp_reg_read(struct mcp *, unsigned int);
+void mcp_enable(struct mcp *);
+void mcp_disable(struct mcp *);
+#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
+
+struct mcp *mcp_host_alloc(struct device *, size_t);
+int mcp_host_register(struct mcp *);
+void mcp_host_unregister(struct mcp *);
+
+struct mcp_driver {
+       struct device_driver drv;
+       int (*probe)(struct mcp *);
+       void (*remove)(struct mcp *);
+       int (*suspend)(struct mcp *, pm_message_t);
+       int (*resume)(struct mcp *);
+};
+
+int mcp_driver_register(struct mcp_driver *);
+void mcp_driver_unregister(struct mcp_driver *);
+
+#define mcp_get_drvdata(mcp)   dev_get_drvdata(&(mcp)->attached_device)
+#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d)
+
+#define mcp_priv(mcp)          ((void *)((mcp)+1))
+
+#endif
index eeb9f6668e69167044b3b41bf6559479f30dd5ab..3c5904834fe8289db5672fae41a543d9bc7c6059 100644 (file)
@@ -361,7 +361,7 @@ static void mmc_decode_cid(struct mmc_card *card)
 
        default:
                printk("%s: card has unknown MMCA version %d\n",
-                       card->host->host_name, card->csd.mmca_vsn);
+                       mmc_hostname(card->host), card->csd.mmca_vsn);
                mmc_card_set_bad(card);
                break;
        }
@@ -383,7 +383,7 @@ static void mmc_decode_csd(struct mmc_card *card)
        csd_struct = UNSTUFF_BITS(resp, 126, 2);
        if (csd_struct != 1 && csd_struct != 2) {
                printk("%s: unrecognised CSD structure version %d\n",
-                       card->host->host_name, csd_struct);
+                       mmc_hostname(card->host), csd_struct);
                mmc_card_set_bad(card);
                return;
        }
@@ -551,7 +551,7 @@ static void mmc_discover_cards(struct mmc_host *host)
                }
                if (err != MMC_ERR_NONE) {
                        printk(KERN_ERR "%s: error requesting CID: %d\n",
-                               host->host_name, err);
+                               mmc_hostname(host), err);
                        break;
                }
 
@@ -796,17 +796,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 {
        struct mmc_host *host;
 
-       host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+       host = mmc_alloc_host_sysfs(extra, dev);
        if (host) {
-               memset(host, 0, sizeof(struct mmc_host) + extra);
-
                spin_lock_init(&host->lock);
                init_waitqueue_head(&host->wq);
                INIT_LIST_HEAD(&host->cards);
                INIT_WORK(&host->detect, mmc_rescan, host);
 
-               host->dev = dev;
-
                /*
                 * By default, hosts do not support SGIO or large requests.
                 * They have to set these according to their abilities.
@@ -828,15 +824,15 @@ EXPORT_SYMBOL(mmc_alloc_host);
  */
 int mmc_add_host(struct mmc_host *host)
 {
-       static unsigned int host_num;
+       int ret;
 
-       snprintf(host->host_name, sizeof(host->host_name),
-                "mmc%d", host_num++);
-
-       mmc_power_off(host);
-       mmc_detect_change(host);
+       ret = mmc_add_host_sysfs(host);
+       if (ret == 0) {
+               mmc_power_off(host);
+               mmc_detect_change(host);
+       }
 
-       return 0;
+       return ret;
 }
 
 EXPORT_SYMBOL(mmc_add_host);
@@ -859,6 +855,7 @@ void mmc_remove_host(struct mmc_host *host)
        }
 
        mmc_power_off(host);
+       mmc_remove_host_sysfs(host);
 }
 
 EXPORT_SYMBOL(mmc_remove_host);
@@ -872,7 +869,7 @@ EXPORT_SYMBOL(mmc_remove_host);
 void mmc_free_host(struct mmc_host *host)
 {
        flush_scheduled_work();
-       kfree(host);
+       mmc_free_host_sysfs(host);
 }
 
 EXPORT_SYMBOL(mmc_free_host);
index b498dffe0b118c48d392b6d4c39730dfb03ab67a..97bae00292fafdfdfc7d785d9b4725603e5583d5 100644 (file)
@@ -13,4 +13,9 @@
 void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
 int mmc_register_card(struct mmc_card *card);
 void mmc_remove_card(struct mmc_card *card);
+
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
+int mmc_add_host_sysfs(struct mmc_host *host);
+void mmc_remove_host_sysfs(struct mmc_host *host);
+void mmc_free_host_sysfs(struct mmc_host *host);
 #endif
index 5556cd3b555917768f7fc4d341e4b8c93f63db80..ad8949810fc5cbeb79de505265ed57fb1aeba6b9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -20,6 +21,7 @@
 
 #define dev_to_mmc_card(d)     container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)       container_of(d, struct mmc_driver, drv)
+#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
 
 #define MMC_ATTR(name, fmt, args...)                                   \
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)        \
@@ -206,7 +208,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
 int mmc_register_card(struct mmc_card *card)
 {
        snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
-                "%s:%04x", card->host->host_name, card->rca);
+                "%s:%04x", mmc_hostname(card->host), card->rca);
 
        return device_add(&card->dev);
 }
@@ -224,13 +226,97 @@ void mmc_remove_card(struct mmc_card *card)
 }
 
 
+static void mmc_host_classdev_release(struct class_device *dev)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       kfree(host);
+}
+
+static struct class mmc_host_class = {
+       .name           = "mmc_host",
+       .release        = mmc_host_classdev_release,
+};
+
+static DEFINE_IDR(mmc_host_idr);
+static DEFINE_SPINLOCK(mmc_host_lock);
+
+/*
+ * Internal function. Allocate a new MMC host.
+ */
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
+{
+       struct mmc_host *host;
+
+       host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+       if (host) {
+               memset(host, 0, sizeof(struct mmc_host) + extra);
+
+               host->dev = dev;
+               host->class_dev.dev = host->dev;
+               host->class_dev.class = &mmc_host_class;
+               class_device_initialize(&host->class_dev);
+       }
+
+       return host;
+}
+
+/*
+ * Internal function. Register a new MMC host with the MMC class.
+ */
+int mmc_add_host_sysfs(struct mmc_host *host)
+{
+       int err;
+
+       if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
+               return -ENOMEM;
+
+       spin_lock(&mmc_host_lock);
+       err = idr_get_new(&mmc_host_idr, host, &host->index);
+       spin_unlock(&mmc_host_lock);
+       if (err)
+               return err;
+
+       snprintf(host->class_dev.class_id, BUS_ID_SIZE,
+                "mmc%d", host->index);
+
+       return class_device_add(&host->class_dev);
+}
+
+/*
+ * Internal function. Unregister a MMC host with the MMC class.
+ */
+void mmc_remove_host_sysfs(struct mmc_host *host)
+{
+       class_device_del(&host->class_dev);
+
+       spin_lock(&mmc_host_lock);
+       idr_remove(&mmc_host_idr, host->index);
+       spin_unlock(&mmc_host_lock);
+}
+
+/*
+ * Internal function. Free a MMC host.
+ */
+void mmc_free_host_sysfs(struct mmc_host *host)
+{
+       class_device_put(&host->class_dev);
+}
+
+
 static int __init mmc_init(void)
 {
-       return bus_register(&mmc_bus_type);
+       int ret = bus_register(&mmc_bus_type);
+       if (ret == 0) {
+               ret = class_register(&mmc_host_class);
+               if (ret)
+                       bus_unregister(&mmc_bus_type);
+       }
+       return ret;
 }
 
 static void __exit mmc_exit(void)
 {
+       class_unregister(&mmc_host_class);
        bus_unregister(&mmc_bus_type);
 }
 
index 7a42966d755bd00a7defabfe47e8d69fe4820aac..716c4ef4faf6f8c46c9582d5211d5fba3a332255 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(host,fmt,args...)  \
-       pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args)
+       pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
 #else
 #define DBG(host,fmt,args...)  do { } while (0)
 #endif
@@ -541,7 +541,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
        mmc_add_host(mmc);
 
        printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
-               mmc->host_name, amba_rev(dev), amba_config(dev),
+               mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
                dev->res.start, dev->irq[0], dev->irq[1]);
 
        init_timer(&host->timer);
index 974f2f36bdbe6abe21d4ba06d31418e8bfcb2674..402c2d661fb2814d06983d6a6f0e3c89c110e89f 100644 (file)
@@ -1796,7 +1796,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
        
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: W83L51xD", mmc->host_name);
+       printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
        if (host->chip_id != 0)
                printk(" id %x", (int)host->chip_id);
        printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
index 8edb6936fb9b846810645f6f3f6de4164dec172a..79e8aa6f2b9edfc215e43b1a1b0a934274a680f4 100644 (file)
@@ -131,6 +131,8 @@ config NET_SB1000
 
        source "drivers/net/arcnet/Kconfig"
 
+source "drivers/net/phy/Kconfig"
+
 #
 #      Ethernet
 #
index 63c6d1e6d4d982937ada0fdaca07003ec29ef9e6..a369ae284a9a23cd5aaa7590ea584573df6dbe78 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 #
 
 obj-$(CONFIG_MII) += mii.o
+obj-$(CONFIG_PHYLIB) += phy/
 
 obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
index 3707df6b0cfaf5a734ef7de6e636fd8a1aecaa76..60304f7e7e5b9703a6973a733cb452ff44517b18 100644 (file)
@@ -87,7 +87,6 @@ extern struct net_device *mvme147lance_probe(int unit);
 extern struct net_device *tc515_probe(int unit);
 extern struct net_device *lance_probe(int unit);
 extern struct net_device *mace_probe(int unit);
-extern struct net_device *macsonic_probe(int unit);
 extern struct net_device *mac8390_probe(int unit);
 extern struct net_device *mac89x0_probe(int unit);
 extern struct net_device *mc32_probe(int unit);
@@ -284,9 +283,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
 #ifdef CONFIG_MACMACE          /* Mac 68k Quadra AV builtin Ethernet */
        {mace_probe, 0},
 #endif
-#ifdef CONFIG_MACSONIC         /* Mac SONIC-based Ethernet of all sorts */ 
-       {macsonic_probe, 0},
-#endif
 #ifdef CONFIG_MAC8390           /* NuBus NS8390-based cards */
        {mac8390_probe, 0},
 #endif
@@ -318,17 +314,9 @@ static void __init ethif_probe2(int unit)
 #ifdef CONFIG_TR
 /* Token-ring device probe */
 extern int ibmtr_probe_card(struct net_device *);
-extern struct net_device *sk_isa_probe(int unit);
-extern struct net_device *proteon_probe(int unit);
 extern struct net_device *smctr_probe(int unit);
 
 static struct devprobe2 tr_probes2[] __initdata = {
-#ifdef CONFIG_SKISA
-       {sk_isa_probe, 0},
-#endif
-#ifdef CONFIG_PROTEON
-       {proteon_probe, 0},
-#endif
 #ifdef CONFIG_SMCTR
        {smctr_probe, 0},
 #endif
index 5ce606d9dc03f9b145c3024abecfca20ec65fd9d..19e829b567d0e7735908b5562e8e0a9214803896 100644 (file)
@@ -1106,18 +1106,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
                        }
                }
 
-               if (found) {
-                       /* a slave was found that is using the mac address
-                        * of the new slave
-                        */
-                       printk(KERN_ERR DRV_NAME
-                              ": Error: the hw address of slave %s is not "
-                              "unique - cannot enslave it!",
-                              slave->dev->name);
-                       return -EINVAL;
-               }
+               if (!found)
+                       return 0;
 
-               return 0;
+               /* Try setting slave mac to bond address and fall-through
+                  to code handling that situation below... */
+               alb_set_slave_mac_addr(slave, bond->dev->dev_addr,
+                                      bond->alb_info.rlb_enabled);
        }
 
        /* The slave's address is equal to the address of the bond.
index 2c930da90a854d957f881cff3b3032ce0b1ff921..94c9f68dd16bacf4686eac5cb7da66062bf8df33 100644 (file)
@@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_
        return 0;
 }
 
+#define BOND_INTERSECT_FEATURES \
+       (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
+
+/* 
+ * Compute the features available to the bonding device by 
+ * intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
+ * Call this after attaching or detaching a slave to update the 
+ * bond's features.
+ */
+static int bond_compute_features(struct bonding *bond)
+{
+       int i;
+       struct slave *slave;
+       struct net_device *bond_dev = bond->dev;
+       int features = bond->bond_features;
+
+       bond_for_each_slave(bond, slave, i) {
+               struct net_device * slave_dev = slave->dev;
+               if (i == 0) {
+                       features |= BOND_INTERSECT_FEATURES;
+               }
+               features &=
+                       ~(~slave_dev->features & BOND_INTERSECT_FEATURES);
+       }
+
+       /* turn off NETIF_F_SG if we need a csum and h/w can't do it */
+       if ((features & NETIF_F_SG) && 
+               !(features & (NETIF_F_IP_CSUM |
+                             NETIF_F_NO_CSUM |
+                             NETIF_F_HW_CSUM))) {
+               features &= ~NETIF_F_SG;
+       }
+
+       bond_dev->features = features;
+
+       return 0;
+}
+
 /* enslave device <slave> to bond device <master> */
 static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
@@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de
        new_slave->delay = 0;
        new_slave->link_failure_count = 0;
 
+       bond_compute_features(bond);
+
        if (bond->params.miimon && !bond->params.use_carrier) {
                link_reporting = bond_check_dev_link(bond, slave_dev, 1);
 
@@ -2015,7 +2055,7 @@ err_free:
 
 err_undo_flags:
        bond_dev->features = old_features;
-
        return res;
 }
 
@@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de
        /* release the slave from its bond */
        bond_detach_slave(bond, slave);
 
+       bond_compute_features(bond);
+
        if (bond->primary_slave == slave) {
                bond->primary_slave = NULL;
        }
@@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev)
                        bond_alb_deinit_slave(bond, slave);
                }
 
+               bond_compute_features(bond);
+
                /* now that the slave is detached, unlock and perform
                 * all the undo steps that should not be called from
                 * within a lock.
@@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond
 static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev)
 {
        struct net_device *bond_dev = slave_dev->master;
+       struct bonding *bond = bond_dev->priv;
 
        switch (event) {
        case NETDEV_UNREGISTER:
@@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                 * TODO: handle changing the primary's name
                 */
                break;
+       case NETDEV_FEAT_CHANGE:
+               bond_compute_features(bond);
+               break;
        default:
                break;
        }
@@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode)
        }
 }
 
+static struct ethtool_ops bond_ethtool_ops = {
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .get_sg                 = ethtool_op_get_sg,
+};
+
 /*
  * Does not allocate but creates a /proc entry.
  * Allowed to fail.
@@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
        bond_dev->stop = bond_close;
        bond_dev->get_stats = bond_get_stats;
        bond_dev->do_ioctl = bond_do_ioctl;
+       bond_dev->ethtool_ops = &bond_ethtool_ops;
        bond_dev->set_multicast_list = bond_set_multicast_list;
        bond_dev->change_mtu = bond_change_mtu;
        bond_dev->set_mac_address = bond_set_mac_address;
@@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
                               NETIF_F_HW_VLAN_RX |
                               NETIF_F_HW_VLAN_FILTER);
 
+       bond->bond_features = bond_dev->features;
+
 #ifdef CONFIG_PROC_FS
        bond_create_proc_entry(bond);
 #endif
index d27f377b3eeb52bf2f8a47c3f3b6a5a61463faad..3881969808627cebcb7ed6a25f6b9b3557b6a1ec 100644 (file)
@@ -211,6 +211,9 @@ struct bonding {
        struct   bond_params params;
        struct   list_head vlan_list;
        struct   vlan_group *vlgrp;
+       /* the features the bonding device supports, independently 
+        * of any slaves */
+       int      bond_features; 
 };
 
 /**
index b82fd15d08911f3f004485c060986bc7a338d464..9b596e0bbf95cc04d73448a38098e9dc3f003bae 100644 (file)
@@ -2767,7 +2767,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                                        "  next_to_use          <%x>\n"
                                        "  next_to_clean        <%x>\n"
                                        "buffer_info[next_to_clean]\n"
-                                       "  dma                  <%zx>\n"
+                                       "  dma                  <%llx>\n"
                                        "  time_stamp           <%lx>\n"
                                        "  next_to_watch        <%x>\n"
                                        "  jiffies              <%lx>\n"
@@ -2776,7 +2776,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
                                E1000_READ_REG(&adapter->hw, TDT),
                                tx_ring->next_to_use,
                                i,
-                               tx_ring->buffer_info[i].dma,
+                               (unsigned long long)tx_ring->buffer_info[i].dma,
                                tx_ring->buffer_info[i].time_stamp,
                                eop,
                                jiffies,
index 1795425f512e1f789dbccea4492cc1d659ed2111..8c62ced2c9b2304a99808f07a26ecb61ee0ce169 100644 (file)
@@ -1263,8 +1263,8 @@ speedo_init_rx_ring(struct net_device *dev)
        for (i = 0; i < RX_RING_SIZE; i++) {
                struct sk_buff *skb;
                skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-               /* XXX: do we really want to call this before the NULL check? --hch */
-               rx_align(skb);                  /* Align IP on 16 byte boundary */
+               if (skb)
+                       rx_align(skb);        /* Align IP on 16 byte boundary */
                sp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;                  /* OK.  Just initially short of Rx bufs. */
@@ -1654,8 +1654,8 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
        struct sk_buff *skb;
        /* Get a fresh skbuff to replace the consumed one. */
        skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-       /* XXX: do we really want to call this before the NULL check? --hch */
-       rx_align(skb);                          /* Align IP on 16 byte boundary */
+       if (skb)
+               rx_align(skb);          /* Align IP on 16 byte boundary */
        sp->rx_skbuff[entry] = skb;
        if (skb == NULL) {
                sp->rx_ringp[entry] = NULL;
index 64f0f697c958ad399317fe7cc628bf93d9f73018..7d93948aec83410e2ba2100111b4e88bd74a4909 100644 (file)
  *     0.33: 16 May 2005: Support for MCP51 added.
  *     0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
  *     0.35: 26 Jun 2005: Support for MCP55 added.
+ *     0.36: 28 Jun 2005: Add jumbo frame support.
+ *     0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list
+ *     0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of
+ *                        per-packet flags.
+ *      0.39: 18 Jul 2005: Add 64bit descriptor support.
+ *      0.40: 19 Jul 2005: Add support for mac address change.
+ *      0.41: 30 Jul 2005: Write back original MAC in nv_close instead
+ *                        of nv_remove
+ *      0.42: 06 Aug 2005: Fix lack of link speed initialization
+ *                        in the second (and later) nv_open call
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.35"
+#define FORCEDETH_VERSION              "0.41"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
  * Hardware access:
  */
 
-#define DEV_NEED_LASTPACKET1   0x0001  /* set LASTPACKET1 in tx flags */
-#define DEV_IRQMASK_1          0x0002  /* use NVREG_IRQMASK_WANTED_1 for irq mask */
-#define DEV_IRQMASK_2          0x0004  /* use NVREG_IRQMASK_WANTED_2 for irq mask */
-#define DEV_NEED_TIMERIRQ      0x0008  /* set the timer irq flag in the irq mask */
-#define DEV_NEED_LINKTIMER     0x0010  /* poll link settings. Relies on the timer irq */
+#define DEV_NEED_TIMERIRQ      0x0001  /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER     0x0002  /* poll link settings. Relies on the timer irq */
+#define DEV_HAS_LARGEDESC      0x0004  /* device supports jumbo frames and needs packet format 2 */
+#define DEV_HAS_HIGH_DMA        0x0008  /* device supports 64bit dma */
 
 enum {
        NvRegIrqStatus = 0x000,
@@ -146,13 +155,16 @@ enum {
 #define NVREG_IRQ_RX                   0x0002
 #define NVREG_IRQ_RX_NOBUF             0x0004
 #define NVREG_IRQ_TX_ERR               0x0008
-#define NVREG_IRQ_TX2                  0x0010
+#define NVREG_IRQ_TX_OK                        0x0010
 #define NVREG_IRQ_TIMER                        0x0020
 #define NVREG_IRQ_LINK                 0x0040
+#define NVREG_IRQ_TX_ERROR             0x0080
 #define NVREG_IRQ_TX1                  0x0100
-#define NVREG_IRQMASK_WANTED_1         0x005f
-#define NVREG_IRQMASK_WANTED_2         0x0147
-#define NVREG_IRQ_UNKNOWN              (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
+#define NVREG_IRQMASK_WANTED           0x00df
+
+#define NVREG_IRQ_UNKNOWN      (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
+                                       NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
+                                       NVREG_IRQ_TX1))
 
        NvRegUnknownSetupReg6 = 0x008,
 #define NVREG_UNKSETUP6_VAL            3
@@ -286,6 +298,18 @@ struct ring_desc {
        u32 FlagLen;
 };
 
+struct ring_desc_ex {
+       u32 PacketBufferHigh;
+       u32 PacketBufferLow;
+       u32 Reserved;
+       u32 FlagLen;
+};
+
+typedef union _ring_type {
+       struct ring_desc* orig;
+       struct ring_desc_ex* ex;
+} ring_type;
+
 #define FLAG_MASK_V1 0xffff0000
 #define FLAG_MASK_V2 0xffffc000
 #define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
@@ -293,7 +317,7 @@ struct ring_desc {
 
 #define NV_TX_LASTPACKET       (1<<16)
 #define NV_TX_RETRYERROR       (1<<19)
-#define NV_TX_LASTPACKET1      (1<<24)
+#define NV_TX_FORCED_INTERRUPT (1<<24)
 #define NV_TX_DEFERRED         (1<<26)
 #define NV_TX_CARRIERLOST      (1<<27)
 #define NV_TX_LATECOLLISION    (1<<28)
@@ -303,7 +327,7 @@ struct ring_desc {
 
 #define NV_TX2_LASTPACKET      (1<<29)
 #define NV_TX2_RETRYERROR      (1<<18)
-#define NV_TX2_LASTPACKET1     (1<<23)
+#define NV_TX2_FORCED_INTERRUPT        (1<<30)
 #define NV_TX2_DEFERRED                (1<<25)
 #define NV_TX2_CARRIERLOST     (1<<26)
 #define NV_TX2_LATECOLLISION   (1<<27)
@@ -379,9 +403,13 @@ struct ring_desc {
 #define TX_LIMIT_START 62
 
 /* rx/tx mac addr + type + vlan + align + slack*/
-#define RX_NIC_BUFSIZE         (ETH_DATA_LEN + 64)
-/* even more slack */
-#define RX_ALLOC_BUFSIZE       (ETH_DATA_LEN + 128)
+#define NV_RX_HEADERS          (64)
+/* even more slack. */
+#define NV_RX_ALLOC_PAD                (64)
+
+/* maximum mtu size */
+#define NV_PKTLIMIT_1  ETH_DATA_LEN    /* hard limit not known */
+#define NV_PKTLIMIT_2  9100    /* Actual limit according to NVidia: 9202 */
 
 #define OOM_REFILL     (1+HZ/20)
 #define POLL_WAIT      (1+HZ/100)
@@ -396,6 +424,7 @@ struct ring_desc {
  */
 #define DESC_VER_1     0x0
 #define DESC_VER_2     (0x02100|NVREG_TXRXCTL_RXCHECK)
+#define DESC_VER_3      (0x02200|NVREG_TXRXCTL_RXCHECK)
 
 /* PHY defines */
 #define PHY_OUI_MARVELL        0x5043
@@ -468,11 +497,12 @@ struct fe_priv {
        /* rx specific fields.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
-       struct ring_desc *rx_ring;
+       ring_type rx_ring;
        unsigned int cur_rx, refill_rx;
        struct sk_buff *rx_skbuff[RX_RING];
        dma_addr_t rx_dma[RX_RING];
        unsigned int rx_buf_sz;
+       unsigned int pkt_limit;
        struct timer_list oom_kick;
        struct timer_list nic_poll;
 
@@ -484,7 +514,7 @@ struct fe_priv {
        /*
         * tx specific fields.
         */
-       struct ring_desc *tx_ring;
+       ring_type tx_ring;
        unsigned int next_tx, nic_tx;
        struct sk_buff *tx_skbuff[TX_RING];
        dma_addr_t tx_dma[TX_RING];
@@ -519,6 +549,11 @@ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
                & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
 }
 
+static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
+{
+       return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+}
+
 static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
                                int delay, int delaymax, const char *msg)
 {
@@ -792,7 +827,7 @@ static int nv_alloc_rx(struct net_device *dev)
                nr = refill_rx % RX_RING;
                if (np->rx_skbuff[nr] == NULL) {
 
-                       skb = dev_alloc_skb(RX_ALLOC_BUFSIZE);
+                       skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
                        if (!skb)
                                break;
 
@@ -803,9 +838,16 @@ static int nv_alloc_rx(struct net_device *dev)
                }
                np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len,
                                                PCI_DMA_FROMDEVICE);
-               np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
-               wmb();
-               np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                       np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+                       wmb();
+                       np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+               } else {
+                       np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+                       np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+                       wmb();
+                       np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+               }
                dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
                                        dev->name, refill_rx);
                refill_rx++;
@@ -831,19 +873,37 @@ static void nv_do_rx_refill(unsigned long data)
        enable_irq(dev->irq);
 }
 
-static int nv_init_ring(struct net_device *dev)
+static void nv_init_rx(struct net_device *dev) 
 {
        struct fe_priv *np = get_nvpriv(dev);
        int i;
 
-       np->next_tx = np->nic_tx = 0;
-       for (i = 0; i < TX_RING; i++)
-               np->tx_ring[i].FlagLen = 0;
-
        np->cur_rx = RX_RING;
        np->refill_rx = 0;
        for (i = 0; i < RX_RING; i++)
-               np->rx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->rx_ring.orig[i].FlagLen = 0;
+               else
+                       np->rx_ring.ex[i].FlagLen = 0;
+}
+
+static void nv_init_tx(struct net_device *dev)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       int i;
+
+       np->next_tx = np->nic_tx = 0;
+       for (i = 0; i < TX_RING; i++)
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->tx_ring.orig[i].FlagLen = 0;
+               else
+                       np->tx_ring.ex[i].FlagLen = 0;
+}
+
+static int nv_init_ring(struct net_device *dev)
+{
+       nv_init_tx(dev);
+       nv_init_rx(dev);
        return nv_alloc_rx(dev);
 }
 
@@ -852,7 +912,10 @@ static void nv_drain_tx(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        int i;
        for (i = 0; i < TX_RING; i++) {
-               np->tx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->tx_ring.orig[i].FlagLen = 0;
+               else
+                       np->tx_ring.ex[i].FlagLen = 0;
                if (np->tx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev, np->tx_dma[i],
                                                np->tx_skbuff[i]->len,
@@ -869,7 +932,10 @@ static void nv_drain_rx(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        int i;
        for (i = 0; i < RX_RING; i++) {
-               np->rx_ring[i].FlagLen = 0;
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       np->rx_ring.orig[i].FlagLen = 0;
+               else
+                       np->rx_ring.ex[i].FlagLen = 0;
                wmb();
                if (np->rx_skbuff[i]) {
                        pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -900,11 +966,19 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
        np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
                                        PCI_DMA_TODEVICE);
 
-       np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+       else {
+               np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+               np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+       }
 
        spin_lock_irq(&np->lock);
        wmb();
-       np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
+       else
+               np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
        dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
                                dev->name, np->next_tx);
        {
@@ -942,7 +1016,10 @@ static void nv_tx_done(struct net_device *dev)
        while (np->nic_tx != np->next_tx) {
                i = np->nic_tx % TX_RING;
 
-               Flags = le32_to_cpu(np->tx_ring[i].FlagLen);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+               else
+                       Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
 
                dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
                                        dev->name, np->nic_tx, Flags);
@@ -993,9 +1070,56 @@ static void nv_tx_timeout(struct net_device *dev)
        struct fe_priv *np = get_nvpriv(dev);
        u8 __iomem *base = get_hwbase(dev);
 
-       dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
+       printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
                        readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
 
+       {
+               int i;
+
+               printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
+                               dev->name, (unsigned long)np->ring_addr,
+                               np->next_tx, np->nic_tx);
+               printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
+               for (i=0;i<0x400;i+= 32) {
+                       printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                                       i,
+                                       readl(base + i + 0), readl(base + i + 4),
+                                       readl(base + i + 8), readl(base + i + 12),
+                                       readl(base + i + 16), readl(base + i + 20),
+                                       readl(base + i + 24), readl(base + i + 28));
+               }
+               printk(KERN_INFO "%s: Dumping tx ring\n", dev->name);
+               for (i=0;i<TX_RING;i+= 4) {
+                       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                               printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
+                                      i, 
+                                      le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
+                                      le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+                       } else {
+                               printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+                                      i, 
+                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
+                                      le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+                       }
+               }
+       }
+
        spin_lock_irq(&np->lock);
 
        /* 1) stop tx engine */
@@ -1009,7 +1133,10 @@ static void nv_tx_timeout(struct net_device *dev)
                printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
                nv_drain_tx(dev);
                np->next_tx = np->nic_tx = 0;
-               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               else
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
                netif_wake_queue(dev);
        }
 
@@ -1084,8 +1211,13 @@ static void nv_rx_process(struct net_device *dev)
                        break;  /* we scanned the whole ring - do not continue */
 
                i = np->cur_rx % RX_RING;
-               Flags = le32_to_cpu(np->rx_ring[i].FlagLen);
-               len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+                       Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+                       len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
+               } else {
+                       Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+                       len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
+               }
 
                dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
                                        dev->name, np->cur_rx, Flags);
@@ -1207,15 +1339,133 @@ next_pkt:
        }
 }
 
+static void set_bufsize(struct net_device *dev)
+{
+       struct fe_priv *np = netdev_priv(dev);
+
+       if (dev->mtu <= ETH_DATA_LEN)
+               np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS;
+       else
+               np->rx_buf_sz = dev->mtu + NV_RX_HEADERS;
+}
+
 /*
  * nv_change_mtu: dev->change_mtu function
  * Called with dev_base_lock held for read.
  */
 static int nv_change_mtu(struct net_device *dev, int new_mtu)
 {
-       if (new_mtu > ETH_DATA_LEN)
+       struct fe_priv *np = get_nvpriv(dev);
+       int old_mtu;
+
+       if (new_mtu < 64 || new_mtu > np->pkt_limit)
                return -EINVAL;
+
+       old_mtu = dev->mtu;
        dev->mtu = new_mtu;
+
+       /* return early if the buffer sizes will not change */
+       if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN)
+               return 0;
+       if (old_mtu == new_mtu)
+               return 0;
+
+       /* synchronized against open : rtnl_lock() held by caller */
+       if (netif_running(dev)) {
+               u8 *base = get_hwbase(dev);
+               /*
+                * It seems that the nic preloads valid ring entries into an
+                * internal buffer. The procedure for flushing everything is
+                * guessed, there is probably a simpler approach.
+                * Changing the MTU is a rare event, it shouldn't matter.
+                */
+               disable_irq(dev->irq);
+               spin_lock_bh(&dev->xmit_lock);
+               spin_lock(&np->lock);
+               /* stop engines */
+               nv_stop_rx(dev);
+               nv_stop_tx(dev);
+               nv_txrx_reset(dev);
+               /* drain rx queue */
+               nv_drain_rx(dev);
+               nv_drain_tx(dev);
+               /* reinit driver view of the rx queue */
+               nv_init_rx(dev);
+               nv_init_tx(dev);
+               /* alloc new rx buffers */
+               set_bufsize(dev);
+               if (nv_alloc_rx(dev)) {
+                       if (!np->in_shutdown)
+                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+               }
+               /* reinit nic view of the rx queue */
+               writel(np->rx_buf_sz, base + NvRegOffloadConfig);
+               writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+               else
+                       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
+               writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
+                       base + NvRegRingSizes);
+               pci_push(base);
+               writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+               pci_push(base);
+
+               /* restart rx engine */
+               nv_start_rx(dev);
+               nv_start_tx(dev);
+               spin_unlock(&np->lock);
+               spin_unlock_bh(&dev->xmit_lock);
+               enable_irq(dev->irq);
+       }
+       return 0;
+}
+
+static void nv_copy_mac_to_hw(struct net_device *dev)
+{
+       u8 *base = get_hwbase(dev);
+       u32 mac[2];
+
+       mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+                       (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+       mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+
+       writel(mac[0], base + NvRegMacAddrA);
+       writel(mac[1], base + NvRegMacAddrB);
+}
+
+/*
+ * nv_set_mac_address: dev->set_mac_address function
+ * Called with rtnl_lock() held.
+ */
+static int nv_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       struct sockaddr *macaddr = (struct sockaddr*)addr;
+
+       if(!is_valid_ether_addr(macaddr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       /* synchronized against open : rtnl_lock() held by caller */
+       memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
+
+       if (netif_running(dev)) {
+               spin_lock_bh(&dev->xmit_lock);
+               spin_lock_irq(&np->lock);
+
+               /* stop rx engine */
+               nv_stop_rx(dev);
+
+               /* set mac address */
+               nv_copy_mac_to_hw(dev);
+
+               /* restart rx engine */
+               nv_start_rx(dev);
+               spin_unlock_irq(&np->lock);
+               spin_unlock_bh(&dev->xmit_lock);
+       } else {
+               nv_copy_mac_to_hw(dev);
+       }
        return 0;
 }
 
@@ -1470,7 +1720,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
                if (!(events & np->irqmask))
                        break;
 
-               if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
+               if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) {
                        spin_lock(&np->lock);
                        nv_tx_done(dev);
                        spin_unlock(&np->lock);
@@ -1761,6 +2011,50 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        return 0;
 }
 
+#define FORCEDETH_REGS_VER     1
+#define FORCEDETH_REGS_SIZE    0x400 /* 256 32-bit registers */
+
+static int nv_get_regs_len(struct net_device *dev)
+{
+       return FORCEDETH_REGS_SIZE;
+}
+
+static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       u32 *rbuf = buf;
+       int i;
+
+       regs->version = FORCEDETH_REGS_VER;
+       spin_lock_irq(&np->lock);
+       for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++)
+               rbuf[i] = readl(base + i*sizeof(u32));
+       spin_unlock_irq(&np->lock);
+}
+
+static int nv_nway_reset(struct net_device *dev)
+{
+       struct fe_priv *np = get_nvpriv(dev);
+       int ret;
+
+       spin_lock_irq(&np->lock);
+       if (np->autoneg) {
+               int bmcr;
+
+               bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+               bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+               mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+       spin_unlock_irq(&np->lock);
+
+       return ret;
+}
+
 static struct ethtool_ops ops = {
        .get_drvinfo = nv_get_drvinfo,
        .get_link = ethtool_op_get_link,
@@ -1768,6 +2062,9 @@ static struct ethtool_ops ops = {
        .set_wol = nv_set_wol,
        .get_settings = nv_get_settings,
        .set_settings = nv_set_settings,
+       .get_regs_len = nv_get_regs_len,
+       .get_regs = nv_get_regs,
+       .nway_reset = nv_nway_reset,
 };
 
 static int nv_open(struct net_device *dev)
@@ -1792,6 +2089,7 @@ static int nv_open(struct net_device *dev)
        writel(0, base + NvRegAdapterControl);
 
        /* 2) initialize descriptor rings */
+       set_bufsize(dev);
        oom = nv_init_ring(dev);
 
        writel(0, base + NvRegLinkSpeed);
@@ -1802,20 +2100,14 @@ static int nv_open(struct net_device *dev)
        np->in_shutdown = 0;
 
        /* 3) set mac address */
-       {
-               u32 mac[2];
-
-               mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
-                               (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
-               mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
-
-               writel(mac[0], base + NvRegMacAddrA);
-               writel(mac[1], base + NvRegMacAddrB);
-       }
+       nv_copy_mac_to_hw(dev);
 
        /* 4) give hw rings */
        writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr);
-       writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+       else
+               writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
        writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
                base + NvRegRingSizes);
 
@@ -1837,7 +2129,7 @@ static int nv_open(struct net_device *dev)
        writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
        writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
        writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
-       writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig);
+       writel(np->rx_buf_sz, base + NvRegOffloadConfig);
 
        writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
        get_random_bytes(&i, sizeof(i));
@@ -1888,6 +2180,9 @@ static int nv_open(struct net_device *dev)
                writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
                dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
        }
+       /* set linkspeed to invalid value, thus force nv_update_linkspeed
+        * to init hw */
+       np->linkspeed = 0;
        ret = nv_update_linkspeed(dev);
        nv_start_rx(dev);
        nv_start_tx(dev);
@@ -1942,6 +2237,12 @@ static int nv_close(struct net_device *dev)
        if (np->wolenabled)
                nv_start_rx(dev);
 
+       /* special op: write back the misordered MAC address - otherwise
+        * the next nv_probe would see a wrong address.
+        */
+       writel(np->orig_mac[0], base + NvRegMacAddrA);
+       writel(np->orig_mac[1], base + NvRegMacAddrB);
+
        /* FIXME: power down nic */
 
        return 0;
@@ -2006,32 +2307,55 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        }
 
        /* handle different descriptor versions */
-       if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
-               np->desc_ver = DESC_VER_1;
-       else
+       if (id->driver_data & DEV_HAS_HIGH_DMA) {
+               /* packet format 3: supports 40-bit addressing */
+               np->desc_ver = DESC_VER_3;
+               if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
+                       printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
+                                       pci_name(pci_dev));
+               }
+       } else if (id->driver_data & DEV_HAS_LARGEDESC) {
+               /* packet format 2: supports jumbo frames */
                np->desc_ver = DESC_VER_2;
+       } else {
+               /* original packet format */
+               np->desc_ver = DESC_VER_1;
+       }
+
+       np->pkt_limit = NV_PKTLIMIT_1;
+       if (id->driver_data & DEV_HAS_LARGEDESC)
+               np->pkt_limit = NV_PKTLIMIT_2;
 
        err = -ENOMEM;
        np->base = ioremap(addr, NV_PCI_REGSZ);
        if (!np->base)
                goto out_relreg;
        dev->base_addr = (unsigned long)np->base;
+
        dev->irq = pci_dev->irq;
-       np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
-                                               &np->ring_addr);
-       if (!np->rx_ring)
-               goto out_unmap;
-       np->tx_ring = &np->rx_ring[RX_RING];
+
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+               np->rx_ring.orig = pci_alloc_consistent(pci_dev,
+                                       sizeof(struct ring_desc) * (RX_RING + TX_RING),
+                                       &np->ring_addr);
+               if (!np->rx_ring.orig)
+                       goto out_unmap;
+               np->tx_ring.orig = &np->rx_ring.orig[RX_RING];
+       } else {
+               np->rx_ring.ex = pci_alloc_consistent(pci_dev,
+                                       sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
+                                       &np->ring_addr);
+               if (!np->rx_ring.ex)
+                       goto out_unmap;
+               np->tx_ring.ex = &np->rx_ring.ex[RX_RING];
+       }
 
        dev->open = nv_open;
        dev->stop = nv_close;
        dev->hard_start_xmit = nv_start_xmit;
        dev->get_stats = nv_get_stats;
        dev->change_mtu = nv_change_mtu;
+       dev->set_mac_address = nv_set_mac_address;
        dev->set_multicast_list = nv_set_multicast;
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = nv_poll_controller;
@@ -2080,17 +2404,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        if (np->desc_ver == DESC_VER_1) {
                np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
-               if (id->driver_data & DEV_NEED_LASTPACKET1)
-                       np->tx_flags |= NV_TX_LASTPACKET1;
        } else {
                np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
-               if (id->driver_data & DEV_NEED_LASTPACKET1)
-                       np->tx_flags |= NV_TX2_LASTPACKET1;
        }
-       if (id->driver_data & DEV_IRQMASK_1)
-               np->irqmask = NVREG_IRQMASK_WANTED_1;
-       if (id->driver_data & DEV_IRQMASK_2)
-               np->irqmask = NVREG_IRQMASK_WANTED_2;
+       np->irqmask = NVREG_IRQMASK_WANTED;
        if (id->driver_data & DEV_NEED_TIMERIRQ)
                np->irqmask |= NVREG_IRQ_TIMER;
        if (id->driver_data & DEV_NEED_LINKTIMER) {
@@ -2155,8 +2472,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        return 0;
 
 out_freering:
-       pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
-                               np->rx_ring, np->ring_addr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
+                                   np->rx_ring.orig, np->ring_addr);
+       else
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING),
+                                   np->rx_ring.ex, np->ring_addr);
        pci_set_drvdata(pci_dev, NULL);
 out_unmap:
        iounmap(get_hwbase(dev));
@@ -2174,18 +2495,14 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
 {
        struct net_device *dev = pci_get_drvdata(pci_dev);
        struct fe_priv *np = get_nvpriv(dev);
-       u8 __iomem *base = get_hwbase(dev);
 
        unregister_netdev(dev);
 
-       /* special op: write back the misordered MAC address - otherwise
-        * the next nv_probe would see a wrong address.
-        */
-       writel(np->orig_mac[0], base + NvRegMacAddrA);
-       writel(np->orig_mac[1], base + NvRegMacAddrB);
-
        /* free all structures */
-       pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr);
+       else
+               pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr);
        iounmap(get_hwbase(dev));
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
@@ -2195,109 +2512,64 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
 
 static struct pci_device_id pci_tbl[] = {
        {       /* nForce Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_1,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce2 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_2,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_3,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* nForce3 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
        },
        {       /* CK804 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* CK804 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP04 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP04 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP51 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP51 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP55 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {       /* MCP55 Ethernet Controller */
-               .vendor = PCI_VENDOR_ID_NVIDIA,
-               .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
        },
        {0,},
 };
index f9e3be96963cde79ded8cd0b556294a6bd9987ec..0b230222bfeab592fa23ec7836accddc79df7a62 100644 (file)
@@ -308,12 +308,6 @@ static int sp_set_mac_address(struct net_device *dev, void *addr)
 {
        struct sockaddr_ax25 *sa = addr;
 
-       if (sa->sax25_family != AF_AX25)
-               return -EINVAL;
-
-       if (!sa->sax25_ndigis)
-               return -EINVAL;
-
        spin_lock_irq(&dev->xmit_lock);
        memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
        spin_unlock_irq(&dev->xmit_lock);
@@ -668,6 +662,9 @@ static int sixpack_open(struct tty_struct *tty)
        netif_start_queue(dev);
 
        init_timer(&sp->tx_t);
+       sp->tx_t.function = sp_xmit_on_air;
+       sp->tx_t.data = (unsigned long) sp;
+
        init_timer(&sp->resync_t);
 
        spin_unlock_bh(&sp->lock);
index 0cd54306e63680c6030a8ebdb82f9eff62aa7a4a..de087cd609d98fcf916c638187ed0df9b0e9eb59 100644 (file)
@@ -1,6 +1,6 @@
 config MKISS
        tristate "Serial port KISS driver"
-       depends on AX25 && BROKEN_ON_SMP
+       depends on AX25
        ---help---
          KISS is a protocol used for the exchange of data between a computer
          and a Terminal Node Controller (a small embedded system commonly
index a7f15d9f13e5ccd04faa36b6dda826c20e750fbb..5298096afbdb6efc7a9031ec2d746a0e3438772f 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/kmod.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 /* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
@@ -287,7 +288,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index 612ad452bee03b32d0dc0188907b37face5c7a9a..3b1bef1ee21507ec9a453382ed94810d0d5053ce 100644 (file)
@@ -84,6 +84,7 @@
 #include <linux/baycom.h>
 #include <linux/parport.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/bug.h>
 #include <asm/system.h>
@@ -165,7 +166,7 @@ static void __inline__ baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index 25f270b053788cbcb7b87265cab9036ca8add64a..232793d2ce6b0a46bf7d4a1a04e6683ac7624d14 100644 (file)
@@ -79,6 +79,7 @@
 #include <asm/io.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -159,7 +160,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index eead85d009627980818e9c66b8420deca995ec46..be596a3eb3fd9b164b6107410498d4dde7a76ace 100644 (file)
@@ -69,6 +69,7 @@
 #include <asm/io.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
+#include <linux/jiffies.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -150,7 +151,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
         * measure the interrupt frequency
         */
        bc->debug_vals.cur_intcnt++;
-       if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+       if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
                bc->debug_vals.last_jiffies = cur_jiffies;
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
                bc->debug_vals.cur_intcnt = 0;
index 3035422f5ad8c867dfdfaeb151f7e05647c572ca..63b1a2b86acb19650fdee9e84efb2e86e7971bed 100644 (file)
@@ -1,30 +1,19 @@
 /*
- *     MKISS Driver
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
  *
- *     This module:
- *             This module is free software; you can redistribute it and/or
- *             modify it under the terms of the GNU General Public License
- *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
  *
- *             This module implements the AX.25 protocol for kernel-based
- *             devices like TTYs. It interfaces between a raw TTY, and the
- *             kernel's AX.25 protocol layers, just like slip.c.
- *             AX.25 needs to be separated from slip.c while slip.c is no
- *             longer a static kernel device since it is a module.
- *             This method clears the way to implement other kiss protocols
- *             like mkiss smack g8bpq ..... so far only mkiss is implemented.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
- * Hans Alblas <hans@esrac.ele.tue.nl>
- *
- *     History
- *     Jonathan (G4KLX)        Fixed to match Linux networking changes - 2.1.15.
- *     Matthias (DG2FEF)       Added support for FlexNet CRC (on special request)
- *                              Fixed bug in ax25_close(): dev_lock_wait() was
- *                              called twice, causing a deadlock.
- *     Jeroen (PE1RXQ)         Removed old MKISS_MAGIC stuff and calls to
- *                             MOD_*_USE_COUNT
- *                             Remove cli() and fix rtnl lock usage.
+ * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl>
+ * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
  */
 
 #include <linux/config.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/jiffies.h>
 
 #include <net/ax25.h>
 
-#include "mkiss.h"
-
 #ifdef CONFIG_INET
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #endif
 
-static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
-
-typedef struct ax25_ctrl {
-       struct ax_disp ctrl;    /*                              */
-       struct net_device  dev; /* the device                   */
-} ax25_ctrl_t;
-
-static ax25_ctrl_t **ax25_ctrls;
-
-int ax25_maxdev = AX25_MAXDEV;         /* Can be overridden with insmod! */
-
-static struct tty_ldisc        ax_ldisc;
-
-static int ax25_init(struct net_device *);
-static int kiss_esc(unsigned char *, unsigned char *, int);
-static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int);
-static void kiss_unesc(struct ax_disp *, unsigned char);
+#define AX_MTU         236
+
+/* SLIP/KISS protocol characters. */
+#define END             0300           /* indicates end of frame       */
+#define ESC             0333           /* indicates byte stuffing      */
+#define ESC_END         0334           /* ESC ESC_END means END 'data' */
+#define ESC_ESC         0335           /* ESC ESC_ESC means ESC 'data' */
+
+struct mkiss {
+       struct tty_struct       *tty;   /* ptr to TTY structure         */
+       struct net_device       *dev;   /* easy for intr handling       */
+
+       /* These are pointers to the malloc()ed frame buffers. */
+       spinlock_t              buflock;/* lock for rbuf and xbuf */
+       unsigned char           *rbuff; /* receiver buffer              */
+       int                     rcount; /* received chars counter       */
+       unsigned char           *xbuff; /* transmitter buffer           */
+       unsigned char           *xhead; /* pointer to next byte to XMIT */
+       int                     xleft;  /* bytes left in XMIT queue     */
+
+       struct net_device_stats stats;
+
+       /* Detailed SLIP statistics. */
+       int             mtu;            /* Our mtu (to spot changes!)   */
+       int             buffsize;       /* Max buffers sizes            */
+
+       unsigned long   flags;          /* Flag values/ mode etc        */
+                                       /* long req'd: used by set_bit --RR */
+#define AXF_INUSE      0               /* Channel in use               */
+#define AXF_ESCAPE     1               /* ESC received                 */
+#define AXF_ERROR      2               /* Parity, etc. error           */
+#define AXF_KEEPTEST   3               /* Keepalive test flag          */
+#define AXF_OUTWAIT    4               /* is outpacket was flag        */
+
+       int             mode;
+        int            crcmode;        /* MW: for FlexNet, SMACK etc.  */
+#define CRC_MODE_NONE   0
+#define CRC_MODE_FLEX   1
+#define CRC_MODE_SMACK  2
+
+       atomic_t                refcnt;
+       struct semaphore        dead_sem;
+};
 
 /*---------------------------------------------------------------------------*/
 
-static const unsigned short Crc_flex_table[] = {
-  0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
-  0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
-  0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
-  0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
-  0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
-  0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
-  0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
-  0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
-  0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
-  0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
-  0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
-  0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
-  0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
-  0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
-  0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
-  0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
-  0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
-  0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
-  0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
-  0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
-  0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
-  0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
-  0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
-  0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
-  0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
-  0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
-  0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
-  0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
-  0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
-  0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
-  0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
-  0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
+static const unsigned short crc_flex_table[] = {
+       0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38,
+       0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770,
+       0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9,
+       0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1,
+       0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a,
+       0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672,
+       0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb,
+       0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3,
+       0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c,
+       0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574,
+       0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd,
+       0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5,
+       0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e,
+       0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476,
+       0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf,
+       0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7,
+       0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30,
+       0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378,
+       0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1,
+       0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9,
+       0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32,
+       0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a,
+       0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3,
+       0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb,
+       0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34,
+       0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c,
+       0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5,
+       0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd,
+       0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36,
+       0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e,
+       0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7,
+       0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff
 };
 
-/*---------------------------------------------------------------------------*/
-
 static unsigned short calc_crc_flex(unsigned char *cp, int size)
 {
-    unsigned short crc = 0xffff;
-    
-    while (size--)
-       crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+       unsigned short crc = 0xffff;
 
-    return crc;
-}
+       while (size--)
+               crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
 
-/*---------------------------------------------------------------------------*/
+       return crc;
+}
 
 static int check_crc_flex(unsigned char *cp, int size)
 {
-  unsigned short crc = 0xffff;
+       unsigned short crc = 0xffff;
 
-  if (size < 3)
-      return -1;
+       if (size < 3)
+               return -1;
 
-  while (size--)
-      crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
+       while (size--)
+               crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff];
 
-  if ((crc & 0xffff) != 0x7070) 
-      return -1;
+       if ((crc & 0xffff) != 0x7070)
+               return -1;
 
-  return 0;
+       return 0;
 }
 
-/*---------------------------------------------------------------------------*/
+/*
+ * Standard encapsulation
+ */
 
-/* Find a free channel, and link in this `tty' line. */
-static inline struct ax_disp *ax_alloc(void)
+static int kiss_esc(unsigned char *s, unsigned char *d, int len)
 {
-       ax25_ctrl_t *axp=NULL;
-       int i;
+       unsigned char *ptr = d;
+       unsigned char c;
 
-       for (i = 0; i < ax25_maxdev; i++) {
-               axp = ax25_ctrls[i];
+       /*
+        * Send an initial END character to flush out any data that may have
+        * accumulated in the receiver due to line noise.
+        */
 
-               /* Not allocated ? */
-               if (axp == NULL)
-                       break;
+       *ptr++ = END;
 
-               /* Not in use ? */
-               if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags))
+       while (len-- > 0) {
+               switch (c = *s++) {
+               case END:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_END;
                        break;
+               case ESC:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_ESC;
+                       break;
+               default:
+                       *ptr++ = c;
+                       break;
+               }
        }
 
-       /* Sorry, too many, all slots in use */
-       if (i >= ax25_maxdev)
-               return NULL;
+       *ptr++ = END;
+
+       return ptr - d;
+}
+
+/*
+ * MW:
+ * OK its ugly, but tell me a better solution without copying the
+ * packet to a temporary buffer :-)
+ */
+static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
+       int len)
+{
+       unsigned char *ptr = d;
+       unsigned char c=0;
+
+       *ptr++ = END;
+       while (len > 0) {
+               if (len > 2)
+                       c = *s++;
+               else if (len > 1)
+                       c = crc >> 8;
+               else if (len > 0)
+                       c = crc & 0xff;
+
+               len--;
 
-       /* If no channels are available, allocate one */
-       if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) {
-               axp = ax25_ctrls[i];
+               switch (c) {
+               case END:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_END;
+                       break;
+               case ESC:
+                       *ptr++ = ESC;
+                       *ptr++ = ESC_ESC;
+                       break;
+               default:
+                       *ptr++ = c;
+                       break;
+               }
        }
-       memset(axp, 0, sizeof(ax25_ctrl_t));
-
-       /* Initialize channel control data */
-       set_bit(AXF_INUSE, &axp->ctrl.flags);
-       sprintf(axp->dev.name, "ax%d", i++);
-       axp->ctrl.tty      = NULL;
-       axp->dev.base_addr = i;
-       axp->dev.priv      = (void *)&axp->ctrl;
-       axp->dev.next      = NULL;
-       axp->dev.init      = ax25_init;
-
-       if (axp != NULL) {
-               /*
-                * register device so that it can be ifconfig'ed
-                * ax25_init() will be called as a side-effect
-                * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl !
-                */
-               if (register_netdev(&axp->dev) == 0) {
-                       /* (Re-)Set the INUSE bit.   Very Important! */
-                       set_bit(AXF_INUSE, &axp->ctrl.flags);
-                       axp->ctrl.dev = &axp->dev;
-                       axp->dev.priv = (void *) &axp->ctrl;
-
-                       return &axp->ctrl;
-               } else {
-                       clear_bit(AXF_INUSE,&axp->ctrl.flags);
-                       printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n");
+       *ptr++ = END;
+
+       return ptr - d;
+}
+
+/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
+static void ax_bump(struct mkiss *ax)
+{
+       struct sk_buff *skb;
+       int count;
+
+       spin_lock_bh(&ax->buflock);
+       if (ax->rbuff[0] > 0x0f) {
+               if (ax->rbuff[0] & 0x20) {
+                       ax->crcmode = CRC_MODE_FLEX;
+                       if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
+                               ax->stats.rx_errors++;
+                               return;
+                       }
+                       ax->rcount -= 2;
+                        /* dl9sau bugfix: the trailling two bytes flexnet crc
+                         * will not be passed to the kernel. thus we have
+                         * to correct the kissparm signature, because it
+                         * indicates a crc but there's none
+                        */
+                        *ax->rbuff &= ~0x20;
                }
+       }
+       spin_unlock_bh(&ax->buflock);
+
+       count = ax->rcount;
+
+       if ((skb = dev_alloc_skb(count)) == NULL) {
+               printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
+                      ax->dev->name);
+               ax->stats.rx_dropped++;
+               return;
        }
 
-       return NULL;
+       spin_lock_bh(&ax->buflock);
+       memcpy(skb_put(skb,count), ax->rbuff, count);
+       spin_unlock_bh(&ax->buflock);
+       skb->protocol = ax25_type_trans(skb, ax->dev);
+       netif_rx(skb);
+       ax->dev->last_rx = jiffies;
+       ax->stats.rx_packets++;
+       ax->stats.rx_bytes += count;
 }
 
-/* Free an AX25 channel. */
-static inline void ax_free(struct ax_disp *ax)
+static void kiss_unesc(struct mkiss *ax, unsigned char s)
 {
-       /* Free all AX25 frame buffers. */
-       if (ax->rbuff)
-               kfree(ax->rbuff);
-       ax->rbuff = NULL;
-       if (ax->xbuff)
-               kfree(ax->xbuff);
-       ax->xbuff = NULL;
-       if (!test_and_clear_bit(AXF_INUSE, &ax->flags))
-               printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name);
+       switch (s) {
+       case END:
+               /* drop keeptest bit = VSV */
+               if (test_bit(AXF_KEEPTEST, &ax->flags))
+                       clear_bit(AXF_KEEPTEST, &ax->flags);
+
+               if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
+                       ax_bump(ax);
+
+               clear_bit(AXF_ESCAPE, &ax->flags);
+               ax->rcount = 0;
+               return;
+
+       case ESC:
+               set_bit(AXF_ESCAPE, &ax->flags);
+               return;
+       case ESC_ESC:
+               if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
+                       s = ESC;
+               break;
+       case ESC_END:
+               if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
+                       s = END;
+               break;
+       }
+
+       spin_lock_bh(&ax->buflock);
+       if (!test_bit(AXF_ERROR, &ax->flags)) {
+               if (ax->rcount < ax->buffsize) {
+                       ax->rbuff[ax->rcount++] = s;
+                       spin_unlock_bh(&ax->buflock);
+                       return;
+               }
+
+               ax->stats.rx_over_errors++;
+               set_bit(AXF_ERROR, &ax->flags);
+       }
+       spin_unlock_bh(&ax->buflock);
+}
+
+static int ax_set_mac_address(struct net_device *dev, void *addr)
+{
+       struct sockaddr_ax25 *sa = addr;
+
+       spin_lock_irq(&dev->xmit_lock);
+       memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
+       spin_unlock_irq(&dev->xmit_lock);
+
+       return 0;
 }
 
-static void ax_changedmtu(struct ax_disp *ax)
+/*---------------------------------------------------------------------------*/
+
+static void ax_changedmtu(struct mkiss *ax)
 {
        struct net_device *dev = ax->dev;
        unsigned char *xbuff, *rbuff, *oxbuff, *orbuff;
@@ -236,7 +348,8 @@ static void ax_changedmtu(struct ax_disp *ax)
        rbuff = kmalloc(len + 4, GFP_ATOMIC);
 
        if (xbuff == NULL || rbuff == NULL)  {
-               printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n",
+               printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, "
+                      "MTU change cancelled.\n",
                       ax->dev->name);
                dev->mtu = ax->mtu;
                if (xbuff != NULL)
@@ -258,7 +371,7 @@ static void ax_changedmtu(struct ax_disp *ax)
                        memcpy(ax->xbuff, ax->xhead, ax->xleft);
                } else  {
                        ax->xleft = 0;
-                       ax->tx_dropped++;
+                       ax->stats.tx_dropped++;
                }
        }
 
@@ -269,7 +382,7 @@ static void ax_changedmtu(struct ax_disp *ax)
                        memcpy(ax->rbuff, orbuff, ax->rcount);
                } else  {
                        ax->rcount = 0;
-                       ax->rx_over_errors++;
+                       ax->stats.rx_over_errors++;
                        set_bit(AXF_ERROR, &ax->flags);
                }
        }
@@ -279,72 +392,14 @@ static void ax_changedmtu(struct ax_disp *ax)
 
        spin_unlock_bh(&ax->buflock);
 
-       if (oxbuff != NULL)
-               kfree(oxbuff);
-       if (orbuff != NULL)
-               kfree(orbuff);
-}
-
-
-/* Set the "sending" flag.  This must be atomic. */
-static inline void ax_lock(struct ax_disp *ax)
-{
-       netif_stop_queue(ax->dev);
-}
-
-
-/* Clear the "sending" flag.  This must be atomic. */
-static inline void ax_unlock(struct ax_disp *ax)
-{
-       netif_start_queue(ax->dev);
-}
-
-/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */
-static void ax_bump(struct ax_disp *ax)
-{
-       struct sk_buff *skb;
-       int count;
-
-       spin_lock_bh(&ax->buflock);
-       if (ax->rbuff[0] > 0x0f) {
-               if (ax->rbuff[0] & 0x20) {
-                       ax->crcmode = CRC_MODE_FLEX;
-                       if (check_crc_flex(ax->rbuff, ax->rcount) < 0) {
-                               ax->rx_errors++;
-                               return;
-                       }
-                       ax->rcount -= 2;
-                        /* dl9sau bugfix: the trailling two bytes flexnet crc
-                         * will not be passed to the kernel. thus we have
-                         * to correct the kissparm signature, because it
-                         * indicates a crc but there's none
-                        */
-                        *ax->rbuff &= ~0x20;
-               }
-       }
-       spin_unlock_bh(&ax->buflock);
-
-       count = ax->rcount;
-
-       if ((skb = dev_alloc_skb(count)) == NULL) {
-               printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name);
-               ax->rx_dropped++;
-               return;
-       }
-
-       spin_lock_bh(&ax->buflock);
-       memcpy(skb_put(skb,count), ax->rbuff, count);
-       spin_unlock_bh(&ax->buflock);
-       skb->protocol = ax25_type_trans(skb, ax->dev);
-       netif_rx(skb);
-       ax->dev->last_rx = jiffies;
-       ax->rx_packets++;
-       ax->rx_bytes+=count;
+       kfree(oxbuff);
+       kfree(orbuff);
 }
 
 /* Encapsulate one AX.25 packet and stuff into a TTY queue. */
-static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
+static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
 {
+       struct mkiss *ax = netdev_priv(dev);
        unsigned char *p;
        int actual, count;
 
@@ -354,8 +409,8 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
        if (len > ax->mtu) {            /* Sigh, shouldn't occur BUT ... */
                len = ax->mtu;
                printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name);
-               ax->tx_dropped++;
-               ax_unlock(ax);
+               ax->stats.tx_dropped++;
+               netif_start_queue(dev);
                return;
        }
 
@@ -376,10 +431,11 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
                 break;
        }
        
-       ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+       set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
        actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
-       ax->tx_packets++;
-       ax->tx_bytes+=actual;
+       ax->stats.tx_packets++;
+       ax->stats.tx_bytes += actual;
+
        ax->dev->trans_start = jiffies;
        ax->xleft = count - actual;
        ax->xhead = ax->xbuff + actual;
@@ -387,37 +443,10 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len)
        spin_unlock_bh(&ax->buflock);
 }
 
-/*
- * Called by the driver when there's room for more data.  If we have
- * more packets to send, we send them here.
- */
-static void ax25_write_wakeup(struct tty_struct *tty)
-{
-       int actual;
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
-
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))
-               return;
-       if (ax->xleft <= 0)  {
-               /* Now serial buffer is almost free & we can start
-                * transmission of another packet
-                */
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
-               netif_wake_queue(ax->dev);
-               return;
-       }
-
-       actual = tty->driver->write(tty, ax->xhead, ax->xleft);
-       ax->xleft -= actual;
-       ax->xhead += actual;
-}
-
 /* Encapsulate an AX.25 packet and kick it into a TTY queue. */
 static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
 
        if (!netif_running(dev))  {
                printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
@@ -429,7 +458,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
                 * May be we must check transmitter timeout here ?
                 *      14 Oct 1994 Dmitry Gorodchanin.
                 */
-               if (jiffies - dev->trans_start  < 20 * HZ) {
+               if (time_before(jiffies, dev->trans_start + 20 * HZ)) {
                        /* 20 sec timeout not reached */
                        return 1;
                }
@@ -439,20 +468,30 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
                       "bad line quality" : "driver error");
 
                ax->xleft = 0;
-               ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               ax_unlock(ax);
+               clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
+               netif_start_queue(dev);
        }
 
        /* We were not busy, so we are now... :-) */
        if (skb != NULL) {
-               ax_lock(ax);
-               ax_encaps(ax, skb->data, skb->len);
+               netif_stop_queue(dev);
+               ax_encaps(dev, skb->data, skb->len);
                kfree_skb(skb);
        }
 
        return 0;
 }
 
+static int ax_open_dev(struct net_device *dev)
+{
+       struct mkiss *ax = netdev_priv(dev);
+
+       if (ax->tty == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 
 /* Return the frame type ID */
@@ -481,7 +520,7 @@ static int ax_rebuild_header(struct sk_buff *skb)
 /* Open the low-level part of the AX25 channel. Easy! */
 static int ax_open(struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
        unsigned long len;
 
        if (ax->tty == NULL)
@@ -518,7 +557,6 @@ static int ax_open(struct net_device *dev)
 
        spin_lock_init(&ax->buflock);
 
-       netif_start_queue(dev);
        return 0;
 
 noxbuff:
@@ -532,68 +570,100 @@ norbuff:
 /* Close the low-level part of the AX25 channel. Easy! */
 static int ax_close(struct net_device *dev)
 {
-       struct ax_disp *ax = netdev_priv(dev);
+       struct mkiss *ax = netdev_priv(dev);
 
-       if (ax->tty == NULL)
-               return -EBUSY;
-
-       ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       if (ax->tty)
+               clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
 
        netif_stop_queue(dev);
 
        return 0;
 }
 
-static int ax25_receive_room(struct tty_struct *tty)
+static struct net_device_stats *ax_get_stats(struct net_device *dev)
 {
-       return 65536;  /* We can handle an infinite amount of data. :-) */
+       struct mkiss *ax = netdev_priv(dev);
+
+       return &ax->stats;
+}
+
+static void ax_setup(struct net_device *dev)
+{
+       static char ax25_bcast[AX25_ADDR_LEN] =
+               {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
+       static char ax25_test[AX25_ADDR_LEN] =
+               {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+
+       /* Finish setting up the DEVICE info. */
+       dev->mtu             = AX_MTU;
+       dev->hard_start_xmit = ax_xmit;
+       dev->open            = ax_open_dev;
+       dev->stop            = ax_close;
+       dev->get_stats       = ax_get_stats;
+       dev->set_mac_address = ax_set_mac_address;
+       dev->hard_header_len = 0;
+       dev->addr_len        = 0;
+       dev->type            = ARPHRD_AX25;
+       dev->tx_queue_len    = 10;
+       dev->hard_header     = ax_header;
+       dev->rebuild_header  = ax_rebuild_header;
+
+       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
+
+       dev->flags      = IFF_BROADCAST | IFF_MULTICAST;
 }
 
 /*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of data has been received, which can now be decapsulated
- * and sent on to the AX.25 layer for further processing.
+ * We have a potential race on dereferencing tty->disc_data, because the tty
+ * layer provides no locking at all - thus one cpu could be running
+ * sixpack_receive_buf while another calls sixpack_close, which zeroes
+ * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The
+ * best way to fix this is to use a rwlock in the tty struct, but for now we
+ * use a single global rwlock for all ttys in ppp line discipline.
  */
-static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+
+static struct mkiss *mkiss_get(struct tty_struct *tty)
 {
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       struct mkiss *ax;
 
-       if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))
-               return;
+       read_lock(&disc_data_lock);
+       ax = tty->disc_data;
+       if (ax)
+               atomic_inc(&ax->refcnt);
+       read_unlock(&disc_data_lock);
 
-       /*
-        * Argh! mtu change time! - costs us the packet part received
-        * at the change
-        */
-       if (ax->mtu != ax->dev->mtu + 73)
-               ax_changedmtu(ax);
-
-       /* Read the characters out of the buffer */
-       while (count--) {
-               if (fp != NULL && *fp++) {
-                       if (!test_and_set_bit(AXF_ERROR, &ax->flags))
-                               ax->rx_errors++;
-                       cp++;
-                       continue;
-               }
+       return ax;
+}
 
-               kiss_unesc(ax, *cp++);
-       }
+static void mkiss_put(struct mkiss *ax)
+{
+       if (atomic_dec_and_test(&ax->refcnt))
+               up(&ax->dead_sem);
 }
 
-static int ax25_open(struct tty_struct *tty)
+static int mkiss_open(struct tty_struct *tty)
 {
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       struct net_device *dev;
+       struct mkiss *ax;
        int err;
 
-       /* First make sure we're not already connected. */
-       if (ax && ax->magic == AX25_MAGIC)
-               return -EEXIST;
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
 
-       /* OK.  Find a free AX25 channel to use. */
-       if ((ax = ax_alloc()) == NULL)
-               return -ENFILE;
+       dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
+       if (!dev) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       ax = netdev_priv(dev);
+       ax->dev = dev;
+
+       spin_lock_init(&ax->buflock);
+       atomic_set(&ax->refcnt, 1);
+       init_MUTEX_LOCKED(&ax->dead_sem);
 
        ax->tty = tty;
        tty->disc_data = ax;
@@ -602,283 +672,212 @@ static int ax25_open(struct tty_struct *tty)
                tty->driver->flush_buffer(tty);
 
        /* Restore default settings */
-       ax->dev->type = ARPHRD_AX25;
+       dev->type = ARPHRD_AX25;
 
        /* Perform the low-level AX25 initialization. */
-       if ((err = ax_open(ax->dev)))
-               return err;
+       if ((err = ax_open(ax->dev))) {
+               goto out_free_netdev;
+       }
 
-       /* Done.  We have linked the TTY line to a channel. */
-       return ax->dev->base_addr;
-}
+       if (register_netdev(dev))
+               goto out_free_buffers;
 
-static void ax25_close(struct tty_struct *tty)
-{
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
+       netif_start_queue(dev);
 
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC)
-               return;
+       /* Done.  We have linked the TTY line to a channel. */
+       return 0;
 
-       unregister_netdev(ax->dev);
+out_free_buffers:
+       kfree(ax->rbuff);
+       kfree(ax->xbuff);
 
-       tty->disc_data = NULL;
-       ax->tty        = NULL;
+out_free_netdev:
+       free_netdev(dev);
 
-       ax_free(ax);
+out:
+       return err;
 }
 
-
-static struct net_device_stats *ax_get_stats(struct net_device *dev)
+static void mkiss_close(struct tty_struct *tty)
 {
-       static struct net_device_stats stats;
-       struct ax_disp *ax = netdev_priv(dev);
-
-       memset(&stats, 0, sizeof(struct net_device_stats));
-
-       stats.rx_packets     = ax->rx_packets;
-       stats.tx_packets     = ax->tx_packets;
-       stats.rx_bytes       = ax->rx_bytes;
-       stats.tx_bytes       = ax->tx_bytes;
-       stats.rx_dropped     = ax->rx_dropped;
-       stats.tx_dropped     = ax->tx_dropped;
-       stats.tx_errors      = ax->tx_errors;
-       stats.rx_errors      = ax->rx_errors;
-       stats.rx_over_errors = ax->rx_over_errors;
-
-       return &stats;
-}
+       struct mkiss *ax;
 
+       write_lock(&disc_data_lock);
+       ax = tty->disc_data;
+       tty->disc_data = NULL;
+       write_unlock(&disc_data_lock);
 
-/************************************************************************
- *                        STANDARD ENCAPSULATION                        *
- ************************************************************************/
-
-static int kiss_esc(unsigned char *s, unsigned char *d, int len)
-{
-       unsigned char *ptr = d;
-       unsigned char c;
+       if (ax == 0)
+               return;
 
        /*
-        * Send an initial END character to flush out any
-        * data that may have accumulated in the receiver
-        * due to line noise.
+        * We have now ensured that nobody can start using ap from now on, but
+        * we have to wait for all existing users to finish.
         */
+       if (!atomic_dec_and_test(&ax->refcnt))
+               down(&ax->dead_sem);
 
-       *ptr++ = END;
-
-       while (len-- > 0) {
-               switch (c = *s++) {
-                       case END:
-                               *ptr++ = ESC;
-                               *ptr++ = ESC_END;
-                               break;
-                       case ESC:
-                               *ptr++ = ESC;
-                               *ptr++ = ESC_ESC;
-                               break;
-                       default:
-                               *ptr++ = c;
-                               break;
-               }
-       }
+       unregister_netdev(ax->dev);
 
-       *ptr++ = END;
+       /* Free all AX25 frame buffers. */
+       kfree(ax->rbuff);
+       kfree(ax->xbuff);
 
-       return ptr - d;
+       ax->tty = NULL;
 }
 
-/*
- * MW:
- * OK its ugly, but tell me a better solution without copying the
- * packet to a temporary buffer :-)
- */
-static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len)
+/* Perform I/O control on an active ax25 channel. */
+static int mkiss_ioctl(struct tty_struct *tty, struct file *file,
+       unsigned int cmd, unsigned long arg)
 {
-       unsigned char *ptr = d;
-       unsigned char c=0;
-
-       *ptr++ = END;
-       while (len > 0) {
-               if (len > 2) 
-                       c = *s++;
-               else if (len > 1)
-                       c = crc >> 8;
-               else if (len > 0)
-                       c = crc & 0xff;
+       struct mkiss *ax = mkiss_get(tty);
+       struct net_device *dev = ax->dev;
+       unsigned int tmp, err;
 
-               len--;
+       /* First make sure we're connected. */
+       if (ax == NULL)
+               return -ENXIO;
 
-               switch (c) {
-                        case END:
-                                *ptr++ = ESC;
-                                *ptr++ = ESC_END;
-                                break;
-                        case ESC:
-                                *ptr++ = ESC;
-                                *ptr++ = ESC_ESC;
-                                break;
-                        default:
-                                *ptr++ = c;
-                                break;
+       switch (cmd) {
+       case SIOCGIFNAME:
+               err = copy_to_user((void __user *) arg, ax->dev->name,
+                                  strlen(ax->dev->name) + 1) ? -EFAULT : 0;
+               break;
+
+       case SIOCGIFENCAP:
+               err = put_user(4, (int __user *) arg);
+               break;
+
+       case SIOCSIFENCAP:
+               if (get_user(tmp, (int __user *) arg)) {
+                       err = -EFAULT;
+                       break;
                }
-       }
-       *ptr++ = END;
-       return ptr - d;         
-}
 
-static void kiss_unesc(struct ax_disp *ax, unsigned char s)
-{
-       switch (s) {
-               case END:
-                       /* drop keeptest bit = VSV */
-                       if (test_bit(AXF_KEEPTEST, &ax->flags))
-                               clear_bit(AXF_KEEPTEST, &ax->flags);
+               ax->mode = tmp;
+               dev->addr_len        = AX25_ADDR_LEN;
+               dev->hard_header_len = AX25_KISS_HEADER_LEN +
+                                      AX25_MAX_HEADER_LEN + 3;
+               dev->type            = ARPHRD_AX25;
 
-                       if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2))
-                               ax_bump(ax);
+               err = 0;
+               break;
 
-                       clear_bit(AXF_ESCAPE, &ax->flags);
-                       ax->rcount = 0;
-                       return;
+       case SIOCSIFHWADDR: {
+               char addr[AX25_ADDR_LEN];
+printk(KERN_INFO "In SIOCSIFHWADDR");
 
-               case ESC:
-                       set_bit(AXF_ESCAPE, &ax->flags);
-                       return;
-               case ESC_ESC:
-                       if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
-                               s = ESC;
+               if (copy_from_user(&addr,
+                                  (void __user *) arg, AX25_ADDR_LEN)) {
+                       err = -EFAULT;
                        break;
-               case ESC_END:
-                       if (test_and_clear_bit(AXF_ESCAPE, &ax->flags))
-                               s = END;
-                       break;
-       }
-
-       spin_lock_bh(&ax->buflock);
-       if (!test_bit(AXF_ERROR, &ax->flags)) {
-               if (ax->rcount < ax->buffsize) {
-                       ax->rbuff[ax->rcount++] = s;
-                       spin_unlock_bh(&ax->buflock);
-                       return;
                }
 
-               ax->rx_over_errors++;
-               set_bit(AXF_ERROR, &ax->flags);
+               spin_lock_irq(&dev->xmit_lock);
+               memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
+               spin_unlock_irq(&dev->xmit_lock);
+
+               err = 0;
+               break;
+       }
+       default:
+               err = -ENOIOCTLCMD;
        }
-       spin_unlock_bh(&ax->buflock);
-}
 
+       mkiss_put(ax);
 
-static int ax_set_mac_address(struct net_device *dev, void __user *addr)
-{
-       if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN))
-               return -EFAULT;
-       return 0;
+       return err;
 }
 
-static int ax_set_dev_mac_address(struct net_device *dev, void *addr)
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of data has been received, which can now be decapsulated
+ * and sent on to the AX.25 layer for further processing.
+ */
+static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+       char *fp, int count)
 {
-       struct sockaddr *sa = addr;
-
-       memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
+       struct mkiss *ax = mkiss_get(tty);
 
-       return 0;
-}
-
-
-/* Perform I/O control on an active ax25 channel. */
-static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void __user *arg)
-{
-       struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
-       unsigned int tmp;
+       if (!ax)
+               return;
 
-       /* First make sure we're connected. */
-       if (ax == NULL || ax->magic != AX25_MAGIC)
-               return -EINVAL;
+       /*
+        * Argh! mtu change time! - costs us the packet part received
+        * at the change
+        */
+       if (ax->mtu != ax->dev->mtu + 73)
+               ax_changedmtu(ax);
 
-       switch (cmd) {
-               case SIOCGIFNAME:
-                       if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1))
-                               return -EFAULT;
-                       return 0;
-
-               case SIOCGIFENCAP:
-                       return put_user(4, (int __user *)arg);
-
-               case SIOCSIFENCAP:
-                       if (get_user(tmp, (int __user *)arg))
-                               return -EFAULT;
-                       ax->mode = tmp;
-                       ax->dev->addr_len        = AX25_ADDR_LEN;         /* sizeof an AX.25 addr */
-                       ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
-                       ax->dev->type            = ARPHRD_AX25;
-                       return 0;
-
-                case SIOCSIFHWADDR:
-                       return ax_set_mac_address(ax->dev, arg);
+       /* Read the characters out of the buffer */
+       while (count--) {
+               if (fp != NULL && *fp++) {
+                       if (!test_and_set_bit(AXF_ERROR, &ax->flags))
+                               ax->stats.rx_errors++;
+                       cp++;
+                       continue;
+               }
 
-               default:
-                       return -ENOIOCTLCMD;
+               kiss_unesc(ax, *cp++);
        }
+
+       mkiss_put(ax);
+       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
+           && tty->driver->unthrottle)
+               tty->driver->unthrottle(tty);
 }
 
-static int ax_open_dev(struct net_device *dev)
+static int mkiss_receive_room(struct tty_struct *tty)
 {
-       struct ax_disp *ax = netdev_priv(dev);
-
-       if (ax->tty == NULL)
-               return -ENODEV;
-
-       return 0;
+       return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
-
-/* Initialize the driver.  Called by network startup. */
-static int ax25_init(struct net_device *dev)
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void mkiss_write_wakeup(struct tty_struct *tty)
 {
-       struct ax_disp *ax = netdev_priv(dev);
-
-       static char ax25_bcast[AX25_ADDR_LEN] =
-               {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
-       static char ax25_test[AX25_ADDR_LEN] =
-               {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
-
-       if (ax == NULL)         /* Allocation failed ?? */
-               return -ENODEV;
+       struct mkiss *ax = mkiss_get(tty);
+       int actual;
 
-       /* Set up the "AX25 Control Block". (And clear statistics) */
-       memset(ax, 0, sizeof (struct ax_disp));
-       ax->magic  = AX25_MAGIC;
-       ax->dev    = dev;
+       if (!ax)
+               return;
 
-       /* Finish setting up the DEVICE info. */
-       dev->mtu             = AX_MTU;
-       dev->hard_start_xmit = ax_xmit;
-       dev->open            = ax_open_dev;
-       dev->stop            = ax_close;
-       dev->get_stats       = ax_get_stats;
-       dev->set_mac_address = ax_set_dev_mac_address;
-       dev->hard_header_len = 0;
-       dev->addr_len        = 0;
-       dev->type            = ARPHRD_AX25;
-       dev->tx_queue_len    = 10;
-       dev->hard_header     = ax_header;
-       dev->rebuild_header  = ax_rebuild_header;
+       if (ax->xleft <= 0)  {
+               /* Now serial buffer is almost free & we can start
+                * transmission of another packet
+                */
+               clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
-       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
-       memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
+               netif_wake_queue(ax->dev);
+               goto out;
+       }
 
-       /* New-style flags. */
-       dev->flags      = IFF_BROADCAST | IFF_MULTICAST;
+       actual = tty->driver->write(tty, ax->xhead, ax->xleft);
+       ax->xleft -= actual;
+       ax->xhead += actual;
 
-       return 0;
+out:
+       mkiss_put(ax);
 }
 
+static struct tty_ldisc ax_ldisc = {
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "mkiss",
+       .open           = mkiss_open,
+       .close          = mkiss_close,
+       .ioctl          = mkiss_ioctl,
+       .receive_buf    = mkiss_receive_buf,
+       .receive_room   = mkiss_receive_room,
+       .write_wakeup   = mkiss_write_wakeup
+};
 
-/* ******************************************************************** */
-/* *                   Init MKISS driver                             * */
-/* ******************************************************************** */
+static char banner[] __initdata = KERN_INFO \
+       "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
+static char msg_regfail[] __initdata = KERN_ERR \
+       "mkiss: can't register line discipline (err = %d)\n";
 
 static int __init mkiss_init_driver(void)
 {
@@ -886,64 +885,27 @@ static int __init mkiss_init_driver(void)
 
        printk(banner);
 
-       if (ax25_maxdev < 4)
-         ax25_maxdev = 4; /* Sanity */
+       if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0)
+               printk(msg_regfail);
 
-       if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n");
-               return -ENOMEM;
-       }
-
-       /* Clear the pointer array, we allocate devices when we need them */
-       memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */
-
-       /* Fill in our line protocol discipline, and register it */
-       ax_ldisc.magic          = TTY_LDISC_MAGIC;
-       ax_ldisc.name           = "mkiss";
-       ax_ldisc.open           = ax25_open;
-       ax_ldisc.close          = ax25_close;
-       ax_ldisc.ioctl          = (int (*)(struct tty_struct *, struct file *,
-                                       unsigned int, unsigned long))ax25_disp_ioctl;
-       ax_ldisc.receive_buf    = ax25_receive_buf;
-       ax_ldisc.receive_room   = ax25_receive_room;
-       ax_ldisc.write_wakeup   = ax25_write_wakeup;
-
-       if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) {
-               printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status);
-               kfree(ax25_ctrls);
-       }
        return status;
 }
 
+static const char msg_unregfail[] __exitdata = KERN_ERR \
+       "mkiss: can't unregister line discipline (err = %d)\n";
+
 static void __exit mkiss_exit_driver(void)
 {
-       int i;
-
-       for (i = 0; i < ax25_maxdev; i++) {
-               if (ax25_ctrls[i]) {
-                       /*
-                       * VSV = if dev->start==0, then device
-                       * unregistered while close proc.
-                       */
-                       if (netif_running(&ax25_ctrls[i]->dev))
-                               unregister_netdev(&ax25_ctrls[i]->dev);
-                       kfree(ax25_ctrls[i]);
-               }
-       }
+       int ret;
 
-       kfree(ax25_ctrls);
-       ax25_ctrls = NULL;
-
-       if ((i = tty_unregister_ldisc(N_AX25)))
-               printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i);
+       if ((ret = tty_unregister_ldisc(N_AX25)))
+               printk(msg_unregfail, ret);
 }
 
-MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");
+MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
 MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
-MODULE_PARM(ax25_maxdev, "i");
-MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_AX25);
+
 module_init(mkiss_init_driver);
 module_exit(mkiss_exit_driver);
-
index f8d3385c7842d3fe6f34b6d672da43353ce139a4..c83271b386215cefef859df73572f34bc535fa17 100644 (file)
@@ -119,7 +119,7 @@ struct ixgb_adapter;
  * so a DMA handle can be stored along with the buffer */
 struct ixgb_buffer {
        struct sk_buff *skb;
-       uint64_t dma;
+       dma_addr_t dma;
        unsigned long time_stamp;
        uint16_t length;
        uint16_t next_to_watch;
index 3aae110c55606ced13769acddf7d87c2649d1a4f..661a46b95a61e4a73a88f1774d8a3cc3564d8734 100644 (file)
@@ -565,24 +565,6 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw,
        }
 }
 
-/******************************************************************************
- * return the compatibility flags from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          compatibility flags if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_compatibility(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->compatibility));
-
-       return(0);
-}
 
 /******************************************************************************
  * return the Printed Board Assembly number from EEPROM
@@ -602,81 +584,6 @@ ixgb_get_ee_pba_number(struct ixgb_hw *hw)
        return(0);
 }
 
-/******************************************************************************
- * return the Initialization Control Word 1 from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Initialization Control Word 1 if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->init_ctrl_reg_1));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Initialization Control Word 2 from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Initialization Control Word 2 if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->init_ctrl_reg_2));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Subsystem Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Subsystem Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_subsystem_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->subsystem_id));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Sub Vendor Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Sub Vendor Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_subvendor_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->subvendor_id));
-
-       return(0);
-}
 
 /******************************************************************************
  * return the Device Id from EEPROM
@@ -694,81 +601,6 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw)
        if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
                return (le16_to_cpu(ee_map->device_id));
 
-       return(0);
-}
-
-/******************************************************************************
- * return the Vendor Id from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          Device Id if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_vendor_id(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->vendor_id));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the Software Defined Pins Register from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          SDP Register if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint16_t
-ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->swdpins_reg));
-
-       return(0);
+       return (0);
 }
 
-/******************************************************************************
- * return the D3 Power Management Bits from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          D3 Power Management Bits if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint8_t
-ixgb_get_ee_d3_power(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->d3_power));
-
-       return(0);
-}
-
-/******************************************************************************
- * return the D0 Power Management Bits from EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Returns:
- *          D0 Power Management Bits if EEPROM contents are valid, 0 otherwise
- ******************************************************************************/
-uint8_t
-ixgb_get_ee_d0_power(struct ixgb_hw *hw)
-{
-       struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
-
-       if(ixgb_check_and_get_eeprom_data(hw) == TRUE)
-               return (le16_to_cpu(ee_map->d0_power));
-
-       return(0);
-}
index 3fa113854eebc3d27c8cda25e0d5600a30a48e0e..9d026ed77ddd4250660ad117d76c2e319e6d3eda 100644 (file)
@@ -98,10 +98,10 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
 static int
 ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
-       ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+       ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
        ecmd->port = PORT_FIBRE;
        ecmd->transceiver = XCVR_EXTERNAL;
 
@@ -120,7 +120,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 static int
 ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        if(ecmd->autoneg == AUTONEG_ENABLE ||
           ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
@@ -130,6 +130,12 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
                ixgb_down(adapter, TRUE);
                ixgb_reset(adapter);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
+               
        } else
                ixgb_reset(adapter);
 
@@ -140,7 +146,7 @@ static void
 ixgb_get_pauseparam(struct net_device *netdev,
                         struct ethtool_pauseparam *pause)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        
        pause->autoneg = AUTONEG_DISABLE;
@@ -159,7 +165,7 @@ static int
 ixgb_set_pauseparam(struct net_device *netdev,
                         struct ethtool_pauseparam *pause)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        
        if(pause->autoneg == AUTONEG_ENABLE)
@@ -177,6 +183,11 @@ ixgb_set_pauseparam(struct net_device *netdev,
        if(netif_running(adapter->netdev)) {
                ixgb_down(adapter, TRUE);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        } else
                ixgb_reset(adapter);
                
@@ -186,19 +197,26 @@ ixgb_set_pauseparam(struct net_device *netdev,
 static uint32_t
 ixgb_get_rx_csum(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
+
        return adapter->rx_csum;
 }
 
 static int
 ixgb_set_rx_csum(struct net_device *netdev, uint32_t data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
+
        adapter->rx_csum = data;
 
        if(netif_running(netdev)) {
                ixgb_down(adapter,TRUE);
                ixgb_up(adapter);
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        } else
                ixgb_reset(adapter);
        return 0;
@@ -246,14 +264,15 @@ static void
 ixgb_get_regs(struct net_device *netdev,
                   struct ethtool_regs *regs, void *p)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint32_t *reg = p;
        uint32_t *reg_start = reg;
        uint8_t i;
 
        /* the 1 (one) below indicates an attempt at versioning, if the
-        * interface in ethtool or the driver this 1 should be incremented */
+        * interface in ethtool or the driver changes, this 1 should be
+        * incremented */
        regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id;
 
        /* General Registers */
@@ -283,7 +302,8 @@ ixgb_get_regs(struct net_device *netdev,
        *reg++ = IXGB_READ_REG(hw, RAIDC);      /*  19 */
        *reg++ = IXGB_READ_REG(hw, RXCSUM);     /*  20 */
 
-       for (i = 0; i < IXGB_RAR_ENTRIES; i++) {
+       /* there are 16 RAR entries in hardware, we only use 3 */
+       for(i = 0; i < 16; i++) {
                *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */
                *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */
        }
@@ -391,7 +411,7 @@ static int
 ixgb_get_eeprom(struct net_device *netdev,
                  struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        int i, max_len, first_word, last_word;
@@ -439,7 +459,7 @@ static int
 ixgb_set_eeprom(struct net_device *netdev,
                  struct ethtool_eeprom *eeprom, uint8_t *bytes)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint16_t *eeprom_buff;
        void *ptr;
@@ -497,7 +517,7 @@ static void
 ixgb_get_drvinfo(struct net_device *netdev,
                   struct ethtool_drvinfo *drvinfo)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        strncpy(drvinfo->driver,  ixgb_driver_name, 32);
        strncpy(drvinfo->version, ixgb_driver_version, 32);
@@ -512,7 +532,7 @@ static void
 ixgb_get_ringparam(struct net_device *netdev,
                struct ethtool_ringparam *ring)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_desc_ring *txdr = &adapter->tx_ring;
        struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
 
@@ -530,7 +550,7 @@ static int
 ixgb_set_ringparam(struct net_device *netdev,
                struct ethtool_ringparam *ring)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_desc_ring *txdr = &adapter->tx_ring;
        struct ixgb_desc_ring *rxdr = &adapter->rx_ring;
        struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new;
@@ -573,6 +593,11 @@ ixgb_set_ringparam(struct net_device *netdev,
                adapter->tx_ring = tx_new;
                if((err = ixgb_up(adapter)))
                        return err;
+               /* be optimistic about our link, since we were up before */
+               adapter->link_speed = 10000;
+               adapter->link_duplex = FULL_DUPLEX;
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
        }
 
        return 0;
@@ -607,7 +632,7 @@ ixgb_led_blink_callback(unsigned long data)
 static int
 ixgb_phys_id(struct net_device *netdev, uint32_t data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
@@ -643,7 +668,7 @@ static void
 ixgb_get_ethtool_stats(struct net_device *netdev, 
                struct ethtool_stats *stats, uint64_t *data)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int i;
 
        ixgb_update_stats(adapter);
index 97898efe7cc8075698ee51f7f35e7cd6a4cd63d1..8bcf31ed10c221ad5609f57f6fecc155d5fbc81a 100644 (file)
@@ -822,17 +822,8 @@ extern void ixgb_clear_vfta(struct ixgb_hw *hw);
 
 /* Access functions to eeprom data */
 void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr);
-uint16_t ixgb_get_ee_compatibility(struct ixgb_hw *hw);
 uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_subsystem_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_subvendor_id(struct ixgb_hw *hw);
 uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_vendor_id(struct ixgb_hw *hw);
-uint16_t ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw);
-uint8_t ixgb_get_ee_d3_power(struct ixgb_hw *hw);
-uint8_t ixgb_get_ee_d0_power(struct ixgb_hw *hw);
 boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
 uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
 
index 097b90ccf575b2d17e8f6f67458bcd6003dba96c..5c555373adbe5802054b2ed3558219269d0e9ca5 100644 (file)
 #include "ixgb.h"
 
 /* Change Log
+ * 1.0.96 04/19/05
+ * - Make needlessly global code static -- bunk@stusta.de
+ * - ethtool cleanup -- shemminger@osdl.org
+ * - Support for MODULE_VERSION -- linville@tuxdriver.com
+ * - add skb_header_cloned check to the tso path -- herbert@apana.org.au
  * 1.0.88 01/05/05
  * - include fix to the condition that determines when to quit NAPI - Robert Olsson
  * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
@@ -47,10 +52,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-
-#define DRV_VERSION "1.0.95-k2"DRIVERNAPI
+#define DRV_VERSION            "1.0.100-k2"DRIVERNAPI
 char ixgb_driver_version[] = DRV_VERSION;
-char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
+static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
 
 /* ixgb_pci_tbl - PCI Device ID Table
  *
@@ -145,10 +149,12 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
 /* some defines for controlling descriptor fetches in h/w */
-#define RXDCTL_PTHRESH_DEFAULT 128     /* chip considers prefech below this */
-#define RXDCTL_HTHRESH_DEFAULT 16      /* chip will only prefetch if tail is 
-                                          pushed this many descriptors from head */
 #define RXDCTL_WTHRESH_DEFAULT 16      /* chip writes back at this many or RXT0 */
+#define RXDCTL_PTHRESH_DEFAULT 0               /* chip considers prefech below
+                                                * this */
+#define RXDCTL_HTHRESH_DEFAULT 0               /* chip will only prefetch if tail
+                                                * is pushed this many descriptors
+                                                * from head */
 
 /**
  * ixgb_init_module - Driver Registration Routine
@@ -376,7 +382,7 @@ ixgb_probe(struct pci_dev *pdev,
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
        pci_set_drvdata(pdev, netdev);
-       adapter = netdev->priv;
+       adapter = netdev_priv(netdev);
        adapter->netdev = netdev;
        adapter->pdev = pdev;
        adapter->hw.back = adapter;
@@ -512,7 +518,7 @@ static void __devexit
 ixgb_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        unregister_netdev(netdev);
 
@@ -583,7 +589,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter)
 static int
 ixgb_open(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int err;
 
        /* allocate transmit descriptors */
@@ -626,7 +632,7 @@ err_setup_tx:
 static int
 ixgb_close(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ixgb_down(adapter, TRUE);
 
@@ -1017,7 +1023,7 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter)
 static int
 ixgb_set_mac(struct net_device *netdev, void *p)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
 
        if(!is_valid_ether_addr(addr->sa_data))
@@ -1043,7 +1049,7 @@ ixgb_set_mac(struct net_device *netdev, void *p)
 static void
 ixgb_set_multi(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        struct dev_mc_list *mc_ptr;
        uint32_t rctl;
@@ -1371,7 +1377,7 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
 static int
 ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        unsigned int first;
        unsigned int tx_flags = 0;
        unsigned long flags;
@@ -1425,7 +1431,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 static void
 ixgb_tx_timeout(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
        schedule_work(&adapter->tx_timeout_task);
@@ -1434,7 +1440,7 @@ ixgb_tx_timeout(struct net_device *netdev)
 static void
 ixgb_tx_timeout_task(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        ixgb_down(adapter, TRUE);
        ixgb_up(adapter);
@@ -1451,7 +1457,7 @@ ixgb_tx_timeout_task(struct net_device *netdev)
 static struct net_device_stats *
 ixgb_get_stats(struct net_device *netdev)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
 
        return &adapter->net_stats;
 }
@@ -1467,7 +1473,7 @@ ixgb_get_stats(struct net_device *netdev)
 static int
 ixgb_change_mtu(struct net_device *netdev, int new_mtu)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
        int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH;
 
@@ -1522,7 +1528,8 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
 
                multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32);
                /* fix up multicast stats by removing broadcasts */
-               multi -= bcast;
+               if(multi >= bcast)
+                       multi -= bcast;
                
                adapter->stats.mprcl += (multi & 0xFFFFFFFF);
                adapter->stats.mprch += (multi >> 32);
@@ -1641,7 +1648,7 @@ static irqreturn_t
 ixgb_intr(int irq, void *data, struct pt_regs *regs)
 {
        struct net_device *netdev = data;
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
        uint32_t icr = IXGB_READ_REG(hw, ICR);
 #ifndef CONFIG_IXGB_NAPI
@@ -1688,7 +1695,7 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs)
 static int
 ixgb_clean(struct net_device *netdev, int *budget)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        int work_to_do = min(*budget, netdev->quota);
        int tx_cleaned;
        int work_done = 0;
@@ -2017,7 +2024,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
 static void
 ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t ctrl, rctl;
 
        ixgb_irq_disable(adapter);
@@ -2055,7 +2062,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
 static void
 ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        /* add VID to filter table */
@@ -2069,7 +2076,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
 static void
 ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
 {
-       struct ixgb_adapter *adapter = netdev->priv;
+       struct ixgb_adapter *adapter = netdev_priv(netdev);
        uint32_t vfta, index;
 
        ixgb_irq_disable(adapter);
index 7fec613e1675496167be6fb2c7777209d7e0fe84..8423cb6875f06d75ac38f18881199a5f2b8acb41 100644 (file)
@@ -1,5 +1,10 @@
 /*
- * sonic.c
+ * jazzsonic.c
+ *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, and (from the mac68k project) introduced
+ * dhd's support for 16-bit cards.
  *
  * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
  * 
@@ -28,8 +33,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/bitops.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device;
 
 #define SONIC_MEM_SIZE 0x100
 
-#define SREGS_PAD(n)    u16 n;
-
 #include "sonic.h"
 
 /*
  * Macros to access SONIC registers
  */
-#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))
+#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg))
 
 #define SONIC_WRITE(reg,val)                                           \
 do {                                                                   \
-       *((volatile unsigned int *)base_addr+(reg)) = (val);            \
+       *((volatile unsigned int *)dev->base_addr+(reg)) = (val);               \
 } while (0)
 
 
-/* use 0 for production, 1 for verification, >2 for debug */
+/* use 0 for production, 1 for verification, >1 for debug */
 #ifdef SONIC_DEBUG
 static unsigned int sonic_debug = SONIC_DEBUG;
 #else 
@@ -85,18 +88,18 @@ static unsigned short known_revisions[] =
        0xffff                  /* end of list */
 };
 
-static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
-                               unsigned int irq)
+static int __init sonic_probe1(struct net_device *dev)
 {
        static unsigned version_printed;
        unsigned int silicon_revision;
        unsigned int val;
-       struct sonic_local *lp;
+       struct sonic_local *lp = netdev_priv(dev);
        int err = -ENODEV;
        int i;
 
-       if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
+       if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string))
                return -EBUSY;
+
        /*
         * get the Silicon Revision ID. If this is one of the known
         * one assume that we found a SONIC ethernet controller at
@@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
        if (sonic_debug  &&  version_printed++ == 0)
                printk(version);
 
-       printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr);
-
-       /* Fill in the 'dev' fields. */
-       dev->base_addr = base_addr;
-       dev->irq = irq;
+       printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr);
 
        /*
         * Put the sonic into software reset, then
@@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
                dev->dev_addr[i*2+1] = val >> 8;
        }
 
-       printk("HW Address ");
-       for (i = 0; i < 6; i++) {
-               printk("%2.2x", dev->dev_addr[i]);
-               if (i<5)
-                       printk(":");
-       }
-
-       printk(" IRQ %d\n", irq);
-
        err = -ENOMEM;
     
        /* Initialize the device structure. */
-       if (dev->priv == NULL) {
-               /*
-                * the memory be located in the same 64kb segment
-                */
-               lp = NULL;
-               i = 0;
-               do {
-                       lp = kmalloc(sizeof(*lp), GFP_KERNEL);
-                       if ((unsigned long) lp >> 16
-                           != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
-                               /* FIXME, free the memory later */
-                               kfree(lp);
-                               lp = NULL;
-                       }
-               } while (lp == NULL && i++ < 20);
-
-               if (lp == NULL) {
-                       printk("%s: couldn't allocate memory for descriptors\n",
-                              dev->name);
-                       goto out;
-               }
 
-               memset(lp, 0, sizeof(struct sonic_local));
-
-               /* get the virtual dma address */
-               lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp));
-               if (lp->cda_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for "
-                              "descriptors\n", dev->name);
-                       goto out1;
-               }
-
-               lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
-               lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
-               lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-       
-               /* allocate receive buffer area */
-               /* FIXME, maybe we should use skbs */
-               lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL);
-               if (!lp->rba) {
-                       printk("%s: couldn't allocate receive buffers\n",
-                              dev->name);
-                       goto out2;
-               }
+       lp->dma_bitmode = SONIC_BITMODE32;
 
-               /* get virtual dma address */
-               lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba),
-                                          SONIC_NUM_RRS * SONIC_RBSIZE);
-               if (lp->rba_laddr == ~0UL) {
-                       printk("%s: couldn't get DMA page entry for receive "
-                              "buffers\n",dev->name);
-                       goto out3;
-               }
-
-               /* now convert pointer to KSEG1 pointer */
-               lp->rba = (char *)KSEG1ADDR(lp->rba);
-               flush_cache_all();
-               dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
+       /* Allocate the entire chunk of memory for the descriptors.
+           Note that this cannot cross a 64K boundary. */
+       if ((lp->descriptors = dma_alloc_coherent(lp->device,
+                               SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                               &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
+               goto out;
        }
 
-       lp = (struct sonic_local *)dev->priv;
+       /* Now set up the pointers to point to the appropriate places */
+       lp->cda = lp->descriptors;
+       lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+       lp->cda_laddr = lp->descriptors_laddr;
+       lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+
        dev->open = sonic_open;
        dev->stop = sonic_close;
        dev->hard_start_xmit = sonic_send_packet;
-       dev->get_stats  = sonic_get_stats;
+       dev->get_stats = sonic_get_stats;
        dev->set_multicast_list = &sonic_multicast_list;
+       dev->tx_timeout = sonic_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
 
        /*
@@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr,
        SONIC_WRITE(SONIC_MPT,0xffff);
 
        return 0;
-out3:
-       kfree(lp->rba);
-out2:
-       vdma_free(lp->cda_laddr);
-out1:
-       kfree(lp);
 out:
-       release_region(base_addr, SONIC_MEM_SIZE);
+       release_region(dev->base_addr, SONIC_MEM_SIZE);
        return err;
 }
 
@@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device)
 {
        struct net_device *dev;
        struct sonic_local *lp;
-       unsigned long base_addr;
        int err = 0;
        int i;
 
@@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device)
        if (mips_machgroup != MACH_GROUP_JAZZ)
                return -ENODEV;
 
-       dev = alloc_etherdev(0);
+       dev = alloc_etherdev(sizeof(struct sonic_local));
        if (!dev)
                return -ENOMEM;
 
+       lp = netdev_priv(dev);
+       lp->device = device;
+       SET_NETDEV_DEV(dev, device);
+       SET_MODULE_OWNER(dev);
+
        netdev_boot_setup_check(dev);
-       base_addr = dev->base_addr;
 
-       if (base_addr >= KSEG0) { /* Check a single specified location. */
-               err = sonic_probe1(dev, base_addr, dev->irq);
-       } else if (base_addr != 0) { /* Don't probe at all. */
+       if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
+               err = sonic_probe1(dev);
+       } else if (dev->base_addr != 0) { /* Don't probe at all. */
                err = -ENXIO;
        } else {
                for (i = 0; sonic_portlist[i].port; i++) {
-                       int io = sonic_portlist[i].port;
-                       if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0)
+                       dev->base_addr = sonic_portlist[i].port;
+                       dev->irq = sonic_portlist[i].irq;
+                       if (sonic_probe1(dev) == 0)
                                break;
                }
                if (!sonic_portlist[i].port)
@@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device)
        if (err)
                goto out1;
 
+       printk("%s: MAC ", dev->name);
+       for (i = 0; i < 6; i++) {
+               printk("%2.2x", dev->dev_addr[i]);
+               if (i < 5)
+                       printk(":");
+       }
+       printk(" IRQ %d\n", dev->irq);
+
        return 0;
 
 out1:
-       lp = dev->priv;
-       vdma_free(lp->rba_laddr);
-       kfree(lp->rba);
-       vdma_free(lp->cda_laddr);
-       kfree(lp);
        release_region(dev->base_addr, SONIC_MEM_SIZE);
 out:
        free_netdev(dev);
@@ -296,21 +256,22 @@ out:
        return err;
 }
 
-/*
- *      SONIC uses a normal IRQ
- */
-#define sonic_request_irq       request_irq
-#define sonic_free_irq          free_irq
+MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
+module_param(sonic_debug, int, 0);
+MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
 
-#define sonic_chiptomem(x)      KSEG1ADDR(vdma_log2phys(x))
+#define SONIC_IRQ_FLAG SA_INTERRUPT
 
 #include "sonic.c"
 
 static int __devexit jazz_sonic_device_remove (struct device *device)
 {
        struct net_device *dev = device->driver_data;
+       struct sonic_local* lp = netdev_priv(dev);
 
        unregister_netdev (dev);
+       dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                         lp->descriptors, lp->descriptors_laddr);
        release_region (dev->base_addr, SONIC_MEM_SIZE);
        free_netdev (dev);
 
@@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = {
        .probe  = jazz_sonic_probe,
        .remove = __devexit_p(jazz_sonic_device_remove),
 };
-                                                                                
+
 static void jazz_sonic_platform_release (struct device *device)
 {
        struct platform_device *pldev;
@@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device)
 static int __init jazz_sonic_init_module(void)
 {
        struct platform_device *pldev;
+       int err;
 
-       if (driver_register(&jazz_sonic_driver)) {
+       if ((err = driver_register(&jazz_sonic_driver))) {
                printk(KERN_ERR "Driver registration failed\n");
-               return -ENOMEM;
+               return err;
        }
 
        jazz_sonic_device = NULL;
index 1f61f0cc95d81238a4120df48dc8a9afe2e067c0..690a1aae0b34705c6d04cb08bc31f1c3dbc72c0d 100644 (file)
@@ -68,6 +68,7 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
  * of largesending device modulo TCP checksum, which is ignored for loopback.
  */
 
+#ifdef LOOPBACK_TSO
 static void emulate_large_send_offload(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
@@ -119,6 +120,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
 
        dev_kfree_skb(skb);
 }
+#endif /* LOOPBACK_TSO */
 
 /*
  * The higher levels take care of making this non-reentrant (it's
@@ -130,12 +132,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
 
        skb_orphan(skb);
 
-       skb->protocol=eth_type_trans(skb,dev);
-       skb->dev=dev;
+       skb->protocol = eth_type_trans(skb,dev);
+       skb->dev = dev;
 #ifndef LOOPBACK_MUST_CHECKSUM
        skb->ip_summed = CHECKSUM_UNNECESSARY;
 #endif
 
+#ifdef LOOPBACK_TSO
        if (skb_shinfo(skb)->tso_size) {
                BUG_ON(skb->protocol != htons(ETH_P_IP));
                BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
@@ -143,14 +146,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
                emulate_large_send_offload(skb);
                return 0;
        }
-
+#endif
        dev->last_rx = jiffies;
 
        lb_stats = &per_cpu(loopback_stats, get_cpu());
        lb_stats->rx_bytes += skb->len;
-       lb_stats->tx_bytes += skb->len;
+       lb_stats->tx_bytes = lb_stats->rx_bytes;
        lb_stats->rx_packets++;
-       lb_stats->tx_packets++;
+       lb_stats->tx_packets = lb_stats->rx_packets;
        put_cpu();
 
        netif_rx(skb);
@@ -208,9 +211,12 @@ struct net_device loopback_dev = {
        .type                   = ARPHRD_LOOPBACK,      /* 0x0001*/
        .rebuild_header         = eth_rebuild_header,
        .flags                  = IFF_LOOPBACK,
-       .features               = NETIF_F_SG|NETIF_F_FRAGLIST
-                                 |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA
-                                 |NETIF_F_LLTX,
+       .features               = NETIF_F_SG | NETIF_F_FRAGLIST
+#ifdef LOOPBACK_TSO
+                                 | NETIF_F_TSO
+#endif
+                                 | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
+                                 | NETIF_F_LLTX,
        .ethtool_ops            = &loopback_ethtool_ops,
 };
 
index be28c65de729e5b4682b80788a70d48ebf3d9c7d..405e18365edef4c353b681937ebf63eb3971def7 100644 (file)
@@ -1,6 +1,12 @@
 /*
  * macsonic.c
  *
+ * (C) 2005 Finn Thain
+ *
+ * Converted to DMA API, converted to unified driver model, made it work as
+ * a module again, and from the mac68k project, introduced more 32-bit cards
+ * and dhd's support for 16-bit cards.
+ *
  * (C) 1998 Alan Cox
  *
  * Debugging Andreas Ehliar, Michael Schmitz
@@ -26,8 +32,8 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/types.h>
-#include <linux/ctype.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -41,8 +47,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
 
-#define SREGS_PAD(n)    u16 n;
+static char mac_sonic_string[] = "macsonic";
+static struct platform_device *mac_sonic_device;
 
 #include "sonic.h"
 
-#define SONIC_READ(reg) \
-       nubus_readl(base_addr+(reg))
-#define SONIC_WRITE(reg,val) \
-       nubus_writel((val), base_addr+(reg))
-#define sonic_read(dev, reg) \
-       nubus_readl((dev)->base_addr+(reg))
-#define sonic_write(dev, reg, val) \
-       nubus_writel((val), (dev)->base_addr+(reg))
-
+/* These should basically be bus-size and endian independent (since
+   the SONIC is at least smart enough that it uses the same endianness
+   as the host, unlike certain less enlightened Macintosh NICs) */
+#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \
+             + lp->reg_offset))
+#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \
+             + lp->reg_offset))
+
+/* use 0 for production, 1 for verification, >1 for debug */
+#ifdef SONIC_DEBUG
+static unsigned int sonic_debug = SONIC_DEBUG;
+#else 
+static unsigned int sonic_debug = 1;
+#endif
 
-static int sonic_debug;
 static int sonic_version_printed;
 
-static int reg_offset;
-
 extern int mac_onboard_sonic_probe(struct net_device* dev);
 extern int mac_nubus_sonic_probe(struct net_device* dev);
 
@@ -108,40 +117,6 @@ enum macsonic_type {
 
 #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr)
 
-struct net_device * __init macsonic_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(0);
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0)
-               sprintf(dev->name, "eth%d", unit);
-
-       SET_MODULE_OWNER(dev);
-
-       /* This will catch fatal stuff like -ENOMEM as well as success */
-       err = mac_onboard_sonic_probe(dev);
-       if (err == 0)
-               goto found;
-       if (err != -ENODEV)
-               goto out;
-       err = mac_nubus_sonic_probe(dev);
-       if (err)
-               goto out;
-found:
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       kfree(dev->priv);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
 /*
  * For reversing the PROM address
  */
@@ -160,103 +135,55 @@ static inline void bit_reverse_addr(unsigned char addr[6])
 
 int __init macsonic_init(struct net_device* dev)
 {
-       struct sonic_local* lp = NULL;
-       int i;
+       struct sonic_local* lp = netdev_priv(dev);
 
        /* Allocate the entire chunk of memory for the descriptors.
            Note that this cannot cross a 64K boundary. */
-       for (i = 0; i < 20; i++) {
-               unsigned long desc_base, desc_top;
-               if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) {
-                       printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
-                       return -ENOMEM;
-               }
-
-               desc_base = (unsigned long) lp;
-               desc_top = desc_base + sizeof(struct sonic_local);
-               if ((desc_top & 0xffff) >= (desc_base & 0xffff))
-                       break;
-               /* Hmm. try again (FIXME: does this actually work?) */
-               kfree(lp);
-               printk(KERN_DEBUG
-                      "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
-                      dev->name, desc_base, desc_top);
-       }
-
-       if (lp == NULL) {
-               printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
-                      dev->name);
+       if ((lp->descriptors = dma_alloc_coherent(lp->device,
+                   SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+                   &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
+               printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id);
                return -ENOMEM;
-       }                      
-
-       dev->priv = lp;
-
-#if 0
-       /* this code is only here as a curiousity...   mainly, where the 
-          fuck did SONIC_BUS_SCALE come from, and what was it supposed
-          to do?  the normal allocation works great for 32 bit stuffs..  */
+       }
 
        /* Now set up the pointers to point to the appropriate places */
-       lp->cda = lp->sonic_desc;
-       lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->cda = lp->descriptors;
+       lp->tda = lp->cda + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
        lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
-                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
        lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
-                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
 
-#endif
-       
-       memset(lp, 0, sizeof(struct sonic_local));
-
-       lp->cda_laddr = (unsigned int)&(lp->cda);
-       lp->tda_laddr = (unsigned int)lp->tda;
-       lp->rra_laddr = (unsigned int)lp->rra;
-       lp->rda_laddr = (unsigned int)lp->rda;
-
-       /* FIXME, maybe we should use skbs */
-       if ((lp->rba = (char *)
-            kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
-               printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
-               dev->priv = NULL;
-               kfree(lp);
-               return -ENOMEM;
-       }
-
-       lp->rba_laddr = (unsigned int)lp->rba;
-
-       {
-               int rs, ds;
-
-               /* almost always 12*4096, but let's not take chances */
-               rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
-               /* almost always under a page, but let's not take chances */
-               ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096;
-               kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
-               kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER);
-       }
-       
-#if 0
-       flush_cache_all();
-#endif
+       lp->cda_laddr = lp->descriptors_laddr;
+       lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
+       lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+                            * SONIC_BUS_SCALE(lp->dma_bitmode));
 
        dev->open = sonic_open;
        dev->stop = sonic_close;
        dev->hard_start_xmit = sonic_send_packet;
        dev->get_stats = sonic_get_stats;
        dev->set_multicast_list = &sonic_multicast_list;
+       dev->tx_timeout = sonic_tx_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
 
        /*
         * clear tally counter
         */
-       sonic_write(dev, SONIC_CRCT, 0xffff);
-       sonic_write(dev, SONIC_FAET, 0xffff);
-       sonic_write(dev, SONIC_MPT, 0xffff);
+       SONIC_WRITE(SONIC_CRCT, 0xffff);
+       SONIC_WRITE(SONIC_FAET, 0xffff);
+       SONIC_WRITE(SONIC_MPT, 0xffff);
 
        return 0;
 }
 
 int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
 {
+       struct sonic_local *lp = netdev_priv(dev);
        const int prom_addr = ONBOARD_SONIC_PROM_BASE;
        int i;
 
@@ -270,6 +197,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
           why this is so. */
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
                bit_reverse_addr(dev->dev_addr);
        else
@@ -281,22 +209,23 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
            the card... */
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
        {
                unsigned short val;
 
                printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
                
-               sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
-               sonic_write(dev, SONIC_CEP, 15);
+               SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+               SONIC_WRITE(SONIC_CEP, 15);
 
-               val = sonic_read(dev, SONIC_CAP2);
+               val = SONIC_READ(SONIC_CAP2);
                dev->dev_addr[5] = val >> 8;
                dev->dev_addr[4] = val & 0xff;
-               val = sonic_read(dev, SONIC_CAP1);
+               val = SONIC_READ(SONIC_CAP1);
                dev->dev_addr[3] = val >> 8;
                dev->dev_addr[2] = val & 0xff;
-               val = sonic_read(dev, SONIC_CAP0);
+               val = SONIC_READ(SONIC_CAP0);
                dev->dev_addr[1] = val >> 8;
                dev->dev_addr[0] = val & 0xff;
                
@@ -311,6 +240,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
 
        if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
            memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+           memcmp(dev->dev_addr, "\x00\x80\x19", 3) &&
            memcmp(dev->dev_addr, "\x00\x05\x02", 3))
        {
                /*
@@ -325,8 +255,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
 {
        /* Bwahahaha */
        static int once_is_more_than_enough;
-       int i;
-       int dma_bitmode;
+       struct sonic_local* lp = netdev_priv(dev);
+       int sr;
+       int commslot = 0;
        
        if (once_is_more_than_enough)
                return -ENODEV;
@@ -335,20 +266,18 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
        if (!MACH_IS_MAC)
                return -ENODEV;
 
-       printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
-
        if (macintosh_config->ether_type != MAC_ETHER_SONIC)
-       {
-               printk("none.\n");
                return -ENODEV;
-       }
-
+       
+       printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
+       
        /* Bogus probing, on the models which may or may not have
           Ethernet (BTW, the Ethernet *is* always at the same
           address, and nothing else lives there, at least if Apple's
           documentation is