diff -ruN linux-2.4.20/Documentation/filesystems/Locking linux-2.4.20.updates/Documentation/filesystems/Locking --- linux-2.4.20/Documentation/filesystems/Locking Thu Nov 28 16:53:08 2002 +++ linux-2.4.20.updates/Documentation/filesystems/Locking Sun Mar 23 14:56:29 2003 @@ -93,6 +93,7 @@ void (*delete_inode) (struct inode *); void (*put_super) (struct super_block *); void (*write_super) (struct super_block *); + int (*sync_fs) (struct super_block *); int (*statfs) (struct super_block *, struct statfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); @@ -108,6 +109,7 @@ clear_inode: no put_super: yes yes maybe (see below) write_super: yes yes maybe (see below) +write_super: yes no maybe (see below) statfs: yes no no remount_fs: yes yes maybe (see below) umount_begin: yes no maybe (see below) diff -ruN linux-2.4.20/fs/buffer.c linux-2.4.20.updates/fs/buffer.c --- linux-2.4.20/fs/buffer.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20.updates/fs/buffer.c Sun Mar 23 14:56:29 2003 @@ -328,6 +328,8 @@ if (sb->s_dirt && sb->s_op && sb->s_op->write_super) sb->s_op->write_super(sb); unlock_super(sb); + if (sb->s_op && sb->s_op->sync_fs) + sb->s_op->sync_fs(sb); unlock_kernel(); return sync_buffers(dev, 1); @@ -346,7 +348,7 @@ lock_kernel(); sync_inodes(dev); DQUOT_SYNC(dev); - sync_supers(dev); + sync_supers(dev, 1); unlock_kernel(); return sync_buffers(dev, 1); @@ -2833,7 +2835,7 @@ { lock_kernel(); sync_unlocked_inodes(); - sync_supers(0); + sync_supers(0, 0); unlock_kernel(); for (;;) { diff -ruN linux-2.4.20/fs/ext3/namei.c linux-2.4.20.updates/fs/ext3/namei.c --- linux-2.4.20/fs/ext3/namei.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20.updates/fs/ext3/namei.c Sun Mar 23 14:56:29 2003 @@ -429,8 +429,11 @@ { int err = ext3_add_entry(handle, dentry, inode); if (!err) { - d_instantiate(dentry, inode); - return 0; + err = ext3_mark_inode_dirty(handle, inode); + if (err == 0) { + d_instantiate(dentry, inode); + return 0; + } } ext3_dec_count(handle, inode); iput(inode); @@ -465,7 +468,6 @@ inode->i_fop = &ext3_file_operations; inode->i_mapping->a_ops = &ext3_aops; err = ext3_add_nondir(handle, dentry, inode); - ext3_mark_inode_dirty(handle, inode); } ext3_journal_stop(handle, dir); return err; @@ -490,7 +492,6 @@ if (!IS_ERR(inode)) { init_special_inode(inode, mode, rdev); err = ext3_add_nondir(handle, dentry, inode); - ext3_mark_inode_dirty(handle, inode); } ext3_journal_stop(handle, dir); return err; @@ -934,7 +935,6 @@ } inode->u.ext3_i.i_disksize = inode->i_size; err = ext3_add_nondir(handle, dentry, inode); - ext3_mark_inode_dirty(handle, inode); out_stop: ext3_journal_stop(handle, dir); return err; @@ -971,7 +971,6 @@ atomic_inc(&inode->i_count); err = ext3_add_nondir(handle, dentry, inode); - ext3_mark_inode_dirty(handle, inode); ext3_journal_stop(handle, dir); return err; } diff -ruN linux-2.4.20/fs/ext3/super.c linux-2.4.20.updates/fs/ext3/super.c --- linux-2.4.20/fs/ext3/super.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20.updates/fs/ext3/super.c Sun Mar 23 14:56:29 2003 @@ -47,6 +47,8 @@ static void ext3_clear_journal_err(struct super_block * sb, struct ext3_super_block * es); +static int ext3_sync_fs(struct super_block * sb); + #ifdef CONFIG_JBD_DEBUG int journal_no_write[2]; @@ -454,6 +456,7 @@ delete_inode: ext3_delete_inode, /* BKL not held. We take it */ put_super: ext3_put_super, /* BKL held */ write_super: ext3_write_super, /* BKL held */ + sync_fs: ext3_sync_fs, write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */ unlockfs: ext3_unlockfs, /* BKL not held. We take it */ statfs: ext3_statfs, /* BKL held */ @@ -1577,24 +1580,22 @@ * This implicitly triggers the writebehind on sync(). */ -static int do_sync_supers = 0; -MODULE_PARM(do_sync_supers, "i"); -MODULE_PARM_DESC(do_sync_supers, "Write superblocks synchronously"); - void ext3_write_super (struct super_block * sb) { + if (down_trylock(&sb->s_lock) == 0) + BUG(); + sb->s_dirt = 0; + log_start_commit(EXT3_SB(sb)->s_journal, NULL); +} + +static int ext3_sync_fs(struct super_block *sb) +{ tid_t target; - if (down_trylock(&sb->s_lock) == 0) - BUG(); /* aviro detector */ sb->s_dirt = 0; target = log_start_commit(EXT3_SB(sb)->s_journal, NULL); - - if (do_sync_supers) { - unlock_super(sb); - log_wait_commit(EXT3_SB(sb)->s_journal, target); - lock_super(sb); - } + log_wait_commit(EXT3_SB(sb)->s_journal, target); + return 0; } /* diff -ruN linux-2.4.20/fs/super.c linux-2.4.20.updates/fs/super.c --- linux-2.4.20/fs/super.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20.updates/fs/super.c Sun Mar 23 14:56:29 2003 @@ -445,7 +445,7 @@ * hold up the sync while mounting a device. (The newly * mounted device won't need syncing.) */ -void sync_supers(kdev_t dev) +void sync_supers(kdev_t dev, int wait) { struct super_block * sb; @@ -454,6 +454,8 @@ if (sb) { if (sb->s_dirt) write_super(sb); + if (wait && sb->s_op && sb->s_op->sync_fs) + sb->s_op->sync_fs(sb); drop_super(sb); } return; @@ -467,6 +469,8 @@ spin_unlock(&sb_lock); down_read(&sb->s_umount); write_super(sb); + if (wait && sb->s_op && sb->s_op->sync_fs) + sb->s_op->sync_fs(sb); drop_super(sb); goto restart; } else diff -ruN linux-2.4.20/include/linux/fs.h linux-2.4.20.updates/include/linux/fs.h --- linux-2.4.20/include/linux/fs.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20.updates/include/linux/fs.h Sun Mar 23 14:58:20 2003 @@ -894,6 +894,7 @@ void (*delete_inode) (struct inode *); void (*put_super) (struct super_block *); void (*write_super) (struct super_block *); + int (*sync_fs) (struct super_block *); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); int (*statfs) (struct super_block *, struct statfs *); @@ -1240,7 +1241,7 @@ extern int inode_has_buffers(struct inode *); extern int filemap_fdatasync(struct address_space *); extern int filemap_fdatawait(struct address_space *); -extern void sync_supers(kdev_t); +extern void sync_supers(kdev_t, int wait); extern int bmap(struct inode *, int); extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int); --- linux-2.4.20.orig/include/linux/pci_ids.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/linux/pci_ids.h Sun Feb 16 13:59:52 2003 @@ -1544,6 +1581,9 @@ #define PCI_DEVICE_ID_TIGON3_5702FE 0x164d #define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 #define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 +#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 +#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 +#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 #define PCI_VENDOR_ID_SYBA 0x1592 #define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 --- linux-2.4.20.orig/drivers/net/tg3.h Thu Nov 28 16:53:14 2002 +++ linux-2.4.20/drivers/net/tg3.h Tue Feb 18 21:08:05 2003 @@ -2,7 +2,7 @@ * tg3.h: Definitions for Broadcom Tigon3 ethernet driver. * * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) - * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com) + * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com) */ #ifndef _T3_H @@ -25,9 +25,6 @@ #define RX_STD_MAX_SIZE 1536 #define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */ -#if TG3_MINI_RING_WORKS -#define RX_MINI_MAX_SIZE 256 -#endif /* First 256 bytes are a mirror of PCI config space. */ #define TG3PCI_VENDOR 0x00000000 @@ -116,6 +113,8 @@ #define CHIPREV_ID_5703_A2 0x1002 #define CHIPREV_ID_5703_A3 0x1003 #define CHIPREV_ID_5704_A0 0x2000 +#define CHIPREV_ID_5704_A1 0x2001 +#define CHIPREV_ID_5704_A2 0x2002 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -457,6 +456,7 @@ #define RCV_RULE_DISABLE_MASK 0x7fffffff #define MAC_RCV_RULE_CFG 0x00000500 #define RCV_RULE_CFG_DEFAULT_CLASS 0x00000008 +#define MAC_LOW_WMARK_MAX_RX_FRAME 0x00000504 /* 0x504 --> 0x590 unused */ #define MAC_SERDES_CFG 0x00000590 #define MAC_SERDES_STAT 0x00000594 @@ -1139,6 +1139,7 @@ #define GRC_MISC_CFG_BOARD_ID_5703S 0x00002000 #define GRC_MISC_CFG_BOARD_ID_5704 0x00000000 #define GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000 +#define GRC_MISC_CFG_BOARD_ID_5704_A2 0x00008000 #define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000 #define GRC_LOCAL_CTRL 0x00006808 #define GRC_LCLCTRL_INT_ACTIVE 0x00000001 @@ -1301,9 +1302,7 @@ #define NIC_SRAM_MAC_ADDR_HIGH_MBOX 0x00000c14 #define NIC_SRAM_MAC_ADDR_LOW_MBOX 0x00000c18 -#if TG3_MINI_RING_WORKS #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 -#endif #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 #define NIC_SRAM_DMA_DESC_POOL_SIZE 0x00002000 @@ -1453,9 +1452,7 @@ #define RXD_FLAGS_SHIFT 0 #define RXD_FLAG_END 0x0004 -#if TG3_MINI_RING_WORKS #define RXD_FLAG_MINI 0x0800 -#endif #define RXD_FLAG_JUMBO 0x0020 #define RXD_FLAG_VLAN 0x0040 #define RXD_FLAG_ERROR 0x0400 @@ -1490,9 +1487,7 @@ #define RXD_OPAQUE_INDEX_SHIFT 0 #define RXD_OPAQUE_RING_STD 0x00010000 #define RXD_OPAQUE_RING_JUMBO 0x00020000 -#if TG3_MINI_RING_WORKS #define RXD_OPAQUE_RING_MINI 0x00040000 -#endif #define RXD_OPAQUE_RING_MASK 0x00070000 }; @@ -1728,6 +1723,8 @@ }; struct tg3 { + /* begin "general, frequently-used members" cacheline section */ + /* SMP locking strategy: * * lock: Held during all operations except TX packet @@ -1741,18 +1738,51 @@ * necessary for acquisition of 'tx_lock'. */ spinlock_t lock; - spinlock_t tx_lock; + spinlock_t indirect_lock; + unsigned long regs; + struct net_device *dev; + struct pci_dev *pdev; + + struct tg3_hw_status *hw_status; + dma_addr_t status_mapping; + + u32 msg_enable; + + /* begin "tx thread" cacheline section */ u32 tx_prod; u32 tx_cons; + u32 tx_pending; + + spinlock_t tx_lock; + + /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ + struct tg3_tx_buffer_desc *tx_ring; + struct tx_ring_info *tx_buffers; + dma_addr_t tx_desc_mapping; + + /* begin "rx thread" cacheline section */ u32 rx_rcb_ptr; u32 rx_std_ptr; u32 rx_jumbo_ptr; -#if TG3_MINI_RING_WORKS - u32 rx_mini_ptr; + u32 rx_pending; + u32 rx_jumbo_pending; +#if TG3_VLAN_TAG_USED + struct vlan_group *vlgrp; #endif - spinlock_t indirect_lock; + struct tg3_rx_buffer_desc *rx_std; + struct ring_info *rx_std_buffers; + dma_addr_t rx_std_mapping; + + struct tg3_rx_buffer_desc *rx_jumbo; + struct ring_info *rx_jumbo_buffers; + dma_addr_t rx_jumbo_mapping; + + struct tg3_rx_buffer_desc *rx_rcb; + dma_addr_t rx_rcb_mapping; + + /* begin "everything else" cacheline(s) section */ struct net_device_stats net_stats; struct net_device_stats net_stats_prev; unsigned long phy_crc_errors; @@ -1765,6 +1795,7 @@ #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 #define TG3_FLAG_USE_MI_INTERRUPT 0x00000010 #define TG3_FLAG_ENABLE_ASF 0x00000020 +#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 #define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 #define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 @@ -1790,8 +1821,8 @@ #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 - - u32 msg_enable; + u32 tg3_flags2; +#define TG3_FLG2_RESTART_TIMER 0x00000001 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -1806,13 +1837,6 @@ struct tg3_link_config link_config; struct tg3_bufmgr_config bufmgr_config; - u32 rx_pending; -#if TG3_MINI_RING_WORKS - u32 rx_mini_pending; -#endif - u32 rx_jumbo_pending; - u32 tx_pending; - /* cache h/w values, often passed straight to h/w */ u32 rx_mode; u32 tx_mode; @@ -1865,38 +1889,9 @@ (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) - unsigned long regs; - struct pci_dev *pdev; - struct net_device *dev; -#if TG3_VLAN_TAG_USED - struct vlan_group *vlgrp; -#endif - - struct tg3_rx_buffer_desc *rx_std; - struct ring_info *rx_std_buffers; - dma_addr_t rx_std_mapping; -#if TG3_MINI_RING_WORKS - struct tg3_rx_buffer_desc *rx_mini; - struct ring_info *rx_mini_buffers; - dma_addr_t rx_mini_mapping; -#endif - struct tg3_rx_buffer_desc *rx_jumbo; - struct ring_info *rx_jumbo_buffers; - dma_addr_t rx_jumbo_mapping; - - struct tg3_rx_buffer_desc *rx_rcb; - dma_addr_t rx_rcb_mapping; - - /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ - struct tg3_tx_buffer_desc *tx_ring; - struct tx_ring_info *tx_buffers; - dma_addr_t tx_desc_mapping; - - struct tg3_hw_status *hw_status; - dma_addr_t status_mapping; - struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; + struct tq_struct reset_task; }; #endif /* !(_T3_H) */ --- linux-2.4.20.orig/drivers/net/tg3.c Thu Nov 28 16:53:14 2002 +++ linux-2.4.20/drivers/net/tg3.c Tue Feb 18 21:08:05 2003 @@ -1,8 +1,8 @@ -/* $Id: tg3.c,v 1.43.2.80 2002/03/14 00:10:04 davem Exp $ +/* * tg3.c: Broadcom Tigon3 ethernet driver. * * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) - * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com) + * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@pobox.com) */ #include @@ -33,15 +33,6 @@ #define PCI_DMA_BUS_IS_PHYS 1 #endif -/* Either I can't figure out how they secretly implemented it (ie. RXD flags - * for mini ring, where it should go in NIC sram, and how many entries the NIC - * firmware expects) or it isn't really fully implemented. Perhaps Broadcom - * wants people to pay for a "performance enhanced" version of their firmware + - * binary-only driver that has the mini ring actually implemented. - * These kids today... -DaveM - */ -#define TG3_MINI_RING_WORKS 0 - #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define TG3_VLAN_TAG_USED 1 #else @@ -59,8 +50,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.2" -#define DRV_MODULE_RELDATE "Nov 14, 2002" +#define DRV_MODULE_VERSION "1.4c" +#define DRV_MODULE_RELDATE "Feb 18, 2003" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -90,10 +81,6 @@ */ #define TG3_RX_RING_SIZE 512 #define TG3_DEF_RX_RING_PENDING 200 -#if TG3_MINI_RING_WORKS -#define TG3_RX_MINI_RING_SIZE 256 /* ??? */ -#define TG3_DEF_RX_MINI_RING_PENDING 100 -#endif #define TG3_RX_JUMBO_RING_SIZE 256 #define TG3_DEF_RX_JUMBO_RING_PENDING 100 #define TG3_RX_RCB_RING_SIZE 1024 @@ -102,10 +89,6 @@ #define TG3_RX_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ TG3_RX_RING_SIZE) -#if TG3_MINI_RING_WORKS -#define TG3_RX_MINI_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ - TG3_RX_MINI_RING_SIZE) -#endif #define TG3_RX_JUMBO_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ TG3_RX_JUMBO_RING_SIZE) #define TG3_RX_RCB_RING_BYTES (sizeof(struct tg3_rx_buffer_desc) * \ @@ -121,9 +104,6 @@ #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) #define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64) -#if TG3_MINI_RING_WORKS -#define RX_MINI_PKT_BUF_SZ (256 + tp->rx_offset + 64) -#endif #define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64) /* minimum number of free TX descriptors required to wake up TX process */ @@ -132,7 +112,7 @@ static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; -MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@mandrakesoft.com)"); +MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)"); MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver"); MODULE_LICENSE("GPL"); MODULE_PARM(tg3_debug, "i"); @@ -157,6 +137,12 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_SYSKONNECT, 0x4400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, @@ -179,6 +165,8 @@ spin_unlock_irqrestore(&tp->indirect_lock, flags); } else { writel(val, tp->regs + off); + if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0) + readl(tp->regs + off); } } @@ -224,33 +212,68 @@ tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } +static inline void tg3_cond_int(struct tg3 *tp) +{ + if (tp->hw_status->status & SD_STATUS_UPDATED) + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); +} + static void tg3_enable_ints(struct tg3 *tp) { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); - if (tp->hw_status->status & SD_STATUS_UPDATED) { - tw32(GRC_LOCAL_CTRL, - tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + tg3_cond_int(tp); +} + +/* these netif_xxx funcs should be moved into generic net layer */ +static void netif_poll_disable(struct net_device *dev) +{ + while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); } - tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } -static inline void tg3_mask_ints(struct tg3 *tp) +static inline void netif_poll_enable(struct net_device *dev) { - tw32(TG3PCI_MISC_HOST_CTRL, - (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); + clear_bit(__LINK_STATE_RX_SCHED, &dev->state); } -static inline void tg3_unmask_ints(struct tg3 *tp) +/* same as netif_rx_complete, except that local_irq_save(flags) + * has already been issued + */ +static inline void __netif_rx_complete(struct net_device *dev) { - tw32(TG3PCI_MISC_HOST_CTRL, - (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - if (tp->hw_status->status & SD_STATUS_UPDATED) { - tw32(GRC_LOCAL_CTRL, - tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); - } + if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG(); + list_del(&dev->poll_list); + clear_bit(__LINK_STATE_RX_SCHED, &dev->state); +} + +static inline void netif_tx_disable(struct net_device *dev) +{ + spin_lock_bh(&dev->xmit_lock); + netif_stop_queue(dev); + spin_unlock_bh(&dev->xmit_lock); +} + +static inline void tg3_netif_stop(struct tg3 *tp) +{ + netif_poll_disable(tp->dev); + netif_tx_disable(tp->dev); +} + +static inline void tg3_netif_start(struct tg3 *tp) +{ + netif_wake_queue(tp->dev); + /* NOTE: unconditional netif_wake_queue is only appropriate + * so long as all callers are assured to have free tx slots + * (such as after tg3_init_hw) + */ + netif_poll_enable(tp->dev); + tg3_cond_int(tp); } static void tg3_switch_clocks(struct tg3 *tp) @@ -412,7 +435,6 @@ } static int tg3_setup_phy(struct tg3 *); -static int tg3_halt(struct tg3 *); static int tg3_set_power_state(struct tg3 *tp, int state) { @@ -483,8 +505,6 @@ tg3_setup_phy(tp); } - tg3_halt(tp); - pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { @@ -916,6 +936,20 @@ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + /* Some third-party PHYs need to be reset on link going + * down. + * + * XXX 5705 note: This workaround also applies to 5705_a0 + */ + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) && + netif_carrier_ok(tp->dev)) { + tg3_readphy(tp, MII_BMSR, &bmsr); + tg3_readphy(tp, MII_BMSR, &bmsr); + if (!(bmsr & BMSR_LSTATUS)) + tg3_phy_reset(tp, 1); + } + if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1784,16 +1818,7 @@ src_map = &tp->rx_jumbo_buffers[src_idx]; skb_size = RX_JUMBO_PKT_BUF_SZ; break; -#if TG3_MINI_RING_WORKS - case RXD_OPAQUE_RING_MINI: - dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE; - desc = &tp->rx_mini[dest_idx]; - map = &tp->rx_mini_buffers[dest_idx]; - if (src_idx >= 0) - src_map = &tp->rx_mini_buffers[src_idx]; - skb_size = RX_MINI_PKT_BUF_SZ; - break; -#endif + default: return -EINVAL; }; @@ -1854,15 +1879,7 @@ src_desc = &tp->rx_jumbo[src_idx]; src_map = &tp->rx_jumbo_buffers[src_idx]; break; -#if TG3_MINI_RING_WORKS - case RXD_OPAQUE_RING_MINI: - dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE; - dest_desc = &tp->rx_mini[dest_idx]; - dest_map = &tp->rx_mini_buffers[dest_idx]; - src_desc = &tp->rx_mini[src_idx]; - src_map = &tp->rx_mini_buffers[src_idx]; - break; -#endif + default: return; }; @@ -1938,14 +1955,6 @@ skb = tp->rx_jumbo_buffers[desc_idx].skb; post_ptr = &tp->rx_jumbo_ptr; } -#if TG3_MINI_RING_WORKS - else if (opaque_key == RXD_OPAQUE_RING_MINI) { - dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx], - mapping); - skb = tp->rx_mini_buffers[desc_idx].skb; - post_ptr = &tp->rx_mini_ptr; - } -#endif else { goto next_pkt_nopost; } @@ -1965,7 +1974,6 @@ len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */ - /* Kill the copy case if we ever get the mini ring working. */ if (len > RX_COPY_THRESHOLD) { int skb_size; @@ -2000,13 +2008,12 @@ } if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) && - (desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) { - skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) - >> RXD_TCPCSUM_SHIFT); - skb->ip_summed = CHECKSUM_HW; - } else { + (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && + (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK) + >> RXD_TCPCSUM_SHIFT) == 0xffff)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else skb->ip_summed = CHECKSUM_NONE; - } skb->protocol = eth_type_trans(skb, tp->dev); #if TG3_VLAN_TAG_USED @@ -2051,15 +2058,6 @@ if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW); } -#if TG3_MINI_RING_WORKS - if (work_mask & RXD_OPAQUE_RING_MINI) { - sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE; - tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, - sw_idx); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW); - } -#endif return received; } @@ -2068,10 +2066,12 @@ { struct tg3 *tp = netdev->priv; struct tg3_hw_status *sblk = tp->hw_status; + unsigned long flags; int done; - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, flags); + /* handle link change and other phy events */ if (!(tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES))) { @@ -2082,12 +2082,19 @@ } } + /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { spin_lock(&tp->tx_lock); tg3_tx(tp); spin_unlock(&tp->tx_lock); } + spin_unlock_irqrestore(&tp->lock, flags); + + /* run RX thread, within the bounds set by NAPI. + * All RX "locking" is done by ensuring outside + * code synchronizes with dev->poll() + */ done = 1; if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) { int orig_budget = *budget; @@ -2105,44 +2112,35 @@ done = 0; } + /* if no more work, tell net stack and NIC we're done */ if (done) { - netif_rx_complete(netdev); - tg3_unmask_ints(tp); + spin_lock_irqsave(&tp->lock, flags); + __netif_rx_complete(netdev); + tg3_enable_ints(tp); + spin_unlock_irqrestore(&tp->lock, flags); } - spin_unlock_irq(&tp->lock); - return (done ? 0 : 1); } -static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp) +static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp) { struct tg3_hw_status *sblk = tp->hw_status; - int work_exists = 0; + unsigned int work_exists = 0; + /* check for phy events */ if (!(tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES))) { if (sblk->status & SD_STATUS_LINK_CHG) work_exists = 1; } + /* check for RX/TX work to do */ if (sblk->idx[0].tx_consumer != tp->tx_cons || sblk->idx[0].rx_producer != tp->rx_rcb_ptr) work_exists = 1; - if (!work_exists) - return; - - if (netif_rx_schedule_prep(dev)) { - /* NOTE: These writes are posted by the readback of - * the mailbox register done by our caller. - */ - tg3_mask_ints(tp); - __netif_rx_schedule(dev); - } else { - printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", - dev->name); - } + return work_exists; } static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -2155,15 +2153,32 @@ spin_lock_irqsave(&tp->lock, flags); if (sblk->status & SD_STATUS_UPDATED) { + /* + * writing any value to intr-mbox-0 clears PCI INTA# and + * chip-internal interrupt pending events. + * writing non-zero to intr-mbox-0 additional tells the + * NIC to stop sending us irqs, engaging "in-intr-handler" + * event coalescing. + */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + /* + * Flush PCI write. This also guarantees that our + * status block has been flushed to host memory. + */ + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); sblk->status &= ~SD_STATUS_UPDATED; - tg3_interrupt_main_work(dev, tp); - - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000000); - tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + if (likely(tg3_has_work(dev, tp))) + netif_rx_schedule(dev); /* schedule NAPI poll */ + else { + /* no work, shared interrupt perhaps? re-enable + * interrupts, and flush that PCI write + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + 0x00000000); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + } } spin_unlock_irqrestore(&tp->lock, flags); @@ -2171,17 +2186,21 @@ static void tg3_init_rings(struct tg3 *); static int tg3_init_hw(struct tg3 *); +static int tg3_halt(struct tg3 *); -static void tg3_tx_timeout(struct net_device *dev) +static void tg3_reset_task(void *_data) { - struct tg3 *tp = dev->priv; + struct tg3 *tp = _data; + unsigned int restart_timer; - printk(KERN_ERR PFX "%s: transmit timed out, resetting\n", - dev->name); + tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); + restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; + tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; + tg3_halt(tp); tg3_init_rings(tp); tg3_init_hw(tp); @@ -2189,7 +2208,20 @@ spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); - netif_wake_queue(dev); + tg3_netif_start(tp); + + if (restart_timer) + mod_timer(&tp->timer, jiffies + 1); +} + +static void tg3_tx_timeout(struct net_device *dev) +{ + struct tg3 *tp = dev->priv; + + printk(KERN_ERR PFX "%s: transmit timed out, resetting\n", + dev->name); + + schedule_task(&tp->reset_task); } #if !PCI_DMA_BUS_IS_PHYS @@ -2264,11 +2296,6 @@ return -1; } - /* NOTE: Broadcom's driver botches this case up really bad. - * This is especially true if any of the frag pages - * are in highmem. It will instantly oops in that case. - */ - /* New SKB is guarenteed to be linear. */ entry = *start; new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, @@ -2674,6 +2701,17 @@ return 0; } +static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, + int new_mtu) +{ + dev->mtu = new_mtu; + + if (new_mtu > ETH_DATA_LEN) + tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE; + else + tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE; +} + static int tg3_change_mtu(struct net_device *dev, int new_mtu) { struct tg3 *tp = dev->priv; @@ -2685,27 +2723,24 @@ /* We'll just catch it later when the * device is up'd. */ - dev->mtu = new_mtu; + tg3_set_mtu(dev, tp, new_mtu); return 0; } + tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_halt(tp); - dev->mtu = new_mtu; - - if (new_mtu > ETH_DATA_LEN) - tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE; - else - tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE; + tg3_set_mtu(dev, tp, new_mtu); tg3_init_rings(tp); tg3_init_hw(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); + tg3_netif_start(tp); return 0; } @@ -2734,20 +2769,7 @@ dev_kfree_skb_any(rxp->skb); rxp->skb = NULL; } -#if TG3_MINI_RING_WORKS - for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) { - rxp = &tp->rx_mini_buffers[i]; - if (rxp->skb == NULL) - continue; - pci_unmap_single(tp->pdev, - pci_unmap_addr(rxp, mapping), - RX_MINI_PKT_BUF_SZ - tp->rx_offset, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any(rxp->skb); - rxp->skb = NULL; - } -#endif for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { rxp = &tp->rx_jumbo_buffers[i]; @@ -2812,9 +2834,6 @@ /* Zero out all descriptors. */ memset(tp->rx_std, 0, TG3_RX_RING_BYTES); -#if TG3_MINI_RING_WORKS - memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES); -#endif memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES); memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES); @@ -2847,19 +2866,7 @@ rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT)); } -#if TG3_MINI_RING_WORKS - for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) { - struct tg3_rx_buffer_desc *rxd; - rxd = &tp->rx_mini[i]; - rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64) - << RXD_LEN_SHIFT; - rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) | - RXD_FLAG_MINI; - rxd->opaque = (RXD_OPAQUE_RING_MINI | - (i << RXD_OPAQUE_INDEX_SHIFT)); - } -#endif if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) { struct tg3_rx_buffer_desc *rxd; @@ -2881,14 +2888,6 @@ break; } -#if TG3_MINI_RING_WORKS - for (i = 0; i < tp->rx_mini_pending; i++) { - if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI, - -1, i) < 0) - break; - } -#endif - if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { for (i = 0; i < tp->rx_jumbo_pending; i++) { if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, @@ -2913,13 +2912,6 @@ tp->rx_std, tp->rx_std_mapping); tp->rx_std = NULL; } -#if TG3_MINI_RING_WORKS - if (tp->rx_mini) { - pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES, - tp->rx_mini, tp->rx_mini_mapping); - tp->rx_mini = NULL; - } -#endif if (tp->rx_jumbo) { pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, tp->rx_jumbo, tp->rx_jumbo_mapping); @@ -2955,9 +2947,6 @@ { tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) * (TG3_RX_RING_SIZE + -#if TG3_MINI_RING_WORKS - TG3_RX_MINI_RING_SIZE + -#endif TG3_RX_JUMBO_RING_SIZE)) + (sizeof(struct tx_ring_info) * TG3_TX_RING_SIZE), @@ -2965,29 +2954,14 @@ if (!tp->rx_std_buffers) return -ENOMEM; -#if TG3_MINI_RING_WORKS memset(tp->rx_std_buffers, 0, (sizeof(struct ring_info) * (TG3_RX_RING_SIZE + - TG3_RX_MINI_RING_SIZE + TG3_RX_JUMBO_RING_SIZE)) + (sizeof(struct tx_ring_info) * TG3_TX_RING_SIZE)); -#else - memset(tp->rx_std_buffers, 0, - (sizeof(struct ring_info) * - (TG3_RX_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE)) + - (sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE)); -#endif -#if TG3_MINI_RING_WORKS - tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; - tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE]; -#else tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; -#endif tp->tx_buffers = (struct tx_ring_info *) &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; @@ -2996,14 +2970,6 @@ if (!tp->rx_std) goto err_out; -#if TG3_MINI_RING_WORKS - tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES, - &tp->rx_mini_mapping); - - if (!tp->rx_mini) - goto err_out; -#endif - tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES, &tp->rx_jumbo_mapping); @@ -3150,6 +3116,7 @@ static void tg3_chip_reset(struct tg3 *tp) { u32 val; + u32 flags_save; /* Force NVRAM to settle. * This deals with a chip bug which can result in EEPROM @@ -3166,8 +3133,21 @@ } } + /* + * We must avoid the readl() that normally takes place. + * It locks machines, causes machine checks, and other + * fun things. So, temporarily disable the 5701 + * hardware workaround, while we do the reset. + */ + flags_save = tp->tg3_flags; + tp->tg3_flags &= ~TG3_FLAG_5701_REG_WRITE_BUG; + + /* do the reset */ tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET); + /* restore 5701 hardware bug workaround flag */ + tp->tg3_flags = flags_save; + /* Flush PCI posted writes. The normal MMIO registers * are inaccessible at this time so this is the only * way to make this reliably. I tried to use indirect @@ -4119,8 +4099,6 @@ * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries. * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries. * - * ??? No space allocated for mini receive ring? :( - * * The size of each ring is fixed in the firmware, but the location is * configurable. */ @@ -4133,19 +4111,8 @@ tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC); -#if TG3_MINI_RING_WORKS - tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, - ((u64) tp->rx_mini_mapping >> 32)); - tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, - ((u64) tp->rx_mini_mapping & 0xffffffff)); - tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, - RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT); - tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR, - NIC_SRAM_RX_MINI_BUFFER_DESC); -#else tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED); -#endif if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) { tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, @@ -4163,9 +4130,6 @@ /* Setup replenish thresholds. */ tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8); -#if TG3_MINI_RING_WORKS - tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8); -#endif tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8); /* Clear out send RCB ring in SRAM. */ @@ -4213,13 +4177,6 @@ tp->rx_std_ptr); if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW); -#if TG3_MINI_RING_WORKS - tp->rx_mini_ptr = tp->rx_mini_pending; - tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, - tp->rx_mini_ptr); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW); -#endif if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) tp->rx_jumbo_ptr = tp->rx_jumbo_pending; @@ -4400,6 +4357,12 @@ if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) tw32(MAC_SERDES_CFG, 0x616000); + /* Prevent chip from dropping frames when flow control + * is enabled. + */ + tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2); + tr32(MAC_LOW_WMARK_MAX_RX_FRAME); + err = tg3_setup_phy(tp); if (err) return err; @@ -4468,8 +4431,9 @@ static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; + unsigned long flags; - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, flags); spin_lock(&tp->tx_lock); /* All of this garbage is because when using non-tagged @@ -4485,9 +4449,11 @@ } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tg3_halt(tp); - tg3_init_rings(tp); - tg3_init_hw(tp); + tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; + spin_unlock(&tp->tx_lock); + spin_unlock_irqrestore(&tp->lock, flags); + schedule_task(&tp->reset_task); + return; } /* This part only runs once per second. */ @@ -4551,7 +4517,7 @@ } spin_unlock(&tp->tx_lock); - spin_unlock_irq(&tp->lock); + spin_unlock_irqrestore(&tp->lock, flags); tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); @@ -4618,8 +4584,6 @@ return err; } - netif_start_queue(dev); - spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); @@ -4628,6 +4592,8 @@ spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); + netif_start_queue(dev); + return 0; } @@ -4840,23 +4806,6 @@ readl(rxd + 0x0), readl(rxd + 0x4), readl(rxd + 0x8), readl(rxd + 0xc)); } -#if TG3_MINI_RING_WORKS - for (i = 0; i < 6; i++) { - unsigned long rxd; - - rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC - + (i * sizeof(struct tg3_rx_buffer_desc)); - printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n", - i, - readl(rxd + 0x0), readl(rxd + 0x4), - readl(rxd + 0x8), readl(rxd + 0xc)); - rxd += (4 * sizeof(u32)); - printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n", - i, - readl(rxd + 0x0), readl(rxd + 0x4), - readl(rxd + 0x8), readl(rxd + 0xc)); - } -#endif for (i = 0; i < 6; i++) { unsigned long rxd; @@ -5387,19 +5336,11 @@ struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; ering.rx_max_pending = TG3_RX_RING_SIZE - 1; -#if TG3_MINI_RING_WORKS - ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1; -#else ering.rx_mini_max_pending = 0; -#endif ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1; ering.rx_pending = tp->rx_pending; -#if TG3_MINI_RING_WORKS - ering.rx_mini_pending = tp->rx_mini_pending; -#else ering.rx_mini_pending = 0; -#endif ering.rx_jumbo_pending = tp->rx_jumbo_pending; ering.tx_pending = tp->tx_pending; @@ -5414,20 +5355,15 @@ return -EFAULT; if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) || -#if TG3_MINI_RING_WORKS - (ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) || -#endif (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || (ering.tx_pending > TG3_TX_RING_SIZE - 1)) return -EINVAL; + tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tp->rx_pending = ering.rx_pending; -#if TG3_MINI_RING_WORKS - tp->rx_mini_pending = ering.rx_mini_pending; -#endif tp->rx_jumbo_pending = ering.rx_jumbo_pending; tp->tx_pending = ering.tx_pending; @@ -5437,6 +5373,7 @@ netif_wake_queue(tp->dev); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); + tg3_netif_start(tp); return 0; } @@ -5459,6 +5396,7 @@ if (copy_from_user(&epause, useraddr, sizeof(epause))) return -EFAULT; + tg3_netif_stop(tp); spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); if (epause.autoneg) @@ -5478,6 +5416,7 @@ tg3_init_hw(tp); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); + tg3_netif_start(tp); return 0; } @@ -5939,7 +5878,8 @@ tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) && + (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)) { tg3_writephy(tp, 0x1c, 0x8d68); tg3_writephy(tp, 0x1c, 0x8d68); } @@ -6145,15 +6085,33 @@ pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); } } + + /* Back to back register writes can cause problems on this chip, + * the workaround is to read back all reg writes except those to + * mailbox regs. See tg3_write_indirect_reg32(). + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) + tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG; + if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) tp->tg3_flags |= TG3_FLAG_PCI_32BIT; + /* Chip-specific fixup from Broadcom driver */ + if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) && + (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) { + pci_state_reg |= PCISTATE_RETRY_SAME_DMA; + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg); + } + /* Force the chip into D0. */ err = tg3_set_power_state(tp, 0); - if (err) + if (err) { + printk(KERN_ERR PFX "(%s) transition to D0 failed\n", + tp->pdev->slot_name); return err; + } /* 5700 B0 chips do not support checksumming correctly due * to hardware bugs. @@ -6161,18 +6119,14 @@ if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Regardless of whether checksums work or not, we configure - * the StrongARM chips to not compute the pseudo header checksums - * in either direction. Because of the way Linux checksum support - * works we do not need the chips to do this, and taking the load - * off of the TX/RX onboard StrongARM cpus means that they will not be - * the bottleneck. Whoever wrote Broadcom's driver did not - * understand the situation at all. He could have bothered - * to read Jes's Acenic driver because the logic (and this part of - * the Tigon2 hardware/firmware) is pretty much identical. + /* Pseudo-header checksum is done by hardware logic and not + * the offload processers, so make the chip do the pseudo- + * header checksums on receive. For transmit it is more + * convenient to do the pseudo-header checksum in software + * as Linux does that on transmit for us in all cases. */ tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM; - tp->tg3_flags |= TG3_FLAG_NO_RX_PSEUDO_CSUM; + tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM; /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call @@ -6250,19 +6204,8 @@ if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) tp->tg3_flags |= TG3_FLAG_HOST_TXDS; - /* Quick sanity check. Make sure we see an expected - * value here. - */ grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; - if (grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5700 && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5701 && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 && - grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1) - return -ENODEV; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) { @@ -6270,14 +6213,16 @@ tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ; } - /* ROFL, you should see Broadcom's driver code implementing - * this, stuff like "if (a || b)" where a and b are always - * mutually exclusive. DaveM finds like 6 bugs today, hello! - */ + /* this one is limited to 10/100 only */ if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; err = tg3_phy_probe(tp); + if (err) { + printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n", + tp->pdev->slot_name, err); + /* ... but do not return immediately ... */ + } tg3_read_partno(tp); @@ -6331,17 +6276,10 @@ /* 5700 chips can get confused if TX buffers straddle the * 4GB address boundary in some cases. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) { - /* ROFL! Latest Broadcom driver disables NETIF_F_HIGHDMA - * in this case instead of fixing their workaround code. - * - * Like, hey, there is this skb_copy() thing guys, - * use it. Oh I can't stop laughing... - */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) tp->dev->hard_start_xmit = tg3_start_xmit_4gbug; - } else { + else tp->dev->hard_start_xmit = tg3_start_xmit; - } tp->rx_offset = 2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && @@ -6507,6 +6445,7 @@ (0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) | (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) | (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); + /* XXX 5705 note: set MIN_DMA to zero here */ } else { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) tp->dma_rwctrl = @@ -6524,13 +6463,20 @@ (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); /* Wheee, some more chip bugs... */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 || - tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 || - tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 || - tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) - tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f); + + if (ccval == 0x6 || ccval == 0x7) + tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; + } } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) + tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA + << DMA_RWCTRL_MIN_DMA_SHIFT); + /* We don't do this on x86 because it seems to hurt performace. * It does help things on other platforms though. */ @@ -6594,8 +6540,11 @@ } #endif - /* Remove this if it causes problems for some boards. */ - tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { + /* Remove this if it causes problems for some boards. */ + tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT; + } tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); @@ -6825,6 +6774,7 @@ spin_lock_init(&tp->lock); spin_lock_init(&tp->tx_lock); spin_lock_init(&tp->indirect_lock); + PREPARE_TQUEUE(&tp->reset_task, tg3_reset_task, tp); tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len); if (tp->regs == 0UL) { @@ -6839,9 +6789,6 @@ tg3_init_bufmgr_config(tp); tp->rx_pending = TG3_DEF_RX_RING_PENDING; -#if TG3_MINI_RING_WORKS - tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING; -#endif tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; tp->tx_pending = TG3_DEF_TX_RING_PENDING; @@ -6958,6 +6905,8 @@ if (!netif_running(dev)) return 0; + tg3_netif_stop(tp); + spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); tg3_disable_ints(tp); @@ -6984,6 +6933,7 @@ spin_unlock_irq(&tp->lock); netif_device_attach(dev); + tg3_netif_start(tp); } return err; @@ -7014,6 +6964,8 @@ spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); + tg3_netif_start(tp); + return 0; } diff -ruN linux-2.4.20.orig/arch/alpha/kernel/entry.S linux-2.4.20/arch/alpha/kernel/entry.S --- linux-2.4.20.orig/arch/alpha/kernel/entry.S Fri Aug 2 18:39:42 2002 +++ linux-2.4.20/arch/alpha/kernel/entry.S Mon Mar 17 10:51:53 2003 @@ -231,12 +231,12 @@ .end kernel_clone /* - * kernel_thread(fn, arg, clone_flags) + * arch_kernel_thread(fn, arg, clone_flags) */ .align 3 .globl kernel_thread .ent kernel_thread -kernel_thread: +arch_kernel_thread: ldgp $29,0($27) /* we can be called from a module */ .frame $30, 4*8, $26 subq $30,4*8,$30 diff -ruN linux-2.4.20.orig/arch/arm/kernel/process.c linux-2.4.20/arch/arm/kernel/process.c --- linux-2.4.20.orig/arch/arm/kernel/process.c Fri Aug 2 18:39:42 2002 +++ linux-2.4.20/arch/arm/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -366,7 +366,7 @@ * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { pid_t __ret; diff -ruN linux-2.4.20.orig/arch/cris/kernel/entry.S linux-2.4.20/arch/cris/kernel/entry.S --- linux-2.4.20.orig/arch/cris/kernel/entry.S Fri Aug 2 18:39:42 2002 +++ linux-2.4.20/arch/cris/kernel/entry.S Mon Mar 17 10:51:53 2003 @@ -736,12 +736,12 @@ * the grosser the code, at least with the gcc version in cris-dist-1.13. */ -/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ +/* int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ /* r10 r11 r12 */ .text - .global kernel_thread -kernel_thread: + .global arch_kernel_thread +arch_kernel_thread: /* Save ARG for later. */ move.d $r11, $r13 diff -ruN linux-2.4.20.orig/arch/i386/kernel/process.c linux-2.4.20/arch/i386/kernel/process.c --- linux-2.4.20.orig/arch/i386/kernel/process.c Fri Aug 2 18:39:42 2002 +++ linux-2.4.20/arch/i386/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -485,7 +485,7 @@ /* * Create a kernel thread */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { long retval, d0; @@ -508,6 +508,7 @@ "r" (arg), "r" (fn), "b" (flags | CLONE_VM) : "memory"); + return retval; } diff -ruN linux-2.4.20.orig/arch/ia64/kernel/process.c linux-2.4.20/arch/ia64/kernel/process.c --- linux-2.4.20.orig/arch/ia64/kernel/process.c Thu Nov 28 16:53:09 2002 +++ linux-2.4.20/arch/ia64/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -224,7 +224,7 @@ * | | <-- sp (lowest addr) * +---------------------+ * - * Note: if we get called through kernel_thread() then the memory + * Note: if we get called through arch_kernel_thread() then the memory * above "(highest addr)" is valid kernel stack memory that needs to * be copied as well. * @@ -479,7 +479,7 @@ } pid_t -kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) +arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { struct task_struct *parent = current; int result, tid; diff -ruN linux-2.4.20.orig/arch/m68k/kernel/process.c linux-2.4.20/arch/m68k/kernel/process.c --- linux-2.4.20.orig/arch/m68k/kernel/process.c Fri Aug 2 18:39:43 2002 +++ linux-2.4.20/arch/m68k/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -124,7 +124,7 @@ /* * Create a kernel thread */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int pid; mm_segment_t fs; diff -ruN linux-2.4.20.orig/arch/mips/kernel/process.c linux-2.4.20/arch/mips/kernel/process.c --- linux-2.4.20.orig/arch/mips/kernel/process.c Thu Nov 28 16:53:10 2002 +++ linux-2.4.20/arch/mips/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -152,7 +152,7 @@ /* * Create a kernel thread */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { long retval; diff -ruN linux-2.4.20.orig/arch/mips64/kernel/process.c linux-2.4.20/arch/mips64/kernel/process.c --- linux-2.4.20.orig/arch/mips64/kernel/process.c Thu Nov 28 16:53:10 2002 +++ linux-2.4.20/arch/mips64/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -151,7 +151,7 @@ /* * Create a kernel thread */ -int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { int retval; diff -ruN linux-2.4.20.orig/arch/parisc/kernel/process.c linux-2.4.20/arch/parisc/kernel/process.c --- linux-2.4.20.orig/arch/parisc/kernel/process.c Thu Nov 28 16:53:10 2002 +++ linux-2.4.20/arch/parisc/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -163,7 +163,7 @@ */ extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { /* diff -ruN linux-2.4.20.orig/arch/ppc/kernel/misc.S linux-2.4.20/arch/ppc/kernel/misc.S --- linux-2.4.20.orig/arch/ppc/kernel/misc.S Thu Nov 28 16:53:11 2002 +++ linux-2.4.20/arch/ppc/kernel/misc.S Mon Mar 17 10:51:53 2003 @@ -898,9 +898,9 @@ /* * Create a kernel thread - * kernel_thread(fn, arg, flags) + * arch_kernel_thread(fn, arg, flags) */ -_GLOBAL(kernel_thread) +_GLOBAL(arch_kernel_thread) mr r6,r3 /* function */ ori r3,r5,CLONE_VM /* flags */ li r0,__NR_clone diff -ruN linux-2.4.20.orig/arch/ppc64/kernel/misc.S linux-2.4.20/arch/ppc64/kernel/misc.S --- linux-2.4.20.orig/arch/ppc64/kernel/misc.S Thu Nov 28 16:53:11 2002 +++ linux-2.4.20/arch/ppc64/kernel/misc.S Mon Mar 17 10:51:53 2003 @@ -493,9 +493,9 @@ /* * Create a kernel thread - * kernel_thread(fn, arg, flags) + * arch_kernel_thread(fn, arg, flags) */ -_GLOBAL(kernel_thread) +_GLOBAL(arch_kernel_thread) mr r6,r3 /* function */ ori r3,r5,CLONE_VM /* flags */ li r0,__NR_clone diff -ruN linux-2.4.20.orig/arch/s390/kernel/process.c linux-2.4.20/arch/s390/kernel/process.c --- linux-2.4.20.orig/arch/s390/kernel/process.c Fri Aug 2 18:39:43 2002 +++ linux-2.4.20/arch/s390/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -105,7 +105,7 @@ show_trace((unsigned long *) regs->gprs[15]); } -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; int retval; diff -ruN linux-2.4.20.orig/arch/s390x/kernel/process.c linux-2.4.20/arch/s390x/kernel/process.c --- linux-2.4.20.orig/arch/s390x/kernel/process.c Thu Nov 28 16:53:11 2002 +++ linux-2.4.20/arch/s390x/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -102,7 +102,7 @@ show_trace((unsigned long *) regs->gprs[15]); } -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; int retval; diff -ruN linux-2.4.20.orig/arch/sh/kernel/process.c linux-2.4.20/arch/sh/kernel/process.c --- linux-2.4.20.orig/arch/sh/kernel/process.c Mon Oct 15 14:36:48 2001 +++ linux-2.4.20/arch/sh/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -118,7 +118,7 @@ * This is the mechanism for creating a new kernel thread. * */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ register unsigned long __sc0 __asm__ ("r0"); register unsigned long __sc3 __asm__ ("r3") = __NR_clone; diff -ruN linux-2.4.20.orig/arch/sparc/kernel/process.c linux-2.4.20/arch/sparc/kernel/process.c --- linux-2.4.20.orig/arch/sparc/kernel/process.c Fri Aug 2 18:39:43 2002 +++ linux-2.4.20/arch/sparc/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -676,7 +676,7 @@ * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { long retval; diff -ruN linux-2.4.20.orig/arch/sparc64/kernel/process.c linux-2.4.20/arch/sparc64/kernel/process.c --- linux-2.4.20.orig/arch/sparc64/kernel/process.c Thu Nov 28 16:53:12 2002 +++ linux-2.4.20/arch/sparc64/kernel/process.c Mon Mar 17 10:51:53 2003 @@ -673,7 +673,7 @@ * a system call from a "real" process, but the process memory space will * not be free'd until both the parent and the child have exited. */ -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { long retval; diff -ruN linux-2.4.20.orig/fs/exec.c linux-2.4.20/fs/exec.c --- linux-2.4.20.orig/fs/exec.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/fs/exec.c Mon Mar 17 10:51:58 2003 @@ -572,8 +572,10 @@ current->sas_ss_sp = current->sas_ss_size = 0; - if (current->euid == current->uid && current->egid == current->gid) + if (current->euid == current->uid && current->egid == current->gid) { current->mm->dumpable = 1; + current->task_dumpable = 1; + } name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -965,7 +967,7 @@ binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; - if (!current->mm->dumpable) + if (!is_dumpable(current)) goto fail; current->mm->dumpable = 0; if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) diff -ruN linux-2.4.20.orig/include/asm-alpha/processor.h linux-2.4.20/include/asm-alpha/processor.h --- linux-2.4.20.orig/include/asm-alpha/processor.h Fri Oct 5 13:11:05 2001 +++ linux-2.4.20/include/asm-alpha/processor.h Mon Mar 17 10:51:58 2003 @@ -119,7 +119,7 @@ extern void release_thread(struct task_struct *); /* Create a kernel thread without removing it from tasklists. */ -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-arm/processor.h linux-2.4.20/include/asm-arm/processor.h --- linux-2.4.20.orig/include/asm-arm/processor.h Fri Aug 2 18:39:45 2002 +++ linux-2.4.20/include/asm-arm/processor.h Mon Mar 17 10:51:58 2003 @@ -117,7 +117,7 @@ /* * Create a new kernel thread */ -extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); #endif diff -ruN linux-2.4.20.orig/include/asm-cris/processor.h linux-2.4.20/include/asm-cris/processor.h --- linux-2.4.20.orig/include/asm-cris/processor.h Fri Aug 2 18:39:45 2002 +++ linux-2.4.20/include/asm-cris/processor.h Mon Mar 17 10:51:58 2003 @@ -81,7 +81,7 @@ #define INIT_THREAD { \ 0, 0, 0x20 } /* ccr = int enable, nothing else */ -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* give the thread a program location * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) diff -ruN linux-2.4.20.orig/include/asm-i386/processor.h linux-2.4.20/include/asm-i386/processor.h --- linux-2.4.20.orig/include/asm-i386/processor.h Fri Aug 2 18:39:45 2002 +++ linux-2.4.20/include/asm-i386/processor.h Mon Mar 17 10:51:58 2003 @@ -433,7 +433,7 @@ /* * create a kernel thread without removing it from tasklists */ -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ extern void copy_segments(struct task_struct *p, struct mm_struct * mm); diff -ruN linux-2.4.20.orig/include/asm-ia64/processor.h linux-2.4.20/include/asm-ia64/processor.h --- linux-2.4.20.orig/include/asm-ia64/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-ia64/processor.h Mon Mar 17 10:51:58 2003 @@ -373,7 +373,7 @@ * do_basic_setup() and the timing is such that free_initmem() has * been called already. */ -extern int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); +extern int arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ #define copy_segments(tsk, mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-m68k/processor.h linux-2.4.20/include/asm-m68k/processor.h --- linux-2.4.20.orig/include/asm-m68k/processor.h Fri Oct 5 13:11:05 2001 +++ linux-2.4.20/include/asm-m68k/processor.h Mon Mar 17 10:51:58 2003 @@ -105,7 +105,7 @@ { } -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-mips/processor.h linux-2.4.20/include/asm-mips/processor.h --- linux-2.4.20.orig/include/asm-mips/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-mips/processor.h Mon Mar 17 10:51:58 2003 @@ -188,7 +188,7 @@ /* Free all resources held by a thread. */ #define release_thread(thread) do { } while(0) -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ #define copy_segments(p, mm) do { } while(0) diff -ruN linux-2.4.20.orig/include/asm-mips64/processor.h linux-2.4.20/include/asm-mips64/processor.h --- linux-2.4.20.orig/include/asm-mips64/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-mips64/processor.h Mon Mar 17 10:51:58 2003 @@ -231,7 +231,7 @@ /* Free all resources held by a thread. */ #define release_thread(thread) do { } while(0) -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ #define copy_segments(p, mm) do { } while(0) diff -ruN linux-2.4.20.orig/include/asm-parisc/processor.h linux-2.4.20/include/asm-parisc/processor.h --- linux-2.4.20.orig/include/asm-parisc/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-parisc/processor.h Mon Mar 17 10:51:58 2003 @@ -289,7 +289,7 @@ /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm); diff -ruN linux-2.4.20.orig/include/asm-ppc/processor.h linux-2.4.20/include/asm-ppc/processor.h --- linux-2.4.20.orig/include/asm-ppc/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-ppc/processor.h Mon Mar 17 10:51:58 2003 @@ -626,7 +626,7 @@ /* * Create a new kernel thread. */ -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* * Bus types diff -ruN linux-2.4.20.orig/include/asm-ppc64/processor.h linux-2.4.20/include/asm-ppc64/processor.h --- linux-2.4.20.orig/include/asm-ppc64/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-ppc64/processor.h Mon Mar 17 10:51:58 2003 @@ -609,7 +609,7 @@ /* * Create a new kernel thread. */ -extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); +extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); /* * Bus types diff -ruN linux-2.4.20.orig/include/asm-s390/processor.h linux-2.4.20/include/asm-s390/processor.h --- linux-2.4.20.orig/include/asm-s390/processor.h Fri Aug 2 18:39:45 2002 +++ linux-2.4.20/include/asm-s390/processor.h Mon Mar 17 10:51:58 2003 @@ -113,7 +113,7 @@ /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ #define copy_segments(nr, mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-s390x/processor.h linux-2.4.20/include/asm-s390x/processor.h --- linux-2.4.20.orig/include/asm-s390x/processor.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/asm-s390x/processor.h Mon Mar 17 10:51:58 2003 @@ -128,7 +128,7 @@ /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* Copy and release all segment info associated with a VM */ #define copy_segments(nr, mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-sh/processor.h linux-2.4.20/include/asm-sh/processor.h --- linux-2.4.20.orig/include/asm-sh/processor.h Fri Oct 5 13:11:05 2001 +++ linux-2.4.20/include/asm-sh/processor.h Mon Mar 17 10:51:58 2003 @@ -137,7 +137,7 @@ /* * create a kernel thread without removing it from tasklists */ -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); /* * Bus types diff -ruN linux-2.4.20.orig/include/asm-sparc/processor.h linux-2.4.20/include/asm-sparc/processor.h --- linux-2.4.20.orig/include/asm-sparc/processor.h Thu Oct 11 00:42:47 2001 +++ linux-2.4.20/include/asm-sparc/processor.h Mon Mar 17 10:51:58 2003 @@ -146,7 +146,7 @@ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) -extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); #define copy_segments(tsk, mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/asm-sparc64/processor.h linux-2.4.20/include/asm-sparc64/processor.h --- linux-2.4.20.orig/include/asm-sparc64/processor.h Fri Aug 2 18:39:45 2002 +++ linux-2.4.20/include/asm-sparc64/processor.h Mon Mar 17 10:51:58 2003 @@ -270,7 +270,7 @@ /* Free all resources held by a thread. */ #define release_thread(tsk) do { } while(0) -extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); +extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); #define copy_segments(tsk, mm) do { } while (0) #define release_segments(mm) do { } while (0) diff -ruN linux-2.4.20.orig/include/linux/sched.h linux-2.4.20/include/linux/sched.h --- linux-2.4.20.orig/include/linux/sched.h Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/include/linux/sched.h Mon Mar 17 10:59:08 2003 @@ -339,6 +339,7 @@ /* ??? */ unsigned long personality; int did_exec:1; + unsigned task_dumpable:1; pid_t pid; pid_t pgrp; pid_t tty_old_pgrp; @@ -448,6 +449,8 @@ #define PT_TRACESYSGOOD 0x00000008 #define PT_PTRACE_CAP 0x00000010 /* ptracer can follow suid-exec */ +#define is_dumpable(tsk) ((tsk)->task_dumpable && (tsk)->mm && (tsk)->mm->dumpable) + /* * Limit the stack by to some sane default: root can always * increase this limit if needed.. 8MB seems reasonable. @@ -803,6 +806,8 @@ extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); +extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + #define __wait_event(wq, condition) \ do { \ wait_queue_t __wait; \ diff -ruN linux-2.4.20.orig/kernel/fork.c linux-2.4.20/kernel/fork.c --- linux-2.4.20.orig/kernel/fork.c Thu Nov 28 16:53:15 2002 +++ linux-2.4.20/kernel/fork.c Mon Mar 17 10:51:58 2003 @@ -27,6 +27,7 @@ #include #include #include +#include /* The idle threads do not count.. */ int nr_threads; @@ -565,6 +566,31 @@ p->flags = new_flags; } +long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct task_struct *task = current; + unsigned old_task_dumpable; + long ret; + + /* lock out any potential ptracer */ + task_lock(task); + if (task->ptrace) { + task_unlock(task); + return -EPERM; + } + + old_task_dumpable = task->task_dumpable; + task->task_dumpable = 0; + task_unlock(task); + + ret = arch_kernel_thread(fn, arg, flags); + + /* never reached in child process, only in parent */ + current->task_dumpable = old_task_dumpable; + + return ret; +} + /* * Ok, this is the main fork-routine. It copies the system process * information (task[nr]) and sets up the necessary registers. It also diff -ruN linux-2.4.20.orig/kernel/ptrace.c linux-2.4.20/kernel/ptrace.c --- linux-2.4.20.orig/kernel/ptrace.c Fri Aug 2 18:39:46 2002 +++ linux-2.4.20/kernel/ptrace.c Mon Mar 17 10:51:58 2003 @@ -21,6 +21,10 @@ */ int ptrace_check_attach(struct task_struct *child, int kill) { + mb(); + if (!is_dumpable(child)) + return -EPERM; + if (!(child->ptrace & PT_PTRACED)) return -ESRCH; @@ -70,7 +74,7 @@ (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto bad; rmb(); - if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) + if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE)) goto bad; /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) @@ -136,6 +140,8 @@ /* Worry about races with exit() */ task_lock(tsk); mm = tsk->mm; + if (!is_dumpable(tsk) || (&init_mm == mm)) + mm = NULL; if (mm) atomic_inc(&mm->mm_users); task_unlock(tsk); diff -ruN linux-2.4.20.orig/kernel/sys.c linux-2.4.20/kernel/sys.c --- linux-2.4.20.orig/kernel/sys.c Fri Aug 2 18:39:46 2002 +++ linux-2.4.20/kernel/sys.c Mon Mar 17 10:51:58 2003 @@ -1219,7 +1219,7 @@ error = put_user(current->pdeath_signal, (int *)arg2); break; case PR_GET_DUMPABLE: - if (current->mm->dumpable) + if (is_dumpable(current)) error = 1; break; case PR_SET_DUMPABLE: @@ -1227,7 +1227,8 @@ error = -EINVAL; break; } - current->mm->dumpable = arg2; + if (is_dumpable(current)) + current->mm->dumpable = arg2; break; case PR_SET_UNALIGN: #ifdef SET_UNALIGN_CTL --- linux-2.4.20/Makefile~ Mon Apr 14 07:28:55 2003 +++ linux-2.4.20/Makefile Mon Apr 14 07:28:55 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = +EXTRAVERSION =-uv2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)