--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 8 07:57:54 2007
+From: Andreas Oberritter <obi@linuxtv.org>
+Date: Sun, 08 Apr 2007 10:56:40 -0400
+Subject: DVB: pluto2: fix incorrect TSCR register setting
+To: stable@kernel.org
+Message-ID: <461902A8.7070309@linuxtv.org>
+
+From: Andreas Oberritter <obi@linuxtv.org>
+
+DVB: pluto2: fix incorrect TSCR register setting
+
+The ADEF bits in the TSCR register have different meanings in read
+and write mode. For this reason ADEF has to be reset on every
+read-modify-write operation.
+
+This patch introduces a special write function for this register, which
+takes care of it.
+
+Thanks to Holger Magnussen for pointing my nose at this problem.
+
+(cherry picked from commit 1489f90a49f0603a393e1800d729050f6e332bec)
+
+Signed-off-by: Andreas Oberritter <obi@linuxtv.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/pluto2/pluto2.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+--- a/drivers/media/dvb/pluto2/pluto2.c
++++ b/drivers/media/dvb/pluto2/pluto2.c
+@@ -149,6 +149,15 @@ static inline void pluto_rw(struct pluto
+ writel(val, &pluto->io_mem[reg]);
+ }
+
++static void pluto_write_tscr(struct pluto *pluto, u32 val)
++{
++ /* set the number of packets */
++ val &= ~TSCR_ADEF;
++ val |= TS_DMA_PACKETS / 2;
++
++ pluto_writereg(pluto, REG_TSCR, val);
++}
++
+ static void pluto_setsda(void *data, int state)
+ {
+ struct pluto *pluto = data;
+@@ -213,11 +222,11 @@ static void pluto_reset_ts(struct pluto
+
+ if (val & TSCR_RSTN) {
+ val &= ~TSCR_RSTN;
+- pluto_writereg(pluto, REG_TSCR, val);
++ pluto_write_tscr(pluto, val);
+ }
+ if (reenable) {
+ val |= TSCR_RSTN;
+- pluto_writereg(pluto, REG_TSCR, val);
++ pluto_write_tscr(pluto, val);
+ }
+ }
+
+@@ -339,7 +348,7 @@ static irqreturn_t pluto_irq(int irq, vo
+ }
+
+ /* ACK the interrupt */
+- pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK);
++ pluto_write_tscr(pluto, tscr | TSCR_IACK);
+
+ return IRQ_HANDLED;
+ }
+@@ -348,9 +357,6 @@ static void __devinit pluto_enable_irqs(
+ {
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+- /* set the number of packets */
+- val &= ~TSCR_ADEF;
+- val |= TS_DMA_PACKETS / 2;
+ /* disable AFUL and LOCK interrupts */
+ val |= (TSCR_MSKA | TSCR_MSKL);
+ /* enable DMA and OVERFLOW interrupts */
+@@ -358,7 +364,7 @@ static void __devinit pluto_enable_irqs(
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+- pluto_writereg(pluto, REG_TSCR, val);
++ pluto_write_tscr(pluto, val);
+ }
+
+ static void pluto_disable_irqs(struct pluto *pluto)
+@@ -370,7 +376,7 @@ static void pluto_disable_irqs(struct pl
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+- pluto_writereg(pluto, REG_TSCR, val);
++ pluto_write_tscr(pluto, val);
+ }
+
+ static int __devinit pluto_hw_init(struct pluto *pluto)
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 8 07:55:51 2007
+From: Andreas Oberritter <obi@linuxtv.org>
+Date: Sun, 08 Apr 2007 10:54:27 -0400
+Subject: DVB: tda10086: fix DiSEqC message length
+To: stable@kernel.org
+Message-ID: <46190223.1020501@linuxtv.org>
+
+From: Andreas Oberritter <obi@linuxtv.org>
+
+DVB: tda10086: fix DiSEqC message length
+
+Setting the message length to zero means to send one byte, so you need a
+subtraction instead of an addition.
+
+(cherry picked from commit d420cb44693b8370cbf06c3e31b4b5dec66c9f86)
+
+Signed-off-by: Andreas Oberritter <obi@linuxtv.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/frontends/tda10086.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/dvb/frontends/tda10086.c
++++ b/drivers/media/dvb/frontends/tda10086.c
+@@ -212,7 +212,7 @@ static int tda10086_send_master_cmd (str
+ for(i=0; i< cmd->msg_len; i++) {
+ tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
+ }
+- tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len + 1) << 4));
++ tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len - 1) << 4));
+
+ tda10086_diseqc_wait(state);
+
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Apr 10 20:32:35 2007
+From: Neil Brown <neilb@suse.de>
+Date: Wed, 11 Apr 2007 13:31:07 +1000
+Subject: Fix calculation for size of filemap_attr array in md/bitmap.
+To: Reuben Farrelly <reuben-linuxkernel@reub.net>
+Cc: linux-raid@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>, stable@kernel.org, linux-kernel@vger.kernel.org
+Message-ID: <17948.22139.163549.68639@notabene.brown>
+
+From: Neil Brown <neilb@suse.de>
+
+If 'num_pages' were ever 1 more than a multiple of 8 (32bit platforms)
+for of 16 (64 bit platforms). filemap_attr would be allocated one
+'unsigned long' shorter than required. We need a round-up in there.
+
+
+Signed-off-by: Neil Brown <neilb@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/md/bitmap.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/md/bitmap.c
++++ b/drivers/md/bitmap.c
+@@ -863,9 +863,7 @@ static int bitmap_init_from_disk(struct
+
+ /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
+ bitmap->filemap_attr = kzalloc(
+- (((num_pages*4/8)+sizeof(unsigned long)-1)
+- /sizeof(unsigned long))
+- *sizeof(unsigned long),
++ roundup( DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
+ GFP_KERNEL);
+ if (!bitmap->filemap_attr)
+ goto out;
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Apr 11 02:09:00 2007
+From: Adam Kropelin <akropel1@rochester.rr.com>
+Date: Wed, 11 Apr 2007 11:13:13 +0200 (CEST)
+Subject: HID: Do not discard truncated input reports
+To: stable@kernel.org
+Cc: Adam Kropelin <akropel1@rochester.rr.com>
+Message-ID: <Pine.LNX.4.64.0704111111400.13232@jikos.suse.cz>
+
+From: Adam Kropelin <akropel1@rochester.rr.com>
+
+HID: Do not discard truncated input reports
+
+Truncated reports should not be discarded since it prevents buggy
+devices from communicating with userspace.
+
+Prior to the regession introduced in 2.6.20, a shorter-than-expected
+report in hid_input_report() was passed thru after having the missing
+bytes cleared. This behavior was established over a few patches in the
+2.6.early-teens days, including commit
+cd6104572bca9e4afe0dcdb8ecd65ef90b01297b.
+
+This patch restores the previous behavior and fixes the regression.
+
+Signed-off-by: Adam Kropelin <akropel1@rochester.rr.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/hid/hid-core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -975,7 +975,7 @@ int hid_input_report(struct hid_device *
+
+ if (size < rsize) {
+ dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
+- return -1;
++ memset(data + size, 0, rsize - size);
+ }
+
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
--- /dev/null
+From stable-bounces@linux.kernel.org Mon Apr 2 05:26:55 2007
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Mon, 02 Apr 2007 14:25:31 +0200
+Subject: i386: fix file_read_actor() and pipe_read() for original i386 systems
+To: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Manfred Spraul <manfred@colorfullife.com>, Adrian Bunk <bunk@stusta.de>, Ingo Molnar <mingo@elte.hu>, Andrew Morton <akpm@linux-foundation.org>
+Message-ID: <1175516731.28263.129.camel@localhost.localdomain>
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+The __copy_to_user_inatomic() calls in file_read_actor() and pipe_read()
+are broken on original i386 machines, where WP-works-ok == false, as
+__copy_to_user_inatomic() on such systems calls functions which might
+sleep and/or contain cond_resched() calls inside of a kmap_atomic()
+region.
+
+The original check for WP-works-ok was in access_ok(), but got moved
+during the 2.5 series to fix a race vs. swap.
+
+Return the number of bytes to copy in the case where we are in an atomic
+region, so the non atomic code pathes in file_read_actor() and
+pipe_read() are taken.
+
+This could be optimized to avoid the kmap_atomic by moving the check for
+WP-works-ok into fault_in_pages_writeable(), but this is more intrusive
+and can be done later.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Acked-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/i386/lib/usercopy.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/arch/i386/lib/usercopy.c
++++ b/arch/i386/lib/usercopy.c
+@@ -10,6 +10,7 @@
+ #include <linux/blkdev.h>
+ #include <linux/module.h>
+ #include <linux/backing-dev.h>
++#include <linux/interrupt.h>
+ #include <asm/uaccess.h>
+ #include <asm/mmx.h>
+
+@@ -719,6 +720,14 @@ unsigned long __copy_to_user_ll(void __u
+ #ifndef CONFIG_X86_WP_WORKS_OK
+ if (unlikely(boot_cpu_data.wp_works_ok == 0) &&
+ ((unsigned long )to) < TASK_SIZE) {
++ /*
++ * When we are in an atomic section (see
++ * mm/filemap.c:file_read_actor), return the full
++ * length to take the slow path.
++ */
++ if (in_atomic())
++ return n;
++
+ /*
+ * CPU does not honor the WP bit when writing
+ * from supervisory mode, and due to preemption or SMP,
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 1 11:41:56 2007
+From: Jan Beulich <jbeulich@novell.com>
+Date: Sun, 1 Apr 2007 20:41:26 +0200
+Subject: kbuild: fix dependency generation
+To: Oleg Verych <olecom@flower.upol.cz>
+Cc: Andrew Morton <akpm@osdl.org>, Linus Torvalds <torvalds@osdl.org>, stable@kernel.org, Jan Beulich <jbeulich@novell.com>
+Message-ID: <20070401184126.GA10113@uranus.ravnborg.org>
+Content-Disposition: inline
+
+From: Jan Beulich <jbeulich@novell.com>
+
+Commit 2e3646e51b2d6415549b310655df63e7e0d7a080 changed the way
+the split config tree is built, but failed to also adjust fixdep
+accordingly - if changing a config option from or to m, files
+referencing the respective CONFIG_..._MODULE (but not the
+corresponding CONFIG_...) didn't get rebuilt.
+
+The problem is that trisate symbol are represent with three
+different symbols:
+SYMBOL=n => no symbol defined
+SYMBOL=y => CONFIG_SYMBOL defined to '1'
+SYMBOL=m => CONFIG_SYMBOL_MODULE defined to '1'
+
+But conf_split_config do not distingush between the =y and =m case,
+so only the =y case is honoured.
+This is fixed in fixdep so when a CONFIG symbol with
+_MODULE is found we skip that part and only look
+for the CONFIG_SYMBOL version.
+
+Signed-off-by: Jan Beulich <jbeulich@novell.com>
+Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ scripts/basic/fixdep.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/scripts/basic/fixdep.c
++++ b/scripts/basic/fixdep.c
+@@ -28,9 +28,11 @@
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *
+- * To be exact, split-include populates a tree in include/config/,
+- * e.g. include/config/his/driver.h, which contains the #define/#undef
+- * for the CONFIG_HIS_DRIVER option.
++ * kconfig populates a tree in include/config/ with an empty file
++ * for each config symbol and when the configuration is updated
++ * the files representing changed config options are touched
++ * which then let make pick up the changes and the files that use
++ * the config symbols are rebuilt.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+@@ -245,6 +247,8 @@ void parse_config_file(char *map, size_t
+ continue;
+
+ found:
++ if (!memcmp(q - 7, "_MODULE", 7))
++ q -= 7;
+ use_config(p+7, q-p-7);
+ }
+ }
--- /dev/null
+kbuild-fix-dependency-generation.patch
+i386-fix-file_read_actor-and-pipe_read-for-original-i386-systems.patch
+sky2-reliable-recovery.patch
+skge-carrier.patch
+sky2-carrier.patch
+sky2-ec-clocks-resume.patch
+sky2-ec-u-a1.patch
+dvb-tda10086-fix-diseqc-message-length.patch
+dvb-pluto2-fix-incorrect-tscr-register-setting.patch
+hid-do-not-discard-truncated-input-reports.patch
+fix-calculation-for-size-of-filemap_attr-array-in-md-bitmap.patch
--- /dev/null
+From stable-bounces@linux.kernel.org Sat Apr 7 16:45:03 2007
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+Date: Sat, 07 Apr 2007 16:42:06 -0700
+Subject: skge: turn carrier off when down
+Cc: netdev@vger.kernel.org, stable@kernel.org
+Message-ID: <20070407234235.566060329@linux-foundation.org>
+Content-Disposition: inline; filename=skge-carrier.patch
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Driver needs to turn off carrier when down, otherwise it can
+confuse bonding and bridging and looks like carrier is on immediately
+when it is brought back up.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/skge.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/skge.c
++++ b/drivers/net/skge.c
+@@ -2462,6 +2462,7 @@ static int skge_down(struct net_device *
+ printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
+
+ netif_stop_queue(dev);
++ netif_carrier_off(dev);
+ if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
+ cancel_rearming_delayed_work(&skge->link_thread);
+
--- /dev/null
+From stable-bounces@linux.kernel.org Sat Apr 7 16:44:38 2007
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+Date: Sat, 07 Apr 2007 16:42:07 -0700
+Subject: sky2: turn carrier off when down
+Cc: netdev@vger.kernel.org, stable@kernel.org
+Message-ID: <20070407234235.799379023@linux-foundation.org>
+Content-Disposition: inline; filename=sky2-carrier.patch
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Driver needs to turn off carrier when down.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/sky2.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -1506,6 +1506,7 @@ static int sky2_down(struct net_device *
+
+ /* Stop more packets from being queued */
+ netif_stop_queue(dev);
++ netif_carrier_off(dev);
+
+ /* Disable port IRQ */
+ imask = sky2_read32(hw, B0_IMSK);
--- /dev/null
+From stable-bounces@linux.kernel.org Sat Apr 7 16:44:47 2007
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+Date: Sat, 07 Apr 2007 16:42:08 -0700
+Subject: sky2: turn on clocks when doing resume
+Cc: netdev@vger.kernel.org, stable@kernel.org
+Message-ID: <20070407234236.129627887@linux-foundation.org>
+Content-Disposition: inline; filename=sky2-ec-clocks-resume.patch
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Some of these chips are disabled until clock is enabled.
+This fixes:
+ http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=404107
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/sky2.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -2421,6 +2421,10 @@ static int sky2_reset(struct sky2_hw *hw
+ return -EOPNOTSUPP;
+ }
+
++ /* Make sure and enable all clocks */
++ if (hw->chip_id == CHIP_ID_YUKON_EC_U)
++ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
++
+ hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+
+ /* This rev is really old, and requires untested workarounds */
+@@ -3639,6 +3643,9 @@ static int sky2_resume(struct pci_dev *p
+
+ pci_restore_state(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
++
++ if (hw->chip_id == CHIP_ID_YUKON_EC_U)
++ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ sky2_set_power_state(hw, PCI_D0);
+
+ err = sky2_reset(hw);
--- /dev/null
+From stable-bounces@linux.kernel.org Sat Apr 7 16:45:12 2007
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+Date: Sat, 07 Apr 2007 16:42:09 -0700
+Subject: sky2: phy workarounds for Yukon EC-U A1
+Cc: netdev@vger.kernel.org, stable@kernel.org
+Message-ID: <20070407234236.256434192@linux-foundation.org>
+Content-Disposition: inline; filename=sky2-ec-u-a1.patch
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+The workaround Yukon EC-U wasn't comparing with correct
+version and wasn't doing correct setup. Without it, 88e8056
+throws all sorts of errors.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/sky2.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -524,9 +524,9 @@ static void sky2_phy_init(struct sky2_hw
+ ledover &= ~PHY_M_LED_MO_RX;
+ }
+
+- if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) {
++ if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
++ hw->chip_rev == CHIP_REV_YU_EC_U_A1) {
+ /* apply fixes in PHY AFE */
+- pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
+
+ /* increase differential signal amplitude in 10BASE-T */
+@@ -538,7 +538,7 @@ static void sky2_phy_init(struct sky2_hw
+ gm_phy_write(hw, port, 0x17, 0x2002);
+
+ /* set page register to 0 */
+- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
++ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+ } else {
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Apr 4 11:12:04 2007
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+Date: Wed, 4 Apr 2007 11:10:43 -0700
+Subject: sky2: reliable recovery
+To: stable@kernel.org
+Cc: <davef1624@aol.com>
+Message-ID: <20070404111043.28ecce69@freekitty>
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+This adds working recovery from transmit timeouts. Previous code
+didn't do enough to truly reset chip.
+
+It is a backport of the 2.6.21 code.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/sky2.c | 81 +++++++++++++++++++++++++++++++++++------------------
+ drivers/net/sky2.h | 1
+ 2 files changed, 56 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/sky2.c
++++ b/drivers/net/sky2.c
+@@ -1802,38 +1802,22 @@ static void sky2_tx_timeout(struct net_d
+ {
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+- unsigned txq = txqaddr[sky2->port];
+- u16 report, done;
++ unsigned port = sky2->port;
+
+ if (netif_msg_timer(sky2))
+ printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
+
+- report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
+- done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
+-
+- printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
+- dev->name,
+- sky2->tx_cons, sky2->tx_prod, report, done);
+-
+- if (report != done) {
+- printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
++ /* Get information for bug report :-) */
++ printk(KERN_INFO PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
++ dev->name, sky2->tx_cons, sky2->tx_prod,
++ sky2_read16(hw, port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
++ sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
+
+- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
+- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
+- } else if (report != sky2->tx_cons) {
+- printk(KERN_INFO PFX "status report lost?\n");
+- sky2_tx_complete(sky2, report);
+- } else {
+- printk(KERN_INFO PFX "hardware hung? flushing\n");
++ printk(KERN_INFO PFX "gmac control %#x status %#x\n",
++ gma_read16(hw, port, GM_GP_CTRL), gma_read16(hw, port, GM_GP_STAT));
+
+- sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
+- sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+-
+- sky2_tx_complete(sky2, sky2->tx_prod);
+-
+- sky2_qset(hw, txq);
+- sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
+- }
++ /* can't restart safely under softirq */
++ schedule_work(&hw->restart_work);
+ }
+
+ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
+@@ -2565,6 +2549,49 @@ static int sky2_reset(struct sky2_hw *hw
+ return 0;
+ }
+
++static void sky2_restart(struct work_struct *work)
++{
++ struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
++ struct net_device *dev;
++ int i, err;
++
++ dev_dbg(&hw->pdev->dev, "restarting\n");
++
++ del_timer_sync(&hw->idle_timer);
++
++ rtnl_lock();
++ sky2_write32(hw, B0_IMSK, 0);
++ sky2_read32(hw, B0_IMSK);
++
++ netif_poll_disable(hw->dev[0]);
++
++ for (i = 0; i < hw->ports; i++) {
++ dev = hw->dev[i];
++ if (netif_running(dev))
++ sky2_down(dev);
++ }
++
++ sky2_reset(hw);
++ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
++ netif_poll_enable(hw->dev[0]);
++
++ for (i = 0; i < hw->ports; i++) {
++ dev = hw->dev[i];
++ if (netif_running(dev)) {
++ err = sky2_up(dev);
++ if (err) {
++ printk(KERN_INFO PFX "%s: could not restart %d\n",
++ dev->name, err);
++ dev_close(dev);
++ }
++ }
++ }
++
++ sky2_idle_start(hw);
++
++ rtnl_unlock();
++}
++
+ static u32 sky2_supported_modes(const struct sky2_hw *hw)
+ {
+ if (sky2_is_copper(hw)) {
+@@ -3508,6 +3535,8 @@ static int __devinit sky2_probe(struct p
+ }
+
+ setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
++ INIT_WORK(&hw->restart_work, sky2_restart);
++
+ sky2_idle_start(hw);
+
+ pci_set_drvdata(pdev, hw);
+--- a/drivers/net/sky2.h
++++ b/drivers/net/sky2.h
+@@ -1898,6 +1898,7 @@ struct sky2_hw {
+ dma_addr_t st_dma;
+
+ struct timer_list idle_timer;
++ struct work_struct restart_work;
+ int msi;
+ wait_queue_head_t msi_wait;
+ };