From 48ce8b056c88920c8ac187781048f5dae33c81b9 Mon Sep 17 00:00:00 2001 From: Evgeniy Dushistov Date: Mon, 5 Jun 2006 08:21:03 -0500 Subject: JFS: commit_mutex cleanups I look at code, and see that 1)locks wasn't release in the opposite order in which they were taken 2)in jfs_rename we lock new_ip, and in "error path" we didn't unlock it 3)I see strange expression: "! !" May be this worth to fix? Signed-off-by: Evgeniy Dushistov Signed-off-by: Dave Kleikamp --- fs/jfs/jfs_txnmgr.c | 2 +- fs/jfs/namei.c | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index ac3d66948e8..49618dd94f9 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -2944,7 +2944,7 @@ int jfs_sync(void *arg) * Inode is being freed */ list_del_init(&jfs_ip->anon_inode_list); - } else if (! !mutex_trylock(&jfs_ip->commit_mutex)) { + } else if (mutex_trylock(&jfs_ip->commit_mutex)) { /* * inode will be removed from anonymous list * when it is committed diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 09ea03f6227..295268ad231 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -165,8 +165,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, out3: txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -300,8 +300,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out3: txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -384,8 +384,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); goto out2; } @@ -422,8 +422,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); /* * Truncating the directory index table is not guaranteed. It @@ -503,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); IWRITE_UNLOCK(ip); goto out1; } @@ -527,8 +527,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((new_size = commitZeroLink(tid, ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); IWRITE_UNLOCK(ip); rc = new_size; goto out1; @@ -556,9 +556,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); - + mutex_unlock(&JFS_IP(dip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(dip->i_sb, 0); @@ -847,8 +846,8 @@ static int jfs_link(struct dentry *old_dentry, out: txEnd(tid); - mutex_unlock(&JFS_IP(dir)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dir)->commit_mutex); jfs_info("jfs_link: rc:%d", rc); return rc; @@ -1037,8 +1036,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, out3: txEnd(tid); - mutex_unlock(&JFS_IP(dip)->commit_mutex); mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -1160,10 +1159,11 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (S_ISDIR(new_ip->i_mode)) { new_ip->i_nlink--; if (new_ip->i_nlink) { - mutex_unlock(&JFS_IP(new_dir)->commit_mutex); - mutex_unlock(&JFS_IP(old_ip)->commit_mutex); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); if (old_dir != new_dir) mutex_unlock(&JFS_IP(old_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); if (!S_ISDIR(old_ip->i_mode) && new_ip) IWRITE_UNLOCK(new_ip); jfs_error(new_ip->i_sb, @@ -1281,13 +1281,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, out4: txEnd(tid); - - mutex_unlock(&JFS_IP(new_dir)->commit_mutex); - mutex_unlock(&JFS_IP(old_ip)->commit_mutex); - if (old_dir != new_dir) - mutex_unlock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) mutex_unlock(&JFS_IP(new_ip)->commit_mutex); + if (old_dir != new_dir) + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(new_ip->i_sb, 0); -- cgit v1.2.3 From a487a8f7b6947f6445e5a1aa876522916785d5ec Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 9 Jun 2006 11:29:03 -0700 Subject: e1000: prevent statistics from garbling during bus resets If a PCI bus error/fault triggers a PCI bus reset, attempts to get the ethernet packet count statistics from the hardware will fail, returning garbage data upstream. This patch skips statistics data collection if the PCI device is not on the bus. Signed-off-by: Linas Vepstas Cc: Jesse Brandeburg Signed-off-by: Andrew Morton Acked-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 56c7492e3e9..a373ccb308d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3045,14 +3045,20 @@ void e1000_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; unsigned long flags; uint16_t phy_tmp; #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF - /* Prevent stats update while adapter is being reset */ + /* + * Prevent stats update while adapter is being reset, or if the pci + * connection is down. + */ if (adapter->link_speed == 0) return; + if (pdev->error_state && pdev->error_state != pci_channel_io_normal) + return; spin_lock_irqsave(&adapter->stats_lock, flags); -- cgit v1.2.3 From acfbc9fde2ec7f304398f6ad7644002e07bf84bc Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:24 -0700 Subject: e1000: fix loopback ethtool test Ethtool was reporting that loopback failed randomly on esb2 systems. Upon study it was found that the phy manual was changed with respect to the loopback mode bits. The new value fixes it. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 6ed7f599eba..845d293b2f6 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1246,7 +1246,7 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) } else if (adapter->hw.phy_type == e1000_phy_gg82563) { e1000_write_phy_reg(&adapter->hw, GG82563_PHY_KMRN_MODE_CTRL, - 0x1CE); + 0x1CC); } /* force 1000, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); -- cgit v1.2.3 From 2db10a081c5c1082d58809a1bcf1a6073f4db160 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:28 -0700 Subject: e1000: rework driver hardware reset locking After studying the driver mac reset code it was found that there were multiple race conditions possible to reset the unit twice or bring it e1000_up() double. This fixes all occurences where the driver needs to reset the mac. We also remove irq requesting/releasing into _open and _close so that while the device is _up we will never touch the irq's. This fixes the double free irq bug that people saw. To make sure that the watchdog task doesn't cause another race we let it run as a non-scheduled task. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000.h | 8 ++- drivers/net/e1000/e1000_ethtool.c | 46 ++++++++------ drivers/net/e1000/e1000_main.c | 126 ++++++++++++++++++++++---------------- 3 files changed, 105 insertions(+), 75 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 2bc34fbfa69..2b96ad0482e 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -69,7 +69,6 @@ #ifdef NETIF_F_TSO #include #endif -#include #include #include #include @@ -255,7 +254,6 @@ struct e1000_adapter { spinlock_t tx_queue_lock; #endif atomic_t irq_sem; - struct work_struct watchdog_task; struct work_struct reset_task; uint8_t fc_autoneg; @@ -340,8 +338,13 @@ struct e1000_adapter { #ifdef NETIF_F_TSO boolean_t tso_force; #endif + unsigned long flags; }; +enum e1000_state_t { + __E1000_DRIVER_TESTING, + __E1000_RESETTING, +}; /* e1000_main.c */ extern char e1000_driver_name[]; @@ -349,6 +352,7 @@ extern char e1000_driver_version[]; int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); +void e1000_reinit_locked(struct e1000_adapter *adapter); int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); void e1000_free_all_tx_resources(struct e1000_adapter *adapter); int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 845d293b2f6..cf5c5f46341 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -203,11 +203,9 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) /* reset the link */ - if (netif_running(adapter->netdev)) { - e1000_down(adapter); - e1000_reset(adapter); - e1000_up(adapter); - } else + if (netif_running(adapter->netdev)) + e1000_reinit_locked(adapter); + else e1000_reset(adapter); return 0; @@ -254,10 +252,9 @@ e1000_set_pauseparam(struct net_device *netdev, hw->original_fc = hw->fc; if (adapter->fc_autoneg == AUTONEG_ENABLE) { - if (netif_running(adapter->netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } else + if (netif_running(adapter->netdev)) + e1000_reinit_locked(adapter); + else e1000_reset(adapter); } else return ((hw->media_type == e1000_media_type_fiber) ? @@ -279,10 +276,9 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data) struct e1000_adapter *adapter = netdev_priv(netdev); adapter->rx_csum = data; - if (netif_running(netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } else + if (netif_running(netdev)) + e1000_reinit_locked(adapter); + else e1000_reset(adapter); return 0; } @@ -631,6 +627,9 @@ e1000_set_ringparam(struct net_device *netdev, tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; + while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) + msleep(1); + if (netif_running(adapter->netdev)) e1000_down(adapter); @@ -691,9 +690,11 @@ e1000_set_ringparam(struct net_device *netdev, adapter->rx_ring = rx_new; adapter->tx_ring = tx_new; if ((err = e1000_up(adapter))) - return err; + goto err_setup; } + clear_bit(__E1000_RESETTING, &adapter->flags); + return 0; err_setup_tx: e1000_free_all_rx_resources(adapter); @@ -701,6 +702,8 @@ err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; e1000_up(adapter); +err_setup: + clear_bit(__E1000_RESETTING, &adapter->flags); return err; } @@ -1568,6 +1571,7 @@ e1000_diag_test(struct net_device *netdev, struct e1000_adapter *adapter = netdev_priv(netdev); boolean_t if_running = netif_running(netdev); + set_bit(__E1000_DRIVER_TESTING, &adapter->flags); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ @@ -1582,7 +1586,8 @@ e1000_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; if (if_running) - e1000_down(adapter); + /* indicate we're in test mode */ + dev_close(netdev); else e1000_reset(adapter); @@ -1607,8 +1612,9 @@ e1000_diag_test(struct net_device *netdev, adapter->hw.autoneg = autoneg; e1000_reset(adapter); + clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); if (if_running) - e1000_up(adapter); + dev_open(netdev); } else { /* Online tests */ if (e1000_link_test(adapter, &data[4])) @@ -1619,6 +1625,8 @@ e1000_diag_test(struct net_device *netdev, data[1] = 0; data[2] = 0; data[3] = 0; + + clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); } msleep_interruptible(4 * 1000); } @@ -1807,10 +1815,8 @@ static int e1000_nway_reset(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - if (netif_running(netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } + if (netif_running(netdev)) + e1000_reinit_locked(adapter); return 0; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a373ccb308d..52d698bb259 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -133,7 +133,6 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter, static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); -static void e1000_watchdog_task(struct e1000_adapter *adapter); static void e1000_82547_tx_fifo_stall(unsigned long data); static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); static struct net_device_stats * e1000_get_stats(struct net_device *netdev); @@ -261,6 +260,44 @@ e1000_exit_module(void) module_exit(e1000_exit_module); +static int e1000_request_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int flags, err = 0; + + flags = SA_SHIRQ | SA_SAMPLE_RANDOM; +#ifdef CONFIG_PCI_MSI + if (adapter->hw.mac_type > e1000_82547_rev_2) { + adapter->have_msi = TRUE; + if ((err = pci_enable_msi(adapter->pdev))) { + DPRINTK(PROBE, ERR, + "Unable to allocate MSI interrupt Error: %d\n", err); + adapter->have_msi = FALSE; + } + } + if (adapter->have_msi) + flags &= ~SA_SHIRQ; +#endif + if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags, + netdev->name, netdev))) + DPRINTK(PROBE, ERR, + "Unable to allocate interrupt Error: %d\n", err); + + return err; +} + +static void e1000_free_irq(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + free_irq(adapter->pdev->irq, netdev); + +#ifdef CONFIG_PCI_MSI + if (adapter->have_msi) + pci_disable_msi(adapter->pdev); +#endif +} + /** * e1000_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure @@ -387,7 +424,7 @@ int e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - int i, err; + int i; /* hardware has been reset, we need to reload some things */ @@ -415,24 +452,6 @@ e1000_up(struct e1000_adapter *adapter) E1000_DESC_UNUSED(ring)); } -#ifdef CONFIG_PCI_MSI - if (adapter->hw.mac_type > e1000_82547_rev_2) { - adapter->have_msi = TRUE; - if ((err = pci_enable_msi(adapter->pdev))) { - DPRINTK(PROBE, ERR, - "Unable to allocate MSI interrupt Error: %d\n", err); - adapter->have_msi = FALSE; - } - } -#endif - if ((err = request_irq(adapter->pdev->irq, &e1000_intr, - SA_SHIRQ | SA_SAMPLE_RANDOM, - netdev->name, netdev))) { - DPRINTK(PROBE, ERR, - "Unable to allocate interrupt Error: %d\n", err); - return err; - } - adapter->tx_queue_len = netdev->tx_queue_len; mod_timer(&adapter->watchdog_timer, jiffies); @@ -450,16 +469,10 @@ e1000_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) && - e1000_check_mng_mode(&adapter->hw); + e1000_check_mng_mode(&adapter->hw); e1000_irq_disable(adapter); - free_irq(adapter->pdev->irq, netdev); -#ifdef CONFIG_PCI_MSI - if (adapter->hw.mac_type > e1000_82547_rev_2 && - adapter->have_msi == TRUE) - pci_disable_msi(adapter->pdev); -#endif del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); @@ -495,6 +508,17 @@ e1000_down(struct e1000_adapter *adapter) } } +void +e1000_reinit_locked(struct e1000_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) + msleep(1); + e1000_down(adapter); + e1000_up(adapter); + clear_bit(__E1000_RESETTING, &adapter->flags); +} + void e1000_reset(struct e1000_adapter *adapter) { @@ -758,9 +782,6 @@ e1000_probe(struct pci_dev *pdev, adapter->watchdog_timer.function = &e1000_watchdog; adapter->watchdog_timer.data = (unsigned long) adapter; - INIT_WORK(&adapter->watchdog_task, - (void (*)(void *))e1000_watchdog_task, adapter); - init_timer(&adapter->phy_info_timer); adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; @@ -1078,6 +1099,10 @@ e1000_open(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); int err; + /* disallow open during test */ + if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags)) + return -EBUSY; + /* allocate transmit descriptors */ if ((err = e1000_setup_all_tx_resources(adapter))) @@ -1088,6 +1113,10 @@ e1000_open(struct net_device *netdev) if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; + err = e1000_request_irq(adapter); + if (err) + goto err_up; + if ((err = e1000_up(adapter))) goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; @@ -1131,7 +1160,9 @@ e1000_close(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); + WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); e1000_down(adapter); + e1000_free_irq(adapter); e1000_free_all_tx_resources(adapter); e1000_free_all_rx_resources(adapter); @@ -2201,14 +2232,6 @@ static void e1000_watchdog(unsigned long data) { struct e1000_adapter *adapter = (struct e1000_adapter *) data; - - /* Do the rest outside of interrupt context */ - schedule_work(&adapter->watchdog_task); -} - -static void -e1000_watchdog_task(struct e1000_adapter *adapter) -{ struct net_device *netdev = adapter->netdev; struct e1000_tx_ring *txdr = adapter->tx_ring; uint32_t link, tctl; @@ -2919,8 +2942,7 @@ e1000_reset_task(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - e1000_down(adapter); - e1000_up(adapter); + e1000_reinit_locked(adapter); } /** @@ -3026,10 +3048,8 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) netdev->mtu = new_mtu; - if (netif_running(netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } + if (netif_running(netdev)) + e1000_reinit_locked(adapter); adapter->hw.max_frame_size = max_frame; @@ -4180,10 +4200,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) return retval; } } - if (netif_running(adapter->netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } else + if (netif_running(adapter->netdev)) + e1000_reinit_locked(adapter); + else e1000_reset(adapter); break; case M88E1000_PHY_SPEC_CTRL: @@ -4200,10 +4219,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) case PHY_CTRL: if (mii_reg & MII_CR_POWER_DOWN) break; - if (netif_running(adapter->netdev)) { - e1000_down(adapter); - e1000_up(adapter); - } else + if (netif_running(adapter->netdev)) + e1000_reinit_locked(adapter); + else e1000_reset(adapter); break; } @@ -4462,8 +4480,10 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(netdev); - if (netif_running(netdev)) + if (netif_running(netdev)) { + WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); e1000_down(adapter); + } #ifdef CONFIG_PM /* Implement our own version of pci_save_state(pdev) because pci- -- cgit v1.2.3 From 79f05bf0ba9b41561600f3cdfdf86b5184fc6675 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:32 -0700 Subject: e1000: Make PHY powerup/down a function In relation to the irq work done earlier we also move the PHY powerup and powerdown functions into separate functions and move the calls to _close and _open, making the PHY stay in it's power state as long as the device is _up. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 76 +++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 52d698bb259..813d5e0e458 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -428,14 +428,6 @@ e1000_up(struct e1000_adapter *adapter) /* hardware has been reset, we need to reload some things */ - /* Reset the PHY if it was previously powered down */ - if (adapter->hw.media_type == e1000_media_type_copper) { - uint16_t mii_reg; - e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); - if (mii_reg & MII_CR_POWER_DOWN) - e1000_phy_hw_reset(&adapter->hw); - } - e1000_set_multi(netdev); e1000_restore_vlan(adapter); @@ -464,12 +456,56 @@ e1000_up(struct e1000_adapter *adapter) return 0; } +/** + * e1000_power_up_phy - restore link in case the phy was powered down + * @adapter: address of board private structure + * + * The phy may be powered down to save power and turn off link when the + * driver is unloaded and wake on lan is not enabled (among others) + * *** this routine MUST be followed by a call to e1000_reset *** + * + **/ + +static void e1000_power_up_phy(struct e1000_adapter *adapter) +{ + uint16_t mii_reg = 0; + + /* Just clear the power down bit to wake the phy back up */ + if (adapter->hw.media_type == e1000_media_type_copper) { + /* according to the manual, the phy will retain its + * settings across a power-down/up cycle */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + } +} + +static void e1000_power_down_phy(struct e1000_adapter *adapter) +{ + boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) && + e1000_check_mng_mode(&adapter->hw); + /* Power down the PHY so no link is implied when interface is down + * The PHY cannot be powered down if any of the following is TRUE + * (a) WoL is enabled + * (b) AMT is active + * (c) SoL/IDER session is active */ + if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 && + adapter->hw.media_type == e1000_media_type_copper && + !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) && + !mng_mode_enabled && + !e1000_check_phy_reset_block(&adapter->hw)) { + uint16_t mii_reg = 0; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); + mdelay(1); + } +} + void e1000_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) && - e1000_check_mng_mode(&adapter->hw); e1000_irq_disable(adapter); @@ -489,23 +525,6 @@ e1000_down(struct e1000_adapter *adapter) e1000_reset(adapter); e1000_clean_all_tx_rings(adapter); e1000_clean_all_rx_rings(adapter); - - /* Power down the PHY so no link is implied when interface is down * - * The PHY cannot be powered down if any of the following is TRUE * - * (a) WoL is enabled - * (b) AMT is active - * (c) SoL/IDER session is active */ - if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 && - adapter->hw.media_type == e1000_media_type_copper && - !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) && - !mng_mode_enabled && - !e1000_check_phy_reset_block(&adapter->hw)) { - uint16_t mii_reg; - e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg); - mdelay(1); - } } void @@ -1117,6 +1136,8 @@ e1000_open(struct net_device *netdev) if (err) goto err_up; + e1000_power_up_phy(adapter); + if ((err = e1000_up(adapter))) goto err_up; adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; @@ -1162,6 +1183,7 @@ e1000_close(struct net_device *netdev) WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); e1000_down(adapter); + e1000_power_down_phy(adapter); e1000_free_irq(adapter); e1000_free_all_tx_resources(adapter); -- cgit v1.2.3 From 6fdfef162426766611b1f640138e4720f56e45f8 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:36 -0700 Subject: e1000: fix CONFIG_PM blocks e1000_suspend is called even when !CONFIG_PM. The non-PM code inside of it is properly #ifdef'd. This fixes the compiler warnings when !CONFIG_PM. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 813d5e0e458..7cf5e5dce0d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -177,8 +177,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); -#ifdef CONFIG_PM static int e1000_suspend(struct pci_dev *pdev, pm_message_t state); +#ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev); #endif static void e1000_shutdown(struct pci_dev *pdev); @@ -205,8 +205,8 @@ static struct pci_driver e1000_driver = { .probe = e1000_probe, .remove = __devexit_p(e1000_remove), /* Power Managment Hooks */ -#ifdef CONFIG_PM .suspend = e1000_suspend, +#ifdef CONFIG_PM .resume = e1000_resume, #endif .shutdown = e1000_shutdown, @@ -4498,7 +4498,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t ctrl, ctrl_ext, rctl, manc, status; uint32_t wufc = adapter->wol; +#ifdef CONFIG_PM int retval = 0; +#endif netif_device_detach(netdev); -- cgit v1.2.3 From 0cbabbb0725fa34a37d6b7870b2d2fe17d1a0a94 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:41 -0700 Subject: e1000: small performance tweak by removing double code buffer_info is already filled at the end of this while() loop. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7cf5e5dce0d..76e36a4fd98 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3717,7 +3717,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, buffer_info = &rx_ring->buffer_info[i]; while (staterr & E1000_RXD_STAT_DD) { - buffer_info = &rx_ring->buffer_info[i]; ps_page = &rx_ring->ps_page[i]; ps_page_dma = &rx_ring->ps_page_dma[i]; #ifdef CONFIG_E1000_NAPI -- cgit v1.2.3 From 9a53a2029885e0088e9149679215b95d04deb57b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:45 -0700 Subject: e1000: add smart power down code Smart Power Down is a power saving feature in newer e1000 hardware. We disable it because it causes time to link to be long, but make it a user choice. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_main.c | 15 +++++++++++++++ drivers/net/e1000/e1000_param.c | 25 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 2b96ad0482e..dbdaa332cac 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -338,6 +338,7 @@ struct e1000_adapter { #ifdef NETIF_F_TSO boolean_t tso_force; #endif + boolean_t smart_power_down; /* phy smart power down */ unsigned long flags; }; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 76e36a4fd98..ea18f3085f6 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -607,6 +607,21 @@ e1000_reset(struct e1000_adapter *adapter) e1000_reset_adaptive(&adapter->hw); e1000_phy_get_info(&adapter->hw, &adapter->phy_info); + + if (!adapter->smart_power_down && + (adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572)) { + uint16_t phy_data = 0; + /* speed up time to link by disabling smart power down, ignore + * the return value of this function because there is nothing + * different we would do if it failed */ + e1000_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT, + &phy_data); + phy_data &= ~IGP02E1000_PM_SPD; + e1000_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT, + phy_data); + } + if (adapter->en_mng_pt) { manc = E1000_READ_REG(&adapter->hw, MANC); manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index e55f8969a0f..a8d9295b077 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -183,6 +183,15 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); +/* Enable Smart Power Down of the PHY + * + * Valid Range: 0, 1 + * + * Default Value: 0 (disabled) + */ + +E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); + #define AUTONEG_ADV_DEFAULT 0x2F #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL @@ -494,6 +503,22 @@ e1000_check_options(struct e1000_adapter *adapter) adapter->itr = opt.def; } } + { /* Smart Power Down */ + struct e1000_option opt = { + .type = enable_option, + .name = "PHY Smart Power Down", + .err = "defaulting to Disabled", + .def = OPTION_DISABLED + }; + + if (num_SmartPowerDownEnable > bd) { + int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); + adapter->smart_power_down = spd; + } else { + adapter->smart_power_down = opt.def; + } + } switch (adapter->hw.media_type) { case e1000_media_type_fiber: -- cgit v1.2.3 From a5eafce2ce2fd3a1956657d85908ca691b870e5d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:49 -0700 Subject: e1000: change printk into DPRINTK Changing a printk message to make clear that this message is originating from e1000. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index ea18f3085f6..fc39cbcee2b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2841,7 +2841,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) case e1000_82573: pull_size = min((unsigned int)4, skb->data_len); if (!__pskb_pull_tail(skb, pull_size)) { - printk(KERN_ERR + DPRINTK(DRV, ERR, "__pskb_pull_tail failed.\n"); dev_kfree_skb_any(skb); return NETDEV_TX_OK; -- cgit v1.2.3 From 864c4e45ec6d1bfe16a14d887d5baad201419aba Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:53 -0700 Subject: e1000: recycle skb Recycle an skb to improve performance a bit. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index fc39cbcee2b..c58fafd1c4b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3604,7 +3604,8 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, /* All receives must fit into a single buffer */ E1000_DBG("%s: Receive packet consumed multiple" " buffers\n", netdev->name); - dev_kfree_skb_irq(skb); + /* recycle */ + buffer_info-> skb = skb; goto next_desc; } -- cgit v1.2.3 From 17231712ab89fa085bc235ef19c1e6e0c163e4fc Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:06:59 -0700 Subject: e1000: rework module param code with uninitialized values We can take uninitialized values into account which minimizes code and allows us to simplify the parameter checking code greatly. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_param.c | 167 +++++++++++++++------------------------- 1 file changed, 61 insertions(+), 106 deletions(-) diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index a8d9295b077..bd6c040b3cf 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -45,6 +45,16 @@ */ #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } +/* Module Parameters are always initialized to -1, so that the driver + * can tell the difference between no user specified value or the + * user asking for the default value. + * The true default values are loaded in when e1000_check_options is called. + * + * This is a GCC extension to ANSI C. + * See the item "Labeled Elements in Initializers" in the section + * "Extensions to the C Language Family" of the GCC documentation. + */ + #define E1000_PARAM(X, desc) \ static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ static int num_##X = 0; \ @@ -305,6 +315,7 @@ e1000_check_options(struct e1000_adapter *adapter) DPRINTK(PROBE, NOTICE, "Warning: no configuration for board #%i\n", bd); DPRINTK(PROBE, NOTICE, "Using defaults for all values\n"); + bd = E1000_MAX_NIC; } { /* Transmit Descriptor Count */ @@ -322,14 +333,9 @@ e1000_check_options(struct e1000_adapter *adapter) opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD; - if (num_TxDescriptors > bd) { - tx_ring->count = TxDescriptors[bd]; - e1000_validate_option(&tx_ring->count, &opt, adapter); - E1000_ROUNDUP(tx_ring->count, - REQ_TX_DESCRIPTOR_MULTIPLE); - } else { - tx_ring->count = opt.def; - } + tx_ring->count = TxDescriptors[bd]; + e1000_validate_option(&tx_ring->count, &opt, adapter); + E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); for (i = 0; i < adapter->num_tx_queues; i++) tx_ring[i].count = tx_ring->count; } @@ -348,14 +354,9 @@ e1000_check_options(struct e1000_adapter *adapter) opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD; - if (num_RxDescriptors > bd) { - rx_ring->count = RxDescriptors[bd]; - e1000_validate_option(&rx_ring->count, &opt, adapter); - E1000_ROUNDUP(rx_ring->count, - REQ_RX_DESCRIPTOR_MULTIPLE); - } else { - rx_ring->count = opt.def; - } + rx_ring->count = RxDescriptors[bd]; + e1000_validate_option(&rx_ring->count, &opt, adapter); + E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); for (i = 0; i < adapter->num_rx_queues; i++) rx_ring[i].count = rx_ring->count; } @@ -367,13 +368,9 @@ e1000_check_options(struct e1000_adapter *adapter) .def = OPTION_ENABLED }; - if (num_XsumRX > bd) { - int rx_csum = XsumRX[bd]; - e1000_validate_option(&rx_csum, &opt, adapter); - adapter->rx_csum = rx_csum; - } else { - adapter->rx_csum = opt.def; - } + int rx_csum = XsumRX[bd]; + e1000_validate_option(&rx_csum, &opt, adapter); + adapter->rx_csum = rx_csum; } { /* Flow Control */ @@ -393,13 +390,9 @@ e1000_check_options(struct e1000_adapter *adapter) .p = fc_list }} }; - if (num_FlowControl > bd) { - int fc = FlowControl[bd]; - e1000_validate_option(&fc, &opt, adapter); - adapter->hw.fc = adapter->hw.original_fc = fc; - } else { - adapter->hw.fc = adapter->hw.original_fc = opt.def; - } + int fc = FlowControl[bd]; + e1000_validate_option(&fc, &opt, adapter); + adapter->hw.fc = adapter->hw.original_fc = fc; } { /* Transmit Interrupt Delay */ struct e1000_option opt = { @@ -411,13 +404,8 @@ e1000_check_options(struct e1000_adapter *adapter) .max = MAX_TXDELAY }} }; - if (num_TxIntDelay > bd) { - adapter->tx_int_delay = TxIntDelay[bd]; - e1000_validate_option(&adapter->tx_int_delay, &opt, - adapter); - } else { - adapter->tx_int_delay = opt.def; - } + adapter->tx_int_delay = TxIntDelay[bd]; + e1000_validate_option(&adapter->tx_int_delay, &opt, adapter); } { /* Transmit Absolute Interrupt Delay */ struct e1000_option opt = { @@ -429,13 +417,9 @@ e1000_check_options(struct e1000_adapter *adapter) .max = MAX_TXABSDELAY }} }; - if (num_TxAbsIntDelay > bd) { - adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; - e1000_validate_option(&adapter->tx_abs_int_delay, &opt, - adapter); - } else { - adapter->tx_abs_int_delay = opt.def; - } + adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; + e1000_validate_option(&adapter->tx_abs_int_delay, &opt, + adapter); } { /* Receive Interrupt Delay */ struct e1000_option opt = { @@ -447,13 +431,8 @@ e1000_check_options(struct e1000_adapter *adapter) .max = MAX_RXDELAY }} }; - if (num_RxIntDelay > bd) { - adapter->rx_int_delay = RxIntDelay[bd]; - e1000_validate_option(&adapter->rx_int_delay, &opt, - adapter); - } else { - adapter->rx_int_delay = opt.def; - } + adapter->rx_int_delay = RxIntDelay[bd]; + e1000_validate_option(&adapter->rx_int_delay, &opt, adapter); } { /* Receive Absolute Interrupt Delay */ struct e1000_option opt = { @@ -465,13 +444,9 @@ e1000_check_options(struct e1000_adapter *adapter) .max = MAX_RXABSDELAY }} }; - if (num_RxAbsIntDelay > bd) { - adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; - e1000_validate_option(&adapter->rx_abs_int_delay, &opt, - adapter); - } else { - adapter->rx_abs_int_delay = opt.def; - } + adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; + e1000_validate_option(&adapter->rx_abs_int_delay, &opt, + adapter); } { /* Interrupt Throttling Rate */ struct e1000_option opt = { @@ -483,24 +458,18 @@ e1000_check_options(struct e1000_adapter *adapter) .max = MAX_ITR }} }; - if (num_InterruptThrottleRate > bd) { - adapter->itr = InterruptThrottleRate[bd]; - switch (adapter->itr) { - case 0: - DPRINTK(PROBE, INFO, "%s turned off\n", - opt.name); - break; - case 1: - DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", - opt.name); - break; - default: - e1000_validate_option(&adapter->itr, &opt, - adapter); - break; - } - } else { - adapter->itr = opt.def; + adapter->itr = InterruptThrottleRate[bd]; + switch (adapter->itr) { + case 0: + DPRINTK(PROBE, INFO, "%s turned off\n", opt.name); + break; + case 1: + DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", + opt.name); + break; + default: + e1000_validate_option(&adapter->itr, &opt, adapter); + break; } } { /* Smart Power Down */ @@ -511,13 +480,9 @@ e1000_check_options(struct e1000_adapter *adapter) .def = OPTION_DISABLED }; - if (num_SmartPowerDownEnable > bd) { - int spd = SmartPowerDownEnable[bd]; - e1000_validate_option(&spd, &opt, adapter); - adapter->smart_power_down = spd; - } else { - adapter->smart_power_down = opt.def; - } + int spd = SmartPowerDownEnable[bd]; + e1000_validate_option(&spd, &opt, adapter); + adapter->smart_power_down = spd; } switch (adapter->hw.media_type) { @@ -544,17 +509,18 @@ static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter) { int bd = adapter->bd_number; - if (num_Speed > bd) { + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; + if ((Speed[bd] != OPTION_UNSET)) { DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, " "parameter ignored\n"); } - if (num_Duplex > bd) { + if ((Duplex[bd] != OPTION_UNSET)) { DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, " "parameter ignored\n"); } - if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) { + if ((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) { DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is " "not valid for fiber adapters, " "parameter ignored\n"); @@ -573,6 +539,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter) { int speed, dplx, an; int bd = adapter->bd_number; + bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd; { /* Speed */ struct e1000_opt_list speed_list[] = {{ 0, "" }, @@ -589,12 +556,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .p = speed_list }} }; - if (num_Speed > bd) { - speed = Speed[bd]; - e1000_validate_option(&speed, &opt, adapter); - } else { - speed = opt.def; - } + speed = Speed[bd]; + e1000_validate_option(&speed, &opt, adapter); } { /* Duplex */ struct e1000_opt_list dplx_list[] = {{ 0, "" }, @@ -616,15 +579,11 @@ e1000_check_copper_options(struct e1000_adapter *adapter) "Speed/Duplex/AutoNeg parameter ignored.\n"); return; } - if (num_Duplex > bd) { - dplx = Duplex[bd]; - e1000_validate_option(&dplx, &opt, adapter); - } else { - dplx = opt.def; - } + dplx = Duplex[bd]; + e1000_validate_option(&dplx, &opt, adapter); } - if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) { + if (AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) { DPRINTK(PROBE, INFO, "AutoNeg specified along with Speed or Duplex, " "parameter ignored\n"); @@ -673,19 +632,15 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .p = an_list }} }; - if (num_AutoNeg > bd) { - an = AutoNeg[bd]; - e1000_validate_option(&an, &opt, adapter); - } else { - an = opt.def; - } + an = AutoNeg[bd]; + e1000_validate_option(&an, &opt, adapter); adapter->hw.autoneg_advertised = an; } switch (speed + dplx) { case 0: adapter->hw.autoneg = adapter->fc_autoneg = 1; - if ((num_Speed > bd) && (speed != 0 || dplx != 0)) + if (Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET) DPRINTK(PROBE, INFO, "Speed and duplex autonegotiation enabled\n"); break; -- cgit v1.2.3 From 4ca213a6957318219822c024c8e4c61b3e42a7dc Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:07:08 -0700 Subject: e1000: force register write flushes to circumvent broken platforms A certain AMD64 bridge (8132) has an option to turn on write combining which breaks our adapter. To circumvent this we need to flush every write. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_hw.c | 24 ++++++++++++++++++++++-- drivers/net/e1000/e1000_main.c | 18 +++++++++++------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 3959039b16e..749d621a07d 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -705,8 +705,12 @@ e1000_init_hw(struct e1000_hw *hw) /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); mta_size = E1000_MC_TBL_SIZE; - for(i = 0; i < mta_size; i++) + for(i = 0; i < mta_size; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); + /* use write flush to prevent Memory Write Block (MWB) from + * occuring when accessing our register space */ + E1000_WRITE_FLUSH(hw); + } /* Set the PCI priority bit correctly in the CTRL register. This * determines if the adapter gives priority to receives, or if it @@ -5106,7 +5110,9 @@ e1000_init_rx_addrs(struct e1000_hw *hw) DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < rar_num; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); + E1000_WRITE_FLUSH(hw); } } @@ -5153,7 +5159,9 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, for(i = rar_used_count; i < num_rar_entry; i++) { E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0); + E1000_WRITE_FLUSH(hw); } /* Clear the MTA */ @@ -5161,6 +5169,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, num_mta_entry = E1000_NUM_MTA_REGISTERS; for(i = 0; i < num_mta_entry; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); + E1000_WRITE_FLUSH(hw); } /* Add the new addresses */ @@ -5275,9 +5284,12 @@ e1000_mta_set(struct e1000_hw *hw, if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) { temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1)); E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp); + E1000_WRITE_FLUSH(hw); } else { E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta); + E1000_WRITE_FLUSH(hw); } } @@ -5334,7 +5346,9 @@ e1000_rar_set(struct e1000_hw *hw, } E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high); + E1000_WRITE_FLUSH(hw); } /****************************************************************************** @@ -5354,9 +5368,12 @@ e1000_write_vfta(struct e1000_hw *hw, if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1)); E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp); + E1000_WRITE_FLUSH(hw); } else { E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value); + E1000_WRITE_FLUSH(hw); } } @@ -5392,6 +5409,7 @@ e1000_clear_vfta(struct e1000_hw *hw) * manageability unit */ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0; E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value); + E1000_WRITE_FLUSH(hw); } } @@ -6928,8 +6946,10 @@ e1000_mng_write_cmd_header(struct e1000_hw * hw, length >>= 2; /* The device driver writes the relevant command block into the ram area. */ - for (i = 0; i < length; i++) + for (i = 0; i < length; i++) { E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i)); + E1000_WRITE_FLUSH(hw); + } return E1000_SUCCESS; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c58fafd1c4b..c44ed6f4ba7 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1370,11 +1370,11 @@ e1000_configure_tx(struct e1000_adapter *adapter) tdba = adapter->tx_ring[0].dma; tdlen = adapter->tx_ring[0].count * sizeof(struct e1000_tx_desc); - E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(hw, TDBAH, (tdba >> 32)); E1000_WRITE_REG(hw, TDLEN, tdlen); - E1000_WRITE_REG(hw, TDH, 0); + E1000_WRITE_REG(hw, TDBAH, (tdba >> 32)); + E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(hw, TDT, 0); + E1000_WRITE_REG(hw, TDH, 0); adapter->tx_ring[0].tdh = E1000_TDH; adapter->tx_ring[0].tdt = E1000_TDT; break; @@ -1780,11 +1780,11 @@ e1000_configure_rx(struct e1000_adapter *adapter) case 1: default: rdba = adapter->rx_ring[0].dma; - E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); E1000_WRITE_REG(hw, RDLEN, rdlen); - E1000_WRITE_REG(hw, RDH, 0); + E1000_WRITE_REG(hw, RDBAH, (rdba >> 32)); + E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL)); E1000_WRITE_REG(hw, RDT, 0); + E1000_WRITE_REG(hw, RDH, 0); adapter->rx_ring[0].rdh = E1000_RDH; adapter->rx_ring[0].rdt = E1000_RDT; break; @@ -2189,14 +2189,18 @@ e1000_set_multi(struct net_device *netdev) mc_ptr = mc_ptr->next; } else { E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0); + E1000_WRITE_FLUSH(hw); E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0); + E1000_WRITE_FLUSH(hw); } } /* clear the old settings from the multicast hash table */ - for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) + for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); + E1000_WRITE_FLUSH(hw); + } /* load any remaining addresses into the hash table */ -- cgit v1.2.3 From 7dfee0cb1d506897805b663dd95e9651619a4d4d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:07:50 -0700 Subject: e1000: disable CRC stripping workaround CRC stripping is breaking SMBUS-connected BMC's. We disable this feature to make it work. This fixes related bugs regarding SOL. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c44ed6f4ba7..a9e55dc10c5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1628,9 +1628,6 @@ e1000_setup_rctl(struct e1000_adapter *adapter) E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); - if (adapter->hw.mac_type > e1000_82543) - rctl |= E1000_RCTL_SECRC; - if (adapter->hw.tbi_compatibility_on == 1) rctl |= E1000_RCTL_SBP; else @@ -1696,7 +1693,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rfctl |= E1000_RFCTL_IPV6_DIS; E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl); - rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC; + rctl |= E1000_RCTL_DTYP_PS; psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; -- cgit v1.2.3 From f1b3a85354d3877fae45ef448e7e49c2efd692d5 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:07:56 -0700 Subject: e1000: fix adapter led blinking inconsistency Several e1000 adapters were not blinking correctly or inconsistently. This patch cleans this up and makes them all behave the same as far as possible. Signed-off-by: Jeff Kirsher Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_ethtool.c | 15 +-------------- drivers/net/e1000/e1000_hw.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/net/e1000/e1000_hw.h | 1 + 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index cf5c5f46341..06091553292 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1786,21 +1786,8 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); - } else if (adapter->hw.mac_type < e1000_82573) { - E1000_WRITE_REG(&adapter->hw, LEDCTL, - (E1000_LEDCTL_LED2_BLINK_RATE | - E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT))); - msleep_interruptible(data * 1000); } else { - E1000_WRITE_REG(&adapter->hw, LEDCTL, - (E1000_LEDCTL_LED2_BLINK_RATE | - E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT))); + e1000_blink_led_start(&adapter->hw); msleep_interruptible(data * 1000); } diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 749d621a07d..1c5b18478fb 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -5536,6 +5536,44 @@ e1000_setup_led(struct e1000_hw *hw) return E1000_SUCCESS; } +/****************************************************************************** + * Used on 82571 and later Si that has LED blink bits. + * Callers must use their own timer and should have already called + * e1000_id_led_init() + * Call e1000_cleanup led() to stop blinking + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +e1000_blink_led_start(struct e1000_hw *hw) +{ + int16_t i; + uint32_t ledctl_blink = 0; + + DEBUGFUNC("e1000_id_led_blink_on"); + + if (hw->mac_type < e1000_82571) { + /* Nothing to do */ + return E1000_SUCCESS; + } + if (hw->media_type == e1000_media_type_fiber) { + /* always blink LED0 for PCI-E fiber */ + ledctl_blink = E1000_LEDCTL_LED0_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); + } else { + /* set the blink bit for each LED that's "on" (0x0E) in ledctl_mode2 */ + ledctl_blink = hw->ledctl_mode2; + for (i=0; i < 4; i++) + if (((hw->ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << (i * 8)); + } + + E1000_WRITE_REG(hw, LEDCTL, ledctl_blink); + + return E1000_SUCCESS; +} + /****************************************************************************** * Restores the saved state of the SW controlable LED. * diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 467c9ed944f..941b47d6167 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -401,6 +401,7 @@ int32_t e1000_setup_led(struct e1000_hw *hw); int32_t e1000_cleanup_led(struct e1000_hw *hw); int32_t e1000_led_on(struct e1000_hw *hw); int32_t e1000_led_off(struct e1000_hw *hw); +int32_t e1000_blink_led_start(struct e1000_hw *hw); /* Adaptive IFS Functions */ -- cgit v1.2.3 From ee04022a21764a12e29eee144b72344ebfe0a55c Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:03 -0700 Subject: e1000: M88 PHY workaround M88 rev 2 PHY needs a longer downshift to function properly. This adds a much longer downshift counter for this specific device. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_hw.c | 46 ++++++++++++++++++++++++++++---------------- drivers/net/e1000/e1000_hw.h | 11 +++++++++++ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 1c5b18478fb..37eb351b4c9 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1565,28 +1565,40 @@ e1000_copper_link_mgp_setup(struct e1000_hw *hw) phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; if(hw->disable_polarity_correction == 1) phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if(ret_val) - return ret_val; - - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if(ret_val) + ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) return ret_val; - phy_data |= M88E1000_EPSCR_TX_CLK_25; - if (hw->phy_revision < M88E1011_I_REV_4) { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((hw->phy_revision == E1000_REVISION_2) && + (hw->phy_id == M88E1111_I_PHY_ID)) { + /* Vidalia Phy, set the downshift counter to 5x */ + phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK); + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + ret_val = e1000_write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if(ret_val) - return ret_val; + ret_val = e1000_write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; + } } /* SW Reset the PHY so all changes take effect */ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 941b47d6167..1908e0d3110 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -2765,6 +2765,17 @@ struct e1000_host_command_info { #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 + /* IGP01E1000 Specific Port Config Register - R/W */ #define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010 #define IGP01E1000_PSCFR_PRE_EN 0x0020 -- cgit v1.2.3 From 592600a0536f0d5aab4dc95f19515a37d03430f8 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:09 -0700 Subject: e1000: check return value of _get_speed_and_duplex We were not checking the return value of get_speed_and_duplex properly, whih may contain an error value. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_hw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 37eb351b4c9..784f9505864 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -2737,8 +2737,12 @@ e1000_check_for_link(struct e1000_hw *hw) */ if(hw->tbi_compatibility_en) { uint16_t speed, duplex; - e1000_get_speed_and_duplex(hw, &speed, &duplex); - if(speed != SPEED_1000) { + ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + DEBUGOUT("Error getting link speed and duplex\n"); + return ret_val; + } + if (speed != SPEED_1000) { /* If link speed is not set to gigabit speed, we do not need * to enable TBI compatibility. */ -- cgit v1.2.3 From ab7bc0ad72a12ef8eacc1560c9342aa567f3531d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:13 -0700 Subject: e1000: disable ERT Hardware is reported to have problems with ERT. We disable it for all hardware to make sure we are not seeing unexplainable user problems. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a9e55dc10c5..cc0c77c4c17 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1806,9 +1806,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) E1000_WRITE_REG(hw, RXCSUM, rxcsum); } - if (hw->mac_type == e1000_82573) - E1000_WRITE_REG(hw, ERT, 0x0100); - /* Enable Receives */ E1000_WRITE_REG(hw, RCTL, rctl); } -- cgit v1.2.3 From d37ea5d56293b7a883d2a993df5d8b9fb660ed3b Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:17 -0700 Subject: e1000: add ich8lan core functions This implements the core new functions needed for ich8's internal NIC. This includes: * ich8 specific read/write code * flash/nvm access code * software semaphore flag functions * 10/100 PHY (fe - no gigabit speed) support for low-end versions * A workaround for a powerdown sequence problem discovered that affects a small number of motherboard. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_hw.c | 1000 ++++++++++++++++++++++++++++++++++++++- drivers/net/e1000/e1000_hw.h | 386 ++++++++++++++- drivers/net/e1000/e1000_osdep.h | 13 + 3 files changed, 1392 insertions(+), 7 deletions(-) diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 784f9505864..a3f5ccdfafc 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -3616,12 +3616,121 @@ e1000_phy_reset(struct e1000_hw *hw) return E1000_SUCCESS; } +/****************************************************************************** +* Work-around for 82566 power-down: on D3 entry- +* 1) disable gigabit link +* 2) write VR power-down enable +* 3) read it back +* if successful continue, else issue LCD reset and repeat +* +* hw - struct containing variables accessed by shared code +******************************************************************************/ +void +e1000_phy_powerdown_workaround(struct e1000_hw *hw) +{ + int32_t reg; + uint16_t phy_data; + int32_t retry = 0; + + DEBUGFUNC("e1000_phy_powerdown_workaround"); + + if (hw->phy_type != e1000_phy_igp_3) + return; + + do { + /* Disable link */ + reg = E1000_READ_REG(hw, PHY_CTRL); + E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + + /* Write VR power-down enable */ + e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data); + e1000_write_phy_reg(hw, IGP3_VR_CTRL, phy_data | + IGP3_VR_CTRL_MODE_SHUT); + + /* Read it back and test */ + e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data); + if ((phy_data & IGP3_VR_CTRL_MODE_SHUT) || retry) + break; + + /* Issue PHY reset and repeat at most one more time */ + reg = E1000_READ_REG(hw, CTRL); + E1000_WRITE_REG(hw, CTRL, reg | E1000_CTRL_PHY_RST); + retry++; + } while (retry); + + return; + +} + +/****************************************************************************** +* Work-around for 82566 Kumeran PCS lock loss: +* On link status change (i.e. PCI reset, speed change) and link is up and +* speed is gigabit- +* 0) if workaround is optionally disabled do nothing +* 1) wait 1ms for Kumeran link to come up +* 2) check Kumeran Diagnostic register PCS lock loss bit +* 3) if not set the link is locked (all is good), otherwise... +* 4) reset the PHY +* 5) repeat up to 10 times +* Note: this is only called for IGP3 copper when speed is 1gb. +* +* hw - struct containing variables accessed by shared code +******************************************************************************/ +int32_t +e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw) +{ + int32_t ret_val; + int32_t reg; + int32_t cnt; + uint16_t phy_data; + + if (hw->kmrn_lock_loss_workaround_disabled) + return E1000_SUCCESS; + + /* Make sure link is up before proceeding. If not just return. + * Attempting this while link is negotiating fouls up link + * stability */ + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data); + + if (phy_data & MII_SR_LINK_STATUS) { + for (cnt = 0; cnt < 10; cnt++) { + /* read once to clear */ + ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data); + if (ret_val) + return ret_val; + /* and again to get new status */ + ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data); + if (ret_val) + return ret_val; + + /* check for PCS lock */ + if (!(phy_data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) + return E1000_SUCCESS; + + /* Issue PHY reset */ + e1000_phy_hw_reset(hw); + msec_delay_irq(5); + } + /* Disable GigE link negotiation */ + reg = E1000_READ_REG(hw, PHY_CTRL); + E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE); + + /* unable to acquire PCS lock */ + return E1000_ERR_PHY; + } + + return E1000_SUCCESS; +} + /****************************************************************************** * Probes the expected PHY address for known PHY IDs * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -static int32_t +int32_t e1000_detect_gig_phy(struct e1000_hw *hw) { int32_t phy_init_status, ret_val; @@ -3803,6 +3912,53 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, return E1000_SUCCESS; } +/****************************************************************************** +* Get PHY information from various PHY registers for ife PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +e1000_phy_ife_get_info(struct e1000_hw *hw, + struct e1000_phy_info *phy_info) +{ + int32_t ret_val; + uint16_t phy_data, polarity; + + DEBUGFUNC("e1000_phy_ife_get_info"); + + phy_info->downshift = (e1000_downshift)hw->speed_downgraded; + phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal; + + ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + phy_info->polarity_correction = + (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >> + IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT; + + if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) { + ret_val = e1000_check_polarity(hw, &polarity); + if (ret_val) + return ret_val; + } else { + /* Polarity is forced. */ + polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >> + IFE_PSC_FORCE_POLARITY_SHIFT; + } + phy_info->cable_polarity = polarity; + + ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_info->mdix_mode = + (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >> + IFE_PMC_MDIX_MODE_SHIFT; + + return E1000_SUCCESS; +} + /****************************************************************************** * Get PHY information from various PHY registers fot m88 PHY only. * @@ -7630,4 +7786,846 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) } +/****************************************************************************** + * Configure PCI-Ex no-snoop + * + * hw - Struct containing variables accessed by shared code. + * no_snoop - Bitmap of no-snoop events. + * + * returns: E1000_SUCCESS + * + *****************************************************************************/ +int32_t +e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop) +{ + uint32_t gcr_reg = 0; + + DEBUGFUNC("e1000_set_pci_ex_no_snoop"); + + if (hw->bus_type == e1000_bus_type_unknown) + e1000_get_bus_info(hw); + + if (hw->bus_type != e1000_bus_type_pci_express) + return E1000_SUCCESS; + + if (no_snoop) { + gcr_reg = E1000_READ_REG(hw, GCR); + gcr_reg &= ~(PCI_EX_NO_SNOOP_ALL); + gcr_reg |= no_snoop; + E1000_WRITE_REG(hw, GCR, gcr_reg); + } + if (hw->mac_type == e1000_ich8lan) { + uint32_t ctrl_ext; + + E1000_WRITE_REG(hw, GCR, PCI_EX_82566_SNOOP_ALL); + + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_RO_DIS; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Get software semaphore FLAG bit (SWFLAG). + * SWFLAG is used to synchronize the access to all shared resource between + * SW, FW and HW. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +e1000_get_software_flag(struct e1000_hw *hw) +{ + int32_t timeout = PHY_CFG_TIMEOUT; + uint32_t extcnf_ctrl; + + DEBUGFUNC("e1000_get_software_flag"); + + if (hw->mac_type == e1000_ich8lan) { + while (timeout) { + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; + msec_delay_irq(1); + timeout--; + } + + if (!timeout) { + DEBUGOUT("FW or HW locks the resource too long.\n"); + return -E1000_ERR_CONFIG; + } + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Release software semaphore FLAG bit (SWFLAG). + * SWFLAG is used to synchronize the access to all shared resource between + * SW, FW and HW. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +void +e1000_release_software_flag(struct e1000_hw *hw) +{ + uint32_t extcnf_ctrl; + + DEBUGFUNC("e1000_release_software_flag"); + + if (hw->mac_type == e1000_ich8lan) { + extcnf_ctrl= E1000_READ_REG(hw, EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); + } + + return; +} + +/*************************************************************************** + * + * Disable dynamic power down mode in ife PHY. + * It can be used to workaround band-gap problem. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw) +{ + uint16_t phy_data; + int32_t ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_ife_disable_dynamic_power_down"); + + if (hw->phy_type == e1000_phy_ife) { + ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN; + ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data); + } + + return ret_val; +} + +/*************************************************************************** + * + * Enable dynamic power down mode in ife PHY. + * It can be used to workaround band-gap problem. + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +int32_t +e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw) +{ + uint16_t phy_data; + int32_t ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_ife_enable_dynamic_power_down"); + + if (hw->phy_type == e1000_phy_ife) { + ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN; + ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data); + } + + return ret_val; +} + +/****************************************************************************** + * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access + * register. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to read + * data - word read from the EEPROM + * words - number of words to read + *****************************************************************************/ +int32_t +e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, + uint16_t *data) +{ + int32_t error = E1000_SUCCESS; + uint32_t flash_bank = 0; + uint32_t act_offset = 0; + uint32_t bank_offset = 0; + uint16_t word = 0; + uint16_t i = 0; + + /* We need to know which is the valid flash bank. In the event + * that we didn't allocate eeprom_shadow_ram, we may not be + * managing flash_bank. So it cannot be trusted and needs + * to be updated with each read. + */ + /* Value of bit 22 corresponds to the flash bank we're on. */ + flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0; + + /* Adjust offset appropriately if we're on bank 1 - adjust for word size */ + bank_offset = flash_bank * (hw->flash_bank_size * 2); + + error = e1000_get_software_flag(hw); + if (error != E1000_SUCCESS) + return error; + + for (i = 0; i < words; i++) { + if (hw->eeprom_shadow_ram != NULL && + hw->eeprom_shadow_ram[offset+i].modified == TRUE) { + data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word; + } else { + /* The NVM part needs a byte offset, hence * 2 */ + act_offset = bank_offset + ((offset + i) * 2); + error = e1000_read_ich8_word(hw, act_offset, &word); + if (error != E1000_SUCCESS) + break; + data[i] = word; + } + } + + e1000_release_software_flag(hw); + + return error; +} + +/****************************************************************************** + * Writes a 16 bit word or words to the EEPROM using the ICH8's flash access + * register. Actually, writes are written to the shadow ram cache in the hw + * structure hw->e1000_shadow_ram. e1000_commit_shadow_ram flushes this to + * the NVM, which occurs when the NVM checksum is updated. + * + * hw - Struct containing variables accessed by shared code + * offset - offset of word in the EEPROM to write + * words - number of words to write + * data - words to write to the EEPROM + *****************************************************************************/ +int32_t +e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, + uint16_t *data) +{ + uint32_t i = 0; + int32_t error = E1000_SUCCESS; + + error = e1000_get_software_flag(hw); + if (error != E1000_SUCCESS) + return error; + + /* A driver can write to the NVM only if it has eeprom_shadow_ram + * allocated. Subsequent reads to the modified words are read from + * this cached structure as well. Writes will only go into this + * cached structure unless it's followed by a call to + * e1000_update_eeprom_checksum() where it will commit the changes + * and clear the "modified" field. + */ + if (hw->eeprom_shadow_ram != NULL) { + for (i = 0; i < words; i++) { + if ((offset + i) < E1000_SHADOW_RAM_WORDS) { + hw->eeprom_shadow_ram[offset+i].modified = TRUE; + hw->eeprom_shadow_ram[offset+i].eeprom_word = data[i]; + } else { + error = -E1000_ERR_EEPROM; + break; + } + } + } else { + /* Drivers have the option to not allocate eeprom_shadow_ram as long + * as they don't perform any NVM writes. An attempt in doing so + * will result in this error. + */ + error = -E1000_ERR_EEPROM; + } + + e1000_release_software_flag(hw); + + return error; +} + +/****************************************************************************** + * This function does initial flash setup so that a new read/write/erase cycle + * can be started. + * + * hw - The pointer to the hw structure + ****************************************************************************/ +int32_t +e1000_ich8_cycle_init(struct e1000_hw *hw) +{ + union ich8_hws_flash_status hsfsts; + int32_t error = E1000_ERR_EEPROM; + int32_t i = 0; + + DEBUGFUNC("e1000_ich8_cycle_init"); + + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + + /* May be check the Flash Des Valid bit in Hw status */ + if (hsfsts.hsf_status.fldesvalid == 0) { + DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used."); + return error; + } + + /* Clear FCERR in Hw status by writing 1 */ + /* Clear DAEL in Hw status by writing a 1 */ + hsfsts.hsf_status.flcerr = 1; + hsfsts.hsf_status.dael = 1; + + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + + /* Either we should have a hardware SPI cycle in progress bit to check + * against, in order to start a new cycle or FDONE bit should be changed + * in the hardware so that it is 1 after harware reset, which can then be + * used as an indication whether a cycle is in progress or has been + * completed .. we should also have some software semaphore mechanism to + * guard FDONE or the cycle in progress bit so that two threads access to + * those bits can be sequentiallized or a way so that 2 threads dont + * start the cycle at the same time */ + + if (hsfsts.hsf_status.flcinprog == 0) { + /* There is no cycle running at present, so we can start a cycle */ + /* Begin by setting Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + error = E1000_SUCCESS; + } else { + /* otherwise poll for sometime so the current cycle has a chance + * to end before giving up. */ + for (i = 0; i < ICH8_FLASH_COMMAND_TIMEOUT; i++) { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcinprog == 0) { + error = E1000_SUCCESS; + break; + } + udelay(1); + } + if (error == E1000_SUCCESS) { + /* Successful in waiting for previous cycle to timeout, + * now set the Flash Cycle Done. */ + hsfsts.hsf_status.flcdone = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval); + } else { + DEBUGOUT("Flash controller busy, cannot get access"); + } + } + return error; +} + +/****************************************************************************** + * This function starts a flash cycle and waits for its completion + * + * hw - The pointer to the hw structure + ****************************************************************************/ +int32_t +e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout) +{ + union ich8_hws_flash_ctrl hsflctl; + union ich8_hws_flash_status hsfsts; + int32_t error = E1000_ERR_EEPROM; + uint32_t i = 0; + + /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcgo = 1; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* wait till FDONE bit is set to 1 */ + do { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcdone == 1) + break; + udelay(1); + i++; + } while (i < timeout); + if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) { + error = E1000_SUCCESS; + } + return error; +} + +/****************************************************************************** + * Reads a byte or word from the NVM using the ICH8 flash access registers. + * + * hw - The pointer to the hw structure + * index - The index of the byte or word to read. + * size - Size of data to read, 1=byte 2=word + * data - Pointer to the word to store the value read. + *****************************************************************************/ +int32_t +e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, + uint32_t size, uint16_t* data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + uint32_t flash_data = 0; + int32_t error = -E1000_ERR_EEPROM; + int32_t count = 0; + + DEBUGFUNC("e1000_read_ich8_data"); + + if (size < 1 || size > 2 || data == 0x0 || + index > ICH8_FLASH_LINEAR_ADDR_MASK) + return error; + + flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) + + hw->flash_base_addr; + + do { + udelay(1); + /* Steps */ + error = e1000_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size - 1; + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_READ; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of index into Flash Linear address field in + * Flash Address */ + /* TODO: TBD maybe check the index against the size of flash */ + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT); + + /* Check if FCERR is set to 1, if set to 1, clear it and try the whole + * sequence a few more times, else read in (shift in) the Flash Data0, + * the order is least significant byte first msb to lsb */ + if (error == E1000_SUCCESS) { + flash_data = E1000_READ_ICH8_REG(hw, ICH8_FLASH_FDATA0); + if (size == 1) { + *data = (uint8_t)(flash_data & 0x000000FF); + } else if (size == 2) { + *data = (uint16_t)(flash_data & 0x0000FFFF); + } + break; + } else { + /* If we've gotten here, then things are probably completely hosed, + * but if the error condition is detected, it won't hurt to give + * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle did not complete."); + break; + } + } + } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT); + + return error; +} + +/****************************************************************************** + * Writes One /two bytes to the NVM using the ICH8 flash access registers. + * + * hw - The pointer to the hw structure + * index - The index of the byte/word to read. + * size - Size of data to read, 1=byte 2=word + * data - The byte(s) to write to the NVM. + *****************************************************************************/ +int32_t +e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, + uint16_t data) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + uint32_t flash_data = 0; + int32_t error = -E1000_ERR_EEPROM; + int32_t count = 0; + + DEBUGFUNC("e1000_write_ich8_data"); + + if (size < 1 || size > 2 || data > size * 0xff || + index > ICH8_FLASH_LINEAR_ADDR_MASK) + return error; + + flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) + + hw->flash_base_addr; + + do { + udelay(1); + /* Steps */ + error = e1000_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) + break; + + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ + hsflctl.hsf_ctrl.fldbcount = size -1; + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_WRITE; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of index into Flash Linear address field in + * Flash Address */ + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + if (size == 1) + flash_data = (uint32_t)data & 0x00FF; + else + flash_data = (uint32_t)data; + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FDATA0, flash_data); + + /* check if FCERR is set to 1 , if set to 1, clear it and try the whole + * sequence a few more times else done */ + error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT); + if (error == E1000_SUCCESS) { + break; + } else { + /* If we're here, then things are most likely completely hosed, + * but if the error condition is detected, it won't hurt to give + * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times. + */ + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* Repeat for some time before giving up. */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + DEBUGOUT("Timeout error - flash cycle did not complete."); + break; + } + } + } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT); + + return error; +} + +/****************************************************************************** + * Reads a single byte from the NVM using the ICH8 flash access registers. + * + * hw - pointer to e1000_hw structure + * index - The index of the byte to read. + * data - Pointer to a byte to store the value read. + *****************************************************************************/ +int32_t +e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data) +{ + int32_t status = E1000_SUCCESS; + uint16_t word = 0; + + status = e1000_read_ich8_data(hw, index, 1, &word); + if (status == E1000_SUCCESS) { + *data = (uint8_t)word; + } + + return status; +} + +/****************************************************************************** + * Writes a single byte to the NVM using the ICH8 flash access registers. + * Performs verification by reading back the value and then going through + * a retry algorithm before giving up. + * + * hw - pointer to e1000_hw structure + * index - The index of the byte to write. + * byte - The byte to write to the NVM. + *****************************************************************************/ +int32_t +e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte) +{ + int32_t error = E1000_SUCCESS; + int32_t program_retries; + uint8_t temp_byte; + + e1000_write_ich8_byte(hw, index, byte); + udelay(100); + + for (program_retries = 0; program_retries < 100; program_retries++) { + e1000_read_ich8_byte(hw, index, &temp_byte); + if (temp_byte == byte) + break; + udelay(10); + e1000_write_ich8_byte(hw, index, byte); + udelay(100); + } + if (program_retries == 100) + error = E1000_ERR_EEPROM; + + return error; +} + +/****************************************************************************** + * Writes a single byte to the NVM using the ICH8 flash access registers. + * + * hw - pointer to e1000_hw structure + * index - The index of the byte to read. + * data - The byte to write to the NVM. + *****************************************************************************/ +int32_t +e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data) +{ + int32_t status = E1000_SUCCESS; + uint16_t word = (uint16_t)data; + + status = e1000_write_ich8_data(hw, index, 1, word); + + return status; +} + +/****************************************************************************** + * Reads a word from the NVM using the ICH8 flash access registers. + * + * hw - pointer to e1000_hw structure + * index - The starting byte index of the word to read. + * data - Pointer to a word to store the value read. + *****************************************************************************/ +int32_t +e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data) +{ + int32_t status = E1000_SUCCESS; + status = e1000_read_ich8_data(hw, index, 2, data); + return status; +} + +/****************************************************************************** + * Writes a word to the NVM using the ICH8 flash access registers. + * + * hw - pointer to e1000_hw structure + * index - The starting byte index of the word to read. + * data - The word to write to the NVM. + *****************************************************************************/ +int32_t +e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data) +{ + int32_t status = E1000_SUCCESS; + status = e1000_write_ich8_data(hw, index, 2, data); + return status; +} + +/****************************************************************************** + * Erases the bank specified. Each bank is a 4k block. Segments are 0 based. + * segment N is 4096 * N + flash_reg_addr. + * + * hw - pointer to e1000_hw structure + * segment - 0 for first segment, 1 for second segment, etc. + *****************************************************************************/ +int32_t +e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment) +{ + union ich8_hws_flash_status hsfsts; + union ich8_hws_flash_ctrl hsflctl; + uint32_t flash_linear_address; + int32_t count = 0; + int32_t error = E1000_ERR_EEPROM; + int32_t iteration, seg_size; + int32_t sector_size; + int32_t j = 0; + int32_t error_flag = 0; + + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + + /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */ + /* 00: The Hw sector is 256 bytes, hence we need to erase 16 + * consecutive sectors. The start index for the nth Hw sector can be + * calculated as = segment * 4096 + n * 256 + * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. + * The start index for the nth Hw sector can be calculated + * as = segment * 4096 + * 10: Error condition + * 11: The Hw sector size is much bigger than the size asked to + * erase...error condition */ + if (hsfsts.hsf_status.berasesz == 0x0) { + /* Hw sector size 256 */ + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256; + iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256; + } else if (hsfsts.hsf_status.berasesz == 0x1) { + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K; + iteration = 1; + } else if (hsfsts.hsf_status.berasesz == 0x3) { + sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K; + iteration = 1; + } else { + return error; + } + + for (j = 0; j < iteration ; j++) { + do { + count++; + /* Steps */ + error = e1000_ich8_cycle_init(hw); + if (error != E1000_SUCCESS) { + error_flag = 1; + break; + } + + /* Write a value 11 (block Erase) in Flash Cycle field in Hw flash + * Control */ + hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL); + hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_ERASE; + E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval); + + /* Write the last 24 bits of an index within the block into Flash + * Linear address field in Flash Address. This probably needs to + * be calculated here based off the on-chip segment size and the + * software segment size assumed (4K) */ + /* TBD */ + flash_linear_address = segment * sector_size + j * seg_size; + flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK; + flash_linear_address += hw->flash_base_addr; + + E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address); + + error = e1000_ich8_flash_cycle(hw, 1000000); + /* Check if FCERR is set to 1. If 1, clear it and try the whole + * sequence a few more times else Done */ + if (error == E1000_SUCCESS) { + break; + } else { + hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS); + if (hsfsts.hsf_status.flcerr == 1) { + /* repeat for some time before giving up */ + continue; + } else if (hsfsts.hsf_status.flcdone == 0) { + error_flag = 1; + break; + } + } + } while ((count < ICH8_FLASH_CYCLE_REPEAT_COUNT) && !error_flag); + if (error_flag == 1) + break; + } + if (error_flag != 1) + error = E1000_SUCCESS; + return error; +} + +/****************************************************************************** + * + * Reverse duplex setting without breaking the link. + * + * hw: Struct containing variables accessed by shared code + * + *****************************************************************************/ +int32_t +e1000_duplex_reversal(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; + + if (hw->phy_type != e1000_phy_igp_3) + return E1000_SUCCESS; + + ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data ^= MII_CR_FULL_DUPLEX; + + ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET; + ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data); + + return ret_val; +} + +int32_t +e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, + uint32_t cnf_base_addr, uint32_t cnf_size) +{ + uint32_t ret_val = E1000_SUCCESS; + uint16_t word_addr, reg_data, reg_addr; + uint16_t i; + + /* cnf_base_addr is in DWORD */ + word_addr = (uint16_t)(cnf_base_addr << 1); + + /* cnf_size is returned in size of dwords */ + for (i = 0; i < cnf_size; i++) { + ret_val = e1000_read_eeprom(hw, (word_addr + i*2), 1, ®_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_eeprom(hw, (word_addr + i*2 + 1), 1, ®_addr); + if (ret_val) + return ret_val; + + ret_val = e1000_get_software_flag(hw); + if (ret_val != E1000_SUCCESS) + return ret_val; + + ret_val = e1000_write_phy_reg_ex(hw, (uint32_t)reg_addr, reg_data); + + e1000_release_software_flag(hw); + } + + return ret_val; +} + + +int32_t +e1000_init_lcd_from_nvm(struct e1000_hw *hw) +{ + uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop; + + if (hw->phy_type != e1000_phy_igp_3) + return E1000_SUCCESS; + + /* Check if SW needs configure the PHY */ + reg_data = E1000_READ_REG(hw, FEXTNVM); + if (!(reg_data & FEXTNVM_SW_CONFIG)) + return E1000_SUCCESS; + + /* Wait for basic configuration completes before proceeding*/ + loop = 0; + do { + reg_data = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LAN_INIT_DONE; + udelay(100); + loop++; + } while ((!reg_data) && (loop < 50)); + + /* Clear the Init Done bit for the next init event */ + reg_data = E1000_READ_REG(hw, STATUS); + reg_data &= ~E1000_STATUS_LAN_INIT_DONE; + E1000_WRITE_REG(hw, STATUS, reg_data); + + /* Make sure HW does not configure LCD from PHY extended configuration + before SW configuration */ + reg_data = E1000_READ_REG(hw, EXTCNF_CTRL); + if ((reg_data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) == 0x0000) { + reg_data = E1000_READ_REG(hw, EXTCNF_SIZE); + cnf_size = reg_data & E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH; + cnf_size >>= 16; + if (cnf_size) { + reg_data = E1000_READ_REG(hw, EXTCNF_CTRL); + cnf_base_addr = reg_data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER; + /* cnf_base_addr is in DWORD */ + cnf_base_addr >>= 16; + + /* Configure LCD from extended configuration region. */ + ret_val = e1000_init_lcd_from_nvm_config_region(hw, cnf_base_addr, + cnf_size); + if (ret_val) + return ret_val; + } + } + + return E1000_SUCCESS; +} + + diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 1908e0d3110..f9341e3276b 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -62,6 +62,7 @@ typedef enum { e1000_82572, e1000_82573, e1000_80003es2lan, + e1000_ich8lan, e1000_num_macs } e1000_mac_type; @@ -70,6 +71,7 @@ typedef enum { e1000_eeprom_spi, e1000_eeprom_microwire, e1000_eeprom_flash, + e1000_eeprom_ich8, e1000_eeprom_none, /* No NVM support */ e1000_num_eeprom_types } e1000_eeprom_type; @@ -98,6 +100,11 @@ typedef enum { e1000_fc_default = 0xFF } e1000_fc_type; +struct e1000_shadow_ram { + uint16_t eeprom_word; + boolean_t modified; +}; + /* PCI bus types */ typedef enum { e1000_bus_type_unknown = 0, @@ -218,6 +225,8 @@ typedef enum { e1000_phy_igp, e1000_phy_igp_2, e1000_phy_gg82563, + e1000_phy_igp_3, + e1000_phy_ife, e1000_phy_undefined = 0xFF } e1000_phy_type; @@ -313,6 +322,10 @@ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); +void e1000_phy_powerdown_workaround(struct e1000_hw *hw); +int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw); +int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size); +int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data); @@ -331,6 +344,7 @@ uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw); #define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */ #define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */ #define E1000_MNG_IAMT_MODE 0x3 +#define E1000_MNG_ICH_IAMT_MODE 0x2 #define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */ #define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */ @@ -388,6 +402,8 @@ int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num); int32_t e1000_read_mac_addr(struct e1000_hw * hw); int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); +void e1000_release_software_flag(struct e1000_hw *hw); +int32_t e1000_get_software_flag(struct e1000_hw *hw); /* Filters (multicast, vlan, receive) */ void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); @@ -423,6 +439,29 @@ int32_t e1000_disable_pciex_master(struct e1000_hw *hw); int32_t e1000_get_software_semaphore(struct e1000_hw *hw); void e1000_release_software_semaphore(struct e1000_hw *hw); int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); +int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop); + +int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t *data); +int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t byte); +int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, + uint8_t byte); +int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, + uint16_t *data); +int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, + uint32_t size, uint16_t *data); +int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment); + + +#define E1000_READ_REG_IO(a, reg) \ + e1000_read_reg_io((a), E1000_##reg) +#define E1000_WRITE_REG_IO(a, reg, val) \ + e1000_write_reg_io((a), E1000_##reg, val) /* PCI Device IDs */ #define E1000_DEV_ID_82542 0x1000 @@ -447,6 +486,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D #define E1000_DEV_ID_82541EI 0x1013 #define E1000_DEV_ID_82541EI_MOBILE 0x1018 +#define E1000_DEV_ID_82541ER_LOM 0x1014 #define E1000_DEV_ID_82541ER 0x1078 #define E1000_DEV_ID_82547GI 0x1075 #define E1000_DEV_ID_82541GI 0x1076 @@ -458,18 +498,28 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82546GB_PCIE 0x108A #define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 #define E1000_DEV_ID_82547EI 0x1019 +#define E1000_DEV_ID_82547EI_MOBILE 0x101A #define E1000_DEV_ID_82571EB_COPPER 0x105E #define E1000_DEV_ID_82571EB_FIBER 0x105F #define E1000_DEV_ID_82571EB_SERDES 0x1060 #define E1000_DEV_ID_82572EI_COPPER 0x107D #define E1000_DEV_ID_82572EI_FIBER 0x107E #define E1000_DEV_ID_82572EI_SERDES 0x107F +#define E1000_DEV_ID_82572EI 0x10B9 #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A #define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 +#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA +#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB + +#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 +#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A +#define E1000_DEV_ID_ICH8_IGP_C 0x104B +#define E1000_DEV_ID_ICH8_IFE 0x104C +#define E1000_DEV_ID_ICH8_IGP_M 0x104D #define NODE_ADDRESS_SIZE 6 @@ -540,6 +590,14 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); E1000_IMS_RXSEQ | \ E1000_IMS_LSC) +/* Additional interrupts need to be handled for e1000_ich8lan: + DSW = The FW changed the status of the DISSW bit in FWSM + PHYINT = The LAN connected device generates an interrupt + EPRST = Manageability reset event */ +#define IMS_ICH8LAN_ENABLE_MASK (\ + E1000_IMS_DSW | \ + E1000_IMS_PHYINT | \ + E1000_IMS_EPRST) /* Number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. We @@ -547,6 +605,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); * E1000_RAR_ENTRIES - 1 multicast addresses. */ #define E1000_RAR_ENTRIES 15 +#define E1000_RAR_ENTRIES_ICH8LAN 7 #define MIN_NUMBER_OF_DESCRIPTORS 8 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 @@ -768,6 +827,9 @@ struct e1000_data_desc { #define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */ #define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ +#define E1000_NUM_UNICAST_ICH8LAN 7 +#define E1000_MC_TBL_SIZE_ICH8LAN 32 + /* Receive Address Register */ struct e1000_rar { @@ -777,6 +839,7 @@ struct e1000_rar { /* Number of entries in the Multicast Table Array (MTA). */ #define E1000_NUM_MTA_REGISTERS 128 +#define E1000_NUM_MTA_REGISTERS_ICH8LAN 32 /* IPv4 Address Table Entry */ struct e1000_ipv4_at_entry { @@ -787,6 +850,7 @@ struct e1000_ipv4_at_entry { /* Four wakeup IP addresses are supported */ #define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4 #define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX +#define E1000_IP4AT_SIZE_ICH8LAN 3 #define E1000_IP6AT_SIZE 1 /* IPv6 Address Table Entry */ @@ -845,6 +909,7 @@ struct e1000_ffvt_entry { #define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_SCTL 0x00024 /* SerDes Control - RW */ +#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -873,6 +938,8 @@ struct e1000_ffvt_entry { #define E1000_LEDCTL 0x00E00 /* LED Control - RW */ #define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ #define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ +#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ +#define FEXTNVM_SW_CONFIG 0x0001 #define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ #define E1000_PBS 0x01008 /* Packet Buffer Size */ #define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ @@ -900,11 +967,13 @@ struct e1000_ffvt_entry { #define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ #define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ #define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ -#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */ +#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */ +#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */ #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ #define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ #define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ #define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ #define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ @@ -1051,6 +1120,7 @@ struct e1000_ffvt_entry { #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC #define E1000_82542_SCTL E1000_SCTL +#define E1000_82542_FEXTNVM E1000_FEXTNVM #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1074,6 +1144,19 @@ struct e1000_ffvt_entry { #define E1000_82542_RDLEN0 E1000_82542_RDLEN #define E1000_82542_RDH0 E1000_82542_RDH #define E1000_82542_RDT0 E1000_82542_RDT +#define E1000_82542_SRRCTL(_n) (0x280C + ((_n) << 8)) /* Split and Replication + * RX Control - RW */ +#define E1000_82542_DCA_RXCTRL(_n) (0x02814 + ((_n) << 8)) +#define E1000_82542_RDBAH3 0x02B04 /* RX Desc Base High Queue 3 - RW */ +#define E1000_82542_RDBAL3 0x02B00 /* RX Desc Low Queue 3 - RW */ +#define E1000_82542_RDLEN3 0x02B08 /* RX Desc Length Queue 3 - RW */ +#define E1000_82542_RDH3 0x02B10 /* RX Desc Head Queue 3 - RW */ +#define E1000_82542_RDT3 0x02B18 /* RX Desc Tail Queue 3 - RW */ +#define E1000_82542_RDBAL2 0x02A00 /* RX Desc Base Low Queue 2 - RW */ +#define E1000_82542_RDBAH2 0x02A04 /* RX Desc Base High Queue 2 - RW */ +#define E1000_82542_RDLEN2 0x02A08 /* RX Desc Length Queue 2 - RW */ +#define E1000_82542_RDH2 0x02A10 /* RX Desc Head Queue 2 - RW */ +#define E1000_82542_RDT2 0x02A18 /* RX Desc Tail Queue 2 - RW */ #define E1000_82542_RDTR1 0x00130 #define E1000_82542_RDBAL1 0x00138 #define E1000_82542_RDBAH1 0x0013C @@ -1111,11 +1194,14 @@ struct e1000_ffvt_entry { #define E1000_82542_FLOP E1000_FLOP #define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL #define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE +#define E1000_82542_PHY_CTRL E1000_PHY_CTRL #define E1000_82542_ERT E1000_ERT #define E1000_82542_RXDCTL E1000_RXDCTL +#define E1000_82542_RXDCTL1 E1000_RXDCTL1 #define E1000_82542_RADV E1000_RADV #define E1000_82542_RSRPD E1000_RSRPD #define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_KABGTXD E1000_KABGTXD #define E1000_82542_TDFHS E1000_TDFHS #define E1000_82542_TDFTS E1000_TDFTS #define E1000_82542_TDFPC E1000_TDFPC @@ -1311,13 +1397,16 @@ struct e1000_hw_stats { /* Structure containing variables used by the shared code (e1000_hw.c) */ struct e1000_hw { - uint8_t __iomem *hw_addr; + uint8_t *hw_addr; uint8_t *flash_address; e1000_mac_type mac_type; e1000_phy_type phy_type; uint32_t phy_init_script; e1000_media_type media_type; void *back; + struct e1000_shadow_ram *eeprom_shadow_ram; + uint32_t flash_bank_size; + uint32_t flash_base_addr; e1000_fc_type fc; e1000_bus_speed bus_speed; e1000_bus_width bus_width; @@ -1329,6 +1418,7 @@ struct e1000_hw { uint32_t asf_firmware_present; uint32_t eeprom_semaphore_present; uint32_t swfw_sync_present; + uint32_t swfwhw_semaphore_present; unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; @@ -1388,6 +1478,7 @@ struct e1000_hw { boolean_t in_ifs_mode; boolean_t mng_reg_access_disabled; boolean_t leave_av_bit_off; + boolean_t kmrn_lock_loss_workaround_disabled; }; @@ -1436,6 +1527,7 @@ struct e1000_hw { #define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ #define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ #define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */ /* Device Status */ #define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ @@ -1450,6 +1542,8 @@ struct e1000_hw { #define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ #define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ #define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion + by EEPROM/Flash */ #define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ #define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ @@ -1507,6 +1601,10 @@ struct e1000_hw { #define E1000_STM_OPCODE 0xDB00 #define E1000_HICR_FW_RESET 0xC0 +#define E1000_SHADOW_RAM_WORDS 2048 +#define E1000_ICH8_NVM_SIG_WORD 0x13 +#define E1000_ICH8_NVM_SIG_MASK 0xC0 + /* EEPROM Read */ #define E1000_EERD_START 0x00000001 /* Start Read */ #define E1000_EERD_DONE 0x00000010 /* Read Done */ @@ -1552,7 +1650,6 @@ struct e1000_hw { #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 #define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 #define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 -#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */ #define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ @@ -1592,12 +1689,31 @@ struct e1000_hw { #define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800 /* In-Band Control */ +#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500 #define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010 /* Half-Duplex Control */ #define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004 #define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000 +#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E + +#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000 +#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000 + +#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000 +#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000 +#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003 + +#define E1000_KABGTXD_BGSQLBIAS 0x00050000 + +#define E1000_PHY_CTRL_SPD_EN 0x00000001 +#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 +#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 +#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 +#define E1000_PHY_CTRL_B2B_EN 0x00000080 + /* LED Control */ #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 @@ -1667,6 +1783,9 @@ struct e1000_hw { #define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ #define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ #define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ +#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ +#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ /* Interrupt Cause Set */ #define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1693,6 +1812,9 @@ struct e1000_hw { #define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ #define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ #define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICS_DSW E1000_ICR_DSW +#define E1000_ICS_PHYINT E1000_ICR_PHYINT +#define E1000_ICS_EPRST E1000_ICR_EPRST /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1719,6 +1841,9 @@ struct e1000_hw { #define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ #define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ #define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMS_DSW E1000_ICR_DSW +#define E1000_IMS_PHYINT E1000_ICR_PHYINT +#define E1000_IMS_EPRST E1000_ICR_EPRST /* Interrupt Mask Clear */ #define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1745,6 +1870,9 @@ struct e1000_hw { #define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ #define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ #define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_IMC_DSW E1000_ICR_DSW +#define E1000_IMC_PHYINT E1000_ICR_PHYINT +#define E1000_IMC_EPRST E1000_ICR_EPRST /* Receive Control */ #define E1000_RCTL_RST 0x00000001 /* Software reset */ @@ -1919,9 +2047,10 @@ struct e1000_hw { #define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 #define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 #define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 #define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 #define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 /* Definitions for power management and wakeup registers */ /* Wake Up Control */ @@ -2011,6 +2140,15 @@ struct e1000_hw { #define E1000_FWSM_MODE_SHIFT 1 #define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */ +#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */ +#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */ +#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */ +#define E1000_FWSM_SKUEL_SHIFT 29 +#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */ +#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */ +#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */ +#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */ + /* FFLT Debug Register */ #define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */ @@ -2083,6 +2221,8 @@ struct e1000_host_command_info { E1000_GCR_TXDSCW_NO_SNOOP | \ E1000_GCR_TXDSCR_NO_SNOOP) +#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL + #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ #define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003 @@ -2141,8 +2281,10 @@ struct e1000_host_command_info { #define EEPROM_PHY_CLASS_WORD 0x0007 #define EEPROM_INIT_CONTROL1_REG 0x000A #define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010 #define EEPROM_INIT_CONTROL3_PORT_B 0x0014 #define EEPROM_INIT_3GIO_3 0x001A +#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020 #define EEPROM_INIT_CONTROL3_PORT_A 0x0024 #define EEPROM_CFG 0x0012 #define EEPROM_FLASH_VERSION 0x0032 @@ -2154,10 +2296,16 @@ struct e1000_host_command_info { /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 #define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_RESERVED_82573 0xF746 +#define ID_LED_DEFAULT_82573 0x1811 #define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ (ID_LED_OFF1_OFF2 << 8) | \ (ID_LED_DEF1_DEF2 << 4) | \ (ID_LED_DEF1_DEF2)) +#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ + (ID_LED_DEF1_OFF2 << 8) | \ + (ID_LED_DEF1_ON2 << 4) | \ + (ID_LED_DEF1_DEF2)) #define ID_LED_DEF1_DEF2 0x1 #define ID_LED_DEF1_ON2 0x2 #define ID_LED_DEF1_OFF2 0x3 @@ -2192,6 +2340,11 @@ struct e1000_host_command_info { #define EEPROM_WORD0F_ASM_DIR 0x2000 #define EEPROM_WORD0F_ANE 0x0800 #define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 +#define EEPROM_WORD0F_LPLU 0x0001 + +/* Mask bits for fields in Word 0x10/0x20 of the EEPROM */ +#define EEPROM_WORD1020_GIGA_DISABLE 0x0010 +#define EEPROM_WORD1020_GIGA_DISABLE_NON_D0A 0x0008 /* Mask bits for fields in Word 0x1a of the EEPROM */ #define EEPROM_WORD1A_ASPM_MASK 0x000C @@ -2266,23 +2419,29 @@ struct e1000_host_command_info { #define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010 #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 #define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x0FFF0000 #define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF #define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 /* PBA constants */ +#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ #define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ #define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 #define E1000_PBA_30K 0x001E #define E1000_PBA_32K 0x0020 +#define E1000_PBA_34K 0x0022 #define E1000_PBA_38K 0x0026 #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ +#define E1000_PBS_16K E1000_PBA_16K + /* Flow Control Constants */ #define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 #define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 @@ -2337,7 +2496,7 @@ struct e1000_host_command_info { /* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */ #define AUTO_READ_DONE_TIMEOUT 10 /* Number of milliseconds we wait for PHY configuration done after MAC reset */ -#define PHY_CFG_TIMEOUT 40 +#define PHY_CFG_TIMEOUT 100 #define E1000_TX_BUFFER_SIZE ((uint32_t)1514) @@ -3002,6 +3161,221 @@ struct e1000_host_command_info { #define L1LXT971A_PHY_ID 0x001378E0 #define GG82563_E_PHY_ID 0x01410CA0 + +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define PHY_PAGE_SHIFT 5 +#define PHY_REG(page, reg) \ + (((page) << PHY_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) + +#define IGP3_PHY_PORT_CTRL \ + PHY_REG(769, 17) /* Port General Configuration */ +#define IGP3_PHY_RATE_ADAPT_CTRL \ + PHY_REG(769, 25) /* Rate Adapter Control Register */ + +#define IGP3_KMRN_FIFO_CTRL_STATS \ + PHY_REG(770, 16) /* KMRN FIFO's control/status register */ +#define IGP3_KMRN_POWER_MNG_CTRL \ + PHY_REG(770, 17) /* KMRN Power Management Control Register */ +#define IGP3_KMRN_INBAND_CTRL \ + PHY_REG(770, 18) /* KMRN Inband Control Register */ +#define IGP3_KMRN_DIAG \ + PHY_REG(770, 19) /* KMRN Diagnostic register */ +#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 /* RX PCS is not synced */ +#define IGP3_KMRN_ACK_TIMEOUT \ + PHY_REG(770, 20) /* KMRN Acknowledge Timeouts register */ + +#define IGP3_VR_CTRL \ + PHY_REG(776, 18) /* Voltage regulator control register */ +#define IGP3_VR_CTRL_MODE_SHUT 0x0200 /* Enter powerdown, shutdown VRs */ + +#define IGP3_CAPABILITY \ + PHY_REG(776, 19) /* IGP3 Capability Register */ + +/* Capabilities for SKU Control */ +#define IGP3_CAP_INITIATE_TEAM 0x0001 /* Able to initiate a team */ +#define IGP3_CAP_WFM 0x0002 /* Support WoL and PXE */ +#define IGP3_CAP_ASF 0x0004 /* Support ASF */ +#define IGP3_CAP_LPLU 0x0008 /* Support Low Power Link Up */ +#define IGP3_CAP_DC_AUTO_SPEED 0x0010 /* Support AC/DC Auto Link Speed */ +#define IGP3_CAP_SPD 0x0020 /* Support Smart Power Down */ +#define IGP3_CAP_MULT_QUEUE 0x0040 /* Support 2 tx & 2 rx queues */ +#define IGP3_CAP_RSS 0x0080 /* Support RSS */ +#define IGP3_CAP_8021PQ 0x0100 /* Support 802.1Q & 802.1p */ +#define IGP3_CAP_AMT_CB 0x0200 /* Support active manageability and circuit breaker */ + +#define IGP3_PPC_JORDAN_EN 0x0001 +#define IGP3_PPC_JORDAN_GIGA_SPEED 0x0002 + +#define IGP3_KMRN_PMC_EE_IDLE_LINK_DIS 0x0001 +#define IGP3_KMRN_PMC_K0S_ENTRY_LATENCY_MASK 0x001E +#define IGP3_KMRN_PMC_K0S_MODE1_EN_GIGA 0x0020 +#define IGP3_KMRN_PMC_K0S_MODE1_EN_100 0x0040 + +#define IGP3E1000_PHY_MISC_CTRL 0x1B /* Misc. Ctrl register */ +#define IGP3_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Duplex Manual Set */ + +#define IGP3_KMRN_EXT_CTRL PHY_REG(770, 18) +#define IGP3_KMRN_EC_DIS_INBAND 0x0080 + +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */ +#define IFE_PLUS_E_PHY_ID 0x02A80320 +#define IFE_C_E_PHY_ID 0x02A80310 + +#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status, Control and Address */ +#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special control register */ +#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive False Carrier Counter */ +#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet Counter */ +#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error Frame Counter */ +#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error Counter */ +#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive Premature End Of Frame Error Counter */ +#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of Frame Error Counter */ +#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber Detect Counter */ +#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and Status */ +#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and LED configuration */ +#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */ +#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control (HWI) */ + +#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto reduced power down */ +#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power state of 100BASE-TX */ +#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power state of 10BASE-T */ +#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T polarity */ +#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY address */ +#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed result 1=100Mbs, 0=10Mbs */ +#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation duplex result 1=Full, 0=Half */ +#define IFE_PESC_POLARITY_REVERSED_SHIFT 8 + +#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down disabled */ +#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity, 0=Normal */ +#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity Disabled, 0=Enabled */ +#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled, 0=Normal Jabber Operation */ +#define IFE_PSC_FORCE_POLARITY_SHIFT 5 +#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4 + +#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */ +#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */ +#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ +#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */ +#define IFE_PMC_MDIX_MODE_SHIFT 6 +#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */ + +#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI feature */ +#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed, 0=failed */ +#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses on the wire */ +#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */ +#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */ +#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication type of problem on the line */ +#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to the cable problem, in 80cm granularity */ +#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */ +#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */ +#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ +#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ + +#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */ +#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */ +#define ICH8_FLASH_SEG_SIZE_256 256 +#define ICH8_FLASH_SEG_SIZE_4K 4096 +#define ICH8_FLASH_SEG_SIZE_64K 65536 + +#define ICH8_CYCLE_READ 0x0 +#define ICH8_CYCLE_RESERVED 0x1 +#define ICH8_CYCLE_WRITE 0x2 +#define ICH8_CYCLE_ERASE 0x3 + +#define ICH8_FLASH_GFPREG 0x0000 +#define ICH8_FLASH_HSFSTS 0x0004 +#define ICH8_FLASH_HSFCTL 0x0006 +#define ICH8_FLASH_FADDR 0x0008 +#define ICH8_FLASH_FDATA0 0x0010 +#define ICH8_FLASH_FRACC 0x0050 +#define ICH8_FLASH_FREG0 0x0054 +#define ICH8_FLASH_FREG1 0x0058 +#define ICH8_FLASH_FREG2 0x005C +#define ICH8_FLASH_FREG3 0x0060 +#define ICH8_FLASH_FPR0 0x0074 +#define ICH8_FLASH_FPR1 0x0078 +#define ICH8_FLASH_SSFSTS 0x0090 +#define ICH8_FLASH_SSFCTL 0x0092 +#define ICH8_FLASH_PREOP 0x0094 +#define ICH8_FLASH_OPTYPE 0x0096 +#define ICH8_FLASH_OPMENU 0x0098 + +#define ICH8_FLASH_REG_MAPSIZE 0x00A0 +#define ICH8_FLASH_SECTOR_SIZE 4096 +#define ICH8_GFPREG_BASE_MASK 0x1FFF +#define ICH8_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF + +/* ICH8 GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ +/* Offset 04h HSFSTS */ +union ich8_hws_flash_status { + struct ich8_hsfsts { +#ifdef E1000_BIG_ENDIAN + uint16_t reserved2 :6; + uint16_t fldesvalid :1; + uint16_t flockdn :1; + uint16_t flcdone :1; + uint16_t flcerr :1; + uint16_t dael :1; + uint16_t berasesz :2; + uint16_t flcinprog :1; + uint16_t reserved1 :2; +#else + uint16_t flcdone :1; /* bit 0 Flash Cycle Done */ + uint16_t flcerr :1; /* bit 1 Flash Cycle Error */ + uint16_t dael :1; /* bit 2 Direct Access error Log */ + uint16_t berasesz :2; /* bit 4:3 Block/Sector Erase Size */ + uint16_t flcinprog :1; /* bit 5 flash SPI cycle in Progress */ + uint16_t reserved1 :2; /* bit 13:6 Reserved */ + uint16_t reserved2 :6; /* bit 13:6 Reserved */ + uint16_t fldesvalid :1; /* bit 14 Flash Descriptor Valid */ + uint16_t flockdn :1; /* bit 15 Flash Configuration Lock-Down */ +#endif + } hsf_status; + uint16_t regval; +}; + +/* ICH8 GbE Flash Hardware Sequencing Flash control Register bit breakdown */ +/* Offset 06h FLCTL */ +union ich8_hws_flash_ctrl { + struct ich8_hsflctl { +#ifdef E1000_BIG_ENDIAN + uint16_t fldbcount :2; + uint16_t flockdn :6; + uint16_t flcgo :1; + uint16_t flcycle :2; + uint16_t reserved :5; +#else + uint16_t flcgo :1; /* 0 Flash Cycle Go */ + uint16_t flcycle :2; /* 2:1 Flash Cycle */ + uint16_t reserved :5; /* 7:3 Reserved */ + uint16_t fldbcount :2; /* 9:8 Flash Data Byte Count */ + uint16_t flockdn :6; /* 15:10 Reserved */ +#endif + } hsf_ctrl; + uint16_t regval; +}; + +/* ICH8 Flash Region Access Permissions */ +union ich8_hws_flash_regacc { + struct ich8_flracc { +#ifdef E1000_BIG_ENDIAN + uint32_t gmwag :8; + uint32_t gmrag :8; + uint32_t grwa :8; + uint32_t grra :8; +#else + uint32_t grra :8; /* 0:7 GbE region Read Access */ + uint32_t grwa :8; /* 8:15 GbE region Write Access */ + uint32_t gmrag :8; /* 23:16 GbE Master Read Access Grant */ + uint32_t gmwag :8; /* 31:24 GbE Master Write Access Grant */ +#endif + } hsf_flregacc; + uint16_t regval; +}; + /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF #define PHY_SOF 0x01 diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 048d052be29..2d3e8b06cab 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -127,4 +127,17 @@ typedef enum { #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) +#define E1000_WRITE_ICH8_REG(a, reg, value) ( \ + writel((value), ((a)->flash_address + reg))) + +#define E1000_READ_ICH8_REG(a, reg) ( \ + readl((a)->flash_address + reg)) + +#define E1000_WRITE_ICH8_REG16(a, reg, value) ( \ + writew((value), ((a)->flash_address + reg))) + +#define E1000_READ_ICH8_REG16(a, reg) ( \ + readw((a)->flash_address + reg)) + + #endif /* _E1000_OSDEP_H_ */ -- cgit v1.2.3 From cd94dd0b648ceb64ca5e41d9ccfa99c1e30e92ef Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:22 -0700 Subject: e1000: integrate ich8 support into driver This hooks up the ich8 structure into the driver itself. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_ethtool.c | 80 +++-- drivers/net/e1000/e1000_hw.c | 654 ++++++++++++++++++++++++++++++++------ drivers/net/e1000/e1000_main.c | 120 ++++++- 4 files changed, 725 insertions(+), 130 deletions(-) diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index dbdaa332cac..323a2683417 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -143,6 +143,7 @@ struct e1000_adapter; #define AUTO_ALL_MODES 0 #define E1000_EEPROM_82544_APM 0x0004 +#define E1000_EEPROM_ICH8_APME 0x0004 #define E1000_EEPROM_APME 0x0400 #ifndef E1000_MASTER_SLAVE diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 06091553292..3a0b847fac3 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -109,7 +109,8 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) SUPPORTED_1000baseT_Full| SUPPORTED_Autoneg | SUPPORTED_TP); - + if (hw->phy_type == e1000_phy_ife) + ecmd->supported &= ~SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_TP; if (hw->autoneg == 1) { @@ -573,6 +574,7 @@ e1000_get_drvinfo(struct net_device *netdev, case e1000_82572: case e1000_82573: case e1000_80003es2lan: + case e1000_ich8lan: sprintf(firmware_version, "%d.%d-%d", (eeprom_data & 0xF000) >> 12, (eeprom_data & 0x0FF0) >> 4, @@ -757,6 +759,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) toggle = 0x7FFFF3FF; break; case e1000_82573: + case e1000_ich8lan: toggle = 0x7FFFF033; break; default: @@ -776,11 +779,12 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) } /* restore previous status */ E1000_WRITE_REG(&adapter->hw, STATUS, before); - - REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF); - REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF); + if (adapter->hw.mac_type != e1000_ich8lan) { + REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF); + } REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF); @@ -793,20 +797,22 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF); REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000); - REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB); + before = (adapter->hw.mac_type == e1000_ich8lan ? + 0x06C3B33E : 0x06DFB3FE); + REG_SET_AND_CHECK(RCTL, before, 0x003FFFFB); REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); if (adapter->hw.mac_type >= e1000_82543) { - REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF); + REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); - REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); + if (adapter->hw.mac_type != e1000_ich8lan) + REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); - - for (i = 0; i < E1000_RAR_ENTRIES; i++) { - REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF, - 0xFFFFFFFF); + value = (adapter->hw.mac_type == e1000_ich8lan ? + E1000_RAR_ENTRIES_ICH8LAN : E1000_RAR_ENTRIES); + for (i = 0; i < value; i++) { REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF, 0xFFFFFFFF); } @@ -820,7 +826,9 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) } - for (i = 0; i < E1000_MC_TBL_SIZE; i++) + value = (adapter->hw.mac_type == e1000_ich8lan ? + E1000_MC_TBL_SIZE_ICH8LAN : E1000_MC_TBL_SIZE); + for (i = 0; i < value; i++) REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); *data = 0; @@ -892,6 +900,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) /* Test each interrupt */ for (; i < 10; i++) { + if (adapter->hw.mac_type == e1000_ich8lan && i == 8) + continue; /* Interrupt to test */ mask = 1 << i; @@ -1251,16 +1261,31 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); } - /* force 1000, set loopback */ - e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); - /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); - ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ - ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ - E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ - E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ - E1000_CTRL_FD); /* Force Duplex to FULL */ + + if (adapter->hw.phy_type == e1000_phy_ife) { + /* force 100, set loopback */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x6100); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_100 |/* Force Speed to 100 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } else { + /* force 1000, set loopback */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + } if (adapter->hw.media_type == e1000_media_type_copper && adapter->hw.phy_type == e1000_phy_m88) { @@ -1320,6 +1345,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82572: case e1000_82573: case e1000_80003es2lan: + case e1000_ich8lan: return e1000_integrated_phy_loopback(adapter); break; @@ -1786,6 +1812,16 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); + } else if (adapter->hw.phy_type == e1000_phy_ife) { + if (!adapter->blink_timer.function) { + init_timer(&adapter->blink_timer); + adapter->blink_timer.function = e1000_led_blink_callback; + adapter->blink_timer.data = (unsigned long) adapter; + } + mod_timer(&adapter->blink_timer, jiffies); + msleep_interruptible(data * 1000); + del_timer_sync(&adapter->blink_timer); + e1000_write_phy_reg(&(adapter->hw), IFE_PHY_SPECIAL_CONTROL_LED, 0); } else { e1000_blink_led_start(&adapter->hw); msleep_interruptible(data * 1000); diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index a3f5ccdfafc..583518ae49c 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -101,7 +101,8 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, #define E1000_WRITE_REG_IO(a, reg, val) \ e1000_write_reg_io((a), E1000_##reg, val) -static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw); +static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, + uint16_t duplex); static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw); /* IGP cable length table */ @@ -156,6 +157,14 @@ e1000_set_phy_type(struct e1000_hw *hw) hw->phy_type = e1000_phy_igp; break; } + case IGP03E1000_E_PHY_ID: + hw->phy_type = e1000_phy_igp_3; + break; + case IFE_E_PHY_ID: + case IFE_PLUS_E_PHY_ID: + case IFE_C_E_PHY_ID: + hw->phy_type = e1000_phy_ife; + break; case GG82563_E_PHY_ID: if (hw->mac_type == e1000_80003es2lan) { hw->phy_type = e1000_phy_gg82563; @@ -332,6 +341,7 @@ e1000_set_mac_type(struct e1000_hw *hw) break; case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EI_MOBILE: + case E1000_DEV_ID_82541ER_LOM: hw->mac_type = e1000_82541; break; case E1000_DEV_ID_82541ER: @@ -341,6 +351,7 @@ e1000_set_mac_type(struct e1000_hw *hw) hw->mac_type = e1000_82541_rev_2; break; case E1000_DEV_ID_82547EI: + case E1000_DEV_ID_82547EI_MOBILE: hw->mac_type = e1000_82547; break; case E1000_DEV_ID_82547GI: @@ -354,6 +365,7 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82572EI_COPPER: case E1000_DEV_ID_82572EI_FIBER: case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_82572EI: hw->mac_type = e1000_82572; break; case E1000_DEV_ID_82573E: @@ -361,16 +373,29 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; + case E1000_DEV_ID_80003ES2LAN_COPPER_SPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_SPT: case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->mac_type = e1000_80003es2lan; break; + case E1000_DEV_ID_ICH8_IGP_M_AMT: + case E1000_DEV_ID_ICH8_IGP_AMT: + case E1000_DEV_ID_ICH8_IGP_C: + case E1000_DEV_ID_ICH8_IFE: + case E1000_DEV_ID_ICH8_IGP_M: + hw->mac_type = e1000_ich8lan; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } switch(hw->mac_type) { + case e1000_ich8lan: + hw->swfwhw_semaphore_present = TRUE; + hw->asf_firmware_present = TRUE; + break; case e1000_80003es2lan: hw->swfw_sync_present = TRUE; /* fall through */ @@ -423,6 +448,7 @@ e1000_set_media_type(struct e1000_hw *hw) case e1000_82542_rev2_1: hw->media_type = e1000_media_type_fiber; break; + case e1000_ich8lan: case e1000_82573: /* The STATUS_TBIMODE bit is reserved or reused for the this * device. @@ -527,6 +553,14 @@ e1000_reset_hw(struct e1000_hw *hw) } while(timeout); } + /* Workaround for ICH8 bit corruption issue in FIFO memory */ + if (hw->mac_type == e1000_ich8lan) { + /* Set Tx and Rx buffer allocation to 8k apiece. */ + E1000_WRITE_REG(hw, PBA, E1000_PBA_8K); + /* Set Packet Buffer Size to 16k. */ + E1000_WRITE_REG(hw, PBS, E1000_PBS_16K); + } + /* Issue a global reset to the MAC. This will reset the chip's * transmit, receive, DMA, and link units. It will not effect * the current PCI configuration. The global reset bit is self- @@ -550,6 +584,20 @@ e1000_reset_hw(struct e1000_hw *hw) /* Reset is performed on a shadow of the control register */ E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST)); break; + case e1000_ich8lan: + if (!hw->phy_reset_disable && + e1000_check_phy_reset_block(hw) == E1000_SUCCESS) { + /* e1000_ich8lan PHY HW reset requires MAC CORE reset + * at the same time to make sure the interface between + * MAC and the external PHY is reset. + */ + ctrl |= E1000_CTRL_PHY_RST; + } + + e1000_get_software_flag(hw); + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); + msec_delay(5); + break; default: E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; @@ -591,6 +639,7 @@ e1000_reset_hw(struct e1000_hw *hw) /* fall through */ case e1000_82571: case e1000_82572: + case e1000_ich8lan: case e1000_80003es2lan: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) @@ -633,6 +682,12 @@ e1000_reset_hw(struct e1000_hw *hw) e1000_pci_set_mwi(hw); } + if (hw->mac_type == e1000_ich8lan) { + uint32_t kab = E1000_READ_REG(hw, KABGTXD); + kab |= E1000_KABGTXD_BGSQLBIAS; + E1000_WRITE_REG(hw, KABGTXD, kab); + } + return E1000_SUCCESS; } @@ -675,9 +730,12 @@ e1000_init_hw(struct e1000_hw *hw) /* Disabling VLAN filtering. */ DEBUGOUT("Initializing the IEEE VLAN\n"); - if (hw->mac_type < e1000_82545_rev_3) - E1000_WRITE_REG(hw, VET, 0); - e1000_clear_vfta(hw); + /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */ + if (hw->mac_type != e1000_ich8lan) { + if (hw->mac_type < e1000_82545_rev_3) + E1000_WRITE_REG(hw, VET, 0); + e1000_clear_vfta(hw); + } /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ if(hw->mac_type == e1000_82542_rev2_0) { @@ -705,6 +763,8 @@ e1000_init_hw(struct e1000_hw *hw) /* Zero out the Multicast HASH table */ DEBUGOUT("Zeroing the MTA\n"); mta_size = E1000_MC_TBL_SIZE; + if (hw->mac_type == e1000_ich8lan) + mta_size = E1000_MC_TBL_SIZE_ICH8LAN; for(i = 0; i < mta_size; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); /* use write flush to prevent Memory Write Block (MWB) from @@ -748,6 +808,10 @@ e1000_init_hw(struct e1000_hw *hw) break; } + /* More time needed for PHY to initialize */ + if (hw->mac_type == e1000_ich8lan) + msec_delay(15); + /* Call a subroutine to configure the link and setup flow control. */ ret_val = e1000_setup_link(hw); @@ -761,6 +825,7 @@ e1000_init_hw(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_ich8lan: case e1000_80003es2lan: ctrl |= E1000_TXDCTL_COUNT_DESC; break; @@ -799,6 +864,7 @@ e1000_init_hw(struct e1000_hw *hw) /* Fall through */ case e1000_82571: case e1000_82572: + case e1000_ich8lan: ctrl = E1000_READ_REG(hw, TXDCTL1); ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; if(hw->mac_type >= e1000_82571) @@ -822,6 +888,11 @@ e1000_init_hw(struct e1000_hw *hw) */ e1000_clear_hw_cntrs(hw); + /* ICH8 No-snoop bits are opposite polarity. + * Set to snoop by default after reset. */ + if (hw->mac_type == e1000_ich8lan) + e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL); + if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER || hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) { ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); @@ -909,6 +980,7 @@ e1000_setup_link(struct e1000_hw *hw) */ if (hw->fc == e1000_fc_default) { switch (hw->mac_type) { + case e1000_ich8lan: case e1000_82573: hw->fc = e1000_fc_full; break; @@ -975,9 +1047,12 @@ e1000_setup_link(struct e1000_hw *hw) */ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); - E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); - E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); - E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */ + if (hw->mac_type != e1000_ich8lan) { + E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE); + E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH); + E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); + } E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time); @@ -1241,12 +1316,13 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw) /* Wait 10ms for MAC to configure PHY from eeprom settings */ msec_delay(15); - + if (hw->mac_type != e1000_ich8lan) { /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } /* disable lplu d3 during driver init */ ret_val = e1000_set_d3_lplu_state(hw, FALSE); @@ -1482,8 +1558,7 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw) if (ret_val) return ret_val; - /* Enable Pass False Carrier on the PHY */ - phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, phy_data); @@ -1636,6 +1711,10 @@ e1000_copper_link_autoneg(struct e1000_hw *hw) if(hw->autoneg_advertised == 0) hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; + /* IFE phy only supports 10/100 */ + if (hw->phy_type == e1000_phy_ife) + hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL; + DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); ret_val = e1000_phy_setup_autoneg(hw); if(ret_val) { @@ -1733,6 +1812,26 @@ e1000_setup_copper_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_copper_link"); + switch (hw->mac_type) { + case e1000_80003es2lan: + case e1000_ich8lan: + /* Set the mac to wait the maximum time between each + * iteration and increase the max iterations when + * polling the phy; this fixes erroneous timeouts at 10Mbps. */ + ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + if (ret_val) + return ret_val; + ret_val = e1000_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + if (ret_val) + return ret_val; + reg_data |= 0x3F; + ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + if (ret_val) + return ret_val; + default: + break; + } + /* Check if it is a valid PHY and set PHY mode if necessary. */ ret_val = e1000_copper_link_preconfig(hw); if(ret_val) @@ -1740,10 +1839,8 @@ e1000_setup_copper_link(struct e1000_hw *hw) switch (hw->mac_type) { case e1000_80003es2lan: - ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, - ®_data); - if (ret_val) - return ret_val; + /* Kumeran registers are written-only */ + reg_data = E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT; reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING; ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, reg_data); @@ -1755,6 +1852,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) } if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_copper_link_igp_setup(hw); if(ret_val) @@ -1819,7 +1917,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) * hw - Struct containing variables accessed by shared code ******************************************************************************/ static int32_t -e1000_configure_kmrn_for_10_100(struct e1000_hw *hw) +e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex) { int32_t ret_val = E1000_SUCCESS; uint32_t tipg; @@ -1839,6 +1937,18 @@ e1000_configure_kmrn_for_10_100(struct e1000_hw *hw) tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100; E1000_WRITE_REG(hw, TIPG, tipg); + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + + if (ret_val) + return ret_val; + + if (duplex == HALF_DUPLEX) + reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + else + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + return ret_val; } @@ -1863,6 +1973,14 @@ e1000_configure_kmrn_for_1000(struct e1000_hw *hw) tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; E1000_WRITE_REG(hw, TIPG, tipg); + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, ®_data); + + if (ret_val) + return ret_val; + + reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); + return ret_val; } @@ -1885,10 +2003,13 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) if(ret_val) return ret_val; - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); - if(ret_val) - return ret_val; + if (hw->phy_type != e1000_phy_ife) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } else + mii_1000t_ctrl_reg=0; /* Need to parse both autoneg_advertised and fc and set up * the appropriate PHY registers. First we will parse for @@ -1939,6 +2060,9 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) if(hw->autoneg_advertised & ADVERTISE_1000_FULL) { DEBUGOUT("Advertise 1000mb Full duplex\n"); mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + if (hw->phy_type == e1000_phy_ife) { + DEBUGOUT("e1000_phy_ife is a 10/100 PHY. Gigabit speed is not supported.\n"); + } } /* Check for a software override of the flow control settings, and @@ -2000,9 +2124,11 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw) DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); - if(ret_val) - return ret_val; + if (hw->phy_type != e1000_phy_ife) { + ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + } return E1000_SUCCESS; } @@ -2105,6 +2231,18 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; + /* Disable MDI-X support for 10/100 */ + } else if (hw->phy_type == e1000_phy_ife) { + ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~IFE_PMC_AUTO_MDIX; + phy_data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = e1000_write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, phy_data); + if (ret_val) + return ret_val; } else { /* Clear Auto-Crossover to force MDI manually. IGP requires MDI * forced whenever speed or duplex are forced. @@ -2909,7 +3047,13 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw, if (*speed == SPEED_1000) ret_val = e1000_configure_kmrn_for_1000(hw); else - ret_val = e1000_configure_kmrn_for_10_100(hw); + ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex); + if (ret_val) + return ret_val; + } + + if ((hw->phy_type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { + ret_val = e1000_kumeran_lock_loss_workaround(hw); if (ret_val) return ret_val; } @@ -3099,6 +3243,9 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) DEBUGFUNC("e1000_swfw_sync_acquire"); + if (hw->swfwhw_semaphore_present) + return e1000_get_software_flag(hw); + if (!hw->swfw_sync_present) return e1000_get_hw_eeprom_semaphore(hw); @@ -3138,6 +3285,11 @@ e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) DEBUGFUNC("e1000_swfw_sync_release"); + if (hw->swfwhw_semaphore_present) { + e1000_release_software_flag(hw); + return; + } + if (!hw->swfw_sync_present) { e1000_put_hw_eeprom_semaphore(hw); return; @@ -3180,7 +3332,8 @@ e1000_read_phy_reg(struct e1000_hw *hw, if (e1000_swfw_sync_acquire(hw, swfw)) return -E1000_ERR_SWFW_SYNC; - if((hw->phy_type == e1000_phy_igp || + if ((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -3319,7 +3472,8 @@ e1000_write_phy_reg(struct e1000_hw *hw, if (e1000_swfw_sync_acquire(hw, swfw)) return -E1000_ERR_SWFW_SYNC; - if((hw->phy_type == e1000_phy_igp || + if ((hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -3534,7 +3688,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) E1000_WRITE_FLUSH(hw); if (hw->mac_type >= e1000_82571) - msec_delay(10); + msec_delay_irq(10); e1000_swfw_sync_release(hw, swfw); } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR @@ -3564,6 +3718,12 @@ e1000_phy_hw_reset(struct e1000_hw *hw) ret_val = e1000_get_phy_cfg_done(hw); e1000_release_software_semaphore(hw); + if ((hw->mac_type == e1000_ich8lan) && + (hw->phy_type == e1000_phy_igp_3)) { + ret_val = e1000_init_lcd_from_nvm(hw); + if (ret_val) + return ret_val; + } return ret_val; } @@ -3592,9 +3752,11 @@ e1000_phy_reset(struct e1000_hw *hw) case e1000_82541_rev_2: case e1000_82571: case e1000_82572: + case e1000_ich8lan: ret_val = e1000_phy_hw_reset(hw); if(ret_val) return ret_val; + break; default: ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data); @@ -3742,8 +3904,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw) /* The 82571 firmware may still be configuring the PHY. In this * case, we cannot access the PHY until the configuration is done. So * we explicitly set the PHY values. */ - if(hw->mac_type == e1000_82571 || - hw->mac_type == e1000_82572) { + if (hw->mac_type == e1000_82571 || + hw->mac_type == e1000_82572) { hw->phy_id = IGP01E1000_I_PHY_ID; hw->phy_type = e1000_phy_igp_2; return E1000_SUCCESS; @@ -3760,7 +3922,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw) /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); - if(ret_val) + if (ret_val) return ret_val; hw->phy_id = (uint32_t) (phy_id_high << 16); @@ -3798,6 +3960,12 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_80003es2lan: if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE; break; + case e1000_ich8lan: + if (hw->phy_id == IGP03E1000_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE; + if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -4074,9 +4242,12 @@ e1000_phy_get_info(struct e1000_hw *hw, return -E1000_ERR_CONFIG; } - if(hw->phy_type == e1000_phy_igp || + if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) return e1000_phy_igp_get_info(hw, phy_info); + else if (hw->phy_type == e1000_phy_ife) + return e1000_phy_ife_get_info(hw, phy_info); else return e1000_phy_m88_get_info(hw, phy_info); } @@ -4225,6 +4396,35 @@ e1000_init_eeprom_params(struct e1000_hw *hw) eeprom->use_eerd = TRUE; eeprom->use_eewr = FALSE; break; + case e1000_ich8lan: + { + int32_t i = 0; + uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG); + + eeprom->type = e1000_eeprom_ich8; + eeprom->use_eerd = FALSE; + eeprom->use_eewr = FALSE; + eeprom->word_size = E1000_SHADOW_RAM_WORDS; + + /* Zero the shadow RAM structure. But don't load it from NVM + * so as to save time for driver init */ + if (hw->eeprom_shadow_ram != NULL) { + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + hw->eeprom_shadow_ram[i].modified = FALSE; + hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF; + } + } + + hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) * + ICH8_FLASH_SECTOR_SIZE; + + hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1; + hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK); + hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE; + hw->flash_bank_size /= 2 * sizeof(uint16_t); + + break; + } default: break; } @@ -4645,7 +4845,10 @@ e1000_read_eeprom(struct e1000_hw *hw, return ret_val; } - if(eeprom->type == e1000_eeprom_spi) { + if (eeprom->type == e1000_eeprom_ich8) + return e1000_read_eeprom_ich8(hw, offset, words, data); + + if (eeprom->type == e1000_eeprom_spi) { uint16_t word_in; uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; @@ -4812,7 +5015,10 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) DEBUGFUNC("e1000_is_onboard_nvm_eeprom"); - if(hw->mac_type == e1000_82573) { + if (hw->mac_type == e1000_ich8lan) + return FALSE; + + if (hw->mac_type == e1000_82573) { eecd = E1000_READ_REG(hw, EECD); /* Isolate bits 15 & 16 */ @@ -4862,8 +5068,22 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw) } } - for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { + if (hw->mac_type == e1000_ich8lan) { + /* Drivers must allocate the shadow ram structure for the + * EEPROM checksum to be updated. Otherwise, this bit as well + * as the checksum must both be set correctly for this + * validation to pass. + */ + e1000_read_eeprom(hw, 0x19, 1, &eeprom_data); + if ((eeprom_data & 0x40) == 0) { + eeprom_data |= 0x40; + e1000_write_eeprom(hw, 0x19, 1, &eeprom_data); + e1000_update_eeprom_checksum(hw); + } + } + + for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -4889,6 +5109,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw) int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw) { + uint32_t ctrl_ext; uint16_t checksum = 0; uint16_t i, eeprom_data; @@ -4907,6 +5128,14 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw) return -E1000_ERR_EEPROM; } else if (hw->eeprom.type == e1000_eeprom_flash) { e1000_commit_shadow_ram(hw); + } else if (hw->eeprom.type == e1000_eeprom_ich8) { + e1000_commit_shadow_ram(hw); + /* Reload the EEPROM, or else modifications will not appear + * until after next adapter reset. */ + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_EE_RST; + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + msec_delay(10); } return E1000_SUCCESS; } @@ -4946,6 +5175,9 @@ e1000_write_eeprom(struct e1000_hw *hw, if(eeprom->use_eewr == TRUE) return e1000_write_eeprom_eewr(hw, offset, words, data); + if (eeprom->type == e1000_eeprom_ich8) + return e1000_write_eeprom_ich8(hw, offset, words, data); + /* Prepare the EEPROM for writing */ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) return -E1000_ERR_EEPROM; @@ -5133,11 +5365,17 @@ e1000_commit_shadow_ram(struct e1000_hw *hw) uint32_t flop = 0; uint32_t i = 0; int32_t error = E1000_SUCCESS; - - /* The flop register will be used to determine if flash type is STM */ - flop = E1000_READ_REG(hw, FLOP); + uint32_t old_bank_offset = 0; + uint32_t new_bank_offset = 0; + uint32_t sector_retries = 0; + uint8_t low_byte = 0; + uint8_t high_byte = 0; + uint8_t temp_byte = 0; + boolean_t sector_write_failed = FALSE; if (hw->mac_type == e1000_82573) { + /* The flop register will be used to determine if flash type is STM */ + flop = E1000_READ_REG(hw, FLOP); for (i=0; i < attempts; i++) { eecd = E1000_READ_REG(hw, EECD); if ((eecd & E1000_EECD_FLUPD) == 0) { @@ -5171,6 +5409,106 @@ e1000_commit_shadow_ram(struct e1000_hw *hw) } } + if (hw->mac_type == e1000_ich8lan && hw->eeprom_shadow_ram != NULL) { + /* We're writing to the opposite bank so if we're on bank 1, + * write to bank 0 etc. We also need to erase the segment that + * is going to be written */ + if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) { + new_bank_offset = hw->flash_bank_size * 2; + old_bank_offset = 0; + e1000_erase_ich8_4k_segment(hw, 1); + } else { + old_bank_offset = hw->flash_bank_size * 2; + new_bank_offset = 0; + e1000_erase_ich8_4k_segment(hw, 0); + } + + do { + sector_write_failed = FALSE; + /* Loop for every byte in the shadow RAM, + * which is in units of words. */ + for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) { + /* Determine whether to write the value stored + * in the other NVM bank or a modified value stored + * in the shadow RAM */ + if (hw->eeprom_shadow_ram[i].modified == TRUE) { + low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word; + e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset, + &temp_byte); + udelay(100); + error = e1000_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset, + low_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + high_byte = + (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8); + e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1, + &temp_byte); + udelay(100); + } else { + e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset, + &low_byte); + udelay(100); + error = e1000_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset, low_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1, + &high_byte); + } + + /* If the word is 0x13, then make sure the signature bits + * (15:14) are 11b until the commit has completed. + * This will allow us to write 10b which indicates the + * signature is valid. We want to do this after the write + * has completed so that we don't mark the segment valid + * while the write is still in progress */ + if (i == E1000_ICH8_NVM_SIG_WORD) + high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte; + + error = e1000_verify_write_ich8_byte(hw, + (i << 1) + new_bank_offset + 1, high_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + + if (sector_write_failed == FALSE) { + /* Clear the now not used entry in the cache */ + hw->eeprom_shadow_ram[i].modified = FALSE; + hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF; + } + } + + /* Don't bother writing the segment valid bits if sector + * programming failed. */ + if (sector_write_failed == FALSE) { + /* Finally validate the new segment by setting bit 15:14 + * to 10b in word 0x13 , this can be done without an + * erase as well since these bits are 11 to start with + * and we need to change bit 14 to 0b */ + e1000_read_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, + &high_byte); + high_byte &= 0xBF; + error = e1000_verify_write_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, + high_byte); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + + /* And invalidate the previously valid segment by setting + * its signature word (0x13) high_byte to 0b. This can be + * done without an erase because flash erase sets all bits + * to 1's. We can write 1's to 0's without an erase */ + error = e1000_verify_write_ich8_byte(hw, + E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset, + 0); + if (error != E1000_SUCCESS) + sector_write_failed = TRUE; + } + } while (++sector_retries < 10 && sector_write_failed == TRUE); + } + return error; } @@ -5278,6 +5616,9 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * the other port. */ if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE)) rar_num -= 1; + if (hw->mac_type == e1000_ich8lan) + rar_num = E1000_RAR_ENTRIES_ICH8LAN; + /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); for(i = 1; i < rar_num; i++) { @@ -5288,7 +5629,6 @@ e1000_init_rx_addrs(struct e1000_hw *hw) } } -#if 0 /****************************************************************************** * Updates the MAC's list of multicast addresses. * @@ -5323,6 +5663,8 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear RAR[1-15] */ DEBUGOUT(" Clearing RAR[1-15]\n"); num_rar_entry = E1000_RAR_ENTRIES; + if (hw->mac_type == e1000_ich8lan) + num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN; /* Reserve a spot for the Locally Administered Address to work around * an 82571 issue in which a reset on one port will reload the MAC on * the other port. */ @@ -5339,6 +5681,8 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, /* Clear the MTA */ DEBUGOUT(" Clearing MTA\n"); num_mta_entry = E1000_NUM_MTA_REGISTERS; + if (hw->mac_type == e1000_ich8lan) + num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN; for(i = 0; i < num_mta_entry; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); E1000_WRITE_FLUSH(hw); @@ -5375,7 +5719,6 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, } DEBUGOUT("MC Update Complete\n"); } -#endif /* 0 */ /****************************************************************************** * Hashes an address to determine its location in the multicast table @@ -5398,24 +5741,46 @@ e1000_hash_mc_addr(struct e1000_hw *hw, * LSB MSB */ case 0: - /* [47:36] i.e. 0x563 for above example address */ - hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + if (hw->mac_type == e1000_ich8lan) { + /* [47:38] i.e. 0x158 for above example address */ + hash_value = ((mc_addr[4] >> 6) | (((uint16_t) mc_addr[5]) << 2)); + } else { + /* [47:36] i.e. 0x563 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + } break; case 1: - /* [46:35] i.e. 0xAC6 for above example address */ - hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + if (hw->mac_type == e1000_ich8lan) { + /* [46:37] i.e. 0x2B1 for above example address */ + hash_value = ((mc_addr[4] >> 5) | (((uint16_t) mc_addr[5]) << 3)); + } else { + /* [46:35] i.e. 0xAC6 for above example address */ + hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5)); + } break; case 2: - /* [45:34] i.e. 0x5D8 for above example address */ - hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + if (hw->mac_type == e1000_ich8lan) { + /*[45:36] i.e. 0x163 for above example address */ + hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4)); + } else { + /* [45:34] i.e. 0x5D8 for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + } break; case 3: - /* [43:32] i.e. 0x634 for above example address */ - hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + if (hw->mac_type == e1000_ich8lan) { + /* [43:34] i.e. 0x18D for above example address */ + hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6)); + } else { + /* [43:32] i.e. 0x634 for above example address */ + hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8)); + } break; } hash_value &= 0xFFF; + if (hw->mac_type == e1000_ich8lan) + hash_value &= 0x3FF; return hash_value; } @@ -5443,6 +5808,8 @@ e1000_mta_set(struct e1000_hw *hw, * register are determined by the lower 5 bits of the value. */ hash_reg = (hash_value >> 5) & 0x7F; + if (hw->mac_type == e1000_ich8lan) + hash_reg &= 0x1F; hash_bit = hash_value & 0x1F; mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg); @@ -5537,7 +5904,10 @@ e1000_write_vfta(struct e1000_hw *hw, { uint32_t temp; - if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { + if (hw->mac_type == e1000_ich8lan) + return; + + if ((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) { temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1)); E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value); E1000_WRITE_FLUSH(hw); @@ -5562,6 +5932,9 @@ e1000_clear_vfta(struct e1000_hw *hw) uint32_t vfta_offset = 0; uint32_t vfta_bit_in_reg = 0; + if (hw->mac_type == e1000_ich8lan) + return; + if (hw->mac_type == e1000_82573) { if (hw->mng_cookie.vlan_id != 0) { /* The VFTA is a 4096b bit-field, each identifying a single VLAN @@ -5611,9 +5984,18 @@ e1000_id_led_init(struct e1000_hw * hw) DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } - if((eeprom_data== ID_LED_RESERVED_0000) || - (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT; - for(i = 0; i < 4; i++) { + + if ((hw->mac_type == e1000_82573) && + (eeprom_data == ID_LED_RESERVED_82573)) + eeprom_data = ID_LED_DEFAULT_82573; + else if ((eeprom_data == ID_LED_RESERVED_0000) || + (eeprom_data == ID_LED_RESERVED_FFFF)) { + if (hw->mac_type == e1000_ich8lan) + eeprom_data = ID_LED_DEFAULT_ICH8LAN; + else + eeprom_data = ID_LED_DEFAULT; + } + for (i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; switch(temp) { case ID_LED_ON1_DEF2: @@ -5776,6 +6158,10 @@ e1000_cleanup_led(struct e1000_hw *hw) return ret_val; /* Fall Through */ default: + if (hw->phy_type == e1000_phy_ife) { + e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); + break; + } /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; @@ -5820,7 +6206,10 @@ e1000_led_on(struct e1000_hw *hw) /* Clear SW Defineable Pin 0 to turn on the LED */ ctrl &= ~E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - } else if(hw->media_type == e1000_media_type_copper) { + } else if (hw->phy_type == e1000_phy_ife) { + e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); + } else if (hw->media_type == e1000_media_type_copper) { E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); return E1000_SUCCESS; } @@ -5868,7 +6257,10 @@ e1000_led_off(struct e1000_hw *hw) /* Set SW Defineable Pin 0 to turn off the LED */ ctrl |= E1000_CTRL_SWDPIN0; ctrl |= E1000_CTRL_SWDPIO0; - } else if(hw->media_type == e1000_media_type_copper) { + } else if (hw->phy_type == e1000_phy_ife) { + e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, + (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); + } else if (hw->media_type == e1000_media_type_copper) { E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); return E1000_SUCCESS; } @@ -5906,12 +6298,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, XOFFRXC); temp = E1000_READ_REG(hw, XOFFTXC); temp = E1000_READ_REG(hw, FCRUC); + + if (hw->mac_type != e1000_ich8lan) { temp = E1000_READ_REG(hw, PRC64); temp = E1000_READ_REG(hw, PRC127); temp = E1000_READ_REG(hw, PRC255); temp = E1000_READ_REG(hw, PRC511); temp = E1000_READ_REG(hw, PRC1023); temp = E1000_READ_REG(hw, PRC1522); + } + temp = E1000_READ_REG(hw, GPRC); temp = E1000_READ_REG(hw, BPRC); temp = E1000_READ_REG(hw, MPRC); @@ -5931,12 +6327,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, TOTH); temp = E1000_READ_REG(hw, TPR); temp = E1000_READ_REG(hw, TPT); + + if (hw->mac_type != e1000_ich8lan) { temp = E1000_READ_REG(hw, PTC64); temp = E1000_READ_REG(hw, PTC127); temp = E1000_READ_REG(hw, PTC255); temp = E1000_READ_REG(hw, PTC511); temp = E1000_READ_REG(hw, PTC1023); temp = E1000_READ_REG(hw, PTC1522); + } + temp = E1000_READ_REG(hw, MPTC); temp = E1000_READ_REG(hw, BPTC); @@ -5959,6 +6359,9 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw) temp = E1000_READ_REG(hw, IAC); temp = E1000_READ_REG(hw, ICRXOC); + + if (hw->mac_type == e1000_ich8lan) return; + temp = E1000_READ_REG(hw, ICRXPTC); temp = E1000_READ_REG(hw, ICRXATC); temp = E1000_READ_REG(hw, ICTXPTC); @@ -6139,6 +6542,7 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_width = e1000_bus_width_pciex_1; break; case e1000_82571: + case e1000_ich8lan: case e1000_80003es2lan: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; @@ -6176,8 +6580,6 @@ e1000_get_bus_info(struct e1000_hw *hw) break; } } - -#if 0 /****************************************************************************** * Reads a value from one of the devices registers using port I/O (as opposed * memory mapped I/O). Only 82544 and newer devices support port I/O. @@ -6195,7 +6597,6 @@ e1000_read_reg_io(struct e1000_hw *hw, e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); } -#endif /* 0 */ /****************************************************************************** * Writes a value to one of the devices registers using port I/O (as opposed to @@ -6240,8 +6641,6 @@ e1000_get_cable_length(struct e1000_hw *hw, { int32_t ret_val; uint16_t agc_value = 0; - uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; - uint16_t max_agc = 0; uint16_t i, phy_data; uint16_t cable_length; @@ -6314,6 +6713,8 @@ e1000_get_cable_length(struct e1000_hw *hw, break; } } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */ + uint16_t cur_agc_value; + uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE; uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A, IGP01E1000_PHY_AGC_B, @@ -6326,23 +6727,23 @@ e1000_get_cable_length(struct e1000_hw *hw, if(ret_val) return ret_val; - cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; + cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; - /* Array bound check. */ - if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || - (cur_agc == 0)) + /* Value bound check. */ + if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || + (cur_agc_value == 0)) return -E1000_ERR_PHY; - agc_value += cur_agc; + agc_value += cur_agc_value; /* Update minimal AGC value. */ - if(min_agc > cur_agc) - min_agc = cur_agc; + if (min_agc_value > cur_agc_value) + min_agc_value = cur_agc_value; } /* Remove the minimal AGC result for length < 50m */ - if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) { - agc_value -= min_agc; + if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) { + agc_value -= min_agc_value; /* Get the average length of the remaining 3 channels */ agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1); @@ -6358,7 +6759,10 @@ e1000_get_cable_length(struct e1000_hw *hw, IGP01E1000_AGC_RANGE) : 0; *max_length = e1000_igp_cable_length_table[agc_value] + IGP01E1000_AGC_RANGE; - } else if (hw->phy_type == e1000_phy_igp_2) { + } else if (hw->phy_type == e1000_phy_igp_2 || + hw->phy_type == e1000_phy_igp_3) { + uint16_t cur_agc_index, max_agc_index = 0; + uint16_t min_agc_index = IGP02E1000_AGC_LENGTH_TABLE_SIZE - 1; uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = {IGP02E1000_PHY_AGC_A, IGP02E1000_PHY_AGC_B, @@ -6373,19 +6777,27 @@ e1000_get_cable_length(struct e1000_hw *hw, /* Getting bits 15:9, which represent the combination of course and * fine gain values. The result is a number that can be put into * the lookup table to obtain the approximate cable length. */ - cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & - IGP02E1000_AGC_LENGTH_MASK; + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_AGC_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) + return -E1000_ERR_PHY; /* Remove min & max AGC values from calculation. */ - if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc]) - min_agc = cur_agc; - if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc]) - max_agc = cur_agc; + if (e1000_igp_2_cable_length_table[min_agc_index] > + e1000_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (e1000_igp_2_cable_length_table[max_agc_index] < + e1000_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; - agc_value += e1000_igp_2_cable_length_table[cur_agc]; + agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; } - agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]); + agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + + e1000_igp_2_cable_length_table[max_agc_index]); agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); /* Calculate cable length with the error range of +/- 10 meters. */ @@ -6431,7 +6843,8 @@ e1000_check_polarity(struct e1000_hw *hw, return ret_val; *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> M88E1000_PSSR_REV_POLARITY_SHIFT; - } else if(hw->phy_type == e1000_phy_igp || + } else if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) { /* Read the Status register to check the speed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, @@ -6457,6 +6870,13 @@ e1000_check_polarity(struct e1000_hw *hw, * 100 Mbps this bit is always 0) */ *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED; } + } else if (hw->phy_type == e1000_phy_ife) { + ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL, + &phy_data); + if (ret_val) + return ret_val; + *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >> + IFE_PESC_POLARITY_REVERSED_SHIFT; } return E1000_SUCCESS; } @@ -6484,7 +6904,8 @@ e1000_check_downshift(struct e1000_hw *hw) DEBUGFUNC("e1000_check_downshift"); - if(hw->phy_type == e1000_phy_igp || + if (hw->phy_type == e1000_phy_igp || + hw->phy_type == e1000_phy_igp_3 || hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data); @@ -6501,6 +6922,9 @@ e1000_check_downshift(struct e1000_hw *hw) hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> M88E1000_PSSR_DOWNSHIFT_SHIFT; + } else if (hw->phy_type == e1000_phy_ife) { + /* e1000_phy_ife supports 10/100 speed only */ + hw->speed_downgraded = FALSE; } return E1000_SUCCESS; @@ -6545,7 +6969,9 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw, if(speed == SPEED_1000) { - e1000_get_cable_length(hw, &min_length, &max_length); + ret_val = e1000_get_cable_length(hw, &min_length, &max_length); + if (ret_val) + return ret_val; if((hw->dsp_config_state == e1000_dsp_config_enabled) && min_length >= e1000_igp_cable_length_50) { @@ -6753,20 +7179,27 @@ static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active) { + uint32_t phy_ctrl = 0; int32_t ret_val; uint16_t phy_data; DEBUGFUNC("e1000_set_d3_lplu_state"); - if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2) + if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2 + && hw->phy_type != e1000_phy_igp_3) return E1000_SUCCESS; /* During driver activity LPLU should not be used or it will attain link * from the lowest speeds starting from 10Mbps. The capability is used for * Dx transitions and states */ - if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) { + if (hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) { ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data); - if(ret_val) + if (ret_val) return ret_val; + } else if (hw->mac_type == e1000_ich8lan) { + /* MAC writes into PHY register based on the state transition + * and start auto-negotiation. SW driver can overwrite the settings + * in CSR PHY power control E1000_PHY_CTRL register. */ + phy_ctrl = E1000_READ_REG(hw, PHY_CTRL); } else { ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) @@ -6781,11 +7214,16 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, if(ret_val) return ret_val; } else { + if (hw->mac_type == e1000_ich8lan) { + phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data &= ~IGP02E1000_PM_D3_LPLU; ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during @@ -6821,17 +7259,22 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) { if(hw->mac_type == e1000_82541_rev_2 || - hw->mac_type == e1000_82547_rev_2) { + hw->mac_type == e1000_82547_rev_2) { phy_data |= IGP01E1000_GMII_FLEX_SPD; ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data); if(ret_val) return ret_val; } else { + if (hw->mac_type == e1000_ich8lan) { + phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data |= IGP02E1000_PM_D3_LPLU; ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } } /* When LPLU is enabled we should disable SmartSpeed */ @@ -6866,6 +7309,7 @@ static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active) { + uint32_t phy_ctrl = 0; int32_t ret_val; uint16_t phy_data; DEBUGFUNC("e1000_set_d0_lplu_state"); @@ -6873,15 +7317,24 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw, if(hw->mac_type <= e1000_82547_rev_2) return E1000_SUCCESS; + if (hw->mac_type == e1000_ich8lan) { + phy_ctrl = E1000_READ_REG(hw, PHY_CTRL); + } else { ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); if(ret_val) return ret_val; + } if (!active) { + if (hw->mac_type == e1000_ich8lan) { + phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data &= ~IGP02E1000_PM_D0_LPLU; ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during * Dx states where the power conservation is most important. During @@ -6914,10 +7367,15 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw, } else { + if (hw->mac_type == e1000_ich8lan) { + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; + E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl); + } else { phy_data |= IGP02E1000_PM_D0_LPLU; ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); if (ret_val) return ret_val; + } /* When LPLU is enabled we should disable SmartSpeed */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data); @@ -7191,15 +7649,18 @@ e1000_mng_write_commit( * returns - TRUE when the mode is IAMT or FALSE. ****************************************************************************/ boolean_t -e1000_check_mng_mode( - struct e1000_hw *hw) +e1000_check_mng_mode(struct e1000_hw *hw) { uint32_t fwsm; fwsm = E1000_READ_REG(hw, FWSM); - if((fwsm & E1000_FWSM_MODE_MASK) == - (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + if (hw->mac_type == e1000_ich8lan) { + if ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) + return TRUE; + } else if ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)) return TRUE; return FALSE; @@ -7439,7 +7900,6 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw) E1000_WRITE_REG(hw, CTRL, ctrl); } -#if 0 /*************************************************************************** * * Enables PCI-Express master access. @@ -7463,7 +7923,6 @@ e1000_enable_pciex_master(struct e1000_hw *hw) ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; E1000_WRITE_REG(hw, CTRL, ctrl); } -#endif /* 0 */ /******************************************************************************* * @@ -7529,8 +7988,10 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) case e1000_82572: case e1000_82573: case e1000_80003es2lan: - while(timeout) { - if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; + case e1000_ich8lan: + while (timeout) { + if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) + break; else msec_delay(1); timeout--; } @@ -7570,7 +8031,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) switch (hw->mac_type) { default: - msec_delay(10); + msec_delay_irq(10); break; case e1000_80003es2lan: /* Separate *_CFG_DONE_* bit for each port */ @@ -7753,6 +8214,13 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw) { uint32_t manc = 0; + uint32_t fwsm = 0; + + if (hw->mac_type == e1000_ich8lan) { + fwsm = E1000_READ_REG(hw, FWSM); + return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS + : E1000_BLK_PHY_RESET; + } if (hw->mac_type > e1000_82547_rev_2) manc = E1000_READ_REG(hw, MANC); @@ -7779,6 +8247,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) if((fwsm & E1000_FWSM_MODE_MASK) != 0) return TRUE; break; + case e1000_ich8lan: + return TRUE; default: break; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index cc0c77c4c17..f5c6f08966c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -366,6 +366,7 @@ e1000_release_hw_control(struct e1000_adapter *adapter) { uint32_t ctrl_ext; uint32_t swsm; + uint32_t extcnf; /* Let firmware taken over control of h/w */ switch (adapter->hw.mac_type) { @@ -380,6 +381,11 @@ e1000_release_hw_control(struct e1000_adapter *adapter) swsm = E1000_READ_REG(&adapter->hw, SWSM); E1000_WRITE_REG(&adapter->hw, SWSM, swsm & ~E1000_SWSM_DRV_LOAD); + case e1000_ich8lan: + extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT); + E1000_WRITE_REG(&adapter->hw, CTRL_EXT, + extcnf & ~E1000_CTRL_EXT_DRV_LOAD); + break; default: break; } @@ -401,6 +407,7 @@ e1000_get_hw_control(struct e1000_adapter *adapter) { uint32_t ctrl_ext; uint32_t swsm; + uint32_t extcnf; /* Let firmware know the driver has taken over */ switch (adapter->hw.mac_type) { case e1000_82571: @@ -415,6 +422,11 @@ e1000_get_hw_control(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, SWSM, swsm | E1000_SWSM_DRV_LOAD); break; + case e1000_ich8lan: + extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL); + E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL, + extcnf | E1000_EXTCNF_CTRL_SWFLAG); + break; default: break; } @@ -490,6 +502,7 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter) * (b) AMT is active * (c) SoL/IDER session is active */ if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type != e1000_ich8lan && adapter->hw.media_type == e1000_media_type_copper && !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) && !mng_mode_enabled && @@ -561,6 +574,9 @@ e1000_reset(struct e1000_adapter *adapter) case e1000_82573: pba = E1000_PBA_12K; break; + case e1000_ich8lan: + pba = E1000_PBA_8K; + break; default: pba = E1000_PBA_48K; break; @@ -585,6 +601,12 @@ e1000_reset(struct e1000_adapter *adapter) /* Set the FC high water mark to 90% of the FIFO size. * Required to clear last 3 LSB */ fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8; + /* We can't use 90% on small FIFOs because the remainder + * would be less than 1 full frame. In this case, we size + * it to allow at least a full frame above the high water + * mark. */ + if (pba < E1000_PBA_16K) + fc_high_water_mark = (pba * 1024) - 1600; adapter->hw.fc_high_water = fc_high_water_mark; adapter->hw.fc_low_water = fc_high_water_mark - 8; @@ -622,6 +644,8 @@ e1000_reset(struct e1000_adapter *adapter) phy_data); } + if (adapter->hw.mac_type < e1000_ich8lan) + /* FIXME: this code is duplicate and wrong for PCI Express */ if (adapter->en_mng_pt) { manc = E1000_READ_REG(&adapter->hw, MANC); manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST); @@ -648,6 +672,7 @@ e1000_probe(struct pci_dev *pdev, struct net_device *netdev; struct e1000_adapter *adapter; unsigned long mmio_start, mmio_len; + unsigned long flash_start, flash_len; static int cards_found = 0; static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */ @@ -657,10 +682,12 @@ e1000_probe(struct pci_dev *pdev, if ((err = pci_enable_device(pdev))) return err; - if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { - if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) && + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { E1000_ERR("No usable DMA configuration, aborting\n"); return err; } @@ -740,6 +767,19 @@ e1000_probe(struct pci_dev *pdev, if ((err = e1000_sw_init(adapter))) goto err_sw_init; + /* Flash BAR mapping must happen after e1000_sw_init + * because it depends on mac_type */ + if ((adapter->hw.mac_type == e1000_ich8lan) && + (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { + flash_start = pci_resource_start(pdev, 1); + flash_len = pci_resource_len(pdev, 1); + adapter->hw.flash_address = ioremap(flash_start, flash_len); + if (!adapter->hw.flash_address) { + err = -EIO; + goto err_flashmap; + } + } + if ((err = e1000_check_phy_reset_block(&adapter->hw))) DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); @@ -758,6 +798,8 @@ e1000_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + if (adapter->hw.mac_type == e1000_ich8lan) + netdev->features &= ~NETIF_F_HW_VLAN_FILTER; } #ifdef NETIF_F_TSO @@ -773,11 +815,17 @@ e1000_probe(struct pci_dev *pdev, if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; - /* hard_start_xmit is safe against parallel locking */ netdev->features |= NETIF_F_LLTX; adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); + /* initialize eeprom parameters */ + + if (e1000_init_eeprom_params(&adapter->hw)) { + E1000_ERR("EEPROM initialization failed\n"); + return -EIO; + } + /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ @@ -845,6 +893,11 @@ e1000_probe(struct pci_dev *pdev, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data); eeprom_apme_mask = E1000_EEPROM_82544_APM; break; + case e1000_ich8lan: + e1000_read_eeprom(&adapter->hw, + EEPROM_INIT_CONTROL1_REG, 1, &eeprom_data); + eeprom_apme_mask = E1000_EEPROM_ICH8_APME; + break; case e1000_82546: case e1000_82546_rev_3: case e1000_82571: @@ -904,6 +957,9 @@ e1000_probe(struct pci_dev *pdev, return 0; err_register: + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); +err_flashmap: err_sw_init: err_eeprom: iounmap(adapter->hw.hw_addr); @@ -937,6 +993,7 @@ e1000_remove(struct pci_dev *pdev) flush_scheduled_work(); if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type != e1000_ich8lan && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); if (manc & E1000_MANC_SMBUS_EN) { @@ -965,6 +1022,8 @@ e1000_remove(struct pci_dev *pdev) #endif iounmap(adapter->hw.hw_addr); + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); pci_release_regions(pdev); free_netdev(netdev); @@ -1015,13 +1074,6 @@ e1000_sw_init(struct e1000_adapter *adapter) return -EIO; } - /* initialize eeprom parameters */ - - if (e1000_init_eeprom_params(hw)) { - E1000_ERR("EEPROM initialization failed\n"); - return -EIO; - } - switch (hw->mac_type) { default: break; @@ -1257,8 +1309,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, int size; size = sizeof(struct e1000_buffer) * txdr->count; - - txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); + txdr->buffer_info = vmalloc(size); if (!txdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit descriptor ring\n"); @@ -1486,7 +1537,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, int size, desc_len; size = sizeof(struct e1000_buffer) * rxdr->count; - rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus)); + rxdr->buffer_info = vmalloc(size); if (!rxdr->buffer_info) { DPRINTK(PROBE, ERR, "Unable to allocate memory for the receive descriptor ring\n"); @@ -2145,6 +2196,12 @@ e1000_set_multi(struct net_device *netdev) uint32_t rctl; uint32_t hash_value; int i, rar_entries = E1000_RAR_ENTRIES; + int mta_reg_count = (hw->mac_type == e1000_ich8lan) ? + E1000_NUM_MTA_REGISTERS_ICH8LAN : + E1000_NUM_MTA_REGISTERS; + + if (adapter->hw.mac_type == e1000_ich8lan) + rar_entries = E1000_RAR_ENTRIES_ICH8LAN; /* reserve RAR[14] for LAA over-write work-around */ if (adapter->hw.mac_type == e1000_82571) @@ -2191,7 +2248,7 @@ e1000_set_multi(struct net_device *netdev) /* clear the old settings from the multicast hash table */ - for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++) { + for (i = 0; i < mta_reg_count; i++) { E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); E1000_WRITE_FLUSH(hw); } @@ -2270,8 +2327,16 @@ e1000_watchdog(unsigned long data) struct net_device *netdev = adapter->netdev; struct e1000_tx_ring *txdr = adapter->tx_ring; uint32_t link, tctl; - - e1000_check_for_link(&adapter->hw); + int32_t ret_val; + + ret_val = e1000_check_for_link(&adapter->hw); + if ((ret_val == E1000_ERR_PHY) && + (adapter->hw.phy_type == e1000_phy_igp_3) && + (E1000_READ_REG(&adapter->hw, CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) { + /* See e1000_kumeran_lock_loss_workaround() */ + DPRINTK(LINK, INFO, + "Gigabit has been disabled, downgrading speed\n"); + } if (adapter->hw.mac_type == e1000_82573) { e1000_enable_tx_pkt_filtering(&adapter->hw); if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id) @@ -2837,6 +2902,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_ich8lan: pull_size = min((unsigned int)4, skb->data_len); if (!__pskb_pull_tail(skb, pull_size)) { DPRINTK(DRV, ERR, @@ -3021,6 +3087,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) /* Adapter-specific max frame size limits. */ switch (adapter->hw.mac_type) { case e1000_undefined ... e1000_82542_rev2_1: + case e1000_ich8lan: if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; @@ -3129,12 +3196,15 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.bprc += E1000_READ_REG(hw, BPRC); adapter->stats.mprc += E1000_READ_REG(hw, MPRC); adapter->stats.roc += E1000_READ_REG(hw, ROC); + + if (adapter->hw.mac_type != e1000_ich8lan) { adapter->stats.prc64 += E1000_READ_REG(hw, PRC64); adapter->stats.prc127 += E1000_READ_REG(hw, PRC127); adapter->stats.prc255 += E1000_READ_REG(hw, PRC255); adapter->stats.prc511 += E1000_READ_REG(hw, PRC511); adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); + } adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(hw, MPC); @@ -3162,12 +3232,16 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.totl += E1000_READ_REG(hw, TOTL); adapter->stats.toth += E1000_READ_REG(hw, TOTH); adapter->stats.tpr += E1000_READ_REG(hw, TPR); + + if (adapter->hw.mac_type != e1000_ich8lan) { adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64); adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127); adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255); adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511); adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023); adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522); + } + adapter->stats.mptc += E1000_READ_REG(hw, MPTC); adapter->stats.bptc += E1000_READ_REG(hw, BPTC); @@ -3189,6 +3263,8 @@ e1000_update_stats(struct e1000_adapter *adapter) if (hw->mac_type > e1000_82547_rev_2) { adapter->stats.iac += E1000_READ_REG(hw, IAC); adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC); + + if (adapter->hw.mac_type != e1000_ich8lan) { adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC); adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC); adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC); @@ -3196,6 +3272,7 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC); adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC); adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC); + } } /* Fill out the OS statistics structure */ @@ -4330,18 +4407,21 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); + if (adapter->hw.mac_type != e1000_ich8lan) { /* enable VLAN receive filtering */ rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_VFE; rctl &= ~E1000_RCTL_CFIEN; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); e1000_update_mng_vlan(adapter); + } } else { /* disable VLAN tag insert/strip */ ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl &= ~E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); + if (adapter->hw.mac_type != e1000_ich8lan) { /* disable VLAN filtering */ rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~E1000_RCTL_VFE; @@ -4350,6 +4430,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; } + } } e1000_irq_enable(adapter); @@ -4578,7 +4659,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } + /* FIXME: this code is incorrect for PCI Express */ if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type != e1000_ich8lan && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); if (manc & E1000_MANC_SMBUS_EN) { @@ -4589,6 +4672,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) } } + if (adapter->hw.phy_type == e1000_phy_igp_3) + e1000_phy_powerdown_workaround(&adapter->hw); + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); @@ -4624,7 +4710,9 @@ e1000_resume(struct pci_dev *pdev) netif_device_attach(netdev); + /* FIXME: this code is incorrect for PCI Express */ if (adapter->hw.mac_type >= e1000_82540 && + adapter->hw.mac_type != e1000_ich8lan && adapter->hw.media_type == e1000_media_type_copper) { manc = E1000_READ_REG(&adapter->hw, MANC); manc &= ~(E1000_MANC_ARP_EN); -- cgit v1.2.3 From 1f9e7e3d32f7ff3fd3a936fc9ad59770b3d29774 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:26 -0700 Subject: e1000: allow user to disable ich8 lock loss workaround The workaround for the ich8 lock loss problem is only needed for a very small amount of systems. This adds an option for the user to disable the workaround. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_param.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index bd6c040b3cf..0ef413172c6 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -202,6 +202,15 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); +/* Enable Kumeran Lock Loss workaround + * + * Valid Range: 0, 1 + * + * Default Value: 1 (enabled) + */ + +E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); + #define AUTONEG_ADV_DEFAULT 0x2F #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL @@ -484,6 +493,18 @@ e1000_check_options(struct e1000_adapter *adapter) e1000_validate_option(&spd, &opt, adapter); adapter->smart_power_down = spd; } + { /* Kumeran Lock Loss Workaround */ + struct e1000_option opt = { + .type = enable_option, + .name = "Kumeran Lock Loss Workaround", + .err = "defaulting to Enabled", + .def = OPTION_ENABLED + }; + + int kmrn_lock_loss = KumeranLockLoss[bd]; + e1000_validate_option(&kmrn_lock_loss, &opt, adapter); + adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss; + } switch (adapter->hw.media_type) { case e1000_media_type_fiber: -- cgit v1.2.3 From ae2c3860eb18712b71861bb6fc8d7e11e0f79e6d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:30 -0700 Subject: e1000: add ich8lan device ID's Add the device ID's of the supported ICH8 LAN devices. Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f5c6f08966c..70d2dfe2022 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -73,6 +73,11 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), + INTEL_E1000_ETHERNET_DEVICE(0x1049), + INTEL_E1000_ETHERNET_DEVICE(0x104A), + INTEL_E1000_ETHERNET_DEVICE(0x104B), + INTEL_E1000_ETHERNET_DEVICE(0x104C), + INTEL_E1000_ETHERNET_DEVICE(0x104D), INTEL_E1000_ETHERNET_DEVICE(0x105E), INTEL_E1000_ETHERNET_DEVICE(0x105F), INTEL_E1000_ETHERNET_DEVICE(0x1060), @@ -96,6 +101,8 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x109A), INTEL_E1000_ETHERNET_DEVICE(0x10B5), INTEL_E1000_ETHERNET_DEVICE(0x10B9), + INTEL_E1000_ETHERNET_DEVICE(0x10BA), + INTEL_E1000_ETHERNET_DEVICE(0x10BB), /* required last entry */ {0,} }; -- cgit v1.2.3 From e4ac9773be2ea01b707da0496ab1527ec6cdda4e Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Tue, 27 Jun 2006 09:08:34 -0700 Subject: e1000: increase version to 7.1.9-k2 Increment the version to 7.1.9-k2 Signed-off-by: Jesse Brandeburg Signed-off-by: Auke Kok --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 70d2dfe2022..f9a02c1ab52 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "7.0.38-k4"DRIVERNAPI +#define DRV_VERSION "7.1.9-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; -- cgit v1.2.3 From 20ed7c094dfe33b0e15e8c60f60012b9278631d3 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 5 Jul 2006 14:28:34 -0400 Subject: [netdrvr] 3c59x: snip changelog from source code Driver source code is not the preferred place to store change history. Acked-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/3c59x.c | 166 ---------------------------------------------------- 1 file changed, 166 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 2819de79442..80e8ca013e4 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -17,172 +17,6 @@ 410 Severn Ave., Suite 210 Annapolis MD 21403 - Linux Kernel Additions: - - 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates - 0.99H+lk1.0 - Jeff Garzik - Remove compatibility defines for kernel versions < 2.2.x. - Update for new 2.3.x module interface - LK1.1.2 (March 19, 2000) - * New PCI interface (jgarzik) - - LK1.1.3 25 April 2000, Andrew Morton - - Merged with 3c575_cb.c - - Don't set RxComplete in boomerang interrupt enable reg - - spinlock in vortex_timer to protect mdio functions - - disable local interrupts around call to vortex_interrupt in - vortex_tx_timeout() (So vortex_interrupt can use spin_lock()) - - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl - - In vortex_start_xmit(), move the lock to _after_ we've altered - vp->cur_tx and vp->tx_full. This defeats the race between - vortex_start_xmit() and vortex_interrupt which was identified - by Bogdan Costescu. - - Merged back support for six new cards from various sources - - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus - insertion oops) - - Tell it that 3c905C has NWAY for 100bT autoneg - - Fix handling of SetStatusEnd in 'Too much work..' code, as - per 2.3.99's 3c575_cb (Dave Hinds). - - Split ISR into two for vortex & boomerang - - Fix MOD_INC/DEC races - - Handle resource allocation failures. - - Fix 3CCFE575CT LED polarity - - Make tx_interrupt_mitigation the default - - LK1.1.4 25 April 2000, Andrew Morton - - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs. - - Put vortex_info_tbl into __devinitdata - - In the vortex_error StatsFull HACK, disable stats in vp->intr_enable as well - as in the hardware. - - Increased the loop counter in issue_and_wait from 2,000 to 4,000. - - LK1.1.5 28 April 2000, andrewm - - Added powerpc defines (John Daniel said these work...) - - Some extra diagnostics - - In vortex_error(), reset the Tx on maxCollisions. Otherwise most - chips usually get a Tx timeout. - - Added extra_reset module parm - - Replaced some inline timer manip with mod_timer - (Franois romieu ) - - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway - (this came across from 3c575_cb). - - LK1.1.6 06 Jun 2000, andrewm - - Backed out the PPC defines. - - Use del_timer_sync(), mod_timer(). - - Fix wrapped ulong comparison in boomerang_rx() - - Add IS_TORNADO, use it to suppress 3c905C checksum error msg - (Donald Becker, I Lee Hetherington ) - - Replace union wn3_config with BFINS/BFEXT manipulation for - sparc64 (Pete Zaitcev, Peter Jones) - - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex): - do a netif_wake_queue() to better recover from errors. (Anders Pedersen, - Donald Becker) - - Print a warning on out-of-memory (rate limited to 1 per 10 secs) - - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland) - - LK1.1.7 2 Jul 2000 andrewm - - Better handling of shared IRQs - - Reset the transmitter on a Tx reclaim error - - Fixed crash under OOM during vortex_open() (Mark Hemment) - - Fix Rx cessation problem during OOM (help from Mark Hemment) - - The spinlocks around the mdio access were blocking interrupts for 300uS. - Fix all this to use spin_lock_bh() within mdio_read/write - - Only write to TxFreeThreshold if it's a boomerang - other NICs don't - have one. - - Added 802.3x MAC-layer flow control support - - LK1.1.8 13 Aug 2000 andrewm - - Ignore request_region() return value - already reserved if Cardbus. - - Merged some additional Cardbus flags from Don's 0.99Qk - - Some fixes for 3c556 (Fred Maciel) - - Fix for EISA initialisation (Jan Rekorajski) - - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers - - Fixed MII_XCVR_PWR for 3CCFE575CT - - Added INVERT_LED_PWR, used it. - - Backed out the extra_reset stuff - - LK1.1.9 12 Sep 2000 andrewm - - Backed out the tx_reset_resume flags. It was a no-op. - - In vortex_error, don't reset the Tx on txReclaim errors - - In vortex_error, don't reset the Tx on maxCollisions errors. - Hence backed out all the DownListPtr logic here. - - In vortex_error, give Tornado cards a partial TxReset on - maxCollisions (David Hinds). Defined MAX_COLLISION_RESET for this. - - Redid some driver flags and device names based on pcmcia_cs-3.1.20. - - Fixed a bug where, if vp->tx_full is set when the interface - is downed, it remains set when the interface is upped. Bad - things happen. - - LK1.1.10 17 Sep 2000 andrewm - - Added EEPROM_8BIT for 3c555 (Fred Maciel) - - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg) - - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO" - - LK1.1.11 13 Nov 2000 andrewm - - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER - - LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1) - - Call pci_enable_device before we request our IRQ (Tobias Ringstrom) - - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra) - - Added extended issue_and_wait for the 3c905CX. - - Look for an MII on PHY index 24 first (3c905CX oddity). - - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) - - Don't free skbs we don't own on oom path in vortex_open(). - - LK1.1.13 27 Jan 2001 - - Added explicit `medialock' flag so we can truly - lock the media type down with `options'. - - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo ) - - Added and used EEPROM_NORESET for 3c556B PM resumes. - - Fixed leakage of vp->rx_ring. - - Break out separate HAS_HWCKSM device capability flag. - - Kill vp->tx_full (ANK) - - Merge zerocopy fragment handling (ANK?) - - LK1.1.14 15 Feb 2001 - - Enable WOL. Can be turned on with `enable_wol' module option. - - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul) - - If a device's internalconfig register reports it has NWAY, - use it, even if autoselect is enabled. - - LK1.1.15 6 June 2001 akpm - - Prevent double counting of received bytes (Lars Christensen) - - Add ethtool support (jgarzik) - - Add module parm descriptions (Andrzej M. Krzysztofowicz) - - Implemented alloc_etherdev() API - - Special-case the 'Tx error 82' message. - - LK1.1.16 18 July 2001 akpm - - Make NETIF_F_SG dependent upon nr_free_highpages(), not on CONFIG_HIGHMEM - - Lessen verbosity of bootup messages - - Fix WOL - use new PM API functions. - - Use netif_running() instead of vp->open in suspend/resume. - - Don't reset the interface logic on open/close/rmmod. It upsets - autonegotiation, and hence DHCP (from 0.99T). - - Back out EEPROM_NORESET flag because of the above (we do it for all - NICs). - - Correct 3c982 identification string - - Rename wait_for_completion() to issue_and_wait() to avoid completion.h - clash. - - LK1.1.17 18Dec01 akpm - - PCI ID 9805 is a Python-T, not a dual-port Cyclone. Apparently. - And it has NWAY. - - Mask our advertised modes (vp->advertising) with our capabilities - (MII reg5) when deciding which duplex mode to use. - - Add `global_options' as default for options[]. Ditto global_enable_wol, - global_full_duplex. - - LK1.1.18 01Jul02 akpm - - Fix for undocumented transceiver power-up bit on some 3c566B's - (Donald Becker, Rahul Karnik) - - - See http://www.zip.com.au/~akpm/linux/#3c59x-2.3 for more details. - - Also see Documentation/networking/vortex.txt - - LK1.1.19 10Nov02 Marc Zyngier - - EISA sysfs integration. */ /* -- cgit v1.2.3 From bce305f4fe779f29d99d414685243f5da0803254 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 5 Jul 2006 15:00:40 +0200 Subject: [PATCH] 8139too deadlock fix > stack backtrace: > [] rtl8139_start_xmit+0xd9/0xff [8139too] > [] netpoll_send_skb+0x98/0xea This seems to be a real deadlock... So netpoll_send_skb takes the _xmit_lock, which is all nitty gritty but then rtl8139_start_xmit comes around while that lock is taken, and does spin_unlock_irq(&tp->lock); which.. enables interrupts and softirqs; this is quite bad because the xmit lock is taken in softirq context for the watchdog like this: [] _spin_lock+0x23/0x32 [] dev_watchdog+0x14/0xb1 [] run_timer_softirq+0xf2/0x14a [] __do_softirq+0x55/0xb0 [] do_softirq+0x58/0xbd Which would deadlock now that the spin_unlock_irq() has enabled irqs/softirqs while the _xmit_lock is still held. The patch below turns this into a irqsave/irqrestore pair so that interrupts don't get enabled unconditionally. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Jeff Garzik --- drivers/net/8139too.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index cd9718512d1..e4f4eaff767 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1709,6 +1709,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; unsigned int entry; unsigned int len = skb->len; + unsigned long flags; /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; @@ -1725,7 +1726,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) return 0; } - spin_lock_irq(&tp->lock); + spin_lock_irqsave(&tp->lock, flags); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | max(len, (unsigned int)ETH_ZLEN)); @@ -1736,7 +1737,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); - spin_unlock_irq(&tp->lock); + spin_unlock_irqrestore(&tp->lock, flags); if (netif_msg_tx_queued(tp)) printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n", -- cgit v1.2.3 From fc0a75ce4835187a3f76d6b35f0644d1b168eef5 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Thu, 6 Jul 2006 09:56:30 +0200 Subject: [PATCH] blktrace: fix barrier vs sync typo Signed-off-by: Nathan Scott Signed-off-by: Jens Axboe --- include/linux/blktrace_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index a7e8cef73d1..d95615fc6da 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -11,7 +11,7 @@ enum blktrace_cat { BLK_TC_READ = 1 << 0, /* reads */ BLK_TC_WRITE = 1 << 1, /* writes */ BLK_TC_BARRIER = 1 << 2, /* barrier */ - BLK_TC_SYNC = 1 << 3, /* barrier */ + BLK_TC_SYNC = 1 << 3, /* sync IO */ BLK_TC_QUEUE = 1 << 4, /* queueing/merging */ BLK_TC_REQUEUE = 1 << 5, /* requeueing */ BLK_TC_ISSUE = 1 << 6, /* issue */ -- cgit v1.2.3 From 40359ccb836866435b03a0cb57345002b587d875 Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Thu, 6 Jul 2006 10:03:28 +0200 Subject: [PATCH] blktrace: readahead support Provide the needed kernel support for distinguishing readahead from regular read requests when tracing block devices. Signed-off-by: Nathan Scott Signed-off-by: Jens Axboe --- block/blktrace.c | 5 ++++- include/linux/blktrace_api.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/block/blktrace.c b/block/blktrace.c index 92925e7d9e6..b8c0702777f 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -69,7 +69,7 @@ static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK /* * Bio action bits of interest */ -static u32 bio_act[3] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC) }; +static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD) }; /* * More could be added as needed, taking care to increment the decrementer @@ -79,6 +79,8 @@ static u32 bio_act[3] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_AC (((rw) & (1 << BIO_RW_BARRIER)) >> (BIO_RW_BARRIER - 0)) #define trace_sync_bit(rw) \ (((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1)) +#define trace_ahead_bit(rw) \ + (((rw) & (1 << BIO_RW_AHEAD)) << (BIO_RW_AHEAD - 0)) /* * The worker for the various blk_add_trace*() types. Fills out a @@ -100,6 +102,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, what |= ddir_act[rw & WRITE]; what |= bio_act[trace_barrier_bit(rw)]; what |= bio_act[trace_sync_bit(rw)]; + what |= bio_act[trace_ahead_bit(rw)]; pid = tsk->pid; if (unlikely(act_log_check(bt, what, sector, pid))) diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index d95615fc6da..2346a1db856 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -19,6 +19,7 @@ enum blktrace_cat { BLK_TC_FS = 1 << 8, /* fs requests */ BLK_TC_PC = 1 << 9, /* pc requests */ BLK_TC_NOTIFY = 1 << 10, /* special message */ + BLK_TC_AHEAD = 1 << 11, /* readahead */ BLK_TC_END = 1 << 15, /* only 16-bits, reminder */ }; -- cgit v1.2.3 From 1959d21232931dfa686769a21161413f10d6652f Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 6 Jul 2006 10:18:05 +0200 Subject: [PATCH] Only the first two bits in bio->bi_rw and rq->flags match Not three, as assumed. This causes the barrier bit to be needlessly set for some IO. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 4 ++-- include/linux/blktrace_api.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index ab17c7224bb..61d6b3c65b6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -3491,8 +3491,8 @@ EXPORT_SYMBOL(end_request); void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) { - /* first three bits are identical in rq->flags and bio->bi_rw */ - rq->flags |= (bio->bi_rw & 7); + /* first two bits are identical in rq->flags and bio->bi_rw */ + rq->flags |= (bio->bi_rw & 3); rq->nr_phys_segments = bio_phys_segments(q, bio); rq->nr_hw_segments = bio_hw_segments(q, bio); diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 2346a1db856..7520cc1ff9e 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -148,7 +148,7 @@ static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq, u32 what) { struct blk_trace *bt = q->blk_trace; - int rw = rq->flags & 0x07; + int rw = rq->flags & 0x03; if (likely(!bt)) return; -- cgit v1.2.3 From a496e25dfb25493a57bcee5d66875d6ff80a9093 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 7 Jul 2006 12:31:27 -0400 Subject: [PATCH] Fix cpufreq vs hotplug lockdep recursion. [ There's some not quite baked bits in cpufreq-git right now so sending this on as a patch instead ] On Thu, 2006-07-06 at 07:58 -0700, Tom London wrote: > After installing .2356 I get this each time I boot: > ======================================================= > [ INFO: possible circular locking dependency detected ] > ------------------------------------------------------- > S06cpuspeed/1620 is trying to acquire lock: > (dbs_mutex){--..}, at: [] mutex_lock+0x21/0x24 > > but task is already holding lock: > (cpucontrol){--..}, at: [] mutex_lock+0x21/0x24 > > which lock already depends on the new lock. > make sure the cpu hotplug recursive mutex (yuck) is taken early in the cpufreq codepaths to avoid a AB-BA deadlock. Signed-off-by: Arjan van de Ven Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1ba4039777e..8d328186f77 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -423,6 +423,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, if (cpufreq_parse_governor(str_governor, &new_policy.policy, &new_policy.governor)) return -EINVAL; + lock_cpu_hotplug(); + /* Do not use cpufreq_set_policy here or the user_policy.max will be wrongly overridden */ mutex_lock(&policy->lock); @@ -432,6 +434,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, policy->user_policy.governor = policy->governor; mutex_unlock(&policy->lock); + unlock_cpu_hotplug(); + return ret ? ret : count; } -- cgit v1.2.3 From 5a8da02ba59a9f978e2af4c5da9a029ea5f5ee3b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 7 Jul 2006 16:54:05 -0700 Subject: [NET]: Fix network device interface printk message priority The printk's in the network device interface code should all be tagged with severity. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/dev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 066a60a7528..0096349ee38 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1727,7 +1727,7 @@ static int ing_filter(struct sk_buff *skb) if (dev->qdisc_ingress) { __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd); if (MAX_RED_LOOP < ttl++) { - printk("Redir loop detected Dropping packet (%s->%s)\n", + printk(KERN_WARNING "Redir loop detected Dropping packet (%s->%s)\n", skb->input_dev->name, skb->dev->name); return TC_ACT_SHOT; } @@ -2922,7 +2922,7 @@ int register_netdevice(struct net_device *dev) /* Fix illegal SG+CSUM combinations. */ if ((dev->features & NETIF_F_SG) && !(dev->features & NETIF_F_ALL_CSUM)) { - printk("%s: Dropping NETIF_F_SG since no checksum feature.\n", + printk(KERN_NOTICE "%s: Dropping NETIF_F_SG since no checksum feature.\n", dev->name); dev->features &= ~NETIF_F_SG; } @@ -2930,7 +2930,7 @@ int register_netdevice(struct net_device *dev) /* TSO requires that SG is present as well. */ if ((dev->features & NETIF_F_TSO) && !(dev->features & NETIF_F_SG)) { - printk("%s: Dropping NETIF_F_TSO since no SG feature.\n", + printk(KERN_NOTICE "%s: Dropping NETIF_F_TSO since no SG feature.\n", dev->name); dev->features &= ~NETIF_F_TSO; } -- cgit v1.2.3 From 8ba10ab128e88bfbe58f7164543827ef3c3a2c88 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 8 Jul 2006 02:17:40 +0000 Subject: [CIFS] CIFS_DEBUG2 depends on CIFS Signed-off-by: Steve French --- fs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/Kconfig b/fs/Kconfig index 00aa3d5c5a8..7db05742a92 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1791,6 +1791,7 @@ config CIFS_POSIX config CIFS_DEBUG2 bool "Enable additional CIFS debugging routines" + depends on CIFS help Enabling this option adds a few more debugging routines to the cifs code which slightly increases the size of -- cgit v1.2.3 From c165b0040502ef0d2b5751eef3cd96ea8210ae4c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Sat, 8 Jul 2006 13:28:53 -0700 Subject: [TG3]: add amd8131 to "write reorder" chipsets Add the AMD 8131 bridge to the list of chipsets that reorder writes. Signed-off-by: John W. Linville Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f645921aff8..ce6f3be86da 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10078,6 +10078,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) static struct pci_device_id write_reorder_chipsets[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_8131_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8385_0) }, { }, -- cgit v1.2.3 From 00181fc94648b4bb30d30ef95506055105316051 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Sat, 8 Jul 2006 13:30:09 -0700 Subject: [ATM]: Typo in drivers/atm/Kconfig... From: Matt LaPlante Signed-off-by: Charles Williams Signed-off-by: David S. Miller --- drivers/atm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index 01a9f1cb774..cfa5af883e1 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -398,7 +398,7 @@ config ATM_FORE200E_USE_TASKLET default n help This defers work to be done by the interrupt handler to a - tasklet instead of hanlding everything at interrupt time. This + tasklet instead of handling everything at interrupt time. This may improve the responsive of the host. config ATM_FORE200E_TX_RETRY -- cgit v1.2.3 From 1252ecf63f77ea147bd40f5462c7d9e3d3ae2815 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 8 Jul 2006 13:30:52 -0700 Subject: [ATM]: fix possible recursive locking in skb_migrate() ok this is a real potential deadlock in a way, it takes two locks of 2 skbuffs without doing any kind of lock ordering; I think the following patch should fix it. Just sort the lock taking order by address of the skb.. it's not pretty but it's the best this can do in a minimally invasive way. Signed-off-by: Arjan van de Ven Signed-off-by: Chas Williams Signed-off-by: David S. Miller --- net/atm/ipcommon.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c index 4b1faca5013..1d3de42fada 100644 --- a/net/atm/ipcommon.c +++ b/net/atm/ipcommon.c @@ -25,22 +25,27 @@ /* * skb_migrate appends the list at "from" to "to", emptying "from" in the * process. skb_migrate is atomic with respect to all other skb operations on - * "from" and "to". Note that it locks both lists at the same time, so beware - * of potential deadlocks. + * "from" and "to". Note that it locks both lists at the same time, so to deal + * with the lock ordering, the locks are taken in address order. * * This function should live in skbuff.c or skbuff.h. */ -void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) +void skb_migrate(struct sk_buff_head *from, struct sk_buff_head *to) { unsigned long flags; struct sk_buff *skb_from = (struct sk_buff *) from; struct sk_buff *skb_to = (struct sk_buff *) to; struct sk_buff *prev; - spin_lock_irqsave(&from->lock,flags); - spin_lock(&to->lock); + if ((unsigned long) from < (unsigned long) to) { + spin_lock_irqsave(&from->lock, flags); + spin_lock_nested(&to->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irqsave(&to->lock, flags); + spin_lock_nested(&from->lock, SINGLE_DEPTH_NESTING); + } prev = from->prev; from->next->prev = to->prev; prev->next = skb_to; @@ -51,7 +56,7 @@ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to) from->prev = skb_from; from->next = skb_from; from->qlen = 0; - spin_unlock_irqrestore(&from->lock,flags); + spin_unlock_irqrestore(&from->lock, flags); } -- cgit v1.2.3 From 9c6c6795eda34e4dc38ecac912a16b6314082beb Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 8 Jul 2006 13:33:28 -0700 Subject: [IRDA]: fix drivers/net/irda/ali-ircc.c:ali_ircc_init() The Coverity checker spotted, that from the changes from commit 898b1d16f8230fb912a0c2248df685735c6ceda3 the if (ret) platform_driver_unregister(&ali_ircc_driver); was dead code. This patch changes this function to what seems to have been the intention. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- drivers/net/irda/ali-ircc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index bf1fca5a3fa..e3c8cd5eca6 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -146,7 +146,7 @@ static int __init ali_ircc_init(void) { ali_chip_t *chip; chipio_t info; - int ret = -ENODEV; + int ret; int cfg, cfg_base; int reg, revision; int i = 0; @@ -160,6 +160,7 @@ static int __init ali_ircc_init(void) return ret; } + ret = -ENODEV; /* Probe for all the ALi chipsets we know about */ for (chip= chips; chip->name; chip++, i++) -- cgit v1.2.3 From 89114afd435a486deb8583e89f490fc274444d18 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 8 Jul 2006 13:34:32 -0700 Subject: [NET] gso: Add skb_is_gso This patch adds the wrapper function skb_is_gso which can be used instead of directly testing skb_shinfo(skb)->gso_size. This makes things a little nicer and allows us to change the primary key for indicating whether an skb is GSO (if we ever want to do that). Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 2 +- drivers/net/chelsio/sge.c | 2 +- drivers/net/e1000/e1000_main.c | 7 +++---- drivers/net/forcedeth.c | 2 +- drivers/net/ixgb/ixgb_main.c | 2 +- drivers/net/loopback.c | 2 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/sky2.c | 2 +- drivers/net/typhoon.c | 4 ++-- drivers/s390/net/qeth_main.c | 2 +- include/linux/netdevice.h | 2 +- include/linux/skbuff.h | 5 +++++ net/bridge/br_forward.c | 2 +- net/bridge/br_netfilter.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv4/xfrm4_output.c | 2 +- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/xfrm6_output.c | 2 +- 18 files changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 64b6a72b4f6..db73de0d251 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1639,7 +1639,7 @@ bnx2_tx_int(struct bnx2 *bp) skb = tx_buf->skb; #ifdef BCM_TSO /* partial BD completions possible with TSO packets */ - if (skb_shinfo(skb)->gso_size) { + if (skb_is_gso(skb)) { u16 last_idx, last_ring_idx; last_idx = sw_cons + diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 87f94d939ff..61b3754f50f 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1417,7 +1417,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) struct cpl_tx_pkt *cpl; #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->gso_size) { + if (skb_is_gso(skb)) { int eth_type; struct cpl_tx_pkt_lso *hdr; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f77624f5f17..1f34d06d01b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2394,7 +2394,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, uint8_t ipcss, ipcso, tucss, tucso, hdr_len; int err; - if (skb_shinfo(skb)->gso_size) { + if (skb_is_gso(skb)) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) @@ -2519,7 +2519,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, * tso gets written back prematurely before the data is fully * DMA'd to the controller */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->gso_size) { + !skb_is_gso(skb)) { tx_ring->last_tx_tso = 0; size -= 4; } @@ -2806,8 +2806,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #ifdef NETIF_F_TSO /* Controller Erratum workaround */ - if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->gso_size) + if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) count++; #endif diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 037d870712f..ad81ec68f88 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -1495,7 +1495,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->tx_skbuff[nr] = skb; #ifdef NETIF_F_TSO - if (skb_shinfo(skb)->gso_size) + if (skb_is_gso(skb)) tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); else #endif diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index b91e082483f..7eb08d92913 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) uint16_t ipcse, tucse, mss; int err; - if(likely(skb_shinfo(skb)->gso_size)) { + if (likely(skb_is_gso(skb))) { if (skb_header_cloned(skb)) { err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (err) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 43fef7de8cb..997cbce9af6 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) #endif #ifdef LOOPBACK_TSO - if (skb_shinfo(skb)->gso_size) { + if (skb_is_gso(skb)) { BUG_ON(skb->protocol != htons(ETH_P_IP)); BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index f4c8fd373b9..ee1de971a71 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2116,7 +2116,7 @@ abort_linearize: } idx = (idx + 1) & tx->mask; } while (idx != last_idx); - if (skb_shinfo(skb)->gso_size) { + if (skb_is_gso(skb)) { printk(KERN_ERR "myri10ge: %s: TSO but wanted to linearize?!?!?\n", mgp->dev->name); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 418f169a6a3..31093760aa1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1159,7 +1159,7 @@ static unsigned tx_le_req(const struct sk_buff *skb) count = sizeof(dma_addr_t) / sizeof(u32); count += skb_shinfo(skb)->nr_frags * count; - if (skb_shinfo(skb)->gso_size) + if (skb_is_gso(skb)) ++count; if (skb->ip_summed == CHECKSUM_HW) diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 063816f2b11..4103c37172f 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) * If problems develop with TSO, check this first. */ numDesc = skb_shinfo(skb)->nr_frags + 1; - if(skb_tso_size(skb)) + if (skb_is_gso(skb)) numDesc++; /* When checking for free space in the ring, we need to also @@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) TYPHOON_TX_PF_VLAN_TAG_SHIFT); } - if(skb_tso_size(skb)) { + if (skb_is_gso(skb)) { first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT; first_txd->numDesc++; diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 8e8963f1573..329e12c1fae 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -4457,7 +4457,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; - if (skb_shinfo(skb)->gso_size) + if (skb_is_gso(skb)) large_send = card->options.large_send; /*are we able to do TSO ? If so ,prepare and send it from here */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 85f99f60dee..0359a643001 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1001,7 +1001,7 @@ static inline int net_gso_ok(int features, int gso_type) static inline int skb_gso_ok(struct sk_buff *skb, int features) { - return net_gso_ok(features, skb_shinfo(skb)->gso_size ? + return net_gso_ok(features, skb_is_gso(skb) ? skb_shinfo(skb)->gso_type : 0); } diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 3597b4f1438..0bf31b83578 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1455,5 +1455,10 @@ static inline void skb_init_secmark(struct sk_buff *skb) { } #endif +static inline int skb_is_gso(const struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_size; +} + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 8be9f2123e5..6ccd32b3080 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -35,7 +35,7 @@ static inline unsigned packet_length(const struct sk_buff *skb) int br_dev_queue_push_xmit(struct sk_buff *skb) { /* drop mtu oversized packets except gso */ - if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->gso_size) + if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) kfree_skb(skb); else { #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 8298a5179ae..cbc8a389a0a 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -761,7 +761,7 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) { if (skb->protocol == htons(ETH_P_IP) && skb->len > skb->dev->mtu && - !skb_shinfo(skb)->gso_size) + !skb_is_gso(skb)) return ip_fragment(skb, br_dev_queue_push_xmit); else return br_dev_queue_push_xmit(skb); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ca0e714613f..7c9f9a6421b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -209,7 +209,7 @@ static inline int ip_finish_output(struct sk_buff *skb) return dst_output(skb); } #endif - if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) + if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) return ip_fragment(skb, ip_finish_output2); else return ip_finish_output2(skb); @@ -1095,7 +1095,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, while (size > 0) { int i; - if (skb_shinfo(skb)->gso_size) + if (skb_is_gso(skb)) len = size; else { diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 193363e2293..d16f863cf68 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -134,7 +134,7 @@ static int xfrm4_output_finish(struct sk_buff *skb) } #endif - if (!skb_shinfo(skb)->gso_size) + if (!skb_is_gso(skb)) return xfrm4_output_finish2(skb); skb->protocol = htons(ETH_P_IP); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2c5b44575af..3bc74ce7880 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *skb) int ip6_output(struct sk_buff *skb) { - if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) || + if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) || dst_allfrag(skb->dst)) return ip6_fragment(skb, ip6_output2); else @@ -229,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, skb->priority = sk->sk_priority; mtu = dst_mtu(dst); - if ((skb->len <= mtu) || ipfragok || skb_shinfo(skb)->gso_size) { + if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 48fccb1eca0..0eea60ea9eb 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -122,7 +122,7 @@ static int xfrm6_output_finish(struct sk_buff *skb) { struct sk_buff *segs; - if (!skb_shinfo(skb)->gso_size) + if (!skb_is_gso(skb)) return xfrm6_output_finish2(skb); skb->protocol = htons(ETH_P_IP); -- cgit v1.2.3 From a430a43d087545c96542ee64573237919109d370 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 8 Jul 2006 13:34:56 -0700 Subject: [NET] gso: Fix up GSO packets with broken checksums Certain subsystems in the stack (e.g., netfilter) can break the partial checksum on GSO packets. Until they're fixed, this patch allows this to work by recomputing the partial checksums through the GSO mechanism. Once they've all been converted to update the partial checksum instead of clearing it, this workaround can be removed. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netdevice.h | 8 +++-- include/net/protocol.h | 2 ++ include/net/tcp.h | 1 + net/core/dev.c | 36 ++++++++++++++++--- net/ipv4/af_inet.c | 36 +++++++++++++++++++ net/ipv4/tcp_ipv4.c | 18 ++++++++++ net/ipv6/ipv6_sockglue.c | 89 ++++++++++++++++++++++++++++++++--------------- net/ipv6/tcp_ipv6.c | 19 ++++++++++ 8 files changed, 174 insertions(+), 35 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0359a643001..76cc099c858 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -549,6 +549,7 @@ struct packet_type { struct net_device *); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); + int (*gso_send_check)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; }; @@ -1001,13 +1002,14 @@ static inline int net_gso_ok(int features, int gso_type) static inline int skb_gso_ok(struct sk_buff *skb, int features) { - return net_gso_ok(features, skb_is_gso(skb) ? - skb_shinfo(skb)->gso_type : 0); + return net_gso_ok(features, skb_shinfo(skb)->gso_type); } static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) { - return !skb_gso_ok(skb, dev->features); + return skb_is_gso(skb) && + (!skb_gso_ok(skb, dev->features) || + unlikely(skb->ip_summed != CHECKSUM_HW)); } #endif /* __KERNEL__ */ diff --git a/include/net/protocol.h b/include/net/protocol.h index a225d6371cb..c643bce64e5 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -36,6 +36,7 @@ struct net_protocol { int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); + int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); int no_policy; @@ -51,6 +52,7 @@ struct inet6_protocol int type, int code, int offset, __u32 info); + int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); diff --git a/include/net/tcp.h b/include/net/tcp.h index 3cd803b0d7a..0720bddff1e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1086,6 +1086,7 @@ extern struct request_sock_ops tcp_request_sock_ops; extern int tcp_v4_destroy_sock(struct sock *sk); +extern int tcp_v4_gso_send_check(struct sk_buff *skb); extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); #ifdef CONFIG_PROC_FS diff --git a/net/core/dev.c b/net/core/dev.c index 0096349ee38..4d2b5167d7f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1162,9 +1162,17 @@ int skb_checksum_help(struct sk_buff *skb, int inward) unsigned int csum; int ret = 0, offset = skb->h.raw - skb->data; - if (inward) { - skb->ip_summed = CHECKSUM_NONE; - goto out; + if (inward) + goto out_set_summed; + + if (unlikely(skb_shinfo(skb)->gso_size)) { + static int warned; + + WARN_ON(!warned); + warned = 1; + + /* Let GSO fix up the checksum. */ + goto out_set_summed; } if (skb_cloned(skb)) { @@ -1181,6 +1189,8 @@ int skb_checksum_help(struct sk_buff *skb, int inward) BUG_ON(skb->csum + 2 > offset); *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + +out_set_summed: skb->ip_summed = CHECKSUM_NONE; out: return ret; @@ -1201,17 +1211,35 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); struct packet_type *ptype; int type = skb->protocol; + int err; BUG_ON(skb_shinfo(skb)->frag_list); - BUG_ON(skb->ip_summed != CHECKSUM_HW); skb->mac.raw = skb->data; skb->mac_len = skb->nh.raw - skb->data; __skb_pull(skb, skb->mac_len); + if (unlikely(skb->ip_summed != CHECKSUM_HW)) { + static int warned; + + WARN_ON(!warned); + warned = 1; + + if (skb_header_cloned(skb) && + (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + return ERR_PTR(err); + } + rcu_read_lock(); list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { if (ptype->type == type && !ptype->dev && ptype->gso_segment) { + if (unlikely(skb->ip_summed != CHECKSUM_HW)) { + err = ptype->gso_send_check(skb); + segs = ERR_PTR(err); + if (err || skb_gso_ok(skb, features)) + break; + __skb_push(skb, skb->data - skb->nh.raw); + } segs = ptype->gso_segment(skb, features); break; } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 318d4674faa..c84a32070f8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1097,6 +1097,40 @@ int inet_sk_rebuild_header(struct sock *sk) EXPORT_SYMBOL(inet_sk_rebuild_header); +static int inet_gso_send_check(struct sk_buff *skb) +{ + struct iphdr *iph; + struct net_protocol *ops; + int proto; + int ihl; + int err = -EINVAL; + + if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) + goto out; + + iph = skb->nh.iph; + ihl = iph->ihl * 4; + if (ihl < sizeof(*iph)) + goto out; + + if (unlikely(!pskb_may_pull(skb, ihl))) + goto out; + + skb->h.raw = __skb_pull(skb, ihl); + iph = skb->nh.iph; + proto = iph->protocol & (MAX_INET_PROTOS - 1); + err = -EPROTONOSUPPORT; + + rcu_read_lock(); + ops = rcu_dereference(inet_protos[proto]); + if (likely(ops && ops->gso_send_check)) + err = ops->gso_send_check(skb); + rcu_read_unlock(); + +out: + return err; +} + static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); @@ -1162,6 +1196,7 @@ static struct net_protocol igmp_protocol = { static struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, + .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, .no_policy = 1, }; @@ -1208,6 +1243,7 @@ static int ipv4_proc_init(void); static struct packet_type ip_packet_type = { .type = __constant_htons(ETH_P_IP), .func = ip_rcv, + .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment, }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5a886e6efbb..a891133f00e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -496,6 +496,24 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) } } +int tcp_v4_gso_send_check(struct sk_buff *skb) +{ + struct iphdr *iph; + struct tcphdr *th; + + if (!pskb_may_pull(skb, sizeof(*th))) + return -EINVAL; + + iph = skb->nh.iph; + th = skb->h.th; + + th->check = 0; + th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); + skb->csum = offsetof(struct tcphdr, check); + skb->ip_summed = CHECKSUM_HW; + return 0; +} + /* * This routine will send an RST to the other tcp. * diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0c17dec11c8..43327264e69 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -57,29 +57,11 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; -static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) +static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, + int proto) { - struct sk_buff *segs = ERR_PTR(-EINVAL); - struct ipv6hdr *ipv6h; - struct inet6_protocol *ops; - int proto; + struct inet6_protocol *ops = NULL; - if (unlikely(skb_shinfo(skb)->gso_type & - ~(SKB_GSO_UDP | - SKB_GSO_DODGY | - SKB_GSO_TCP_ECN | - SKB_GSO_TCPV6 | - 0))) - goto out; - - if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) - goto out; - - ipv6h = skb->nh.ipv6h; - proto = ipv6h->nexthdr; - __skb_pull(skb, sizeof(*ipv6h)); - - rcu_read_lock(); for (;;) { struct ipv6_opt_hdr *opth; int len; @@ -88,30 +70,80 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) ops = rcu_dereference(inet6_protos[proto]); if (unlikely(!ops)) - goto unlock; + break; if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) break; } if (unlikely(!pskb_may_pull(skb, 8))) - goto unlock; + break; opth = (void *)skb->data; len = opth->hdrlen * 8 + 8; if (unlikely(!pskb_may_pull(skb, len))) - goto unlock; + break; proto = opth->nexthdr; __skb_pull(skb, len); } - skb->h.raw = skb->data; - if (likely(ops->gso_segment)) - segs = ops->gso_segment(skb, features); + return ops; +} + +static int ipv6_gso_send_check(struct sk_buff *skb) +{ + struct ipv6hdr *ipv6h; + struct inet6_protocol *ops; + int err = -EINVAL; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) + goto out; -unlock: + ipv6h = skb->nh.ipv6h; + __skb_pull(skb, sizeof(*ipv6h)); + err = -EPROTONOSUPPORT; + + rcu_read_lock(); + ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); + if (likely(ops && ops->gso_send_check)) { + skb->h.raw = skb->data; + err = ops->gso_send_check(skb); + } + rcu_read_unlock(); + +out: + return err; +} + +static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct ipv6hdr *ipv6h; + struct inet6_protocol *ops; + + if (unlikely(skb_shinfo(skb)->gso_type & + ~(SKB_GSO_UDP | + SKB_GSO_DODGY | + SKB_GSO_TCP_ECN | + SKB_GSO_TCPV6 | + 0))) + goto out; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) + goto out; + + ipv6h = skb->nh.ipv6h; + __skb_pull(skb, sizeof(*ipv6h)); + segs = ERR_PTR(-EPROTONOSUPPORT); + + rcu_read_lock(); + ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); + if (likely(ops && ops->gso_segment)) { + skb->h.raw = skb->data; + segs = ops->gso_segment(skb, features); + } rcu_read_unlock(); if (unlikely(IS_ERR(segs))) @@ -130,6 +162,7 @@ out: static struct packet_type ipv6_packet_type = { .type = __constant_htons(ETH_P_IPV6), .func = ipv6_rcv, + .gso_send_check = ipv6_gso_send_check, .gso_segment = ipv6_gso_segment, }; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5bdcb9002cf..923989d0520 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -552,6 +552,24 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) } } +static int tcp_v6_gso_send_check(struct sk_buff *skb) +{ + struct ipv6hdr *ipv6h; + struct tcphdr *th; + + if (!pskb_may_pull(skb, sizeof(*th))) + return -EINVAL; + + ipv6h = skb->nh.ipv6h; + th = skb->h.th; + + th->check = 0; + th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, + IPPROTO_TCP, 0); + skb->csum = offsetof(struct tcphdr, check); + skb->ip_summed = CHECKSUM_HW; + return 0; +} static void tcp_v6_send_reset(struct sk_buff *skb) { @@ -1603,6 +1621,7 @@ struct proto tcpv6_prot = { static struct inet6_protocol tcpv6_protocol = { .handler = tcp_v6_rcv, .err_handler = tcp_v6_err, + .gso_send_check = tcp_v6_gso_send_check, .gso_segment = tcp_tso_segment, .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -- cgit v1.2.3 From 26e0fd1ce2418b10713b569a195bdb679233066b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 8 Jul 2006 13:38:55 -0700 Subject: [NET]: Fix IPv4/DECnet routing rule dumping When more rules are present than fit in a single skb, the remaining rules are incorrectly skipped. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/decnet/dn_rules.c | 3 ++- net/ipv4/fib_rules.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 06e785fe575..22f321d9bf9 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -399,9 +399,10 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { if (idx < s_idx) - continue; + goto next; if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) break; +next: idx++; } rcu_read_unlock(); diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 6c642d11d4c..773b12ba4e3 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -457,13 +457,13 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock(); hlist_for_each_entry(r, node, &fib_rules, hlist) { - if (idx < s_idx) - continue; + goto next; if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, NLM_F_MULTI) < 0) break; +next: idx++; } rcu_read_unlock(); -- cgit v1.2.3 From e2a3d40258fe20d205f8ed592e1e2c0d5529c2e1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 8 Jul 2006 15:00:28 -0700 Subject: power: improve inline asm memory constraints Use "+m" rather than a combination of "=m" and "m" for improved clarity and consistency. Signed-off-by: Linus Torvalds --- include/asm-powerpc/atomic.h | 32 ++++++++++++++++---------------- include/asm-powerpc/bitops.h | 16 ++++++++-------- include/asm-powerpc/system.h | 16 ++++++++-------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h index bb3c0ab7e66..53283e2540b 100644 --- a/include/asm-powerpc/atomic.h +++ b/include/asm-powerpc/atomic.h @@ -27,8 +27,8 @@ static __inline__ void atomic_add(int a, atomic_t *v) PPC405_ERR77(0,%3) " stwcx. %0,0,%3 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (a), "r" (&v->counter) : "cc"); } @@ -63,8 +63,8 @@ static __inline__ void atomic_sub(int a, atomic_t *v) PPC405_ERR77(0,%3) " stwcx. %0,0,%3 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (a), "r" (&v->counter) : "cc"); } @@ -97,8 +97,8 @@ static __inline__ void atomic_inc(atomic_t *v) PPC405_ERR77(0,%2) " stwcx. %0,0,%2 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (&v->counter) : "cc"); } @@ -141,8 +141,8 @@ static __inline__ void atomic_dec(atomic_t *v) PPC405_ERR77(0,%2)\ " stwcx. %0,0,%2\n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (&v->counter) : "cc"); } @@ -253,8 +253,8 @@ static __inline__ void atomic64_add(long a, atomic64_t *v) add %0,%2,%0\n\ stdcx. %0,0,%3 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (a), "r" (&v->counter) : "cc"); } @@ -287,8 +287,8 @@ static __inline__ void atomic64_sub(long a, atomic64_t *v) subf %0,%2,%0\n\ stdcx. %0,0,%3 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (a), "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (a), "r" (&v->counter) : "cc"); } @@ -319,8 +319,8 @@ static __inline__ void atomic64_inc(atomic64_t *v) addic %0,%0,1\n\ stdcx. %0,0,%2 \n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (&v->counter) : "cc"); } @@ -361,8 +361,8 @@ static __inline__ void atomic64_dec(atomic64_t *v) addic %0,%0,-1\n\ stdcx. %0,0,%2\n\ bne- 1b" - : "=&r" (t), "=m" (v->counter) - : "r" (&v->counter), "m" (v->counter) + : "=&r" (t), "+m" (v->counter) + : "r" (&v->counter) : "cc"); } diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h index 76e2f08c3c8..c341063d080 100644 --- a/include/asm-powerpc/bitops.h +++ b/include/asm-powerpc/bitops.h @@ -65,8 +65,8 @@ static __inline__ void set_bit(int nr, volatile unsigned long *addr) PPC405_ERR77(0,%3) PPC_STLCX "%0,0,%3\n" "bne- 1b" - : "=&r"(old), "=m"(*p) - : "r"(mask), "r"(p), "m"(*p) + : "=&r" (old), "+m" (*p) + : "r" (mask), "r" (p) : "cc" ); } @@ -82,8 +82,8 @@ static __inline__ void clear_bit(int nr, volatile unsigned long *addr) PPC405_ERR77(0,%3) PPC_STLCX "%0,0,%3\n" "bne- 1b" - : "=&r"(old), "=m"(*p) - : "r"(mask), "r"(p), "m"(*p) + : "=&r" (old), "+m" (*p) + : "r" (mask), "r" (p) : "cc" ); } @@ -99,8 +99,8 @@ static __inline__ void change_bit(int nr, volatile unsigned long *addr) PPC405_ERR77(0,%3) PPC_STLCX "%0,0,%3\n" "bne- 1b" - : "=&r"(old), "=m"(*p) - : "r"(mask), "r"(p), "m"(*p) + : "=&r" (old), "+m" (*p) + : "r" (mask), "r" (p) : "cc" ); } @@ -179,8 +179,8 @@ static __inline__ void set_bits(unsigned long mask, unsigned long *addr) "or %0,%0,%2\n" PPC_STLCX "%0,0,%3\n" "bne- 1b" - : "=&r" (old), "=m" (*addr) - : "r" (mask), "r" (addr), "m" (*addr) + : "=&r" (old), "+m" (*addr) + : "r" (mask), "r" (addr) : "cc"); } diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index d075725bf44..c6569516ba3 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -220,8 +220,8 @@ __xchg_u32(volatile void *p, unsigned long val) " stwcx. %3,0,%2 \n\ bne- 1b" ISYNC_ON_SMP - : "=&r" (prev), "=m" (*(volatile unsigned int *)p) - : "r" (p), "r" (val), "m" (*(volatile unsigned int *)p) + : "=&r" (prev), "+m" (*(volatile unsigned int *)p) + : "r" (p), "r" (val) : "cc", "memory"); return prev; @@ -240,8 +240,8 @@ __xchg_u64(volatile void *p, unsigned long val) " stdcx. %3,0,%2 \n\ bne- 1b" ISYNC_ON_SMP - : "=&r" (prev), "=m" (*(volatile unsigned long *)p) - : "r" (p), "r" (val), "m" (*(volatile unsigned long *)p) + : "=&r" (prev), "+m" (*(volatile unsigned long *)p) + : "r" (p), "r" (val) : "cc", "memory"); return prev; @@ -299,8 +299,8 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) ISYNC_ON_SMP "\n\ 2:" - : "=&r" (prev), "=m" (*p) - : "r" (p), "r" (old), "r" (new), "m" (*p) + : "=&r" (prev), "+m" (*p) + : "r" (p), "r" (old), "r" (new) : "cc", "memory"); return prev; @@ -322,8 +322,8 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) ISYNC_ON_SMP "\n\ 2:" - : "=&r" (prev), "=m" (*p) - : "r" (p), "r" (old), "r" (new), "m" (*p) + : "=&r" (prev), "+m" (*p) + : "r" (p), "r" (old), "r" (new) : "cc", "memory"); return prev; -- cgit v1.2.3 From b862f3b099f3ea672c7438c0b282ce8201d39dfc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 8 Jul 2006 15:24:18 -0700 Subject: i386: improve and correct inline asm memory constraints Use "+m" rather than a combination of "=m" and "m" for improved clarity and consistency. This also fixes some inlines that incorrectly didn't tell the compiler that they read the old value at all, potentially causing the compiler to generate bogus code. It appear that all of those potential bugs were hidden by the use of extra "volatile" specifiers on the data structures in question, though. Signed-off-by: Linus Torvalds --- include/asm-i386/atomic.h | 30 ++++++++++++++---------------- include/asm-i386/futex.h | 10 +++++----- include/asm-i386/local.h | 14 ++++++-------- include/asm-i386/posix_types.h | 4 ++-- include/asm-i386/rwlock.h | 4 ++-- include/asm-i386/rwsem.h | 35 +++++++++++++++++------------------ include/asm-i386/semaphore.h | 8 ++++---- include/asm-i386/spinlock.h | 14 +++++++------- 8 files changed, 57 insertions(+), 62 deletions(-) diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h index 4f061fa7379..51a16624252 100644 --- a/include/asm-i386/atomic.h +++ b/include/asm-i386/atomic.h @@ -46,8 +46,8 @@ static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__( LOCK_PREFIX "addl %1,%0" - :"=m" (v->counter) - :"ir" (i), "m" (v->counter)); + :"+m" (v->counter) + :"ir" (i)); } /** @@ -61,8 +61,8 @@ static __inline__ void atomic_sub(int i, atomic_t *v) { __asm__ __volatile__( LOCK_PREFIX "subl %1,%0" - :"=m" (v->counter) - :"ir" (i), "m" (v->counter)); + :"+m" (v->counter) + :"ir" (i)); } /** @@ -80,8 +80,8 @@ static __inline__ int atomic_sub_and_test(int i, atomic_t *v) __asm__ __volatile__( LOCK_PREFIX "subl %2,%0; sete %1" - :"=m" (v->counter), "=qm" (c) - :"ir" (i), "m" (v->counter) : "memory"); + :"+m" (v->counter), "=qm" (c) + :"ir" (i) : "memory"); return c; } @@ -95,8 +95,7 @@ static __inline__ void atomic_inc(atomic_t *v) { __asm__ __volatile__( LOCK_PREFIX "incl %0" - :"=m" (v->counter) - :"m" (v->counter)); + :"+m" (v->counter)); } /** @@ -109,8 +108,7 @@ static __inline__ void atomic_dec(atomic_t *v) { __asm__ __volatile__( LOCK_PREFIX "decl %0" - :"=m" (v->counter) - :"m" (v->counter)); + :"+m" (v->counter)); } /** @@ -127,8 +125,8 @@ static __inline__ int atomic_dec_and_test(atomic_t *v) __asm__ __volatile__( LOCK_PREFIX "decl %0; sete %1" - :"=m" (v->counter), "=qm" (c) - :"m" (v->counter) : "memory"); + :"+m" (v->counter), "=qm" (c) + : : "memory"); return c != 0; } @@ -146,8 +144,8 @@ static __inline__ int atomic_inc_and_test(atomic_t *v) __asm__ __volatile__( LOCK_PREFIX "incl %0; sete %1" - :"=m" (v->counter), "=qm" (c) - :"m" (v->counter) : "memory"); + :"+m" (v->counter), "=qm" (c) + : : "memory"); return c != 0; } @@ -166,8 +164,8 @@ static __inline__ int atomic_add_negative(int i, atomic_t *v) __asm__ __volatile__( LOCK_PREFIX "addl %2,%0; sets %1" - :"=m" (v->counter), "=qm" (c) - :"ir" (i), "m" (v->counter) : "memory"); + :"+m" (v->counter), "=qm" (c) + :"ir" (i) : "memory"); return c; } diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h index 7b8ceefd010..946d97cfea2 100644 --- a/include/asm-i386/futex.h +++ b/include/asm-i386/futex.h @@ -20,8 +20,8 @@ .align 8\n\ .long 1b,3b\n\ .previous" \ - : "=r" (oldval), "=r" (ret), "=m" (*uaddr) \ - : "i" (-EFAULT), "m" (*uaddr), "0" (oparg), "1" (0)) + : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \ + : "i" (-EFAULT), "0" (oparg), "1" (0)) #define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \ __asm__ __volatile ( \ @@ -38,9 +38,9 @@ .align 8\n\ .long 1b,4b,2b,4b\n\ .previous" \ - : "=&a" (oldval), "=&r" (ret), "=m" (*uaddr), \ + : "=&a" (oldval), "=&r" (ret), "+m" (*uaddr), \ "=&r" (tem) \ - : "r" (oparg), "i" (-EFAULT), "m" (*uaddr), "1" (0)) + : "r" (oparg), "i" (-EFAULT), "1" (0)) static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) @@ -123,7 +123,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) " .long 1b,3b \n" " .previous \n" - : "=a" (oldval), "=m" (*uaddr) + : "=a" (oldval), "+m" (*uaddr) : "i" (-EFAULT), "r" (newval), "0" (oldval) : "memory" ); diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h index 3b4998c51d0..12060e22f7e 100644 --- a/include/asm-i386/local.h +++ b/include/asm-i386/local.h @@ -17,32 +17,30 @@ static __inline__ void local_inc(local_t *v) { __asm__ __volatile__( "incl %0" - :"=m" (v->counter) - :"m" (v->counter)); + :"+m" (v->counter)); } static __inline__ void local_dec(local_t *v) { __asm__ __volatile__( "decl %0" - :"=m" (v->counter) - :"m" (v->counter)); + :"+m" (v->counter)); } static __inline__ void local_add(long i, local_t *v) { __asm__ __volatile__( "addl %1,%0" - :"=m" (v->counter) - :"ir" (i), "m" (v->counter)); + :"+m" (v->counter) + :"ir" (i)); } static __inline__ void local_sub(long i, local_t *v) { __asm__ __volatile__( "subl %1,%0" - :"=m" (v->counter) - :"ir" (i), "m" (v->counter)); + :"+m" (v->counter) + :"ir" (i)); } /* On x86, these are no better than the atomic variants. */ diff --git a/include/asm-i386/posix_types.h b/include/asm-i386/posix_types.h index 4e47ed059ad..133e31e7dfd 100644 --- a/include/asm-i386/posix_types.h +++ b/include/asm-i386/posix_types.h @@ -51,12 +51,12 @@ typedef struct { #undef __FD_SET #define __FD_SET(fd,fdsetp) \ __asm__ __volatile__("btsl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + "+m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_CLR #define __FD_CLR(fd,fdsetp) \ __asm__ __volatile__("btrl %1,%0": \ - "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) + "+m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_ISSET #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ diff --git a/include/asm-i386/rwlock.h b/include/asm-i386/rwlock.h index 94f00195d54..96b0bef2ea5 100644 --- a/include/asm-i386/rwlock.h +++ b/include/asm-i386/rwlock.h @@ -37,7 +37,7 @@ "popl %%eax\n\t" \ "1:\n", \ "subl $1,%0\n\t", \ - "=m" (*(volatile int *)rw) : : "memory") + "+m" (*(volatile int *)rw) : : "memory") #define __build_read_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ @@ -63,7 +63,7 @@ "popl %%eax\n\t" \ "1:\n", \ "subl $" RW_LOCK_BIAS_STR ",%0\n\t", \ - "=m" (*(volatile int *)rw) : : "memory") + "+m" (*(volatile int *)rw) : : "memory") #define __build_write_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ diff --git a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h index 2f07601562e..43113f5608e 100644 --- a/include/asm-i386/rwsem.h +++ b/include/asm-i386/rwsem.h @@ -111,8 +111,8 @@ LOCK_PREFIX " incl (%%eax)\n\t" /* adds 0x00000001, returns the old value " jmp 1b\n" LOCK_SECTION_END "# ending down_read\n\t" - : "=m"(sem->count) - : "a"(sem), "m"(sem->count) + : "+m" (sem->count) + : "a" (sem) : "memory", "cc"); } @@ -133,8 +133,8 @@ LOCK_PREFIX " cmpxchgl %2,%0\n\t" " jnz 1b\n\t" "2:\n\t" "# ending __down_read_trylock\n\t" - : "+m"(sem->count), "=&a"(result), "=&r"(tmp) - : "i"(RWSEM_ACTIVE_READ_BIAS) + : "+m" (sem->count), "=&a" (result), "=&r" (tmp) + : "i" (RWSEM_ACTIVE_READ_BIAS) : "memory", "cc"); return result>=0 ? 1 : 0; } @@ -161,8 +161,8 @@ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtract 0x0000ffff, returns the " jmp 1b\n" LOCK_SECTION_END "# ending down_write" - : "=m"(sem->count), "=d"(tmp) - : "a"(sem), "1"(tmp), "m"(sem->count) + : "+m" (sem->count), "=d" (tmp) + : "a" (sem), "1" (tmp) : "memory", "cc"); } @@ -205,8 +205,8 @@ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old valu " jmp 1b\n" LOCK_SECTION_END "# ending __up_read\n" - : "=m"(sem->count), "=d"(tmp) - : "a"(sem), "1"(tmp), "m"(sem->count) + : "+m" (sem->count), "=d" (tmp) + : "a" (sem), "1" (tmp) : "memory", "cc"); } @@ -231,8 +231,8 @@ LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" /* tries to transition 0xffff0001 -> " jmp 1b\n" LOCK_SECTION_END "# ending __up_write\n" - : "=m"(sem->count) - : "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS), "m"(sem->count) + : "+m" (sem->count) + : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS) : "memory", "cc", "edx"); } @@ -256,8 +256,8 @@ LOCK_PREFIX " addl %2,(%%eax)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 " jmp 1b\n" LOCK_SECTION_END "# ending __downgrade_write\n" - : "=m"(sem->count) - : "a"(sem), "i"(-RWSEM_WAITING_BIAS), "m"(sem->count) + : "+m" (sem->count) + : "a" (sem), "i" (-RWSEM_WAITING_BIAS) : "memory", "cc"); } @@ -268,8 +268,8 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) { __asm__ __volatile__( LOCK_PREFIX "addl %1,%0" - : "=m"(sem->count) - : "ir"(delta), "m"(sem->count)); + : "+m" (sem->count) + : "ir" (delta)); } /* @@ -280,10 +280,9 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) int tmp = delta; __asm__ __volatile__( -LOCK_PREFIX "xadd %0,(%2)" - : "+r"(tmp), "=m"(sem->count) - : "r"(sem), "m"(sem->count) - : "memory"); +LOCK_PREFIX "xadd %0,%1" + : "+r" (tmp), "+m" (sem->count) + : : "memory"); return tmp+delta; } diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index f7a0f310c52..d51e800acf2 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -107,7 +107,7 @@ static inline void down(struct semaphore * sem) "call __down_failed\n\t" "jmp 1b\n" LOCK_SECTION_END - :"=m" (sem->count) + :"+m" (sem->count) : :"memory","ax"); } @@ -132,7 +132,7 @@ static inline int down_interruptible(struct semaphore * sem) "call __down_failed_interruptible\n\t" "jmp 1b\n" LOCK_SECTION_END - :"=a" (result), "=m" (sem->count) + :"=a" (result), "+m" (sem->count) : :"memory"); return result; @@ -157,7 +157,7 @@ static inline int down_trylock(struct semaphore * sem) "call __down_failed_trylock\n\t" "jmp 1b\n" LOCK_SECTION_END - :"=a" (result), "=m" (sem->count) + :"=a" (result), "+m" (sem->count) : :"memory"); return result; @@ -182,7 +182,7 @@ static inline void up(struct semaphore * sem) "jmp 1b\n" LOCK_SECTION_END ".subsection 0\n" - :"=m" (sem->count) + :"+m" (sem->count) : :"memory","ax"); } diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index 87c40f83065..d816c62a7a1 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -65,7 +65,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) alternative_smp( __raw_spin_lock_string, __raw_spin_lock_string_up, - "=m" (lock->slock) : : "memory"); + "+m" (lock->slock) : : "memory"); } /* @@ -79,7 +79,7 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla alternative_smp( __raw_spin_lock_string_flags, __raw_spin_lock_string_up, - "=m" (lock->slock) : "r" (flags) : "memory"); + "+m" (lock->slock) : "r" (flags) : "memory"); } #endif @@ -88,7 +88,7 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock) char oldval; __asm__ __volatile__( "xchgb %b0,%1" - :"=q" (oldval), "=m" (lock->slock) + :"=q" (oldval), "+m" (lock->slock) :"0" (0) : "memory"); return oldval > 0; } @@ -104,7 +104,7 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock) #define __raw_spin_unlock_string \ "movb $1,%0" \ - :"=m" (lock->slock) : : "memory" + :"+m" (lock->slock) : : "memory" static inline void __raw_spin_unlock(raw_spinlock_t *lock) @@ -118,7 +118,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) #define __raw_spin_unlock_string \ "xchgb %b0, %1" \ - :"=q" (oldval), "=m" (lock->slock) \ + :"=q" (oldval), "+m" (lock->slock) \ :"0" (oldval) : "memory" static inline void __raw_spin_unlock(raw_spinlock_t *lock) @@ -199,13 +199,13 @@ static inline int __raw_write_trylock(raw_rwlock_t *lock) static inline void __raw_read_unlock(raw_rwlock_t *rw) { - asm volatile(LOCK_PREFIX "incl %0" :"=m" (rw->lock) : : "memory"); + asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); } static inline void __raw_write_unlock(raw_rwlock_t *rw) { asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0" - : "=m" (rw->lock) : : "memory"); + : "+m" (rw->lock) : : "memory"); } #endif /* __ASM_SPINLOCK_H */ -- cgit v1.2.3 From 953969ddf5b049361ed1e8471cc43dc4134d2a6f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 9 Jul 2006 08:47:46 -0700 Subject: Revert "ACPI: dock driver" This reverts commit a5e1b94008f2a96abf4a0c0371a55a56b320c13e. Adrian Bunk points out that it has build errors, and apparently no maintenance. Throw it out. Signed-off-by: Linus Torvalds --- drivers/acpi/Kconfig | 7 - drivers/acpi/Makefile | 1 - drivers/acpi/dock.c | 739 -------------------------------------------- drivers/acpi/scan.c | 23 -- include/acpi/acpi_bus.h | 2 +- include/acpi/acpi_drivers.h | 17 - 6 files changed, 1 insertion(+), 788 deletions(-) delete mode 100644 drivers/acpi/dock.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fef7bab1224..290c767dd77 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -133,13 +133,6 @@ config ACPI_FAN This driver adds support for ACPI fan devices, allowing user-mode applications to perform basic fan control (on, off, status). -config ACPI_DOCK - tristate "Dock" - depends on !ACPI_IBM_DOCK - default y - help - This driver adds support for ACPI controlled docking stations - config ACPI_PROCESSOR tristate "Processor" default y diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bce7ca27b42..bb5b80a80b1 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,7 +42,6 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o -obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c deleted file mode 100644 index 510a9452429..00000000000 --- a/drivers/acpi/dock.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - * dock.c - ACPI dock station driver - * - * Copyright (C) 2006 Kristen Carlson Accardi - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include - -#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" - -ACPI_MODULE_NAME("dock") -MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); -MODULE_LICENSE("GPL"); - -static struct atomic_notifier_head dock_notifier_list; - -struct dock_station { - acpi_handle handle; - unsigned long last_dock_time; - u32 flags; - spinlock_t dd_lock; - spinlock_t hp_lock; - struct list_head dependent_devices; - struct list_head hotplug_devices; -}; - -struct dock_dependent_device { - struct list_head list; - struct list_head hotplug_list; - acpi_handle handle; - acpi_notify_handler handler; - void *context; -}; - -#define DOCK_DOCKING 0x00000001 -#define DOCK_EVENT KOBJ_DOCK -#define UNDOCK_EVENT KOBJ_UNDOCK - -static struct dock_station *dock_station; - -/***************************************************************************** - * Dock Dependent device functions * - *****************************************************************************/ -/** - * alloc_dock_dependent_device - allocate and init a dependent device - * @handle: the acpi_handle of the dependent device - * - * Allocate memory for a dependent device structure for a device referenced - * by the acpi handle - */ -static struct dock_dependent_device * -alloc_dock_dependent_device(acpi_handle handle) -{ - struct dock_dependent_device *dd; - - dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (dd) { - dd->handle = handle; - INIT_LIST_HEAD(&dd->list); - INIT_LIST_HEAD(&dd->hotplug_list); - } - return dd; -} - -/** - * add_dock_dependent_device - associate a device with the dock station - * @ds: The dock station - * @dd: The dependent device - * - * Add the dependent device to the dock's dependent device list. - */ -static void -add_dock_dependent_device(struct dock_station *ds, - struct dock_dependent_device *dd) -{ - spin_lock(&ds->dd_lock); - list_add_tail(&dd->list, &ds->dependent_devices); - spin_unlock(&ds->dd_lock); -} - -/** - * dock_add_hotplug_device - associate a hotplug handler with the dock station - * @ds: The dock station - * @dd: The dependent device struct - * - * Add the dependent device to the dock's hotplug device list - */ -static void -dock_add_hotplug_device(struct dock_station *ds, - struct dock_dependent_device *dd) -{ - spin_lock(&ds->hp_lock); - list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); - spin_unlock(&ds->hp_lock); -} - -/** - * dock_del_hotplug_device - remove a hotplug handler from the dock station - * @ds: The dock station - * @dd: the dependent device struct - * - * Delete the dependent device from the dock's hotplug device list - */ -static void -dock_del_hotplug_device(struct dock_station *ds, - struct dock_dependent_device *dd) -{ - spin_lock(&ds->hp_lock); - list_del(&dd->hotplug_list); - spin_unlock(&ds->hp_lock); -} - -/** - * find_dock_dependent_device - get a device dependent on this dock - * @ds: the dock station - * @handle: the acpi_handle of the device we want - * - * iterate over the dependent device list for this dock. If the - * dependent device matches the handle, return. - */ -static struct dock_dependent_device * -find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) -{ - struct dock_dependent_device *dd; - - spin_lock(&ds->dd_lock); - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (handle == dd->handle) { - spin_unlock(&ds->dd_lock); - return dd; - } - } - spin_unlock(&ds->dd_lock); - return NULL; -} - -/***************************************************************************** - * Dock functions * - *****************************************************************************/ -/** - * is_dock - see if a device is a dock station - * @handle: acpi handle of the device - * - * If an acpi object has a _DCK method, then it is by definition a dock - * station, so return true. - */ -static int is_dock(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_DCK", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -/** - * is_dock_device - see if a device is on a dock station - * @handle: acpi handle of the device - * - * If this device is either the dock station itself, - * or is a device dependent on the dock station, then it - * is a dock device - */ -int is_dock_device(acpi_handle handle) -{ - if (!dock_station) - return 0; - - if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) - return 1; - - return 0; -} - -EXPORT_SYMBOL_GPL(is_dock_device); - -/** - * dock_present - see if the dock station is present. - * @ds: the dock station - * - * execute the _STA method. note that present does not - * imply that we are docked. - */ -static int dock_present(struct dock_station *ds) -{ - unsigned long sta; - acpi_status status; - - if (ds) { - status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta) - return 1; - } - return 0; -} - - - -/** - * dock_create_acpi_device - add new devices to acpi - * @handle - handle of the device to add - * - * This function will create a new acpi_device for the given - * handle if one does not exist already. This should cause - * acpi to scan for drivers for the given devices, and call - * matching driver's add routine. - * - * Returns a pointer to the acpi_device corresponding to the handle. - */ -static struct acpi_device * dock_create_acpi_device(acpi_handle handle) -{ - struct acpi_device *device = NULL; - struct acpi_device *parent_device; - acpi_handle parent; - int ret; - - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ - acpi_get_parent(handle, &parent); - if (acpi_bus_get_device(parent, &parent_device)) - parent_device = NULL; - - ret = acpi_bus_add(&device, parent_device, handle, - ACPI_BUS_TYPE_DEVICE); - if (ret) { - pr_debug("error adding bus, %x\n", - -ret); - return NULL; - } - } - return device; -} - -/** - * dock_remove_acpi_device - remove the acpi_device struct from acpi - * @handle - the handle of the device to remove - * - * Tell acpi to remove the acpi_device. This should cause any loaded - * driver to have it's remove routine called. - */ -static void dock_remove_acpi_device(acpi_handle handle) -{ - struct acpi_device *device; - int ret; - - if (!acpi_bus_get_device(handle, &device)) { - ret = acpi_bus_trim(device, 1); - if (ret) - pr_debug("error removing bus, %x\n", -ret); - } -} - - -/** - * hotplug_dock_devices - insert or remove devices on the dock station - * @ds: the dock station - * @event: either bus check or eject request - * - * Some devices on the dock station need to have drivers called - * to perform hotplug operations after a dock event has occurred. - * Traverse the list of dock devices that have registered a - * hotplug handler, and call the handler. - */ -static void hotplug_dock_devices(struct dock_station *ds, u32 event) -{ - struct dock_dependent_device *dd; - - spin_lock(&ds->hp_lock); - - /* - * First call driver specific hotplug functions - */ - list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { - if (dd->handler) - dd->handler(dd->handle, event, dd->context); - } - - /* - * Now make sure that an acpi_device is created for each - * dependent device, or removed if this is an eject request. - * This will cause acpi_drivers to be stopped/started if they - * exist - */ - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (event == ACPI_NOTIFY_EJECT_REQUEST) - dock_remove_acpi_device(dd->handle); - else - dock_create_acpi_device(dd->handle); - } - spin_unlock(&ds->hp_lock); -} - -static void dock_event(struct dock_station *ds, u32 event, int num) -{ - struct acpi_device *device; - - device = dock_create_acpi_device(ds->handle); - if (device) - kobject_uevent(&device->kobj, num); -} - -/** - * eject_dock - respond to a dock eject request - * @ds: the dock station - * - * This is called after _DCK is called, to execute the dock station's - * _EJ0 method. - */ -static void eject_dock(struct dock_station *ds) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; - acpi_handle tmp; - - /* all dock devices should have _EJ0, but check anyway */ - status = acpi_get_handle(ds->handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - pr_debug("No _EJ0 support for dock device\n"); - return; - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", - &arg_list, NULL))) - pr_debug("Failed to evaluate _EJ0!\n"); -} - -/** - * handle_dock - handle a dock event - * @ds: the dock station - * @dock: to dock, or undock - that is the question - * - * Execute the _DCK method in response to an acpi event - */ -static void handle_dock(struct dock_station *ds, int dock) -{ - acpi_status status; - struct acpi_object_list arg_list; - union acpi_object arg; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - - acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); - obj = name_buffer.pointer; - - printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); - - /* _DCK method has one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = dock; - status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); - if (ACPI_FAILURE(status)) - pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); - kfree(buffer.pointer); - kfree(name_buffer.pointer); -} - -static inline void dock(struct dock_station *ds) -{ - handle_dock(ds, 1); -} - -static inline void undock(struct dock_station *ds) -{ - handle_dock(ds, 0); -} - -static inline void begin_dock(struct dock_station *ds) -{ - ds->flags |= DOCK_DOCKING; -} - -static inline void complete_dock(struct dock_station *ds) -{ - ds->flags &= ~(DOCK_DOCKING); - ds->last_dock_time = jiffies; -} - -/** - * dock_in_progress - see if we are in the middle of handling a dock event - * @ds: the dock station - * - * Sometimes while docking, false dock events can be sent to the driver - * because good connections aren't made or some other reason. Ignore these - * if we are in the middle of doing something. - */ -static int dock_in_progress(struct dock_station *ds) -{ - if ((ds->flags & DOCK_DOCKING) || - time_before(jiffies, (ds->last_dock_time + HZ))) - return 1; - return 0; -} - -/** - * register_dock_notifier - add yourself to the dock notifier list - * @nb: the callers notifier block - * - * If a driver wishes to be notified about dock events, they can - * use this function to put a notifier block on the dock notifier list. - * this notifier call chain will be called after a dock event, but - * before hotplugging any new devices. - */ -int register_dock_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&dock_notifier_list, nb); -} - -EXPORT_SYMBOL_GPL(register_dock_notifier); - -/** - * unregister_dock_notifier - remove yourself from the dock notifier list - * @nb: the callers notifier block - */ -void unregister_dock_notifier(struct notifier_block *nb) -{ - atomic_notifier_chain_unregister(&dock_notifier_list, nb); -} - -EXPORT_SYMBOL_GPL(unregister_dock_notifier); - -/** - * register_hotplug_dock_device - register a hotplug function - * @handle: the handle of the device - * @handler: the acpi_notifier_handler to call after docking - * @context: device specific data - * - * If a driver would like to perform a hotplug operation after a dock - * event, they can register an acpi_notifiy_handler to be called by - * the dock driver after _DCK is executed. - */ -int -register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, - void *context) -{ - struct dock_dependent_device *dd; - - if (!dock_station) - return -ENODEV; - - /* - * make sure this handle is for a device dependent on the dock, - * this would include the dock station itself - */ - dd = find_dock_dependent_device(dock_station, handle); - if (dd) { - dd->handler = handler; - dd->context = context; - dock_add_hotplug_device(dock_station, dd); - return 0; - } - - return -EINVAL; -} - -EXPORT_SYMBOL_GPL(register_hotplug_dock_device); - -/** - * unregister_hotplug_dock_device - remove yourself from the hotplug list - * @handle: the acpi handle of the device - */ -void unregister_hotplug_dock_device(acpi_handle handle) -{ - struct dock_dependent_device *dd; - - if (!dock_station) - return; - - dd = find_dock_dependent_device(dock_station, handle); - if (dd) - dock_del_hotplug_device(dock_station, dd); -} - -EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); - -/** - * dock_notify - act upon an acpi dock notification - * @handle: the dock station handle - * @event: the acpi event - * @data: our driver data struct - * - * If we are notified to dock, then check to see if the dock is - * present and then dock. Notify all drivers of the dock event, - * and then hotplug and devices that may need hotplugging. For undock - * check to make sure the dock device is still present, then undock - * and hotremove all the devices that may need removing. - */ -static void dock_notify(acpi_handle handle, u32 event, void *data) -{ - struct dock_station *ds = (struct dock_station *)data; - - switch (event) { - case ACPI_NOTIFY_BUS_CHECK: - if (!dock_in_progress(ds) && dock_present(ds)) { - begin_dock(ds); - dock(ds); - if (!dock_present(ds)) { - printk(KERN_ERR PREFIX "Unable to dock!\n"); - break; - } - atomic_notifier_call_chain(&dock_notifier_list, - event, NULL); - hotplug_dock_devices(ds, event); - complete_dock(ds); - dock_event(ds, event, DOCK_EVENT); - } - break; - case ACPI_NOTIFY_DEVICE_CHECK: - /* - * According to acpi spec 3.0a, if a DEVICE_CHECK notification - * is sent and _DCK is present, it is assumed to mean an - * undock request. This notify routine will only be called - * for objects defining _DCK, so we will fall through to eject - * request here. However, we will pass an eject request through - * to the driver who wish to hotplug. - */ - case ACPI_NOTIFY_EJECT_REQUEST: - if (!dock_in_progress(ds) && dock_present(ds)) { - /* - * here we need to generate the undock - * event prior to actually doing the undock - * so that the device struct still exists. - */ - dock_event(ds, event, UNDOCK_EVENT); - hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); - undock(ds); - eject_dock(ds); - if (dock_present(ds)) - printk(KERN_ERR PREFIX "Unable to undock!\n"); - } - break; - default: - printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); - } -} - -/** - * find_dock_devices - find devices on the dock station - * @handle: the handle of the device we are examining - * @lvl: unused - * @context: the dock station private data - * @rv: unused - * - * This function is called by acpi_walk_namespace. It will - * check to see if an object has an _EJD method. If it does, then it - * will see if it is dependent on the dock station. - */ -static acpi_status -find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - acpi_handle tmp; - struct dock_station *ds = (struct dock_station *)context; - struct dock_dependent_device *dd; - - status = acpi_bus_get_ejd(handle, &tmp); - if (ACPI_FAILURE(status)) - return AE_OK; - - if (tmp == ds->handle) { - dd = alloc_dock_dependent_device(handle); - if (dd) - add_dock_dependent_device(ds, dd); - } - - return AE_OK; -} - -/** - * dock_add - add a new dock station - * @handle: the dock station handle - * - * allocated and initialize a new dock station device. Find all devices - * that are on the dock station, and register for dock event notifications. - */ -static int dock_add(acpi_handle handle) -{ - int ret; - acpi_status status; - struct dock_dependent_device *dd; - - /* allocate & initialize the dock_station private data */ - dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); - if (!dock_station) - return -ENOMEM; - dock_station->handle = handle; - dock_station->last_dock_time = jiffies - HZ; - INIT_LIST_HEAD(&dock_station->dependent_devices); - INIT_LIST_HEAD(&dock_station->hotplug_devices); - spin_lock_init(&dock_station->dd_lock); - spin_lock_init(&dock_station->hp_lock); - - /* Find dependent devices */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_devices, dock_station, - NULL); - - /* add the dock station as a device dependent on itself */ - dd = alloc_dock_dependent_device(handle); - if (!dd) { - kfree(dock_station); - return -ENOMEM; - } - add_dock_dependent_device(dock_station, dd); - - /* register for dock events */ - status = acpi_install_notify_handler(dock_station->handle, - ACPI_SYSTEM_NOTIFY, - dock_notify, dock_station); - - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Error installing notify handler\n"); - ret = -ENODEV; - goto dock_add_err; - } - - printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); - - return 0; - -dock_add_err: - kfree(dock_station); - kfree(dd); - return ret; -} - -/** - * dock_remove - free up resources related to the dock station - */ -static int dock_remove(void) -{ - struct dock_dependent_device *dd, *tmp; - acpi_status status; - - if (!dock_station) - return 0; - - /* remove dependent devices */ - list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, - list) - kfree(dd); - - /* remove dock notify handler */ - status = acpi_remove_notify_handler(dock_station->handle, - ACPI_SYSTEM_NOTIFY, - dock_notify); - if (ACPI_FAILURE(status)) - printk(KERN_ERR "Error removing notify handler\n"); - - /* free dock station memory */ - kfree(dock_station); - return 0; -} - -/** - * find_dock - look for a dock station - * @handle: acpi handle of a device - * @lvl: unused - * @context: counter of dock stations found - * @rv: unused - * - * This is called by acpi_walk_namespace to look for dock stations. - */ -static acpi_status -find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - acpi_status status = AE_OK; - - if (is_dock(handle)) { - if (dock_add(handle) >= 0) { - (*count)++; - status = AE_CTRL_TERMINATE; - } - } - return status; -} - -static int __init dock_init(void) -{ - int num = 0; - - dock_station = NULL; - - /* look for a dock station */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock, &num, NULL); - - if (!num) - return -ENODEV; - - return 0; -} - -static void __exit dock_exit(void) -{ - dock_remove(); -} - -postcore_initcall(dock_init); -module_exit(dock_exit); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5fcb50c7b77..cac4fcdcfc8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -663,29 +663,6 @@ static int acpi_bus_find_driver(struct acpi_device *device) Device Enumeration -------------------------------------------------------------------------- */ -acpi_status -acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) -{ - acpi_status status; - acpi_handle tmp; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; - - status = acpi_get_handle(handle, "_EJD", &tmp); - if (ACPI_FAILURE(status)) - return status; - - status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); - if (ACPI_SUCCESS(status)) { - obj = buffer.pointer; - status = acpi_get_handle(NULL, obj->string.pointer, ejd); - kfree(buffer.pointer); - } - return status; -} -EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); - - static int acpi_bus_get_flags(struct acpi_device *device) { acpi_status status = AE_OK; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f338e40bd54..a2b3e390a50 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -334,7 +334,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); int acpi_bus_trim(struct acpi_device *start, int rmdevice); int acpi_bus_start(struct acpi_device *device); -acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd); + int acpi_match_ids(struct acpi_device *device, char *ids); int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 6a5bdcefec6..b425f9bb6d4 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -110,21 +110,4 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type); extern int acpi_specific_hotkey_enabled; -/*-------------------------------------------------------------------------- - Dock Station - -------------------------------------------------------------------------- */ -#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) -extern int is_dock_device(acpi_handle handle); -extern int register_dock_notifier(struct notifier_block *nb); -extern void unregister_dock_notifier(struct notifier_block *nb); -extern int register_hotplug_dock_device(acpi_handle handle, - acpi_notify_handler handler, void *context); -extern void unregister_hotplug_dock_device(acpi_handle handle); -#else -#define is_dock_device(h) (0) -#define register_dock_notifier(nb) (-ENODEV) -#define unregister_dock_notifier(nb) do { } while(0) -#define register_hotplug_dock_device(h1, h2, c) (-ENODEV) -#define unregister_hotplug_dock_device(h) do { } while(0) -#endif #endif /*__ACPI_DRIVERS_H__*/ -- cgit v1.2.3 From ebbaeab18b1c520054ea70e512ac0db7456ede01 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sun, 9 Jul 2006 11:36:23 -0700 Subject: [PKT_SCHED]: act_api: Fix module leak while flushing actions Module reference needs to be given back if message header construction fails. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/sched/act_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 599423cc9d0..0972247a839 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -602,8 +602,8 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) return err; rtattr_failure: - module_put(a->ops->owner); nlmsg_failure: + module_put(a->ops->owner); err_out: kfree_skb(skb); kfree(a); -- cgit v1.2.3 From 24781734643ea2e9fd864f58000e47793e2dcb04 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 9 Jul 2006 12:13:18 -0700 Subject: [ATM] net/atm/clip.c: fix PROC_FS=n compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following compile error with CONFIG_PROC_FS=n by reverting commit dcdb02752ff13a64433c36f2937a58d93ae7a19e: <-- snip --> ... CC net/atm/clip.o net/atm/clip.c: In function ‘atm_clip_init’: net/atm/clip.c:975: error: ‘atm_proc_root’ undeclared (first use in this function) net/atm/clip.c:975: error: (Each undeclared identifier is reported only once net/atm/clip.c:975: error: for each function it appears in.) net/atm/clip.c:977: error: ‘arp_seq_fops’ undeclared (first use in this function) make[2]: *** [net/atm/clip.o] Error 1 <-- snip --> Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/atm/clip.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/atm/clip.c b/net/atm/clip.c index 121bf6f4914..2e62105d91b 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -962,7 +962,6 @@ static struct file_operations arp_seq_fops = { static int __init atm_clip_init(void) { - struct proc_dir_entry *p; neigh_table_init_no_netlink(&clip_tbl); clip_tbl_hook = &clip_tbl; @@ -972,9 +971,15 @@ static int __init atm_clip_init(void) setup_timer(&idle_timer, idle_timer_check, 0); - p = create_proc_entry("arp", S_IRUGO, atm_proc_root); - if (p) - p->proc_fops = &arp_seq_fops; +#ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *p; + + p = create_proc_entry("arp", S_IRUGO, atm_proc_root); + if (p) + p->proc_fops = &arp_seq_fops; + } +#endif return 0; } -- cgit v1.2.3 From 1b30dd359ebec22d035e8b145751319f63772ca1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 9 Jul 2006 12:14:22 -0700 Subject: [AX.25]: Use kzalloc Replace kzalloc instead of kmalloc + memset. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 3 +-- net/ax25/ax25_dev.c | 4 +--- net/netrom/af_netrom.c | 4 +--- net/rose/af_rose.c | 3 +-- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 10a3c0aa839..f12be2acf9b 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -486,10 +486,9 @@ ax25_cb *ax25_create_cb(void) { ax25_cb *ax25; - if ((ax25 = kmalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) + if ((ax25 = kzalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) return NULL; - memset(ax25, 0x00, sizeof(*ax25)); atomic_set(&ax25->refcount, 1); skb_queue_head_init(&ax25->write_queue); diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 47e6e790bd6..b787678220f 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -55,15 +55,13 @@ void ax25_dev_device_up(struct net_device *dev) { ax25_dev *ax25_dev; - if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { + if ((ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); return; } ax25_unregister_sysctl(); - memset(ax25_dev, 0x00, sizeof(*ax25_dev)); - dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; dev_hold(dev); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 389a4119e1b..ecc796878f3 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1382,14 +1382,12 @@ static int __init nr_proto_init(void) return -1; } - dev_nr = kmalloc(nr_ndevs * sizeof(struct net_device *), GFP_KERNEL); + dev_nr = kzalloc(nr_ndevs * sizeof(struct net_device *), GFP_KERNEL); if (dev_nr == NULL) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device array\n"); return -1; } - memset(dev_nr, 0x00, nr_ndevs * sizeof(struct net_device *)); - for (i = 0; i < nr_ndevs; i++) { char name[IFNAMSIZ]; struct net_device *dev; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index d0a67bb3136..c115295ab43 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1490,14 +1490,13 @@ static int __init rose_proto_init(void) rose_callsign = null_ax25_address; - dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL); + dev_rose = kzalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL); if (dev_rose == NULL) { printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n"); rc = -ENOMEM; goto out_proto_unregister; } - memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device*)); for (i = 0; i < rose_ndevs; i++) { struct net_device *dev; char name[IFNAMSIZ]; -- cgit v1.2.3 From f6dd9221dddb3550e60d32aee688588ec208312c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Fri, 7 Jul 2006 20:44:38 -0400 Subject: ACPI: ACPICA 20060707 Added the ACPI_PACKED_POINTERS_NOT_SUPPORTED macro to support C compilers that do not allow the initialization of address pointers within packed structures - even though the hardware itself may support misaligned transfers. Some of the debug data structures are packed by default to minimize size. Added an error message for the case where acpi_os_get_thread_id() returns zero. A non-zero value is required by the core ACPICA code to ensure the proper operation of AML mutexes and recursive control methods. The DSDT is now the only ACPI table that determines whether the AML interpreter is in 32-bit or 64-bit mode. Not really a functional change, but the hooks for per-table 32/64 switching have been removed from the code. A clarification to the ACPI specification is forthcoming in ACPI 3.0B. Fixed a possible leak of an Owner ID in the error path of tbinstal.c acpi_tb_init_table_descriptor() and migrated all table OwnerID deletion to a single place in acpi_tb_uninstall_table() to correct possible leaks when using the acpi_tb_delete_tables_by_type() interface (with assistance from Lance Ortiz.) Fixed a problem with Serialized control methods where the semaphore associated with the method could be over-signaled after multiple method invocations. Fixed two issues with the locking of the internal namespace data structure. Both the Unload() operator and acpi_unload_table() interface now lock the namespace during the namespace deletion associated with the table unload (with assistance from Linn Crosetto.) Fixed problem reports (Valery Podrezov) integrated: - Eliminate unnecessary memory allocation for CreateXxxxField http://bugzilla.kernel.org/show_bug.cgi?id=5426 Fixed problem reports (Fiodor Suietov) integrated: - Incomplete cleanup branches in AcpiTbGetTableRsdt (BZ 369) - On Address Space handler deletion, needless deactivation call (BZ 374) - AcpiRemoveAddressSpaceHandler: validate Device handle parameter (BZ 375) - Possible memory leak, Notify sub-objects of Processor, Power, ThermalZone (BZ 376) - AcpiRemoveAddressSpaceHandler: validate Handler parameter (BZ 378) - Minimum Length of RSDT should be validated (BZ 379) - AcpiRemoveNotifyHandler: return AE_NOT_EXIST if Processor Obj has no Handler (BZ (380) - AcpiUnloadTable: return AE_NOT_EXIST if no table of specified type loaded (BZ 381) Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsinit.c | 10 --------- drivers/acpi/dispatcher/dsmethod.c | 23 ++++---------------- drivers/acpi/dispatcher/dswexec.c | 4 ++-- drivers/acpi/events/evregion.c | 44 ++++++++++++++++++++++---------------- drivers/acpi/events/evxface.c | 44 ++++++++++++++++++++++---------------- drivers/acpi/events/evxfregn.c | 13 ++++++++++- drivers/acpi/executer/exconfig.c | 1 - drivers/acpi/executer/exconvrt.c | 3 +++ drivers/acpi/executer/exsystem.c | 8 +++---- drivers/acpi/namespace/nsalloc.c | 13 ++++++++++- drivers/acpi/tables/tbget.c | 12 ++++++++++- drivers/acpi/tables/tbinstal.c | 21 +++++++++++++++--- drivers/acpi/tables/tbrsdt.c | 27 +++++++++++++++++++---- drivers/acpi/tables/tbxface.c | 32 ++++++++++++++++----------- drivers/acpi/utilities/utdelete.c | 13 +++++++---- drivers/acpi/utilities/utmisc.c | 25 ++++++++++++++++------ drivers/acpi/utilities/utstate.c | 7 ++++++ include/acpi/acconfig.h | 2 +- include/acpi/acinterp.h | 10 ++++++--- include/acpi/aclocal.h | 2 +- include/acpi/acresrc.h | 8 +++++-- 21 files changed, 209 insertions(+), 113 deletions(-) diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index daf51b5b587..1888c055d10 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -116,16 +116,6 @@ acpi_ds_init_one_object(acpi_handle obj_handle, case ACPI_TYPE_METHOD: - /* - * Set the execution data width (32 or 64) based upon the - * revision number of the parent ACPI table. - * TBD: This is really for possible future support of integer width - * on a per-table basis. Currently, we just use a global for the width. - */ - if (info->table_desc->pointer->revision == 1) { - node->flags |= ANOBJ_DATA_WIDTH_32; - } - info->method_count++; break; diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index a39a33f4847..cf888add319 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -134,7 +134,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc) union acpi_operand_object *mutex_desc; acpi_status status; - ACPI_FUNCTION_NAME(ds_create_method_mutex); + ACPI_FUNCTION_TRACE(ds_create_method_mutex); /* Create the new mutex object */ @@ -493,7 +493,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", - (char *)&walk_state->method_node->name, + acpi_ut_get_node_name(walk_state->method_node), walk_state->method_call_op, return_desc)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, @@ -610,6 +610,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); + method_desc->method.mutex->mutex.owner_thread = NULL; } } @@ -620,27 +621,11 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, */ method_node = walk_state->method_node; - /* Lock namespace for possible update */ - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_VOID; - } - - /* - * Delete any namespace entries created immediately underneath - * the method - */ - if (method_node && method_node->child) { - acpi_ns_delete_namespace_subtree(method_node); - } - /* - * Delete any namespace entries created anywhere else within + * Delete any namespace objects created anywhere within * the namespace by the execution of this method */ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } /* Decrement the thread count on the method */ diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index b1ded62d0df..d7a616c3104 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -313,10 +313,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, case AML_CLASS_EXECUTE: case AML_CLASS_CREATE: /* - * Most operators with arguments. + * Most operators with arguments (except create_xxx_field operators) * Start a new result/operand state */ - if (walk_state->opcode != AML_CREATE_FIELD_OP) { + if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) { status = acpi_ds_result_stack_push(walk_state); } break; diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 094a17e4c86..21caae04fe8 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -528,34 +528,40 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, } } - /* Call the setup handler with the deactivate notification */ + /* + * If the region has been activated, call the setup handler + * with the deactivate notification + */ + if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { + region_setup = handler_obj->address_space.setup; + status = + region_setup(region_obj, + ACPI_REGION_DEACTIVATE, + handler_obj->address_space. + context, region_context); - region_setup = handler_obj->address_space.setup; - status = - region_setup(region_obj, ACPI_REGION_DEACTIVATE, - handler_obj->address_space.context, - region_context); + /* Init routine may fail, Just ignore errors */ - /* Init routine may fail, Just ignore errors */ + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "from region handler - deactivate, [%s]", + acpi_ut_get_region_name + (region_obj->region. + space_id))); + } - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "from region init, [%s]", - acpi_ut_get_region_name - (region_obj->region.space_id))); + region_obj->region.flags &= + ~(AOPOBJ_SETUP_COMPLETE); } - region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); - /* * Remove handler reference in the region * - * NOTE: this doesn't mean that the region goes away - * The region is just inaccessible as indicated to - * the _REG method + * NOTE: this doesn't mean that the region goes away, the region + * is just inaccessible as indicated to the _REG method * - * If the region is on the handler's list - * this better be the region's handler + * If the region is on the handler's list, this must be the + * region's handler */ region_obj->region.handler = NULL; acpi_ut_remove_reference(handler_obj); diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 4f948df17ab..923fd2b4695 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -428,7 +428,7 @@ acpi_remove_notify_handler(acpi_handle device, node = acpi_ns_map_handle_to_node(device); if (!node) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Root Object */ @@ -442,7 +442,7 @@ acpi_remove_notify_handler(acpi_handle device, ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -474,7 +474,7 @@ acpi_remove_notify_handler(acpi_handle device, if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; - goto unlock; + goto unlock_and_exit; } /* Check for an existing internal object */ @@ -482,17 +482,21 @@ acpi_remove_notify_handler(acpi_handle device, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; - goto unlock; + goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { + if (!notify_obj) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -510,10 +514,14 @@ acpi_remove_notify_handler(acpi_handle device, if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { + if (!notify_obj) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -530,9 +538,9 @@ acpi_remove_notify_handler(acpi_handle device, } } -unlock: + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -exit: + exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler")); return_ACPI_STATUS(status); @@ -586,7 +594,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure that there isn't a handler there already */ @@ -594,7 +602,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; - goto unlock; + goto unlock_and_exit; } /* Allocate and init handler object */ @@ -602,7 +610,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info)); if (!handler) { status = AE_NO_MEMORY; - goto unlock; + goto unlock_and_exit; } handler->address = address; @@ -613,7 +621,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { - goto unlock; + goto unlock_and_exit; } /* Install the handler */ @@ -628,9 +636,9 @@ acpi_install_gpe_handler(acpi_handle gpe_device, acpi_os_release_lock(acpi_gbl_gpe_lock, flags); -unlock: + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); -exit: + exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler failed")); diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index e8b86a0baad..83b12a9afa3 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -155,7 +155,11 @@ acpi_remove_address_space_handler(acpi_handle device, /* Convert and validate the device handle */ node = acpi_ns_map_handle_to_node(device); - if (!node) { + if (!node || + ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node))) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -178,6 +182,13 @@ acpi_remove_address_space_handler(acpi_handle device, if (handler_obj->address_space.space_id == space_id) { + /* Handler must be the same as the installed handler */ + + if (handler_obj->address_space.handler != handler) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Matched space_id, first dereference this in the Regions */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 83fed079a27..c8341fa5fe0 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -502,7 +502,6 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) * (Offset contains the table_id) */ acpi_ns_delete_namespace_by_owner(table_info->owner_id); - acpi_ut_release_owner_id(&table_info->owner_id); /* Delete the table itself */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index b732e399b1e..544e81a6a43 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -170,6 +170,9 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(result))); + /* Save the Result */ return_desc->integer.value = result; diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 6b5d1e6ce94..28aef3e69ec 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -60,7 +60,7 @@ ACPI_MODULE_NAME("exsystem") * * DESCRIPTION: Implements a semaphore wait with a check to see if the * semaphore is available immediately. If it is not, the - * interpreter is released. + * interpreter is released before waiting. * ******************************************************************************/ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) @@ -110,9 +110,9 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) * * RETURN: Status * - * DESCRIPTION: Implements a semaphore wait with a check to see if the - * semaphore is available immediately. If it is not, the - * interpreter is released. + * DESCRIPTION: Implements a mutex wait with a check to see if the + * mutex is available immediately. If it is not, the + * interpreter is released before waiting. * ******************************************************************************/ diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index dc3f0739a46..55b407aae26 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -386,14 +386,17 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) * specific ID. Used to delete entire ACPI tables. All * reference counts are updated. * + * MUTEX: Locks namespace during deletion walk. + * ******************************************************************************/ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *deletion_node; - u32 level; struct acpi_namespace_node *parent_node; + u32 level; + acpi_status status; ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); @@ -401,6 +404,13 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) return_VOID; } + /* Lock namespace for possible update */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_VOID; + } + deletion_node = NULL; parent_node = acpi_gbl_root_node; child_node = NULL; @@ -469,5 +479,6 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) } } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; } diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 99eacceff56..7856db759af 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -320,6 +320,16 @@ acpi_tb_get_this_table(struct acpi_pointer *address, ACPI_FUNCTION_TRACE(tb_get_this_table); + /* Validate minimum length */ + + if (header->length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, + "Table length (%X) is smaller than minimum (%X)", + header->length, sizeof(struct acpi_table_header))); + + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + /* * Flags contains the current processor mode (Virtual or Physical * addressing) The pointer_type is either Logical or Physical @@ -356,7 +366,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, */ status = acpi_os_map_memory(address->pointer.physical, (acpi_size) header->length, - (void *)&full_table); + ACPI_CAST_PTR(void, &full_table)); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X", diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 7ca2df75bb1..1668a232fb6 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -256,7 +256,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, status = acpi_ut_allocate_owner_id(&table_desc->owner_id); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit1; } /* Install the table into the global data structure */ @@ -274,8 +274,8 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, * at this location, so return an error. */ if (list_head->next) { - ACPI_FREE(table_desc); - return_ACPI_STATUS(AE_ALREADY_EXISTS); + status = AE_ALREADY_EXISTS; + goto error_exit2; } table_desc->next = list_head->next; @@ -335,6 +335,17 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, table_info->owner_id = table_desc->owner_id; table_info->installed_desc = table_desc; return_ACPI_STATUS(AE_OK); + + /* Error exit with cleanup */ + + error_exit2: + + acpi_ut_release_owner_id(&table_desc->owner_id); + + error_exit1: + + ACPI_FREE(table_desc); + return_ACPI_STATUS(status); } /******************************************************************************* @@ -525,6 +536,10 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc acpi_tb_delete_single_table(table_desc); + /* Free the owner ID associated with this table */ + + acpi_ut_release_owner_id(&table_desc->owner_id); + /* Free the table descriptor */ next_desc = table_desc->next; diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index abcb08c2592..0ad3dbb9ebc 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -183,6 +183,17 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) ACPI_FUNCTION_ENTRY(); + /* Validate minimum length */ + + if (table_ptr->length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, + "RSDT/XSDT length (%X) is smaller than minimum (%X)", + table_ptr->length, + sizeof(struct acpi_table_header))); + + return (AE_INVALID_TABLE_LENGTH); + } + /* Search for appropriate signature, RSDT or XSDT */ if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { @@ -210,7 +221,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) ACPI_ERROR((AE_INFO, "Looking for XSDT")); } - ACPI_DUMP_BUFFER((char *)table_ptr, 48); + ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48); return (AE_BAD_SIGNATURE); } @@ -258,7 +269,7 @@ acpi_status acpi_tb_get_table_rsdt(void) status = acpi_tb_validate_rsdt(table_info.pointer); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } /* Get the number of tables defined in the RSDT or XSDT */ @@ -270,14 +281,14 @@ acpi_status acpi_tb_get_table_rsdt(void) status = acpi_tb_convert_to_xsdt(&table_info); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } /* Save the table pointers and allocation info */ status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } acpi_gbl_XSDT = @@ -285,4 +296,12 @@ acpi_status acpi_tb_get_table_rsdt(void) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); return_ACPI_STATUS(status); + + error_cleanup: + + /* Free table allocated by acpi_tb_get_table */ + + acpi_tb_delete_single_table(&table_info); + + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 4e91f298481..7767987be15 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -134,8 +134,8 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables) * RETURN: Status * * DESCRIPTION: This function is called to load a table from the caller's - * buffer. The buffer must contain an entire ACPI Table including - * a valid header. The header fields will be verified, and if it + * buffer. The buffer must contain an entire ACPI Table including + * a valid header. The header fields will be verified, and if it * is determined that the table is invalid, the call will fail. * ******************************************************************************/ @@ -245,15 +245,18 @@ acpi_status acpi_unload_table(acpi_table_type table_type) /* Find all tables of the requested type */ table_desc = acpi_gbl_table_lists[table_type].next; + if (!table_desc) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + while (table_desc) { /* - * Delete all namespace entries owned by this table. Note that these - * entries can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not * simply a position within the hierarchy */ acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - acpi_ut_release_owner_id(&table_desc->owner_id); table_desc = table_desc->next; } @@ -275,12 +278,12 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table) * see acpi_gbl_acpi_table_flag * out_table_header - pointer to the struct acpi_table_header if successful * - * DESCRIPTION: This function is called to get an ACPI table header. The caller + * DESCRIPTION: This function is called to get an ACPI table header. The caller * supplies an pointer to a data area sufficient to contain an ACPI * struct acpi_table_header structure. * * The header contains a length field that can be used to determine - * the size of the buffer needed to contain the entire table. This + * the size of the buffer needed to contain the entire table. This * function is not valid for the RSD PTR table since it does not * have a standard header and is fixed length. * @@ -322,7 +325,8 @@ acpi_get_table_header(acpi_table_type table_type, /* Copy the header to the caller's buffer */ - ACPI_MEMCPY((void *)out_table_header, (void *)tbl_ptr, + ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header), + ACPI_CAST_PTR(void, tbl_ptr), sizeof(struct acpi_table_header)); return_ACPI_STATUS(status); @@ -344,10 +348,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header) * * RETURN: Status * - * DESCRIPTION: This function is called to get an ACPI table. The caller + * DESCRIPTION: This function is called to get an ACPI table. The caller * supplies an out_buffer large enough to contain the entire ACPI - * table. The caller should call the acpi_get_table_header function - * first to determine the buffer size needed. Upon completion + * table. The caller should call the acpi_get_table_header function + * first to determine the buffer size needed. Upon completion * the out_buffer->Length field will indicate the number of bytes * copied into the out_buffer->buf_ptr buffer. This table will be * a complete table including the header. @@ -417,7 +421,9 @@ acpi_get_table(acpi_table_type table_type, /* Copy the table to the buffer */ - ACPI_MEMCPY((void *)ret_buffer->pointer, (void *)tbl_ptr, table_length); + ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer), + ACPI_CAST_PTR(void, tbl_ptr), table_length); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 38ebe1c5433..9d3f1149ba2 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -447,11 +447,16 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) */ switch (ACPI_GET_OBJECT_TYPE(object)) { case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + case ACPI_TYPE_THERMAL: - acpi_ut_update_ref_count(object->device.system_notify, - action); - acpi_ut_update_ref_count(object->device.device_notify, - action); + /* Update the notify objects for these types (if present) */ + + acpi_ut_update_ref_count(object->common_notify. + system_notify, action); + acpi_ut_update_ref_count(object->common_notify. + device_notify, action); break; case ACPI_TYPE_PACKAGE: diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 33268310c73..6d8a8211be9 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -65,7 +65,7 @@ ACPI_MODULE_NAME("utmisc") u8 acpi_ut_is_aml_table(struct acpi_table_header *table) { - /* Ignore tables that contain AML */ + /* These are the only tables that contain executable AML */ if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) || ACPI_COMPARE_NAME(table->signature, PSDT_SIG) || @@ -419,10 +419,15 @@ void acpi_ut_set_integer_width(u8 revision) { if (revision <= 1) { + + /* 32-bit case */ + acpi_gbl_integer_bit_width = 32; acpi_gbl_integer_nybble_width = 8; acpi_gbl_integer_byte_width = 4; } else { + /* 64-bit case (ACPI 2.0+) */ + acpi_gbl_integer_bit_width = 64; acpi_gbl_integer_nybble_width = 16; acpi_gbl_integer_byte_width = 8; @@ -502,6 +507,7 @@ acpi_ut_display_init_pathname(u8 type, * FUNCTION: acpi_ut_valid_acpi_char * * PARAMETERS: Char - The character to be examined + * Position - Byte position (0-3) * * RETURN: TRUE if the character is valid, FALSE otherwise * @@ -609,7 +615,9 @@ acpi_name acpi_ut_repair_name(acpi_name name) * * RETURN: Status and Converted value * - * DESCRIPTION: Convert a string into an unsigned value. + * DESCRIPTION: Convert a string into an unsigned value. Performs either a + * 32-bit or 64-bit conversion, depending on the current mode + * of the interpreter. * NOTE: Does not support Octal strings, not needed. * ******************************************************************************/ @@ -627,7 +635,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) u8 sign_of0x = 0; u8 term = 0; - ACPI_FUNCTION_TRACE(ut_stroul64); + ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); switch (base) { case ACPI_ANY_BASE: @@ -675,11 +683,13 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) } } + /* + * Perform a 32-bit or 64-bit conversion, depending upon the current + * execution mode of the interpreter + */ dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; - /* At least one character in the string here */ - - /* Main loop: convert the string to a 64-bit integer */ + /* Main loop: convert the string to a 32- or 64-bit integer */ while (*string) { if (ACPI_IS_DIGIT(*string)) { @@ -754,6 +764,9 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) all_done: + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(return_value))); + *ret_integer = return_value; return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index 0f5c5bb5def..eaa13d05c85 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -199,6 +199,13 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void) state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD; state->thread.thread_id = acpi_os_get_thread_id(); + /* Check for invalid thread ID - zero is very bad, it will break things */ + + if (!state->thread.thread_id) { + ACPI_ERROR((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId")); + state->thread.thread_id = (acpi_thread_id) 1; + } + return_PTR((struct acpi_thread_state *)state); } diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index b492857fe72..9e6c23c360b 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060623 +#define ACPI_CA_VERSION 0x20060707 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h index 216339a8f1f..91586d0d5bb 100644 --- a/include/acpi/acinterp.h +++ b/include/acpi/acinterp.h @@ -53,10 +53,14 @@ #define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_exdump_info)) /* - * If possible, pack the following structure to byte alignment, since we - * don't care about performance for debug output + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures */ -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) #pragma pack(1) #endif diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 56b80248616..7010fea26b4 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -204,7 +204,7 @@ struct acpi_namespace_node { /* Namespace Node flags */ #define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */ -#define ANOBJ_DATA_WIDTH_32 0x02 /* Parent table uses 32-bit math */ +#define ANOBJ_RESERVED 0x02 /* Available for future use */ #define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h index ad11fc13fbe..80a3b33571b 100644 --- a/include/acpi/acresrc.h +++ b/include/acpi/acresrc.h @@ -50,9 +50,13 @@ /* * If possible, pack the following structures to byte alignment, since we - * don't care about performance for debug output + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures */ -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) #pragma pack(1) #endif -- cgit v1.2.3 From ab8aa06a5c0b75974fb1949365cbb20a15cedf14 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 7 Jul 2006 20:11:07 -0400 Subject: ACPI: acpi_os_get_thread_id() returns current Linux mutexes and the debug code that that reference acpi_os_get_thread_id() are happy with 0. But the AML mutexes in exmutex.c expect a unique non-zero number for each thread - as they track this thread_id to permit the mutex re-entrancy defined by the ACPI spec. http://bugzilla.kernel.org/show_bug.cgi?id=6687 Signed-off-by: Len Brown --- drivers/acpi/executer/exmutex.c | 4 ++-- drivers/acpi/utilities/utdebug.c | 4 ++-- drivers/acpi/utilities/utmutex.c | 8 ++++---- include/acpi/aclocal.h | 2 +- include/acpi/platform/aclinux.h | 5 +++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index d8ac2877cf0..3a39c2e8e10 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -267,9 +267,9 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) { ACPI_ERROR((AE_INFO, "Thread %X cannot release Mutex [%4.4s] acquired by thread %X", - walk_state->thread->thread_id, + (u32) walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - obj_desc->mutex.owner_thread->thread_id)); + (u32) obj_desc->mutex.owner_thread->thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 5ec1cfcc611..bb1eaf9aa65 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -47,7 +47,7 @@ ACPI_MODULE_NAME("utdebug") #ifdef ACPI_DEBUG_OUTPUT -static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF; +static acpi_thread_id acpi_gbl_prev_thread_id; static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; @@ -181,7 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level, if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n", - acpi_gbl_prev_thread_id, thread_id); + (u32) acpi_gbl_prev_thread_id, (u32) thread_id); } acpi_gbl_prev_thread_id = thread_id; diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index dfc8f30ca89..c39062a047c 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -244,14 +244,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %X attempting to acquire Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name(mutex_id))); + (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", - this_thread_id, + (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; @@ -259,7 +259,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) } else { ACPI_EXCEPTION((AE_INFO, status, "Thread %X could not acquire Mutex [%X]", - this_thread_id, mutex_id)); + (u32) this_thread_id, mutex_id)); } return (status); @@ -285,7 +285,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %X releasing Mutex [%s]\n", this_thread_id, + "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 56b80248616..fbafee6e56d 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -127,7 +127,7 @@ typedef u8 acpi_owner_id; /* This Thread ID means that the mutex is not in use (unlocked) */ -#define ACPI_MUTEX_NOT_ACQUIRED (u32) -1 +#define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0 /* Table for the global mutexes */ diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 3f853cabbd4..1cb51bf96ec 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -59,6 +59,7 @@ #include #include #include +#include /* Host-dependent types and defines */ @@ -100,8 +101,8 @@ #define acpi_cpu_flags unsigned long -#define acpi_thread_id u32 +#define acpi_thread_id struct task_struct * -static inline acpi_thread_id acpi_os_get_thread_id(void) { return 0; } +static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; } #endif /* __ACLINUX_H__ */ -- cgit v1.2.3 From d608ab9917fbe9926704c07b27df72ac78133870 Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Mon, 26 Jun 2006 18:18:11 +0200 Subject: [SERIAL] dz: Fix compilation error Fix the following compilation error in the dz serial driver that got introduced with the "kernel console should send CRLF not LFCR" change. CC drivers/serial/dz.o drivers/serial/dz.c: In function 'dz_console_putchar': drivers/serial/dz.c:679: error: 'uport' undeclared (first use in this function) drivers/serial/dz.c:679: error: (Each undeclared identifier is reported only once drivers/serial/dz.c:679: error: for each function it appears in.) Signed-off-by: Martin Michlmayr Signed-off-by: Russell King --- drivers/serial/dz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index d119c8296a7..8a98aae80e2 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -673,7 +673,7 @@ static void dz_reset(struct dz_port *dport) } #ifdef CONFIG_SERIAL_DZ_CONSOLE -static void dz_console_putchar(struct uart_port *port, int ch) +static void dz_console_putchar(struct uart_port *uport, int ch) { struct dz_port *dport = (struct dz_port *)uport; unsigned long flags; -- cgit v1.2.3 From c65b15cfd6b8b74c6f2b3635bf47ee661d351ef3 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Sun, 9 Jul 2006 20:40:17 +0200 Subject: [SERIAL] IP22: fix serial console hangs The patch below fixes serial console hangs as seen on IP22 machines. Typically, while booting, the machine hangs for ~1 minute displaying "INIT: ", then the same thing happens again when init enters in the designated runlevel and finally the getty process on ttyS0 hangs indefinitely (though strace'ing it helps). strace (-e raw=ioctl, otherwise the ioctl() translation is utterly bogus) reveals that getty hangs on ioctl() 0x540f which happens to be TCSETSW (I saw it hang on another console ioctl() but couldn't reproduce that one). A diff between ip22zilog and sunzilog revealed the following differences: 1. the channel A flag being set on up.port.flags instead of up.flags 2. the channel A flag being set on what is marked as being channel B 3. sunzilog has a call to uart_update_timeout(port, termios->c_cflag, baud); at the end of sunzilog_set_termios(), which ip22zilog lacks (on purpose ?) The patch below addresses point 1 and fixes the serial console hangs just fine. However point 2 should be investigated by someone familiar with the IP22 Zilog; it's probably OK as is but even if it is, a comment in ip22zilog.c is badly needed. Point 3 is left as an exercise for whoever feels like digging into ip22zilog :) These are the main obvious differences between ip22zilog and sunzilog. Newer versions of sunzilog (Linus's git tree as of today) are more close to ip22zilog as the sbus_{write,read}b have been changed into simple {write,read}b, which shrinks the diff by a fair amount. Resyncing both drivers should be doable in a few hours time now for someone familiar with the IP22 Zilog hardware. Signed-off-by: Julien BLACHE Signed-off-by: Russell King --- drivers/serial/ip22zilog.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 342042889f6..5ff269fb604 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -1143,9 +1143,8 @@ static void __init ip22zilog_prepare(void) up[(chip * 2) + 1].port.fifosize = 1; up[(chip * 2) + 1].port.ops = &ip22zilog_pops; up[(chip * 2) + 1].port.type = PORT_IP22ZILOG; - up[(chip * 2) + 1].port.flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; up[(chip * 2) + 1].port.line = (chip * 2) + 1; - up[(chip * 2) + 1].flags = 0; + up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A; } } -- cgit v1.2.3 From 3be91ec7388bae3cf1bfb4febcee5ab6c65f409f Mon Sep 17 00:00:00 2001 From: Zang Roy-r61911 Date: Fri, 30 Jun 2006 02:29:58 -0700 Subject: [SERIAL] 8250: add tsi108 serial support The following patch gets rid of CONFIG_TSI108_BRIDGE. I add UPIO_TSI to handle IIR and IER register in serial_in and serial_out. (1) the reason to rewrite serial_in: TSI108 rev Z1 version ERRATA. Reading the UART's Interrupt Identification Register (IIR) clears the Transmit Holding Register Empty (THRE) and Transmit buffer Empty (TEMP) interrupts even if they are not enabled in the Interrupt Enable Register (IER). This leads to loss of the interrupts. Interrupts are not cleared when reading UART registers as 32-bit word. (2) the reason to rewrite serial_out: Check for UART_IER_UUE bit in the autoconfig routine. This section of autoconfig is excluded for Tsi108/109 because bits 7 and 6 are reserved for internal use. They are R/W bits. In addition to incorrect identification, changing these bits (from 00) will make Tsi108/109 UART non-functional. Signed-off-by: Roy Zang Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/serial/8250.c | 12 ++++++++++++ drivers/serial/serial_core.c | 1 + include/linux/serial_core.h | 1 + 3 files changed, 14 insertions(+) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 0995430e4cf..5443fcd3835 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -299,6 +299,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) static unsigned int serial_in(struct uart_8250_port *up, int offset) { + unsigned int tmp; offset = map_8250_in_reg(up, offset) << up->port.regshift; switch (up->port.iotype) { @@ -317,6 +318,13 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset) return __raw_readl(up->port.membase + offset); #endif + case UPIO_TSI: + if (offset == UART_IIR) { + tmp = readl((u32 *)(up->port.membase + UART_RX)); + return (cpu_to_le32(tmp) >> 8) & 0xff; + } else + return readb(up->port.membase + offset); + default: return inb(up->port.iobase + offset); } @@ -346,6 +354,10 @@ serial_out(struct uart_8250_port *up, int offset, int value) __raw_writel(value, up->port.membase + offset); break; #endif + case UPIO_TSI: + if (!((offset == UART_IER) && (value & UART_IER_UUE))) + writeb(value, up->port.membase + offset); + break; default: outb(value, up->port.iobase + offset); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index d5f636fbf29..80ef7d48275 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2036,6 +2036,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) case UPIO_MEM: case UPIO_MEM32: case UPIO_AU: + case UPIO_TSI: snprintf(address, sizeof(address), "MMIO 0x%lx", port->mapbase); break; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 058cba70818..86501a3de2a 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -227,6 +227,7 @@ struct uart_port { #define UPIO_MEM (2) #define UPIO_MEM32 (3) #define UPIO_AU (4) /* Au1x00 type IO */ +#define UPIO_TSI (5) /* Tsi108/109 type IO */ unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ -- cgit v1.2.3 From 68aa2c0d4a36b43ea9c6d77134c94b4501fd2eb4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 30 Jun 2006 02:29:59 -0700 Subject: [SERIAL] 8250: sysrq deadlock fix Fix http://bugzilla.kernel.org/show_bug.cgi?id=6716 Doing a sysrq over a serial line into an SMP machine presently deadlocks. Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/serial/8250.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 5443fcd3835..0ae9ced00ed 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2252,10 +2252,14 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); - if (oops_in_progress) { - locked = spin_trylock_irqsave(&up->port.lock, flags); + local_irq_save(flags); + if (up->port.sysrq) { + /* serial8250_handle_port() already took the lock */ + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); } else - spin_lock_irqsave(&up->port.lock, flags); + spin_lock(&up->port.lock); /* * First save the IER then disable the interrupts @@ -2277,7 +2281,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial_out(up, UART_IER, ier); if (locked) - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock(&up->port.lock); + local_irq_restore(flags); } static int serial8250_console_setup(struct console *co, char *options) -- cgit v1.2.3 From c8f7a62cdde461914c6457d5f4362538ed810bf4 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 9 Jul 2006 17:22:28 -0400 Subject: Revert "Revert "ACPI: dock driver"" This reverts 953969ddf5b049361ed1e8471cc43dc4134d2a6f commit. --- drivers/acpi/Kconfig | 7 + drivers/acpi/Makefile | 1 + drivers/acpi/dock.c | 739 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 23 ++ include/acpi/acpi_bus.h | 2 +- include/acpi/acpi_drivers.h | 17 + 6 files changed, 788 insertions(+), 1 deletion(-) create mode 100644 drivers/acpi/dock.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 290c767dd77..fef7bab1224 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -133,6 +133,13 @@ config ACPI_FAN This driver adds support for ACPI fan devices, allowing user-mode applications to perform basic fan control (on, off, status). +config ACPI_DOCK + tristate "Dock" + depends on !ACPI_IBM_DOCK + default y + help + This driver adds support for ACPI controlled docking stations + config ACPI_PROCESSOR tristate "Processor" default y diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bb5b80a80b1..bce7ca27b42 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o +obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c new file mode 100644 index 00000000000..510a9452429 --- /dev/null +++ b/drivers/acpi/dock.c @@ -0,0 +1,739 @@ +/* + * dock.c - ACPI dock station driver + * + * Copyright (C) 2006 Kristen Carlson Accardi + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" + +ACPI_MODULE_NAME("dock") +MODULE_AUTHOR("Kristen Carlson Accardi"); +MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static struct atomic_notifier_head dock_notifier_list; + +struct dock_station { + acpi_handle handle; + unsigned long last_dock_time; + u32 flags; + spinlock_t dd_lock; + spinlock_t hp_lock; + struct list_head dependent_devices; + struct list_head hotplug_devices; +}; + +struct dock_dependent_device { + struct list_head list; + struct list_head hotplug_list; + acpi_handle handle; + acpi_notify_handler handler; + void *context; +}; + +#define DOCK_DOCKING 0x00000001 +#define DOCK_EVENT KOBJ_DOCK +#define UNDOCK_EVENT KOBJ_UNDOCK + +static struct dock_station *dock_station; + +/***************************************************************************** + * Dock Dependent device functions * + *****************************************************************************/ +/** + * alloc_dock_dependent_device - allocate and init a dependent device + * @handle: the acpi_handle of the dependent device + * + * Allocate memory for a dependent device structure for a device referenced + * by the acpi handle + */ +static struct dock_dependent_device * +alloc_dock_dependent_device(acpi_handle handle) +{ + struct dock_dependent_device *dd; + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + if (dd) { + dd->handle = handle; + INIT_LIST_HEAD(&dd->list); + INIT_LIST_HEAD(&dd->hotplug_list); + } + return dd; +} + +/** + * add_dock_dependent_device - associate a device with the dock station + * @ds: The dock station + * @dd: The dependent device + * + * Add the dependent device to the dock's dependent device list. + */ +static void +add_dock_dependent_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->dd_lock); + list_add_tail(&dd->list, &ds->dependent_devices); + spin_unlock(&ds->dd_lock); +} + +/** + * dock_add_hotplug_device - associate a hotplug handler with the dock station + * @ds: The dock station + * @dd: The dependent device struct + * + * Add the dependent device to the dock's hotplug device list + */ +static void +dock_add_hotplug_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->hp_lock); + list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); + spin_unlock(&ds->hp_lock); +} + +/** + * dock_del_hotplug_device - remove a hotplug handler from the dock station + * @ds: The dock station + * @dd: the dependent device struct + * + * Delete the dependent device from the dock's hotplug device list + */ +static void +dock_del_hotplug_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->hp_lock); + list_del(&dd->hotplug_list); + spin_unlock(&ds->hp_lock); +} + +/** + * find_dock_dependent_device - get a device dependent on this dock + * @ds: the dock station + * @handle: the acpi_handle of the device we want + * + * iterate over the dependent device list for this dock. If the + * dependent device matches the handle, return. + */ +static struct dock_dependent_device * +find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) +{ + struct dock_dependent_device *dd; + + spin_lock(&ds->dd_lock); + list_for_each_entry(dd, &ds->dependent_devices, list) { + if (handle == dd->handle) { + spin_unlock(&ds->dd_lock); + return dd; + } + } + spin_unlock(&ds->dd_lock); + return NULL; +} + +/***************************************************************************** + * Dock functions * + *****************************************************************************/ +/** + * is_dock - see if a device is a dock station + * @handle: acpi handle of the device + * + * If an acpi object has a _DCK method, then it is by definition a dock + * station, so return true. + */ +static int is_dock(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_DCK", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +/** + * is_dock_device - see if a device is on a dock station + * @handle: acpi handle of the device + * + * If this device is either the dock station itself, + * or is a device dependent on the dock station, then it + * is a dock device + */ +int is_dock_device(acpi_handle handle) +{ + if (!dock_station) + return 0; + + if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) + return 1; + + return 0; +} + +EXPORT_SYMBOL_GPL(is_dock_device); + +/** + * dock_present - see if the dock station is present. + * @ds: the dock station + * + * execute the _STA method. note that present does not + * imply that we are docked. + */ +static int dock_present(struct dock_station *ds) +{ + unsigned long sta; + acpi_status status; + + if (ds) { + status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + return 1; + } + return 0; +} + + + +/** + * dock_create_acpi_device - add new devices to acpi + * @handle - handle of the device to add + * + * This function will create a new acpi_device for the given + * handle if one does not exist already. This should cause + * acpi to scan for drivers for the given devices, and call + * matching driver's add routine. + * + * Returns a pointer to the acpi_device corresponding to the handle. + */ +static struct acpi_device * dock_create_acpi_device(acpi_handle handle) +{ + struct acpi_device *device = NULL; + struct acpi_device *parent_device; + acpi_handle parent; + int ret; + + if (acpi_bus_get_device(handle, &device)) { + /* + * no device created for this object, + * so we should create one. + */ + acpi_get_parent(handle, &parent); + if (acpi_bus_get_device(parent, &parent_device)) + parent_device = NULL; + + ret = acpi_bus_add(&device, parent_device, handle, + ACPI_BUS_TYPE_DEVICE); + if (ret) { + pr_debug("error adding bus, %x\n", + -ret); + return NULL; + } + } + return device; +} + +/** + * dock_remove_acpi_device - remove the acpi_device struct from acpi + * @handle - the handle of the device to remove + * + * Tell acpi to remove the acpi_device. This should cause any loaded + * driver to have it's remove routine called. + */ +static void dock_remove_acpi_device(acpi_handle handle) +{ + struct acpi_device *device; + int ret; + + if (!acpi_bus_get_device(handle, &device)) { + ret = acpi_bus_trim(device, 1); + if (ret) + pr_debug("error removing bus, %x\n", -ret); + } +} + + +/** + * hotplug_dock_devices - insert or remove devices on the dock station + * @ds: the dock station + * @event: either bus check or eject request + * + * Some devices on the dock station need to have drivers called + * to perform hotplug operations after a dock event has occurred. + * Traverse the list of dock devices that have registered a + * hotplug handler, and call the handler. + */ +static void hotplug_dock_devices(struct dock_station *ds, u32 event) +{ + struct dock_dependent_device *dd; + + spin_lock(&ds->hp_lock); + + /* + * First call driver specific hotplug functions + */ + list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { + if (dd->handler) + dd->handler(dd->handle, event, dd->context); + } + + /* + * Now make sure that an acpi_device is created for each + * dependent device, or removed if this is an eject request. + * This will cause acpi_drivers to be stopped/started if they + * exist + */ + list_for_each_entry(dd, &ds->dependent_devices, list) { + if (event == ACPI_NOTIFY_EJECT_REQUEST) + dock_remove_acpi_device(dd->handle); + else + dock_create_acpi_device(dd->handle); + } + spin_unlock(&ds->hp_lock); +} + +static void dock_event(struct dock_station *ds, u32 event, int num) +{ + struct acpi_device *device; + + device = dock_create_acpi_device(ds->handle); + if (device) + kobject_uevent(&device->kobj, num); +} + +/** + * eject_dock - respond to a dock eject request + * @ds: the dock station + * + * This is called after _DCK is called, to execute the dock station's + * _EJ0 method. + */ +static void eject_dock(struct dock_station *ds) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + acpi_handle tmp; + + /* all dock devices should have _EJ0, but check anyway */ + status = acpi_get_handle(ds->handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) { + pr_debug("No _EJ0 support for dock device\n"); + return; + } + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", + &arg_list, NULL))) + pr_debug("Failed to evaluate _EJ0!\n"); +} + +/** + * handle_dock - handle a dock event + * @ds: the dock station + * @dock: to dock, or undock - that is the question + * + * Execute the _DCK method in response to an acpi event + */ +static void handle_dock(struct dock_station *ds, int dock) +{ + acpi_status status; + struct acpi_object_list arg_list; + union acpi_object arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); + obj = name_buffer.pointer; + + printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); + + /* _DCK method has one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = dock; + status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); + if (ACPI_FAILURE(status)) + pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); + kfree(buffer.pointer); + kfree(name_buffer.pointer); +} + +static inline void dock(struct dock_station *ds) +{ + handle_dock(ds, 1); +} + +static inline void undock(struct dock_station *ds) +{ + handle_dock(ds, 0); +} + +static inline void begin_dock(struct dock_station *ds) +{ + ds->flags |= DOCK_DOCKING; +} + +static inline void complete_dock(struct dock_station *ds) +{ + ds->flags &= ~(DOCK_DOCKING); + ds->last_dock_time = jiffies; +} + +/** + * dock_in_progress - see if we are in the middle of handling a dock event + * @ds: the dock station + * + * Sometimes while docking, false dock events can be sent to the driver + * because good connections aren't made or some other reason. Ignore these + * if we are in the middle of doing something. + */ +static int dock_in_progress(struct dock_station *ds) +{ + if ((ds->flags & DOCK_DOCKING) || + time_before(jiffies, (ds->last_dock_time + HZ))) + return 1; + return 0; +} + +/** + * register_dock_notifier - add yourself to the dock notifier list + * @nb: the callers notifier block + * + * If a driver wishes to be notified about dock events, they can + * use this function to put a notifier block on the dock notifier list. + * this notifier call chain will be called after a dock event, but + * before hotplugging any new devices. + */ +int register_dock_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&dock_notifier_list, nb); +} + +EXPORT_SYMBOL_GPL(register_dock_notifier); + +/** + * unregister_dock_notifier - remove yourself from the dock notifier list + * @nb: the callers notifier block + */ +void unregister_dock_notifier(struct notifier_block *nb) +{ + atomic_notifier_chain_unregister(&dock_notifier_list, nb); +} + +EXPORT_SYMBOL_GPL(unregister_dock_notifier); + +/** + * register_hotplug_dock_device - register a hotplug function + * @handle: the handle of the device + * @handler: the acpi_notifier_handler to call after docking + * @context: device specific data + * + * If a driver would like to perform a hotplug operation after a dock + * event, they can register an acpi_notifiy_handler to be called by + * the dock driver after _DCK is executed. + */ +int +register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, + void *context) +{ + struct dock_dependent_device *dd; + + if (!dock_station) + return -ENODEV; + + /* + * make sure this handle is for a device dependent on the dock, + * this would include the dock station itself + */ + dd = find_dock_dependent_device(dock_station, handle); + if (dd) { + dd->handler = handler; + dd->context = context; + dock_add_hotplug_device(dock_station, dd); + return 0; + } + + return -EINVAL; +} + +EXPORT_SYMBOL_GPL(register_hotplug_dock_device); + +/** + * unregister_hotplug_dock_device - remove yourself from the hotplug list + * @handle: the acpi handle of the device + */ +void unregister_hotplug_dock_device(acpi_handle handle) +{ + struct dock_dependent_device *dd; + + if (!dock_station) + return; + + dd = find_dock_dependent_device(dock_station, handle); + if (dd) + dock_del_hotplug_device(dock_station, dd); +} + +EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); + +/** + * dock_notify - act upon an acpi dock notification + * @handle: the dock station handle + * @event: the acpi event + * @data: our driver data struct + * + * If we are notified to dock, then check to see if the dock is + * present and then dock. Notify all drivers of the dock event, + * and then hotplug and devices that may need hotplugging. For undock + * check to make sure the dock device is still present, then undock + * and hotremove all the devices that may need removing. + */ +static void dock_notify(acpi_handle handle, u32 event, void *data) +{ + struct dock_station *ds = (struct dock_station *)data; + + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: + if (!dock_in_progress(ds) && dock_present(ds)) { + begin_dock(ds); + dock(ds); + if (!dock_present(ds)) { + printk(KERN_ERR PREFIX "Unable to dock!\n"); + break; + } + atomic_notifier_call_chain(&dock_notifier_list, + event, NULL); + hotplug_dock_devices(ds, event); + complete_dock(ds); + dock_event(ds, event, DOCK_EVENT); + } + break; + case ACPI_NOTIFY_DEVICE_CHECK: + /* + * According to acpi spec 3.0a, if a DEVICE_CHECK notification + * is sent and _DCK is present, it is assumed to mean an + * undock request. This notify routine will only be called + * for objects defining _DCK, so we will fall through to eject + * request here. However, we will pass an eject request through + * to the driver who wish to hotplug. + */ + case ACPI_NOTIFY_EJECT_REQUEST: + if (!dock_in_progress(ds) && dock_present(ds)) { + /* + * here we need to generate the undock + * event prior to actually doing the undock + * so that the device struct still exists. + */ + dock_event(ds, event, UNDOCK_EVENT); + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + undock(ds); + eject_dock(ds); + if (dock_present(ds)) + printk(KERN_ERR PREFIX "Unable to undock!\n"); + } + break; + default: + printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); + } +} + +/** + * find_dock_devices - find devices on the dock station + * @handle: the handle of the device we are examining + * @lvl: unused + * @context: the dock station private data + * @rv: unused + * + * This function is called by acpi_walk_namespace. It will + * check to see if an object has an _EJD method. If it does, then it + * will see if it is dependent on the dock station. + */ +static acpi_status +find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle tmp; + struct dock_station *ds = (struct dock_station *)context; + struct dock_dependent_device *dd; + + status = acpi_bus_get_ejd(handle, &tmp); + if (ACPI_FAILURE(status)) + return AE_OK; + + if (tmp == ds->handle) { + dd = alloc_dock_dependent_device(handle); + if (dd) + add_dock_dependent_device(ds, dd); + } + + return AE_OK; +} + +/** + * dock_add - add a new dock station + * @handle: the dock station handle + * + * allocated and initialize a new dock station device. Find all devices + * that are on the dock station, and register for dock event notifications. + */ +static int dock_add(acpi_handle handle) +{ + int ret; + acpi_status status; + struct dock_dependent_device *dd; + + /* allocate & initialize the dock_station private data */ + dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); + if (!dock_station) + return -ENOMEM; + dock_station->handle = handle; + dock_station->last_dock_time = jiffies - HZ; + INIT_LIST_HEAD(&dock_station->dependent_devices); + INIT_LIST_HEAD(&dock_station->hotplug_devices); + spin_lock_init(&dock_station->dd_lock); + spin_lock_init(&dock_station->hp_lock); + + /* Find dependent devices */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_dock_devices, dock_station, + NULL); + + /* add the dock station as a device dependent on itself */ + dd = alloc_dock_dependent_device(handle); + if (!dd) { + kfree(dock_station); + return -ENOMEM; + } + add_dock_dependent_device(dock_station, dd); + + /* register for dock events */ + status = acpi_install_notify_handler(dock_station->handle, + ACPI_SYSTEM_NOTIFY, + dock_notify, dock_station); + + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Error installing notify handler\n"); + ret = -ENODEV; + goto dock_add_err; + } + + printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); + + return 0; + +dock_add_err: + kfree(dock_station); + kfree(dd); + return ret; +} + +/** + * dock_remove - free up resources related to the dock station + */ +static int dock_remove(void) +{ + struct dock_dependent_device *dd, *tmp; + acpi_status status; + + if (!dock_station) + return 0; + + /* remove dependent devices */ + list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, + list) + kfree(dd); + + /* remove dock notify handler */ + status = acpi_remove_notify_handler(dock_station->handle, + ACPI_SYSTEM_NOTIFY, + dock_notify); + if (ACPI_FAILURE(status)) + printk(KERN_ERR "Error removing notify handler\n"); + + /* free dock station memory */ + kfree(dock_station); + return 0; +} + +/** + * find_dock - look for a dock station + * @handle: acpi handle of a device + * @lvl: unused + * @context: counter of dock stations found + * @rv: unused + * + * This is called by acpi_walk_namespace to look for dock stations. + */ +static acpi_status +find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + acpi_status status = AE_OK; + + if (is_dock(handle)) { + if (dock_add(handle) >= 0) { + (*count)++; + status = AE_CTRL_TERMINATE; + } + } + return status; +} + +static int __init dock_init(void) +{ + int num = 0; + + dock_station = NULL; + + /* look for a dock station */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_dock, &num, NULL); + + if (!num) + return -ENODEV; + + return 0; +} + +static void __exit dock_exit(void) +{ + dock_remove(); +} + +postcore_initcall(dock_init); +module_exit(dock_exit); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index cac4fcdcfc8..5fcb50c7b77 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -663,6 +663,29 @@ static int acpi_bus_find_driver(struct acpi_device *device) Device Enumeration -------------------------------------------------------------------------- */ +acpi_status +acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) +{ + acpi_status status; + acpi_handle tmp; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + + status = acpi_get_handle(handle, "_EJD", &tmp); + if (ACPI_FAILURE(status)) + return status; + + status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + status = acpi_get_handle(NULL, obj->string.pointer, ejd); + kfree(buffer.pointer); + } + return status; +} +EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); + + static int acpi_bus_get_flags(struct acpi_device *device) { acpi_status status = AE_OK; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a2b3e390a50..f338e40bd54 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -334,7 +334,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); int acpi_bus_trim(struct acpi_device *start, int rmdevice); int acpi_bus_start(struct acpi_device *device); - +acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd); int acpi_match_ids(struct acpi_device *device, char *ids); int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index b425f9bb6d4..6a5bdcefec6 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -110,4 +110,21 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type); extern int acpi_specific_hotkey_enabled; +/*-------------------------------------------------------------------------- + Dock Station + -------------------------------------------------------------------------- */ +#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) +extern int is_dock_device(acpi_handle handle); +extern int register_dock_notifier(struct notifier_block *nb); +extern void unregister_dock_notifier(struct notifier_block *nb); +extern int register_hotplug_dock_device(acpi_handle handle, + acpi_notify_handler handler, void *context); +extern void unregister_hotplug_dock_device(acpi_handle handle); +#else +#define is_dock_device(h) (0) +#define register_dock_notifier(nb) (-ENODEV) +#define unregister_dock_notifier(nb) do { } while(0) +#define register_hotplug_dock_device(h1, h2, c) (-ENODEV) +#define unregister_hotplug_dock_device(h) do { } while(0) +#endif #endif /*__ACPI_DRIVERS_H__*/ -- cgit v1.2.3 From b3cf257623fabd8f1ee6700a6d328cc1c5da5a1d Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Sun, 9 Jul 2006 21:12:39 -0400 Subject: [PATCH] i386: use thread_info flags for debug regs and IO bitmaps Use thread info flags to track use of debug registers and IO bitmaps. - add TIF_DEBUG to track when debug registers are active - add TIF_IO_BITMAP to track when I/O bitmap is used - modify __switch_to() to use the new TIF flags Performance tested on Pentium II, ten runs of LMbench context switch benchmark (smaller is better:) before after avg 3.65 3.39 min 3.55 3.33 Signed-off-by: Stephane Eranian Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Acked-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/i386/kernel/ioport.c | 1 + arch/i386/kernel/process.c | 50 ++++++++++++++++++++++++------------------ arch/i386/kernel/ptrace.c | 5 ++++- include/asm-i386/thread_info.h | 7 ++++++ 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index 79026f026b8..498e8bc197d 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -79,6 +79,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) memset(bitmap, 0xff, IO_BITMAP_BYTES); t->io_bitmap_ptr = bitmap; + set_thread_flag(TIF_IO_BITMAP); } /* diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 94e2c87edea..923bb292f47 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -359,16 +359,16 @@ EXPORT_SYMBOL(kernel_thread); */ void exit_thread(void) { - struct task_struct *tsk = current; - struct thread_struct *t = &tsk->thread; - /* The process may have allocated an io port bitmap... nuke it. */ - if (unlikely(NULL != t->io_bitmap_ptr)) { + if (unlikely(test_thread_flag(TIF_IO_BITMAP))) { + struct task_struct *tsk = current; + struct thread_struct *t = &tsk->thread; int cpu = get_cpu(); struct tss_struct *tss = &per_cpu(init_tss, cpu); kfree(t->io_bitmap_ptr); t->io_bitmap_ptr = NULL; + clear_thread_flag(TIF_IO_BITMAP); /* * Careful, clear this in the TSS too: */ @@ -387,6 +387,7 @@ void flush_thread(void) memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); + clear_tsk_thread_flag(tsk, TIF_DEBUG); /* * Forget coprocessor state.. */ @@ -431,7 +432,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, savesegment(gs,p->thread.gs); tsk = current; - if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) { + if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) { p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); if (!p->thread.io_bitmap_ptr) { p->thread.io_bitmap_max = 0; @@ -439,6 +440,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, } memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr, IO_BITMAP_BYTES); + set_tsk_thread_flag(p, TIF_IO_BITMAP); } /* @@ -533,10 +535,24 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) return 1; } -static inline void -handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) +static noinline void __switch_to_xtra(struct task_struct *next_p, + struct tss_struct *tss) { - if (!next->io_bitmap_ptr) { + struct thread_struct *next; + + next = &next_p->thread; + + if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { + set_debugreg(next->debugreg[0], 0); + set_debugreg(next->debugreg[1], 1); + set_debugreg(next->debugreg[2], 2); + set_debugreg(next->debugreg[3], 3); + /* no 4 and 5 */ + set_debugreg(next->debugreg[6], 6); + set_debugreg(next->debugreg[7], 7); + } + + if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) { /* * Disable the bitmap via an invalid offset. We still cache * the previous bitmap owner and the IO bitmap contents: @@ -544,6 +560,7 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss) tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET; return; } + if (likely(next == tss->io_bitmap_owner)) { /* * Previous owner of the bitmap (hence the bitmap content) @@ -671,20 +688,11 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas set_iopl_mask(next->iopl); /* - * Now maybe reload the debug registers + * Now maybe handle debug registers and/or IO bitmaps */ - if (unlikely(next->debugreg[7])) { - set_debugreg(next->debugreg[0], 0); - set_debugreg(next->debugreg[1], 1); - set_debugreg(next->debugreg[2], 2); - set_debugreg(next->debugreg[3], 3); - /* no 4 and 5 */ - set_debugreg(next->debugreg[6], 6); - set_debugreg(next->debugreg[7], 7); - } - - if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) - handle_io_bitmap(next, tss); + if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)) + || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)) + __switch_to_xtra(next_p, tss); disable_tsc(prev_p, next_p); diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index fd7eaf7866e..d3db03f4085 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -468,8 +468,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) for(i=0; i<4; i++) if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) goto out_tsk; + if (data) + set_tsk_thread_flag(child, TIF_DEBUG); + else + clear_tsk_thread_flag(child, TIF_DEBUG); } - addr -= (long) &dummy->u_debugreg; addr = addr >> 2; child->thread.debugreg[addr] = data; diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index 2833fa2c0dd..54d6d7aea93 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -140,6 +140,8 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SECCOMP 8 /* secure computing */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ #define TIF_MEMDIE 16 +#define TIF_DEBUG 17 /* uses debug registers */ +#define TIF_IO_BITMAP 18 /* uses I/O bitmap */ #define _TIF_SYSCALL_TRACE (1< Date: Sun, 9 Jul 2006 22:09:57 -0400 Subject: ACPI: ACPI_DOCK Kconfig HOTPLUG_PCI_ACPI depends on ACPI_DOCK ACPI_IBM_DOCK depends on ACPI_DOCK=n ACPI_DOCK is EXPERIMENTAL, though that doesn't seem to mean much Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 4 ++-- drivers/pci/hotplug/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fef7bab1224..82289f1364f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -135,8 +135,7 @@ config ACPI_FAN config ACPI_DOCK tristate "Dock" - depends on !ACPI_IBM_DOCK - default y + depends on EXPERIMENTAL help This driver adds support for ACPI controlled docking stations @@ -214,6 +213,7 @@ config ACPI_IBM config ACPI_IBM_DOCK bool "Legacy Docking Station Support" depends on ACPI_IBM + depends on ACPI_DOCK=n default n ---help--- Allows the ibm_acpi driver to handle docking station events. diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 222a1cc4aa2..d305d212ad6 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -77,7 +77,7 @@ config HOTPLUG_PCI_IBM config HOTPLUG_PCI_ACPI tristate "ACPI PCI Hotplug driver" - depends on ACPI && HOTPLUG_PCI + depends on ACPI_DOCK && HOTPLUG_PCI help Say Y here if you have a system that supports PCI Hotplug using ACPI. -- cgit v1.2.3 From af4f949c6b4ffa5119aad980626e5b04daca961b Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 9 Jul 2006 16:33:26 -0400 Subject: ACPI: "Device `[%s]' is not power manageable" make message debug only Signed-off-by: Len Brown --- drivers/acpi/bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ea5a0496a4f..b2977695e12 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -192,8 +192,8 @@ int acpi_bus_set_power(acpi_handle handle, int state) /* Make sure this is a valid target state */ if (!device->flags.power_manageable) { - printk(KERN_DEBUG "Device `[%s]' is not power manageable", - device->kobj.name); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable", + device->kobj.name)); return -ENODEV; } /* -- cgit v1.2.3 From e26a2b8f68dca28c734d857517788e3b40b8691d Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 6 Jul 2006 12:14:00 -0400 Subject: ACPI: delete some defaults from ACPI Kconfig No need for video to be always in No need for ACPI dock driver to be always in No need for smart battery driver to be always in Signed-off-by: Andi Kleen Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 290c767dd77..89eacd1bfee 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -107,7 +107,6 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on X86 - default y help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -350,7 +349,6 @@ config ACPI_SBS tristate "Smart Battery System (EXPERIMENTAL)" depends on X86 && I2C depends on EXPERIMENTAL - default y help This driver adds support for the Smart Battery System. Depends on I2C (Device Drivers ---> I2C support) -- cgit v1.2.3 From d75080328affb4b268da430b7074cc8139cc662a Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Tue, 4 Jul 2006 13:06:00 -0400 Subject: ACPI: add 'const' to several ACPI file_operations Signed-off-by: Arjan van de Ven Signed-off-by: Len Brown --- drivers/acpi/ac.c | 2 +- drivers/acpi/battery.c | 6 +++--- drivers/acpi/button.c | 4 ++-- drivers/acpi/ec.c | 2 +- drivers/acpi/event.c | 2 +- drivers/acpi/fan.c | 2 +- drivers/acpi/hotkey.c | 10 +++++----- drivers/acpi/power.c | 2 +- drivers/acpi/processor_core.c | 2 +- drivers/acpi/processor_idle.c | 2 +- drivers/acpi/sleep/proc.c | 6 +++--- drivers/acpi/system.c | 6 +++--- drivers/acpi/thermal.c | 10 +++++----- 13 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 24ccf81d135..96309b9660d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -72,7 +72,7 @@ struct acpi_ac { unsigned long state; }; -static struct file_operations acpi_ac_fops = { +static const struct file_operations acpi_ac_fops = { .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 24bf4dca88c..6e5221707d9 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -557,7 +557,7 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); } -static struct file_operations acpi_battery_info_ops = { +static const struct file_operations acpi_battery_info_ops = { .open = acpi_battery_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -565,7 +565,7 @@ static struct file_operations acpi_battery_info_ops = { .owner = THIS_MODULE, }; -static struct file_operations acpi_battery_state_ops = { +static const struct file_operations acpi_battery_state_ops = { .open = acpi_battery_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -573,7 +573,7 @@ static struct file_operations acpi_battery_state_ops = { .owner = THIS_MODULE, }; -static struct file_operations acpi_battery_alarm_ops = { +static const struct file_operations acpi_battery_alarm_ops = { .open = acpi_battery_alarm_open_fs, .read = seq_read, .write = acpi_battery_write_alarm, diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index fd1ba05eab6..5ef885e82c7 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -87,14 +87,14 @@ struct acpi_button { unsigned long pushed; }; -static struct file_operations acpi_button_info_fops = { +static const struct file_operations acpi_button_info_fops = { .open = acpi_button_info_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_button_state_fops = { +static const struct file_operations acpi_button_state_fops = { .open = acpi_button_state_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 8c5d7df7d34..e5d79636285 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -929,7 +929,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_ec_read_info, PDE(inode)->data); } -static struct file_operations acpi_ec_info_ops = { +static const struct file_operations acpi_ec_info_ops = { .open = acpi_ec_info_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index a901b23e95e..959a893c8d1 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -99,7 +99,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) return 0; } -static struct file_operations acpi_system_event_ops = { +static const struct file_operations acpi_system_event_ops = { .open = acpi_system_open_event, .read = acpi_system_read_event, .release = acpi_system_close_event, diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index daed2460924..045c89477e5 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -120,7 +120,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer, return count; } -static struct file_operations acpi_fan_state_ops = { +static const struct file_operations acpi_fan_state_ops = { .open = acpi_fan_state_open_fs, .read = seq_read, .write = acpi_fan_write_state, diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index fd81a0f5222..32c9d88fd19 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -184,7 +184,7 @@ static union acpi_hotkey *get_hotkey_by_event(struct *hotkey_list, int event); /* event based config */ -static struct file_operations hotkey_config_fops = { +static const struct file_operations hotkey_config_fops = { .open = hotkey_open_config, .read = seq_read, .write = hotkey_write_config, @@ -193,7 +193,7 @@ static struct file_operations hotkey_config_fops = { }; /* polling based config */ -static struct file_operations hotkey_poll_config_fops = { +static const struct file_operations hotkey_poll_config_fops = { .open = hotkey_poll_open_config, .read = seq_read, .write = hotkey_write_config, @@ -202,7 +202,7 @@ static struct file_operations hotkey_poll_config_fops = { }; /* hotkey driver info */ -static struct file_operations hotkey_info_fops = { +static const struct file_operations hotkey_info_fops = { .open = hotkey_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -210,7 +210,7 @@ static struct file_operations hotkey_info_fops = { }; /* action */ -static struct file_operations hotkey_action_fops = { +static const struct file_operations hotkey_action_fops = { .open = hotkey_action_open_fs, .read = seq_read, .write = hotkey_execute_aml_method, @@ -219,7 +219,7 @@ static struct file_operations hotkey_action_fops = { }; /* polling results */ -static struct file_operations hotkey_polling_fops = { +static const struct file_operations hotkey_polling_fops = { .open = hotkey_polling_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5d3447f4582..fec225d1b6b 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -80,7 +80,7 @@ struct acpi_power_resource { static struct list_head acpi_power_resource_list; -static struct file_operations acpi_power_fops = { +static const struct file_operations acpi_power_fops = { .open = acpi_power_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 52674323b14..b13d64415b7 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -102,7 +102,7 @@ static struct acpi_driver acpi_processor_driver = { #define INSTALL_NOTIFY_HANDLER 1 #define UNINSTALL_NOTIFY_HANDLER 2 -static struct file_operations acpi_processor_info_fops = { +static const struct file_operations acpi_processor_info_fops = { .open = acpi_processor_info_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 8e9c26aae8f..71066066d62 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1070,7 +1070,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static struct file_operations acpi_processor_power_fops = { +static const struct file_operations acpi_processor_power_fops = { .open = acpi_processor_power_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 4696a85a98b..34962578039 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -434,7 +434,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static struct file_operations acpi_system_wakeup_device_fops = { +static const struct file_operations acpi_system_wakeup_device_fops = { .open = acpi_system_wakeup_device_open_fs, .read = seq_read, .write = acpi_system_write_wakeup_device, @@ -443,7 +443,7 @@ static struct file_operations acpi_system_wakeup_device_fops = { }; #ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP -static struct file_operations acpi_system_sleep_fops = { +static const struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, .read = seq_read, .write = acpi_system_write_sleep, @@ -452,7 +452,7 @@ static struct file_operations acpi_system_sleep_fops = { }; #endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ -static struct file_operations acpi_system_alarm_fops = { +static const struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, .read = seq_read, .write = acpi_system_write_alarm, diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index c3bb7faad75..d86dcb3c236 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -57,7 +57,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_system_read_info, PDE(inode)->data); } -static struct file_operations acpi_system_info_ops = { +static const struct file_operations acpi_system_info_ops = { .open = acpi_system_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -67,7 +67,7 @@ static struct file_operations acpi_system_info_ops = { static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); -static struct file_operations acpi_system_dsdt_ops = { +static const struct file_operations acpi_system_dsdt_ops = { .read = acpi_system_read_dsdt, }; @@ -94,7 +94,7 @@ acpi_system_read_dsdt(struct file *file, static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t, loff_t *); -static struct file_operations acpi_system_fadt_ops = { +static const struct file_operations acpi_system_fadt_ops = { .read = acpi_system_read_fadt, }; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 503c0b99db1..480a3179688 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -176,21 +176,21 @@ struct acpi_thermal { struct timer_list timer; }; -static struct file_operations acpi_thermal_state_fops = { +static const struct file_operations acpi_thermal_state_fops = { .open = acpi_thermal_state_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_thermal_temp_fops = { +static const struct file_operations acpi_thermal_temp_fops = { .open = acpi_thermal_temp_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_thermal_trip_fops = { +static const struct file_operations acpi_thermal_trip_fops = { .open = acpi_thermal_trip_open_fs, .read = seq_read, .write = acpi_thermal_write_trip_points, @@ -198,7 +198,7 @@ static struct file_operations acpi_thermal_trip_fops = { .release = single_release, }; -static struct file_operations acpi_thermal_cooling_fops = { +static const struct file_operations acpi_thermal_cooling_fops = { .open = acpi_thermal_cooling_open_fs, .read = seq_read, .write = acpi_thermal_write_cooling_mode, @@ -206,7 +206,7 @@ static struct file_operations acpi_thermal_cooling_fops = { .release = single_release, }; -static struct file_operations acpi_thermal_polling_fops = { +static const struct file_operations acpi_thermal_polling_fops = { .open = acpi_thermal_polling_open_fs, .read = seq_read, .write = acpi_thermal_write_polling, -- cgit v1.2.3 From 8970bfe706345223d39d33bfce5f8b29750ab716 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Jul 2006 02:34:45 -0400 Subject: ACPI: SBS: fix initialization, sem2mutex cm_sbs_sem is being downed (via acpi_ac_init->acpi_lock_ac_dir) before it is initialised, with grave results. - Make it a mutex - Initialise it - Make it static - Clean other stuff up. Thanks to Paul Drynoff for reporting and testing. Cc: Rich Townsend Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/cm_sbs.c | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 574a75a166c..a01ce6700bf 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -39,50 +39,43 @@ ACPI_MODULE_NAME("cm_sbs") static struct proc_dir_entry *acpi_ac_dir; static struct proc_dir_entry *acpi_battery_dir; -static struct semaphore cm_sbs_sem; +static DEFINE_MUTEX(cm_sbs_mutex); -static int lock_ac_dir_cnt = 0; -static int lock_battery_dir_cnt = 0; +static int lock_ac_dir_cnt; +static int lock_battery_dir_cnt; struct proc_dir_entry *acpi_lock_ac_dir(void) { - - down(&cm_sbs_sem); - if (!acpi_ac_dir) { + mutex_lock(&cm_sbs_mutex); + if (!acpi_ac_dir) acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); - } if (acpi_ac_dir) { lock_ac_dir_cnt++; } else { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cannot create %s\n", ACPI_AC_CLASS)); } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return acpi_ac_dir; } - EXPORT_SYMBOL(acpi_lock_ac_dir); void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param) { - - down(&cm_sbs_sem); - if (acpi_ac_dir_param) { + mutex_lock(&cm_sbs_mutex); + if (acpi_ac_dir_param) lock_ac_dir_cnt--; - } if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) { remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); acpi_ac_dir = 0; } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); } - EXPORT_SYMBOL(acpi_unlock_ac_dir); struct proc_dir_entry *acpi_lock_battery_dir(void) { - - down(&cm_sbs_sem); + mutex_lock(&cm_sbs_mutex); if (!acpi_battery_dir) { acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); @@ -93,39 +86,28 @@ struct proc_dir_entry *acpi_lock_battery_dir(void) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cannot create %s\n", ACPI_BATTERY_CLASS)); } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return acpi_battery_dir; } - EXPORT_SYMBOL(acpi_lock_battery_dir); void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param) { - - down(&cm_sbs_sem); - if (acpi_battery_dir_param) { + mutex_lock(&cm_sbs_mutex); + if (acpi_battery_dir_param) lock_battery_dir_cnt--; - } if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param && acpi_battery_dir) { remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); acpi_battery_dir = 0; } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return; } - EXPORT_SYMBOL(acpi_unlock_battery_dir); static int __init acpi_cm_sbs_init(void) { - - if (acpi_disabled) - return 0; - - init_MUTEX(&cm_sbs_sem); - return 0; } - subsys_initcall(acpi_cm_sbs_init); -- cgit v1.2.3 From e21c1ca3f98529921c829a792dfdbfc5a5dc393b Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 10 Jul 2006 01:35:51 -0400 Subject: ACPI: acpi_os_allocate() fixes Replace acpi_in_resume with a more general hack to check irqs_disabled() on any kmalloc() from ACPI. While setting (system_state != SYSTEM_RUNNING) on resume seemed more general, Andrew Morton preferred this approach. http://bugzilla.kernel.org/show_bug.cgi?id=3469 Make acpi_os_allocate() into an inline function to allow /proc/slab_allocators to work. Delete some memset() that could fault on allocation failure. Signed-off-by: Len Brown --- drivers/acpi/osl.c | 30 ------------------------------ drivers/acpi/parser/psutils.c | 2 -- drivers/acpi/pci_link.c | 7 ------- drivers/acpi/utilities/utalloc.c | 2 ++ include/acpi/acmacros.h | 8 +++++++- include/acpi/platform/aclinux.h | 22 ++++++++++++++++++++++ 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index eedb05c6dc7..47dfde95b8f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -136,16 +136,6 @@ void acpi_os_vprintf(const char *fmt, va_list args) #endif } - -extern int acpi_in_resume; -void *acpi_os_allocate(acpi_size size) -{ - if (acpi_in_resume) - return kmalloc(size, GFP_ATOMIC); - else - return kmalloc(size, GFP_KERNEL); -} - acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr) { if (efi_enabled) { @@ -1115,26 +1105,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) return (AE_OK); } -/******************************************************************************* - * - * FUNCTION: acpi_os_acquire_object - * - * PARAMETERS: Cache - Handle to cache object - * ReturnObject - Where the object is returned - * - * RETURN: Status - * - * DESCRIPTION: Return a zero-filled object. - * - ******************************************************************************/ - -void *acpi_os_acquire_object(acpi_cache_t * cache) -{ - void *object = kmem_cache_zalloc(cache, GFP_KERNEL); - WARN_ON(!object); - return object; -} - /****************************************************************************** * * FUNCTION: acpi_os_validate_interface diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index 182474ae8ce..d405387b741 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -139,12 +139,10 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) /* The generic op (default) is by far the most common (16 to 1) */ op = acpi_os_acquire_object(acpi_gbl_ps_node_cache); - memset(op, 0, sizeof(struct acpi_parse_obj_common)); } else { /* Extended parseop */ op = acpi_os_acquire_object(acpi_gbl_ps_node_ext_cache); - memset(op, 0, sizeof(struct acpi_parse_obj_named)); } /* Initialize the Op */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 8197c0e4076..7f3e7e77e79 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -780,11 +780,6 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link) return 0; } -/* - * FIXME: this is a workaround to avoid nasty warning. It will be removed - * after every device calls pci_disable_device in .resume. - */ -int acpi_in_resume; static int irqrouter_resume(struct sys_device *dev) { struct list_head *node = NULL; @@ -794,7 +789,6 @@ static int irqrouter_resume(struct sys_device *dev) /* Make sure SCI is enabled again (Apple firmware bug?) */ acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_in_resume = 1; list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { @@ -803,7 +797,6 @@ static int irqrouter_resume(struct sys_device *dev) } acpi_pci_link_resume(link); } - acpi_in_resume = 0; return 0; } diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 5cff17dc78b..f6cbc0b1bfd 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -285,6 +285,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, return (status); } +#ifdef NOT_USED_BY_LINUX /******************************************************************************* * * FUNCTION: acpi_ut_allocate @@ -360,3 +361,4 @@ void *acpi_ut_allocate_zeroed(acpi_size size, return (allocation); } +#endif diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index f1ac6109556..192fa095a51 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -724,9 +724,15 @@ /* Memory allocation */ +#ifndef ACPI_ALLOCATE #define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a),_COMPONENT,_acpi_module_name,__LINE__) +#endif +#ifndef ACPI_ALLOCATE_ZEROED #define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), _COMPONENT,_acpi_module_name,__LINE__) -#define ACPI_FREE(a) kfree(a) +#endif +#ifndef ACPI_FREE +#define ACPI_FREE(a) acpio_os_free(a) +#endif #define ACPI_MEM_TRACKING(a) #else diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 3f853cabbd4..f0118262ac2 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -104,4 +104,26 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) { return 0; } +/* + * The irqs_disabled() check is for resume from RAM. + * Interrupts are off during resume, just like they are for boot. + * However, boot has (system_state != SYSTEM_RUNNING) + * to quiet __might_sleep() in kmalloc() and resume does not. + */ +#include +static inline void *acpi_os_allocate(acpi_size size) { + return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +} +static inline void *acpi_os_allocate_zeroed(acpi_size size) { + return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +} + +static inline void *acpi_os_acquire_object(acpi_cache_t * cache) { + return kmem_cache_zalloc(cache, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL); +} + +#define ACPI_ALLOCATE(a) acpi_os_allocate(a) +#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a) +#define ACPI_FREE(a) kfree(a) + #endif /* __ACLINUX_H__ */ -- cgit v1.2.3 From aadd06e5c56b9ff5117ec77e59eada43dc46e2fc Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 10 Jul 2006 11:00:01 +0200 Subject: [PATCH] splice: fix problems with sys_tee() Several issues noticed/fixed: - We cannot reliably block in link_pipe() while holding both input and output mutexes. So do preparatory checks before locking down both mutexes and doing the link. - The ipipe->nrbufs vs i check was bad, because we could have dropped the ipipe lock in-between. This causes us to potentially look at unknown buffers if we were racing with someone else reading this pipe. Signed-off-by: Jens Axboe --- fs/splice.c | 238 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 133 insertions(+), 105 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 05fd2787be9..684bca3d3a1 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1306,6 +1306,85 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, return error; } +/* + * Make sure there's data to read. Wait for input if we can, otherwise + * return an appropriate error. + */ +static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags) +{ + int ret; + + /* + * Check ->nrbufs without the inode lock first. This function + * is speculative anyways, so missing one is ok. + */ + if (pipe->nrbufs) + return 0; + + ret = 0; + mutex_lock(&pipe->inode->i_mutex); + + while (!pipe->nrbufs) { + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + if (!pipe->writers) + break; + if (!pipe->waiting_writers) { + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } + } + pipe_wait(pipe); + } + + mutex_unlock(&pipe->inode->i_mutex); + return ret; +} + +/* + * Make sure there's writeable room. Wait for room if we can, otherwise + * return an appropriate error. + */ +static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags) +{ + int ret; + + /* + * Check ->nrbufs without the inode lock first. This function + * is speculative anyways, so missing one is ok. + */ + if (pipe->nrbufs < PIPE_BUFFERS) + return 0; + + ret = 0; + mutex_lock(&pipe->inode->i_mutex); + + while (pipe->nrbufs >= PIPE_BUFFERS) { + if (!pipe->readers) { + send_sig(SIGPIPE, current, 0); + ret = -EPIPE; + break; + } + if (flags & SPLICE_F_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + pipe->waiting_writers++; + pipe_wait(pipe); + pipe->waiting_writers--; + } + + mutex_unlock(&pipe->inode->i_mutex); + return ret; +} + /* * Link contents of ipipe to opipe. */ @@ -1314,9 +1393,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, size_t len, unsigned int flags) { struct pipe_buffer *ibuf, *obuf; - int ret, do_wakeup, i, ipipe_first; - - ret = do_wakeup = ipipe_first = 0; + int ret = 0, i = 0, nbuf; /* * Potential ABBA deadlock, work around it by ordering lock @@ -1324,126 +1401,62 @@ static int link_pipe(struct pipe_inode_info *ipipe, * could deadlock (one doing tee from A -> B, the other from B -> A). */ if (ipipe->inode < opipe->inode) { - ipipe_first = 1; - mutex_lock(&ipipe->inode->i_mutex); - mutex_lock(&opipe->inode->i_mutex); + mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD); } else { - mutex_lock(&opipe->inode->i_mutex); - mutex_lock(&ipipe->inode->i_mutex); + mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD); } - for (i = 0;; i++) { + do { if (!opipe->readers) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } - if (ipipe->nrbufs - i) { - ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1)); - /* - * If we have room, fill this buffer - */ - if (opipe->nrbufs < PIPE_BUFFERS) { - int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1); - - /* - * Get a reference to this pipe buffer, - * so we can copy the contents over. - */ - ibuf->ops->get(ipipe, ibuf); - - obuf = opipe->bufs + nbuf; - *obuf = *ibuf; - - /* - * Don't inherit the gift flag, we need to - * prevent multiple steals of this page. - */ - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; - - if (obuf->len > len) - obuf->len = len; - - opipe->nrbufs++; - do_wakeup = 1; - ret += obuf->len; - len -= obuf->len; - - if (!len) - break; - if (opipe->nrbufs < PIPE_BUFFERS) - continue; - } - - /* - * We have input available, but no output room. - * If we already copied data, return that. If we - * need to drop the opipe lock, it must be ordered - * last to avoid deadlocks. - */ - if ((flags & SPLICE_F_NONBLOCK) || !ipipe_first) { - if (!ret) - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - if (do_wakeup) { - smp_mb(); - if (waitqueue_active(&opipe->wait)) - wake_up_interruptible(&opipe->wait); - kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); - do_wakeup = 0; - } + /* + * If we have iterated all input buffers or ran out of + * output room, break. + */ + if (i >= ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS) + break; - opipe->waiting_writers++; - pipe_wait(opipe); - opipe->waiting_writers--; - continue; - } + ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1)); + nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1); /* - * No input buffers, do the usual checks for available - * writers and blocking and wait if necessary + * Get a reference to this pipe buffer, + * so we can copy the contents over. */ - if (!ipipe->writers) - break; - if (!ipipe->waiting_writers) { - if (ret) - break; - } + ibuf->ops->get(ipipe, ibuf); + + obuf = opipe->bufs + nbuf; + *obuf = *ibuf; + /* - * pipe_wait() drops the ipipe mutex. To avoid deadlocks - * with another process, we can only safely do that if - * the ipipe lock is ordered last. + * Don't inherit the gift flag, we need to + * prevent multiple steals of this page. */ - if ((flags & SPLICE_F_NONBLOCK) || ipipe_first) { - if (!ret) - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } + obuf->flags &= ~PIPE_BUF_FLAG_GIFT; - if (waitqueue_active(&ipipe->wait)) - wake_up_interruptible_sync(&ipipe->wait); - kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT); + if (obuf->len > len) + obuf->len = len; - pipe_wait(ipipe); - } + opipe->nrbufs++; + ret += obuf->len; + len -= obuf->len; + i++; + } while (len); mutex_unlock(&ipipe->inode->i_mutex); mutex_unlock(&opipe->inode->i_mutex); - if (do_wakeup) { + /* + * If we put data in the output pipe, wakeup any potential readers. + */ + if (ret > 0) { smp_mb(); if (waitqueue_active(&opipe->wait)) wake_up_interruptible(&opipe->wait); @@ -1464,14 +1477,29 @@ static long do_tee(struct file *in, struct file *out, size_t len, { struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; + int ret = -EINVAL; /* - * Link ipipe to the two output pipes, consuming as we go along. + * Duplicate the contents of ipipe to opipe without actually + * copying the data. */ - if (ipipe && opipe) - return link_pipe(ipipe, opipe, len, flags); + if (ipipe && opipe && ipipe != opipe) { + /* + * Keep going, unless we encounter an error. The ipipe/opipe + * ordering doesn't really matter. + */ + ret = link_ipipe_prep(ipipe, flags); + if (!ret) { + ret = link_opipe_prep(opipe, flags); + if (!ret) { + ret = link_pipe(ipipe, opipe, len, flags); + if (!ret && (flags & SPLICE_F_NONBLOCK)) + ret = -EAGAIN; + } + } + } - return -EINVAL; + return ret; } asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags) -- cgit v1.2.3 From 522536f6b24e63ac946259af65224f107dff7857 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 28 Jun 2006 19:11:21 -0500 Subject: [PATCH] bcm43xx-softmac: Fix an off-by-one condition in handle_irq_noise An assert statement near the start of handle_irq_noise in the softmac version of bcm43xx_main.c is there to protect against out of bound addressing using variable bcm->noisecalc.nr_samples. The arrays in question have a dimension of 8, thus the value must be < 8. Signed-Off-By: Larry.Finger Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e1c5a939bca..3889f79e712 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1547,7 +1547,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) goto generate_new; /* Get the noise samples. */ - assert(bcm->noisecalc.nr_samples <= 8); + assert(bcm->noisecalc.nr_samples < 8); i = bcm->noisecalc.nr_samples; noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); -- cgit v1.2.3 From b312d799b324e895745ffe148def234fc60d5b74 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 5 Jul 2006 15:57:39 +0100 Subject: [PATCH] zd1211rw: usb_clear_halt not allowed in IRQ context We will reimplement halt-clearing later, when we have periodic housekeeping routines in place. This will do as a temporary fix, the EPIPE case has not yet been seen. Signed-off-by: Daniel Drake Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index ce1cb2c6aa8..72f90525bf6 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -375,10 +375,8 @@ static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) case -ENODEV: case -ENOENT: case -ECONNRESET: - goto kfree; case -EPIPE: - usb_clear_halt(urb->dev, EP_INT_IN); - /* FALL-THROUGH */ + goto kfree; default: goto resubmit; } @@ -580,10 +578,8 @@ static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) case -ENODEV: case -ENOENT: case -ECONNRESET: - return; case -EPIPE: - usb_clear_halt(urb->dev, EP_DATA_IN); - /* FALL-THROUGH */ + return; default: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); goto resubmit; @@ -749,11 +745,9 @@ static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) case -ENODEV: case -ENOENT: case -ECONNRESET: + case -EPIPE: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); break; - case -EPIPE: - usb_clear_halt(urb->dev, EP_DATA_OUT); - /* FALL-THROUGH */ default: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); goto resubmit; -- cgit v1.2.3 From 07a18684c92c0156f87ea158b5adc3022485f82a Mon Sep 17 00:00:00 2001 From: Kristen Accardi Date: Mon, 10 Jul 2006 14:19:15 -0400 Subject: ACPI: ACPI_DOCK: Initialize the atomic notifier list Signed-off-by: Kristen Carlson Accardi Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/dock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 510a9452429..1c0a39d8b04 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -627,6 +627,7 @@ static int dock_add(acpi_handle handle) INIT_LIST_HEAD(&dock_station->hotplug_devices); spin_lock_init(&dock_station->dd_lock); spin_lock_init(&dock_station->hp_lock); + ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -- cgit v1.2.3 From 135c294fa3660b979d71bbce1611f9ca721077b5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Jul 2006 04:43:48 -0700 Subject: [PATCH] don't select CONFIG_HOTPLUG It's useful to be able to turn off CONFIG_HOTPLUG for compile-coverage testing and for section-checking coverage. But a few things go and select CONFIG_HOTPLUG, making it a royal PITA to turn the thing off. It's only turnable offable if CONFIG_EMBEDDED anyway. So let's make those things depend on HOTPLUG, not select it. Cc: Greg KH Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/Kconfig | 2 +- drivers/pci/hotplug/Kconfig | 3 +-- drivers/pcmcia/Kconfig | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 80502dc6ed6..0b4e2243693 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -20,7 +20,7 @@ config PREVENT_FIRMWARE_BUILD config FW_LOADER tristate "Userspace firmware loading support" - select HOTPLUG + depends on HOTPLUG ---help--- This option is provided for the case where no in-kernel-tree modules require userspace firmware loading support, but a module built outside diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 222a1cc4aa2..e94099c3e82 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -6,8 +6,7 @@ menu "PCI Hotplug Support" config HOTPLUG_PCI tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - select HOTPLUG + depends on PCI && EXPERIMENTAL && HOTPLUG ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 61cb4b29f55..35f88649d3b 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -6,7 +6,7 @@ menu "PCCARD (PCMCIA/CardBus) support" config PCCARD tristate "PCCard (PCMCIA/CardBus) support" - select HOTPLUG + depends on HOTPLUG ---help--- Say Y here if you want to attach PCMCIA- or PC-cards to your Linux computer. These are credit-card size devices such as network cards, -- cgit v1.2.3 From 1a91023a9f172f820e292f2c5675fb9f8e2636f0 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Jul 2006 04:43:49 -0700 Subject: [PATCH] x86_64: e820.c needs pgtable.h arch/x86_64/kernel/e820.c:42: error: 'MAXMEM' undeclared here (not in a function) Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/e820.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index b8eee4c7888..e56c2adf57a 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From e45b3b6af09dab2a28a7c88b340d0bcdd173e068 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Jul 2006 04:43:50 -0700 Subject: [PATCH] count_vm_events() fix Dopey bug. Causes hopelessly-wrong numbers from vmstat(8) and several other counters. Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmstat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index 3e0daf54133..d673b7b15c3 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -57,7 +57,7 @@ static inline void __count_vm_events(enum vm_event_item item, long delta) static inline void count_vm_events(enum vm_event_item item, long delta) { - get_cpu_var(vm_event_states.event[item])++; + get_cpu_var(vm_event_states.event[item]) += delta; put_cpu(); } -- cgit v1.2.3 From 0a565f7919cfb3d3df2c97d45751cbb83d858f97 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Mon, 10 Jul 2006 04:43:51 -0700 Subject: [PATCH] sched: fix bug in __migrate_task() Problem: In the function __migrate_task(), deactivate_task() followed by activate_task() is used to move the task from one run queue to another. This has two undesirable effects: 1. The task's priority is recalculated. (Nowhere else in the scheduler code is the priority recalculated for a change of CPU.) 2. The task's time stamp is set to the current time. At the very least, this makes the adjustment of the time stamp before the call to deactivate_task() redundant but I believe the problem is more serious as the time stamp now holds the time of the queue change instead of the time at which the task was woken. In addition, unless dest_rq is the same queue as "current" is on the time stamp could be inaccurate due to inter CPU drift. Solution: Replace the call to activate_task() with one to __activate_task(). Signed-off-by: Peter Williams Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 4ee400f9d56..b47819b676f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4877,7 +4877,7 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) p->timestamp = p->timestamp - rq_src->timestamp_last_tick + rq_dest->timestamp_last_tick; deactivate_task(p, rq_src); - activate_task(p, rq_dest, 0); + __activate_task(p, rq_dest); if (TASK_PREEMPTS_CURR(p, rq_dest)) resched_task(rq_dest->curr); } -- cgit v1.2.3 From 2ed6e34f88a0d896a6f889b00693cae0fadacfd0 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Mon, 10 Jul 2006 04:43:52 -0700 Subject: [PATCH] small kernel/sched.c cleanup - constify and optimize stat_nam (thanks to Michael Tokarev!) - spelling and comment fixes Signed-off-by: Andreas Mohr Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sched.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index b47819b676f..d714611f169 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3384,7 +3384,7 @@ EXPORT_SYMBOL(schedule); #ifdef CONFIG_PREEMPT /* - * this is is the entry point to schedule() from in-kernel preemption + * this is the entry point to schedule() from in-kernel preemption * off of preempt_enable. Kernel preemptions off return from interrupt * occur there and call schedule directly. */ @@ -3427,7 +3427,7 @@ need_resched: EXPORT_SYMBOL(preempt_schedule); /* - * this is is the entry point to schedule() from kernel preemption + * this is the entry point to schedule() from kernel preemption * off of irq context. * Note, that this is called and return with irqs disabled. This will * protect us against recursive calling from irq. @@ -3439,7 +3439,7 @@ asmlinkage void __sched preempt_schedule_irq(void) struct task_struct *task = current; int saved_lock_depth; #endif - /* Catch callers which need to be fixed*/ + /* Catch callers which need to be fixed */ BUG_ON(ti->preempt_count || !irqs_disabled()); need_resched: @@ -4650,7 +4650,7 @@ static inline struct task_struct *younger_sibling(struct task_struct *p) return list_entry(p->sibling.next,struct task_struct,sibling); } -static const char *stat_nam[] = { "R", "S", "D", "T", "t", "Z", "X" }; +static const char stat_nam[] = "RSDTtZX"; static void show_task(struct task_struct *p) { @@ -4658,12 +4658,9 @@ static void show_task(struct task_struct *p) unsigned long free = 0; unsigned state; - printk("%-13.13s ", p->comm); state = p->state ? __ffs(p->state) + 1 : 0; - if (state < ARRAY_SIZE(stat_nam)) - printk(stat_nam[state]); - else - printk("?"); + printk("%-13.13s %c", p->comm, + state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?'); #if (BITS_PER_LONG == 32) if (state == TASK_RUNNING) printk(" running "); @@ -5776,7 +5773,7 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2) cache = vmalloc(max_size); if (!cache) { printk("could not vmalloc %d bytes for cache!\n", 2*max_size); - return 1000000; // return 1 msec on very small boxen + return 1000000; /* return 1 msec on very small boxen */ } while (size <= max_size) { -- cgit v1.2.3 From c312feb2931ded0582378712727b7ea017a951bd Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 10 Jul 2006 04:43:53 -0700 Subject: [PATCH] SELinux: decouple fscontext/context mount options Remove the conflict between fscontext and context mount options. If context= is specified without fscontext it will operate just as before, if both are specified we will use mount point labeling and all inodes will get the label specified by context=. The superblock will be labeled with the label of fscontext=, thus affecting operations which check the superblock security context, such as associate permissions. Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 69 ++++++++++++++++++++++++++++++--------- security/selinux/include/objsec.h | 3 +- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 24caaeec889..7e101dbea4c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -246,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb) sbsec->sb = sb; sbsec->sid = SECINITSID_UNLABELED; sbsec->def_sid = SECINITSID_FILE; + sbsec->mntpoint_sid = SECINITSID_UNLABELED; sb->s_security = sbsec; return 0; @@ -329,9 +330,26 @@ static match_table_t tokens = { #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" +static int may_context_mount_sb_relabel(u32 sid, + struct superblock_security_struct *sbsec, + struct task_security_struct *tsec) +{ + int rc; + + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELFROM, NULL); + if (rc) + return rc; + + rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELTO, NULL); + return rc; +} + static int try_context_mount(struct super_block *sb, void *data) { char *context = NULL, *defcontext = NULL; + char *fscontext = NULL; const char *name; u32 sid; int alloc = 0, rc = 0, seen = 0; @@ -374,7 +392,7 @@ static int try_context_mount(struct super_block *sb, void *data) switch (token) { case Opt_context: - if (seen) { + if (seen & (Opt_context|Opt_defcontext)) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; @@ -390,13 +408,13 @@ static int try_context_mount(struct super_block *sb, void *data) break; case Opt_fscontext: - if (seen & (Opt_context|Opt_fscontext)) { + if (seen & Opt_fscontext) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; } - context = match_strdup(&args[0]); - if (!context) { + fscontext = match_strdup(&args[0]); + if (!fscontext) { rc = -ENOMEM; goto out_free; } @@ -441,29 +459,46 @@ static int try_context_mount(struct super_block *sb, void *data) if (!seen) goto out; - if (context) { - rc = security_context_to_sid(context, strlen(context), &sid); + /* sets the context of the superblock for the fs being mounted. */ + if (fscontext) { + rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", - context, sb->s_id, name, rc); + fscontext, sb->s_id, name, rc); goto out_free; } - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELFROM, NULL); + rc = may_context_mount_sb_relabel(sid, sbsec, tsec); if (rc) goto out_free; - rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELTO, NULL); + sbsec->sid = sid; + } + + /* + * Switch to using mount point labeling behavior. + * sets the label used on all file below the mountpoint, and will set + * the superblock context if not already set. + */ + if (context) { + rc = security_context_to_sid(context, strlen(context), &sid); + if (rc) { + printk(KERN_WARNING "SELinux: security_context_to_sid" + "(%s) failed for (dev %s, type %s) errno=%d\n", + context, sb->s_id, name, rc); + goto out_free; + } + + rc = may_context_mount_sb_relabel(sid, sbsec, tsec); if (rc) goto out_free; - sbsec->sid = sid; + if (!fscontext) + sbsec->sid = sid; + sbsec->mntpoint_sid = sid; - if (seen & Opt_context) - sbsec->behavior = SECURITY_FS_USE_MNTPOINT; + sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } if (defcontext) { @@ -495,6 +530,7 @@ out_free: if (alloc) { kfree(context); kfree(defcontext); + kfree(fscontext); } out: return rc; @@ -876,8 +912,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out; isec->sid = sid; break; + case SECURITY_FS_USE_MNTPOINT: + isec->sid = sbsec->mntpoint_sid; + break; default: - /* Default to the fs SID. */ + /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; if (sbsec->proc) { diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index cf54a304169..940178865fc 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -57,8 +57,9 @@ struct file_security_struct { struct superblock_security_struct { struct super_block *sb; /* back pointer to sb object */ struct list_head list; /* list of superblock_security_struct */ - u32 sid; /* SID of file system */ + u32 sid; /* SID of file system superblock */ u32 def_sid; /* default SID for labeling */ + u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior; /* labeling behavior */ unsigned char initialized; /* initialization flag */ unsigned char proc; /* proc fs */ -- cgit v1.2.3 From 0808925ea5684a0ce25483b30e94d4f398804978 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 10 Jul 2006 04:43:55 -0700 Subject: [PATCH] SELinux: add rootcontext= option to label root inode when mounting Introduce a new rootcontext= option to FS mounting. This option will allow you to explicitly label the root inode of an FS being mounted before that FS or inode because visible to userspace. This was found to be useful for things like stateless linux, see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=190001 Signed-off-by: Eric Paris Acked-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 66 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7e101dbea4c..2e8b4dfcbc7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -320,12 +320,14 @@ enum { Opt_context = 1, Opt_fscontext = 2, Opt_defcontext = 4, + Opt_rootcontext = 8, }; static match_table_t tokens = { {Opt_context, "context=%s"}, {Opt_fscontext, "fscontext=%s"}, {Opt_defcontext, "defcontext=%s"}, + {Opt_rootcontext, "rootcontext=%s"}, }; #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" @@ -346,10 +348,25 @@ static int may_context_mount_sb_relabel(u32 sid, return rc; } +static int may_context_mount_inode_relabel(u32 sid, + struct superblock_security_struct *sbsec, + struct task_security_struct *tsec) +{ + int rc; + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELFROM, NULL); + if (rc) + return rc; + + rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__ASSOCIATE, NULL); + return rc; +} + static int try_context_mount(struct super_block *sb, void *data) { char *context = NULL, *defcontext = NULL; - char *fscontext = NULL; + char *fscontext = NULL, *rootcontext = NULL; const char *name; u32 sid; int alloc = 0, rc = 0, seen = 0; @@ -423,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data) seen |= Opt_fscontext; break; + case Opt_rootcontext: + if (seen & Opt_rootcontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_free; + } + rootcontext = match_strdup(&args[0]); + if (!rootcontext) { + rc = -ENOMEM; + goto out_free; + } + if (!alloc) + alloc = 1; + seen |= Opt_rootcontext; + break; + case Opt_defcontext: if (sbsec->behavior != SECURITY_FS_USE_XATTR) { rc = -EINVAL; @@ -501,6 +534,25 @@ static int try_context_mount(struct super_block *sb, void *data) sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } + if (rootcontext) { + struct inode *inode = sb->s_root->d_inode; + struct inode_security_struct *isec = inode->i_security; + rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); + if (rc) { + printk(KERN_WARNING "SELinux: security_context_to_sid" + "(%s) failed for (dev %s, type %s) errno=%d\n", + rootcontext, sb->s_id, name, rc); + goto out_free; + } + + rc = may_context_mount_inode_relabel(sid, sbsec, tsec); + if (rc) + goto out_free; + + isec->sid = sid; + isec->initialized = 1; + } + if (defcontext) { rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); if (rc) { @@ -513,13 +565,7 @@ static int try_context_mount(struct super_block *sb, void *data) if (sid == sbsec->def_sid) goto out_free; - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELFROM, NULL); - if (rc) - goto out_free; - - rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__ASSOCIATE, NULL); + rc = may_context_mount_inode_relabel(sid, sbsec, tsec); if (rc) goto out_free; @@ -531,6 +577,7 @@ out_free: kfree(context); kfree(defcontext); kfree(fscontext); + kfree(rootcontext); } out: return rc; @@ -1882,7 +1929,8 @@ static inline int selinux_option(char *option, int len) { return (match_prefix("context=", sizeof("context=")-1, option, len) || match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || - match_prefix("defcontext=", sizeof("defcontext=")-1, option, len)); + match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || + match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); } static inline void take_option(char **to, char *from, int *first, int len) -- cgit v1.2.3 From 73ce5934e2d855db436566297f12966eb507a435 Mon Sep 17 00:00:00 2001 From: Hisashi Hifumi Date: Mon, 10 Jul 2006 04:43:56 -0700 Subject: [PATCH] reiserfs: fix journaling issue regarding fsync() When write() extends a file(i_size is increased) and fsync() is called, change of inode must be written to journaling area through fsync(). But,currently the i_trans_id is not correctly updated when i_size is increased. So fsync() does not kick the journal writer. Reiserfs_file_write() already updates the transaction when blocks are allocated, but the case when i_size increases and new blocks are not added is not correctly treated. Following patch fix this bug. Signed-off-by: Hisashi Hifumi Cc: Jeff Mahoney Cc: Chris Mason Cc: Hans Reiser Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/reiserfs/file.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 752cea12e30..f318b58510f 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -860,8 +860,12 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han // this sets the proper flags for O_SYNC to trigger a commit mark_inode_dirty(inode); reiserfs_write_unlock(inode->i_sb); - } else + } else { + reiserfs_write_lock(inode->i_sb); + reiserfs_update_inode_transaction(inode); mark_inode_dirty(inode); + reiserfs_write_unlock(inode->i_sb); + } sd_update = 1; } -- cgit v1.2.3 From 64552a50bc80fecb73617336bf197375868faf6e Mon Sep 17 00:00:00 2001 From: Horms Date: Mon, 10 Jul 2006 04:43:58 -0700 Subject: [PATCH] nfs: Update Documentation/nfsroot.txt to include dhcp, syslinux and isolinux * Document the ip command a little differently to make the interaction between defaults and autoconfiguration a little clearer (I hope) * Update autoconfiguration the current set of options, including DHCP * Update the boot methods to add syslinux and isolinux, and remove dd of=/dev/fd0 which is no longer supported by linux * Add a referance to initramfs along side initrd. Should the latter and its document be removed some time soon? * Various cleanups to put the text consistently into the thrid person * Reformated a bit to fit into 80 columns a bit more nicely * Should the bootloaders documentation be removed or split into a separate documentation, it seems somewhat out of scope Signed-off-by: Horms Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/nfsroot.txt | 275 +++++++++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 115 deletions(-) diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt index d56dc71d943..3cc953cb288 100644 --- a/Documentation/nfsroot.txt +++ b/Documentation/nfsroot.txt @@ -4,15 +4,16 @@ Mounting the root filesystem via NFS (nfsroot) Written 1996 by Gero Kuhlmann Updated 1997 by Martin Mares Updated 2006 by Nico Schottelius +Updated 2006 by Horms -If you want to use a diskless system, as an X-terminal or printer -server for example, you have to put your root filesystem onto a -non-disk device. This can either be a ramdisk (see initrd.txt in -this directory for further information) or a filesystem mounted -via NFS. The following text describes on how to use NFS for the -root filesystem. For the rest of this text 'client' means the +In order to use a diskless system, such as an X-terminal or printer server +for example, it is necessary for the root filesystem to be present on a +non-disk device. This may be an initramfs (see Documentation/filesystems/ +ramfs-rootfs-initramfs.txt), a ramdisk (see Documenation/initrd.txt) or a +filesystem mounted via NFS. The following text describes on how to use NFS +for the root filesystem. For the rest of this text 'client' means the diskless system, and 'server' means the NFS server. @@ -21,11 +22,13 @@ diskless system, and 'server' means the NFS server. 1.) Enabling nfsroot capabilities ----------------------------- -In order to use nfsroot you have to select support for NFS during -kernel configuration. Note that NFS cannot be loaded as a module -in this case. The configuration script will then ask you whether -you want to use nfsroot, and if yes what kind of auto configuration -system you want to use. Selecting both BOOTP and RARP is safe. +In order to use nfsroot, NFS client support needs to be selected as +built-in during configuration. Once this has been selected, the nfsroot +option will become available, which should also be selected. + +In the networking options, kernel level autoconfiguration can be selected, +along with the types of autoconfiguration to support. Selecting all of +DHCP, BOOTP and RARP is safe. @@ -33,11 +36,10 @@ system you want to use. Selecting both BOOTP and RARP is safe. 2.) Kernel command line ------------------- -When the kernel has been loaded by a boot loader (either by loadlin, -LILO or a network boot program) it has to be told what root fs device -to use, and where to find the server and the name of the directory -on the server to mount as root. This can be established by a couple -of kernel command line parameters: +When the kernel has been loaded by a boot loader (see below) it needs to be +told what root fs device to use. And in the case of nfsroot, where to find +both the server and the name of the directory on the server to mount as root. +This can be established using the following kernel command line parameters: root=/dev/nfs @@ -49,23 +51,21 @@ root=/dev/nfs nfsroot=[:][,] - If the `nfsroot' parameter is NOT given on the command line, the default - "/tftpboot/%s" will be used. + If the `nfsroot' parameter is NOT given on the command line, + the default "/tftpboot/%s" will be used. - Specifies the IP address of the NFS server. If this field - is not given, the default address as determined by the - `ip' variable (see below) is used. One use of this - parameter is for example to allow using different servers - for RARP and NFS. Usually you can leave this blank. + Specifies the IP address of the NFS server. + The default address is determined by the `ip' parameter + (see below). This parameter allows the use of different + servers for IP autoconfiguration and NFS. - Name of the directory on the server to mount as root. If - there is a "%s" token in the string, the token will be - replaced by the ASCII-representation of the client's IP - address. + Name of the directory on the server to mount as root. + If there is a "%s" token in the string, it will be + replaced by the ASCII-representation of the client's + IP address. Standard NFS options. All options are separated by commas. - If the options field is not given, the following defaults - will be used: + The following defaults are used: port = as given by server portmap daemon rsize = 1024 wsize = 1024 @@ -81,129 +81,174 @@ nfsroot=[:][,] ip=:::::: This parameter tells the kernel how to configure IP addresses of devices - and also how to set up the IP routing table. It was originally called `nfsaddrs', - but now the boot-time IP configuration works independently of NFS, so it - was renamed to `ip' and the old name remained as an alias for compatibility - reasons. + and also how to set up the IP routing table. It was originally called + `nfsaddrs', but now the boot-time IP configuration works independently of + NFS, so it was renamed to `ip' and the old name remained as an alias for + compatibility reasons. If this parameter is missing from the kernel command line, all fields are assumed to be empty, and the defaults mentioned below apply. In general - this means that the kernel tries to configure everything using both - RARP and BOOTP (depending on what has been enabled during kernel confi- - guration, and if both what protocol answer got in first). + this means that the kernel tries to configure everything using + autoconfiguration. + + The parameter can appear alone as the value to the `ip' + parameter (without all the ':' characters before) in which case auto- + configuration is used. + + IP address of the client. - IP address of the client. If empty, the address will either - be determined by RARP or BOOTP. What protocol is used de- - pends on what has been enabled during kernel configuration - and on the parameter. If this parameter is not - empty, neither RARP nor BOOTP will be used. + Default: Determined using autoconfiguration. IP address of the NFS server. If RARP is used to determine the client address and this parameter is NOT empty only - replies from the specified server are accepted. To use - different RARP and NFS server, specify your RARP server - here (or leave it blank), and specify your NFS server in - the `nfsroot' parameter (see above). If this entry is blank - the address of the server is used which answered the RARP - or BOOTP request. - - IP address of a gateway if the server is on a different - subnet. If this entry is empty no gateway is used and the - server is assumed to be on the local network, unless a - value has been received by BOOTP. - - Netmask for local network interface. If this is empty, + replies from the specified server are accepted. + + Only required for for NFS root. That is autoconfiguration + will not be triggered if it is missing and NFS root is not + in operation. + + Default: Determined using autoconfiguration. + The address of the autoconfiguration server is used. + + IP address of a gateway if the server is on a different subnet. + + Default: Determined using autoconfiguration. + + Netmask for local network interface. If unspecified the netmask is derived from the client IP address assuming - classful addressing, unless overridden in BOOTP reply. + classful addressing. - Name of the client. If empty, the client IP address is - used in ASCII notation, or the value received by BOOTP. + Default: Determined using autoconfiguration. - Name of network device to use. If this is empty, all - devices are used for RARP and BOOTP requests, and the - first one we receive a reply on is configured. If you have - only one device, you can safely leave this blank. + Name of the client. May be supplied by autoconfiguration, + but its absence will not trigger autoconfiguration. - Method to use for autoconfiguration. If this is either - 'rarp' or 'bootp', the specified protocol is used. - If the value is 'both' or empty, both protocols are used - so far as they have been enabled during kernel configura- - tion. 'off' means no autoconfiguration. + Default: Client IP address is used in ASCII notation. - The parameter can appear alone as the value to the `ip' - parameter (without all the ':' characters before) in which case auto- - configuration is used. + Name of network device to use. + + Default: If the host only has one device, it is used. + Otherwise the device is determined using + autoconfiguration. This is done by sending + autoconfiguration requests out of all devices, + and using the device that received the first reply. + Method to use for autoconfiguration. In the case of options + which specify multiple autoconfiguration protocols, + requests are sent using all protocols, and the first one + to reply is used. + Only autoconfiguration protocols that have been compiled + into the kernel will be used, regardless of the value of + this option. + off or none: don't use autoconfiguration (default) + on or any: use any protocol available in the kernel + dhcp: use DHCP + bootp: use BOOTP + rarp: use RARP + both: use both BOOTP and RARP but not DHCP + (old option kept for backwards compatibility) -3.) Kernel loader - ------------- + Default: any -To get the kernel into memory different approaches can be used. They -depend on what facilities are available: -3.1) Writing the kernel onto a floppy using dd: - As always you can just write the kernel onto a floppy using dd, - but then it's not possible to use kernel command lines at all. - To substitute the 'root=' parameter, create a dummy device on any - linux system with major number 0 and minor number 255 using mknod: - mknod /dev/boot255 c 0 255 +3.) Boot Loader + ---------- - Then copy the kernel zImage file onto a floppy using dd: +To get the kernel into memory different approaches can be used. +They depend on various facilities being available: - dd if=/usr/src/linux/arch/i386/boot/zImage of=/dev/fd0 - And finally use rdev to set the root device: +3.1) Booting from a floppy using syslinux - rdev /dev/fd0 /dev/boot255 + When building kernels, an easy way to create a boot floppy that uses + syslinux is to use the zdisk or bzdisk make targets which use + and bzimage images respectively. Both targets accept the + FDARGS parameter which can be used to set the kernel command line. - You can then remove the dummy device /dev/boot255 again. There - is no real device available for it. - The other two kernel command line parameters cannot be substi- - tuted with rdev. Therefore, using this method the kernel will - by default use RARP and/or BOOTP, and if it gets an answer via - RARP will mount the directory /tftpboot// as its - root. If it got a BOOTP answer the directory name in that answer - is used. + e.g. + make bzdisk FDARGS="root=/dev/nfs" + + Note that the user running this command will need to have + access to the floppy drive device, /dev/fd0 + + For more information on syslinux, including how to create bootdisks + for prebuilt kernels, see http://syslinux.zytor.com/ + + N.B: Previously it was possible to write a kernel directly to + a floppy using dd, configure the boot device using rdev, and + boot using the resulting floppy. Linux no longer supports this + method of booting. + +3.2) Booting from a cdrom using isolinux + + When building kernels, an easy way to create a bootable cdrom that + uses isolinux is to use the isoimage target which uses a bzimage + image. Like zdisk and bzdisk, this target accepts the FDARGS + parameter which can be used to set the kernel command line. + + e.g. + make isoimage FDARGS="root=/dev/nfs" + + The resulting iso image will be arch//boot/image.iso + This can be written to a cdrom using a variety of tools including + cdrecord. + + e.g. + cdrecord dev=ATAPI:1,0,0 arch/i386/boot/image.iso + + For more information on isolinux, including how to create bootdisks + for prebuilt kernels, see http://syslinux.zytor.com/ 3.2) Using LILO - When using LILO you can specify all necessary command line - parameters with the 'append=' command in the LILO configuration - file. However, to use the 'root=' command you also need to - set up a dummy device as described in 3.1 above. For how to use - LILO and its 'append=' command please refer to the LILO - documentation. + When using LILO all the necessary command line parameters may be + specified using the 'append=' directive in the LILO configuration + file. + + However, to use the 'root=' directive you also need to create + a dummy root device, which may be removed after LILO is run. + + mknod /dev/boot255 c 0 255 + + For information on configuring LILO, please refer to its documentation. 3.3) Using GRUB - When you use GRUB, you simply append the parameters after the kernel - specification: "kernel " (without the quotes). + When using GRUB, kernel parameter are simply appended after the kernel + specification: kernel 3.4) Using loadlin - When you want to boot Linux from a DOS command prompt without - having a local hard disk to mount as root, you can use loadlin. - I was told that it works, but haven't used it myself yet. In - general you should be able to create a kernel command line simi- - lar to how LILO is doing it. Please refer to the loadlin docu- - mentation for further information. + loadlin may be used to boot Linux from a DOS command prompt without + requiring a local hard disk to mount as root. This has not been + thoroughly tested by the authors of this document, but in general + it should be possible configure the kernel command line similarly + to the configuration of LILO. + + Please refer to the loadlin documentation for further information. 3.5) Using a boot ROM - This is probably the most elegant way of booting a diskless - client. With a boot ROM the kernel gets loaded using the TFTP - protocol. As far as I know, no commercial boot ROMs yet - support booting Linux over the network, but there are two - free implementations of a boot ROM available on sunsite.unc.edu - and its mirrors. They are called 'netboot-nfs' and 'etherboot'. - Both contain everything you need to boot a diskless Linux client. + This is probably the most elegant way of booting a diskless client. + With a boot ROM the kernel is loaded using the TFTP protocol. The + authors of this document are not aware of any no commercial boot + ROMs that support booting Linux over the network. However, there + are two free implementations of a boot ROM, netboot-nfs and + etherboot, both of which are available on sunsite.unc.edu, and both + of which contain everything you need to boot a diskless Linux client. 3.6) Using pxelinux - Using pxelinux you specify the kernel you built with + Pxelinux may be used to boot linux using the PXE boot loader + which is present on many modern network cards. + + When using pxelinux, the kernel image is specified using "kernel ". The nfsroot parameters are passed to the kernel by adding them to the "append" line. - You may perhaps also want to fine tune the console output, - see Documentation/serial-console.txt for serial console help. + It is common to use serial console in conjunction with pxeliunx, + see Documentation/serial-console.txt for more information. + + For more information on isolinux, including how to create bootdisks + for prebuilt kernels, see http://syslinux.zytor.com/ -- cgit v1.2.3 From eb0e71c7f388bfcb3f74897f23d0cf09310fc05b Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Mon, 10 Jul 2006 04:43:59 -0700 Subject: [PATCH] Add Computone IntelliPort Plus serial hotplug support Patch Description: Add "Computone IntelliPort Plus serial" hotplug support patch location: http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=8c36723187c0fa5efe0e5c6a9b1e66ed4b824792 [akpm@osdl.org: cleanup] Cc: Randy Dunlap Signed-off-by: Chuck Short Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ip2/ip2main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 518ece7ac65..7907ae88c2f 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -3186,3 +3186,10 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo MODULE_LICENSE("GPL"); + +static struct pci_device_id ip2main_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl); -- cgit v1.2.3 From 7691030bc9732f7d535522dda78cfdd36716def1 Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Mon, 10 Jul 2006 04:43:59 -0700 Subject: [PATCH] Add Specialix IO8+ card support hotplug support Patch Description: Add "Specialix IO8+ card support" hotplug support patch location: http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=d795cfc591bb44f6b3d86d8f054a227cecb44bb4 [akpm@osdl.org: cleanup] Cc: Randy Dunlap Signed-off-by: Chuck Short Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/specialix.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index cb2859249d4..a1d303f9a33 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2584,6 +2584,12 @@ static void __exit specialix_exit_module(void) func_exit(); } +static struct pci_device_id specialx_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) }, + { } +}; +MODULE_DEVICE_TABLE(pci, specialx_pci_tbl); + module_init(specialix_init_module); module_exit(specialix_exit_module); -- cgit v1.2.3 From 25e206b54b9a20e63b6f5194aeebfa13d37e015c Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 10 Jul 2006 04:44:00 -0700 Subject: [PATCH] partitions: let partitions inherit policy from disk Change the partition code in fs/partitions/check.c to initialize a newly detected partition's policy field with that of the containing block device (see patch below). My reasoning is that function set_disk_ro() in block/genhd.c modifies the policy field (read-only indicator) of a disk and all contained partitions. When a partition is detected after the call to set_disk_ro(), the policy field of this partition will currently not inherit the disk's policy field. This behavior poses a problem in cases where a block device can be 'logically de- and reactivated' like e.g. the s390 DASD driver because partition detection may run after the policy field has been modified. Signed-off-by: Peter Oberparleiter Acked-by: Al Viro Makes-sense-to: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/partitions/check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 839634026eb..51c6a748df4 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -339,6 +339,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) p->start_sect = start; p->nr_sects = len; p->partno = part; + p->policy = disk->policy; if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); -- cgit v1.2.3 From 8f72e4028a1ff968000cec4a034f45619fbd7ec4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 10 Jul 2006 04:44:01 -0700 Subject: [PATCH] fadvise: remove dead comments Cc: "Michael Kerrisk" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/fadvise.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/mm/fadvise.c b/mm/fadvise.c index 0a03357a1f8..60a5d55e51d 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -23,18 +23,6 @@ /* * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could * deactivate the pages and clear PG_Referenced. - * - * LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file - * offsets `offset' and `offset+len' inclusive. Any pages which are currently - * under writeout are skipped, whether or not they are dirty. - * - * LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file - * offsets `offset' and `offset+len'. - * - * By combining these two operations the application may do several things: - * - * LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk. - * */ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) { -- cgit v1.2.3 From f9829cceb686f3719215fe43c8593e5f3efe1710 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 10 Jul 2006 04:44:01 -0700 Subject: [PATCH] Minor cleanup to lockdep.c - Use printk formatting for indentation - Don't leave NTFS in the default event filter Signed-off-by: Andi Kleen Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index f32ca78c198..42af5cc31a4 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -169,22 +169,17 @@ EXPORT_SYMBOL(lockdep_internal); */ static int class_filter(struct lock_class *class) { +#if 0 + /* Example */ if (class->name_version == 1 && - !strcmp(class->name, "&rl->lock")) + !strcmp(class->name, "lockname")) return 1; if (class->name_version == 1 && - !strcmp(class->name, "&ni->mrec_lock")) + !strcmp(class->name, "&struct->lockfield")) return 1; - if (class->name_version == 1 && - !strcmp(class->name, "mft_ni_runlist_lock")) - return 1; - if (class->name_version == 1 && - !strcmp(class->name, "mft_ni_mrec_lock")) - return 1; - if (class->name_version == 1 && - !strcmp(class->name, "&vol->lcnbmp_lock")) - return 1; - return 0; +#endif + /* Allow everything else. 0 would be filter everything else */ + return 1; } #endif @@ -408,23 +403,12 @@ static void lockdep_print_held_locks(struct task_struct *curr) print_lock(curr->held_locks + i); } } -/* - * Helper to print a nice hierarchy of lock dependencies: - */ -static void print_spaces(int nr) -{ - int i; - - for (i = 0; i < nr; i++) - printk(" "); -} static void print_lock_class_header(struct lock_class *class, int depth) { int bit; - print_spaces(depth); - printk("->"); + printk("%*s->", depth, ""); print_lock_name(class); printk(" ops: %lu", class->ops); printk(" {\n"); @@ -433,17 +417,14 @@ static void print_lock_class_header(struct lock_class *class, int depth) if (class->usage_mask & (1 << bit)) { int len = depth; - print_spaces(depth); - len += printk(" %s", usage_str[bit]); + len += printk("%*s %s", depth, "", usage_str[bit]); len += printk(" at:\n"); print_stack_trace(class->usage_traces + bit, len); } } - print_spaces(depth); - printk(" }\n"); + printk("%*s }\n", depth, ""); - print_spaces(depth); - printk(" ... key at: "); + printk("%*s ... key at: ",depth,""); print_ip_sym((unsigned long)class->key); } @@ -463,8 +444,7 @@ static void print_lock_dependencies(struct lock_class *class, int depth) DEBUG_LOCKS_WARN_ON(!entry->class); print_lock_dependencies(entry->class, depth + 1); - print_spaces(depth); - printk(" ... acquired at:\n"); + printk("%*s ... acquired at:\n",depth,""); print_stack_trace(&entry->trace, 2); printk("\n"); } -- cgit v1.2.3 From 5fca80e8b4bf5d69b900115b14342133ce81d79e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 10 Jul 2006 04:44:02 -0700 Subject: [PATCH] lockdep: add more rwsem.h documentation Add more documentation to rwsem.h. Signed-off-by: Ingo Molnar Cc: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/rwsem.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index 658afb37c3f..7b524b4109a 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -61,12 +61,25 @@ extern void downgrade_write(struct rw_semaphore *sem); #ifdef CONFIG_DEBUG_LOCK_ALLOC /* - * nested locking: + * nested locking. NOTE: rwsems are not allowed to recurse + * (which occurs if the same task tries to acquire the same + * lock instance multiple times), but multiple locks of the + * same lock class might be taken, if the order of the locks + * is always the same. This ordering rule can be expressed + * to lockdep via the _nested() APIs, but enumerating the + * subclasses that are used. (If the nesting relationship is + * static then another method for expressing nested locking is + * the explicit definition of lock class keys and the use of + * lockdep_set_class() at lock initialization time. + * See Documentation/lockdep-design.txt for more details.) */ extern void down_read_nested(struct rw_semaphore *sem, int subclass); extern void down_write_nested(struct rw_semaphore *sem, int subclass); /* - * Take/release a lock when not the owner will release it: + * Take/release a lock when not the owner will release it. + * + * [ This API should be avoided as much as possible - the + * proper abstraction for this case is completions. ] */ extern void down_read_non_owner(struct rw_semaphore *sem); extern void up_read_non_owner(struct rw_semaphore *sem); -- cgit v1.2.3 From 55794a412fdf9af1744800e5020a4ec6b21e3cdc Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 10 Jul 2006 04:44:03 -0700 Subject: [PATCH] lockdep: improve debug output Make lockdep print which lock is held, in the "kfree() of a live lock" scenario. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/lockdep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 42af5cc31a4..c1f34addd00 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -2551,7 +2551,7 @@ static inline int in_range(const void *start, const void *addr, const void *end) static void print_freed_lock_bug(struct task_struct *curr, const void *mem_from, - const void *mem_to) + const void *mem_to, struct held_lock *hlock) { if (!debug_locks_off()) return; @@ -2563,6 +2563,7 @@ print_freed_lock_bug(struct task_struct *curr, const void *mem_from, printk( "-------------------------\n"); printk("%s/%d is freeing memory %p-%p, with a lock still held there!\n", curr->comm, curr->pid, mem_from, mem_to-1); + print_lock(hlock); lockdep_print_held_locks(curr); printk("\nstack backtrace:\n"); @@ -2596,7 +2597,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) !in_range(mem_from, lock_to, mem_to)) continue; - print_freed_lock_bug(curr, mem_from, mem_to); + print_freed_lock_bug(curr, mem_from, mem_to, hlock); break; } local_irq_restore(flags); -- cgit v1.2.3 From d6d897cec29252b8d0785198cfa6ca16d30c739d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 10 Jul 2006 04:44:04 -0700 Subject: [PATCH] lockdep: core, reduce per-lock class-cache size lockdep_map is embedded into every lock, which blows up data structure sizes all around the kernel. Reduce the class-cache to be for the default class only - that is used in 99.9% of the cases and even if we dont have a class cached, the lookup in the class-hash is lockless. This change reduces the per-lock dep_map overhead by 56 bytes on 64-bit platforms and by 28 bytes on 32-bit platforms. Signed-off-by: Ingo Molnar Cc: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/lockdep.h | 2 +- kernel/lockdep.c | 87 ++++++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 316e0fb8d7b..c040a8c969a 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -120,7 +120,7 @@ struct lock_class { */ struct lockdep_map { struct lock_class_key *key; - struct lock_class *class[MAX_LOCKDEP_SUBCLASSES]; + struct lock_class *class_cache; const char *name; }; diff --git a/kernel/lockdep.c b/kernel/lockdep.c index c1f34addd00..9bad1788451 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -1104,7 +1104,7 @@ extern void __error_too_big_MAX_LOCKDEP_SUBCLASSES(void); * itself, so actual lookup of the hash should be once per lock object. */ static inline struct lock_class * -register_lock_class(struct lockdep_map *lock, unsigned int subclass) +look_up_lock_class(struct lockdep_map *lock, unsigned int subclass) { struct lockdep_subclass_key *key; struct list_head *hash_head; @@ -1148,7 +1148,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass) */ list_for_each_entry(class, hash_head, hash_entry) if (class->key == key) - goto out_set; + return class; + + return NULL; +} + +/* + * Register a lock's class in the hash-table, if the class is not present + * yet. Otherwise we look it up. We cache the result in the lock object + * itself, so actual lookup of the hash should be once per lock object. + */ +static inline struct lock_class * +register_lock_class(struct lockdep_map *lock, unsigned int subclass) +{ + struct lockdep_subclass_key *key; + struct list_head *hash_head; + struct lock_class *class; + + class = look_up_lock_class(lock, subclass); + if (likely(class)) + return class; /* * Debug-check: all keys must be persistent! @@ -1163,6 +1182,9 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass) return NULL; } + key = lock->key->subkeys + subclass; + hash_head = classhashentry(key); + __raw_spin_lock(&hash_lock); /* * We have to do the hash-walk again, to avoid races @@ -1209,8 +1231,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass) out_unlock_set: __raw_spin_unlock(&hash_lock); -out_set: - lock->class[subclass] = class; + if (!subclass) + lock->class_cache = class; DEBUG_LOCKS_WARN_ON(class->subclass != subclass); @@ -1914,7 +1936,7 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name, } lock->name = name; lock->key = key; - memset(lock->class, 0, sizeof(lock->class[0])*MAX_LOCKDEP_SUBCLASSES); + lock->class_cache = NULL; } EXPORT_SYMBOL_GPL(lockdep_init_map); @@ -1928,8 +1950,8 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, unsigned long ip) { struct task_struct *curr = current; + struct lock_class *class = NULL; struct held_lock *hlock; - struct lock_class *class; unsigned int depth, id; int chain_head = 0; u64 chain_key; @@ -1947,8 +1969,11 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, return 0; } - class = lock->class[subclass]; - /* not cached yet? */ + if (!subclass) + class = lock->class_cache; + /* + * Not cached yet or subclass? + */ if (unlikely(!class)) { class = register_lock_class(lock, subclass); if (!class) @@ -2449,48 +2474,44 @@ void lockdep_free_key_range(void *start, unsigned long size) void lockdep_reset_lock(struct lockdep_map *lock) { - struct lock_class *class, *next, *entry; + struct lock_class *class, *next; struct list_head *head; unsigned long flags; int i, j; raw_local_irq_save(flags); - __raw_spin_lock(&hash_lock); /* - * Remove all classes this lock has: + * Remove all classes this lock might have: + */ + for (j = 0; j < MAX_LOCKDEP_SUBCLASSES; j++) { + /* + * If the class exists we look it up and zap it: + */ + class = look_up_lock_class(lock, j); + if (class) + zap_class(class); + } + /* + * Debug check: in the end all mapped classes should + * be gone. */ + __raw_spin_lock(&hash_lock); for (i = 0; i < CLASSHASH_SIZE; i++) { head = classhash_table + i; if (list_empty(head)) continue; list_for_each_entry_safe(class, next, head, hash_entry) { - for (j = 0; j < MAX_LOCKDEP_SUBCLASSES; j++) { - entry = lock->class[j]; - if (class == entry) { - zap_class(class); - lock->class[j] = NULL; - break; - } + if (unlikely(class == lock->class_cache)) { + __raw_spin_unlock(&hash_lock); + DEBUG_LOCKS_WARN_ON(1); + goto out_restore; } } } - - /* - * Debug check: in the end all mapped classes should - * be gone. - */ - for (j = 0; j < MAX_LOCKDEP_SUBCLASSES; j++) { - entry = lock->class[j]; - if (!entry) - continue; - __raw_spin_unlock(&hash_lock); - DEBUG_LOCKS_WARN_ON(1); - raw_local_irq_restore(flags); - return; - } - __raw_spin_unlock(&hash_lock); + +out_restore: raw_local_irq_restore(flags); } -- cgit v1.2.3 From f86bf9b7bcc5d325687a8b80da8ee3eb56e02da7 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 10 Jul 2006 04:44:05 -0700 Subject: [PATCH] lockdep: clean up completion initializer in smpboot.c Clean up lockdep on-stack-completion initializer. (This also removes the dependency on waitqueue_lock_key.) Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/smpboot.c | 4 +--- include/linux/completion.h | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index b7c70596979..975380207b4 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -771,12 +771,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid) unsigned long start_rip; struct create_idle c_idle = { .cpu = cpu, - .done = COMPLETION_INITIALIZER(c_idle.done), + .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), }; DECLARE_WORK(work, do_fork_idle, &c_idle); - lockdep_set_class(&c_idle.done.wait.lock, &waitqueue_lock_key); - /* allocate memory for gdts of secondary cpus. Hotplug is considered */ if (!cpu_gdt_descr[cpu].address && !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) { diff --git a/include/linux/completion.h b/include/linux/completion.h index 251c41e3ddd..268c5a4a2bd 100644 --- a/include/linux/completion.h +++ b/include/linux/completion.h @@ -18,6 +18,9 @@ struct completion { #define COMPLETION_INITIALIZER(work) \ { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) } +#define COMPLETION_INITIALIZER_ONSTACK(work) \ + ({ init_completion(&work); work; }) + #define DECLARE_COMPLETION(work) \ struct completion work = COMPLETION_INITIALIZER(work) @@ -28,7 +31,7 @@ struct completion { */ #ifdef CONFIG_LOCKDEP # define DECLARE_COMPLETION_ONSTACK(work) \ - struct completion work = ({ init_completion(&work); work; }) + struct completion work = COMPLETION_INITIALIZER_ONSTACK(work) #else # define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work) #endif -- cgit v1.2.3 From 1454aed92b6b89cb1fbe3cbecd8ceaa7a122f3b7 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 10 Jul 2006 04:44:05 -0700 Subject: [PATCH] put a comment at register_die_notifier that the export is used {un}register_die_notifier() is used by kdb... document this so that future "remove dead export" rounds can skip this export. Signed-off-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/traps.c | 4 ++-- arch/x86_64/kernel/traps.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 2bf8b55b91f..5cfd4f42eeb 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -100,13 +100,13 @@ int register_die_notifier(struct notifier_block *nb) vmalloc_sync_all(); return atomic_notifier_chain_register(&i386die_chain, nb); } -EXPORT_SYMBOL(register_die_notifier); +EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ int unregister_die_notifier(struct notifier_block *nb) { return atomic_notifier_chain_unregister(&i386die_chain, nb); } -EXPORT_SYMBOL(unregister_die_notifier); +EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) { diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 79d05c48207..eb39a277523 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -76,13 +76,13 @@ int register_die_notifier(struct notifier_block *nb) vmalloc_sync_all(); return atomic_notifier_chain_register(&die_chain, nb); } -EXPORT_SYMBOL(register_die_notifier); +EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ int unregister_die_notifier(struct notifier_block *nb) { return atomic_notifier_chain_unregister(&die_chain, nb); } -EXPORT_SYMBOL(unregister_die_notifier); +EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ static inline void conditional_sti(struct pt_regs *regs) { -- cgit v1.2.3 From 82a854ec4f46c5fbef11b06bb49078ecc5784a2d Mon Sep 17 00:00:00 2001 From: Urs Thuermann Date: Mon, 10 Jul 2006 04:44:06 -0700 Subject: [PATCH] RCU Documentation fix Updater should use _rcu variant of list_del(). Signed-off-by: Urs Thuermann Acked-by: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/RCU/whatisRCU.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 4f41a60e511..318df44259b 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -687,8 +687,9 @@ diff shows how closely related RCU and reader-writer locking can be. + spin_lock(&listmutex); list_for_each_entry(p, head, lp) { if (p->key == key) { - list_del(&p->list); + - list_del(&p->list); - write_unlock(&listmutex); + + list_del_rcu(&p->list); + spin_unlock(&listmutex); + synchronize_rcu(); kfree(p); @@ -736,7 +737,7 @@ Or, for those who prefer a side-by-side listing: 5 write_lock(&listmutex); 5 spin_lock(&listmutex); 6 list_for_each_entry(p, head, lp) { 6 list_for_each_entry(p, head, lp) { 7 if (p->key == key) { 7 if (p->key == key) { - 8 list_del(&p->list); 8 list_del(&p->list); + 8 list_del(&p->list); 8 list_del_rcu(&p->list); 9 write_unlock(&listmutex); 9 spin_unlock(&listmutex); 10 synchronize_rcu(); 10 kfree(p); 11 kfree(p); -- cgit v1.2.3 From 5d8b2ebfa298ec4e6d9fa43e60fb013e8cd963aa Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 10 Jul 2006 04:44:07 -0700 Subject: [PATCH] VFS documentation tweak As I was looking over the get_sb() changes, I stumbled across a little mistake in the documentation updates. Unless we're getting into an interesting new object-oriented realm, I doubt that get_sb() should really return "struct int"... Signed-off-by: Jonathan Corbet Acked-by: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/Locking | 4 ++-- Documentation/filesystems/vfs.txt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index d31efbbdfe5..247d7f619aa 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -142,8 +142,8 @@ see also dquot_operations section. --------------------------- file_system_type --------------------------- prototypes: - struct int (*get_sb) (struct file_system_type *, int, - const char *, void *, struct vfsmount *); + int (*get_sb) (struct file_system_type *, int, + const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); locking rules: may block BKL diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 9d3aed628bc..1cb7e8be927 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -113,8 +113,8 @@ members are defined: struct file_system_type { const char *name; int fs_flags; - struct int (*get_sb) (struct file_system_type *, int, - const char *, void *, struct vfsmount *); + int (*get_sb) (struct file_system_type *, int, + const char *, void *, struct vfsmount *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; -- cgit v1.2.3 From 454d6fbc48374be8f53b9bafaa86530cf8eb3bc1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 10 Jul 2006 04:44:08 -0700 Subject: [PATCH] cdrom: fix bad cgc.buflen assignment The code really means to mask off the high bits, not assign 0xff. Signed-off-by: Jens Axboe Cc: Marcus Meissner Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index ca27ee89240..d239cf8b20b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1837,7 +1837,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; - cgc.cmd[9] = cgc.buflen = 0xff; + cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; -- cgit v1.2.3 From 73ca66b97b73257a7d832d502c36fc19fe847809 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 10 Jul 2006 04:44:09 -0700 Subject: [PATCH] release_firmware() fixes Use release_firmware() to free requested resources. According to Documentation/firmware_class/README the request_firmware() call should be followed by a release_firmware(). Some drivers do not however free the firmware previously allocated with request_firmware(). This patch tries to fix this by making sure that release_firmware() is used as expected. Signed-off-by: Magnus Damm Acked-by: Marcel Holtmann Cc: Mauro Carvalho Chehab Cc: "John W. Linville" Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bcm203x.c | 1 + drivers/media/dvb/frontends/nxt200x.c | 4 ++-- drivers/media/dvb/frontends/or51211.c | 2 +- drivers/media/dvb/frontends/sp8870.c | 2 +- drivers/media/dvb/frontends/sp887x.c | 2 +- drivers/media/video/cx88/cx88-blackbird.c | 3 +++ drivers/net/wireless/spectrum_cs.c | 37 +++++++++++++------------------ 7 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 6f67141f4de..13ba729cdd5 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -234,6 +234,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id data->fw_data = kmalloc(firmware->size, GFP_KERNEL); if (!data->fw_data) { BT_ERR("Can't allocate memory for firmware image"); + release_firmware(firmware); usb_free_urb(data->urb); kfree(data->buffer); kfree(data); diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index 55671cb5255..87c286ee6a0 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -896,9 +896,9 @@ static int nxt2002_init(struct dvb_frontend* fe) } ret = nxt2002_load_firmware(fe, fw); + release_firmware(fw); if (ret) { printk("nxt2002: Writing firmware to device failed\n"); - release_firmware(fw); return ret; } printk("nxt2002: Firmware upload complete\n"); @@ -960,9 +960,9 @@ static int nxt2004_init(struct dvb_frontend* fe) } ret = nxt2004_load_firmware(fe, fw); + release_firmware(fw); if (ret) { printk("nxt2004: Writing firmware to device failed\n"); - release_firmware(fw); return ret; } printk("nxt2004: Firmware upload complete\n"); diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 26bed616fab..2bf124b5368 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -437,10 +437,10 @@ static int or51211_init(struct dvb_frontend* fe) } ret = or51211_load_firmware(fe, fw); + release_firmware(fw); if (ret) { printk(KERN_WARNING "or51211: Writing firmware to " "device failed!\n"); - release_firmware(fw); return ret; } printk(KERN_INFO "or51211: Firmware upload complete.\n"); diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 44ec5b9a469..d98fd5c2e13 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -318,7 +318,6 @@ static int sp8870_init (struct dvb_frontend* fe) printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE); if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { printk("sp8870: no firmware upload (timeout or file not found?)\n"); - release_firmware(fw); return -EIO; } @@ -327,6 +326,7 @@ static int sp8870_init (struct dvb_frontend* fe) release_firmware(fw); return -EIO; } + release_firmware(fw); printk("sp8870: firmware upload complete\n"); /* enable TS output and interface pins */ diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index b0a2b02f660..5c2f8f4e0ae 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -520,9 +520,9 @@ static int sp887x_init(struct dvb_frontend* fe) } ret = sp887x_initial_setup(fe, fw); + release_firmware(fw); if (ret) { printk("sp887x: writing firmware to device failed\n"); - release_firmware(fw); return ret; } printk("sp887x: firmware upload complete\n"); diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 349632b48e9..b60177f173c 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -453,11 +453,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n", firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); + release_firmware(firmware); return -1; } if (0 != memcmp(firmware->data, magic, 8)) { dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n"); + release_firmware(firmware); return -1; } @@ -478,6 +480,7 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) } if (checksum) { dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n"); + release_firmware(firmware); return -1; } release_firmware(firmware); diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 15465278c78..7f78b7801fb 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -34,8 +34,6 @@ #include "orinoco.h" -static unsigned char *primsym; -static unsigned char *secsym; static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; @@ -440,7 +438,7 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) */ static int spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, - const unsigned char *image) + const unsigned char *image, int secondary) { int ret; const unsigned char *ptr; @@ -455,7 +453,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, first_block = (const struct dblock *) ptr; /* Read the PDA */ - if (image != primsym) { + if (secondary) { ret = spectrum_read_pda(hw, pda, sizeof(pda)); if (ret) return ret; @@ -472,7 +470,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, return ret; /* Write the PDA to the adapter */ - if (image != primsym) { + if (secondary) { ret = spectrum_apply_pda(hw, first_block, pda); if (ret) return ret; @@ -487,7 +485,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, ret = hermes_init(hw); /* hermes_reset() should return 0 with the secondary firmware */ - if (image != primsym && ret != 0) + if (secondary && ret != 0) return -ENODEV; /* And this should work with any firmware */ @@ -509,33 +507,30 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, - &handle_to_dev(link)) == 0) { - primsym = fw_entry->data; - } else { + &handle_to_dev(link)) != 0) { printk(KERN_ERR PFX "Cannot find firmware: %s\n", primary_fw_name); return -ENOENT; } - if (request_firmware(&fw_entry, secondary_fw_name, - &handle_to_dev(link)) == 0) { - secsym = fw_entry->data; - } else { - printk(KERN_ERR PFX "Cannot find firmware: %s\n", - secondary_fw_name); - return -ENOENT; - } - /* Load primary firmware */ - ret = spectrum_dl_image(hw, link, primsym); + ret = spectrum_dl_image(hw, link, fw_entry->data, 0); + release_firmware(fw_entry); if (ret) { printk(KERN_ERR PFX "Primary firmware download failed\n"); return ret; } - /* Load secondary firmware */ - ret = spectrum_dl_image(hw, link, secsym); + if (request_firmware(&fw_entry, secondary_fw_name, + &handle_to_dev(link)) != 0) { + printk(KERN_ERR PFX "Cannot find firmware: %s\n", + secondary_fw_name); + return -ENOENT; + } + /* Load secondary firmware */ + ret = spectrum_dl_image(hw, link, fw_entry->data, 1); + release_firmware(fw_entry); if (ret) { printk(KERN_ERR PFX "Secondary firmware download failed\n"); } -- cgit v1.2.3 From acbf8bd738f1357e0e3b97b918bef5be272b176e Mon Sep 17 00:00:00 2001 From: "Luiz Fernando N. Capitulino" Date: Mon, 10 Jul 2006 04:44:11 -0700 Subject: [PATCH] Updates CREDITS file Updates my personal entry in the CREDITS file. Signed-off-by: Luiz Fernando N. Capitulino Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CREDITS b/CREDITS index 66b9e7a9abf..29be6d1fdf4 100644 --- a/CREDITS +++ b/CREDITS @@ -528,11 +528,11 @@ S: Oxford S: United Kingdom N: Luiz Fernando N. Capitulino -E: lcapitulino@terra.com.br -E: lcapitulino@prefeitura.sp.gov.br -W: http://www.telecentros.sp.gov.br -D: Little fixes and a lot of janitorial work -S: E-GOV Telecentros SP +E: lcapitulino@mandriva.com.br +E: lcapitulino@gmail.com +W: http://www.cpu.eti.br +D: misc kernel hacking +S: Mandriva S: Brazil N: Remy Card -- cgit v1.2.3 From 67eb5db5874076db01febed5a1a9281628fa9fb4 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 10 Jul 2006 04:44:11 -0700 Subject: [PATCH] hisax: fix usage of __init* Fix the warnings about the section mismatches for __init* in the HiSax driver. Signed-off-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/hisax/asuscom.c | 6 +++--- drivers/isdn/hisax/avm_a1.c | 2 +- drivers/isdn/hisax/avm_pci.c | 8 ++++---- drivers/isdn/hisax/bkm_a4t.c | 4 ++-- drivers/isdn/hisax/bkm_a8.c | 16 ++++++++-------- drivers/isdn/hisax/config.c | 2 +- drivers/isdn/hisax/diva.c | 14 +++++++------- drivers/isdn/hisax/enternow_pci.c | 4 ++-- drivers/isdn/hisax/gazel.c | 8 ++++---- drivers/isdn/hisax/hfc4s8s_l1.c | 2 +- drivers/isdn/hisax/hfc_2bds0.c | 4 ++-- drivers/isdn/hisax/hfc_2bs0.c | 4 ++-- drivers/isdn/hisax/hfc_pci.c | 6 +++--- drivers/isdn/hisax/hfcscard.c | 6 +++--- drivers/isdn/hisax/icc.c | 8 ++++---- drivers/isdn/hisax/icc.h | 2 +- drivers/isdn/hisax/ipacx.c | 18 +++++++++--------- drivers/isdn/hisax/isurf.c | 4 ++-- drivers/isdn/hisax/ix1_micro.c | 6 +++--- drivers/isdn/hisax/jade.c | 6 +++--- drivers/isdn/hisax/mic.c | 2 +- drivers/isdn/hisax/netjet.c | 2 +- drivers/isdn/hisax/niccy.c | 4 ++-- drivers/isdn/hisax/nj_s.c | 4 ++-- drivers/isdn/hisax/nj_u.c | 4 ++-- drivers/isdn/hisax/s0box.c | 2 +- drivers/isdn/hisax/saphir.c | 2 +- drivers/isdn/hisax/sportster.c | 4 ++-- drivers/isdn/hisax/teleint.c | 2 +- drivers/isdn/hisax/teles0.c | 2 +- drivers/isdn/hisax/telespci.c | 4 ++-- drivers/isdn/hisax/w6692.c | 10 +++++----- 32 files changed, 86 insertions(+), 86 deletions(-) diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c index a98c5e38bbb..93ff941c48f 100644 --- a/drivers/isdn/hisax/asuscom.c +++ b/drivers/isdn/hisax/asuscom.c @@ -297,7 +297,7 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg) } #ifdef __ISAPNP__ -static struct isapnp_device_id asus_ids[] __initdata = { +static struct isapnp_device_id asus_ids[] __devinitdata = { { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), (unsigned long) "Asus1688 PnP" }, @@ -313,11 +313,11 @@ static struct isapnp_device_id asus_ids[] __initdata = { { 0, } }; -static struct isapnp_device_id *ipid __initdata = &asus_ids[0]; +static struct isapnp_device_id *ipid __devinitdata = &asus_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_asuscom(struct IsdnCard *card) { int bytecnt; diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c index 9a8b02557ff..729e906bdc6 100644 --- a/drivers/isdn/hisax/avm_a1.c +++ b/drivers/isdn/hisax/avm_a1.c @@ -178,7 +178,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -int __init +int __devinit setup_avm_a1(struct IsdnCard *card) { u_char val; diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 04f5917bf5a..369afd3a3a4 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -639,7 +639,7 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs) } #endif /* 0 */ -static void __init +static void inithdlc(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_hdlc; @@ -727,13 +727,13 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) } #ifdef CONFIG_PCI -static struct pci_dev *dev_avm __initdata = NULL; +static struct pci_dev *dev_avm __devinitdata = NULL; #endif #ifdef __ISAPNP__ -static struct pnp_card *pnp_avm_c __initdata = NULL; +static struct pnp_card *pnp_avm_c __devinitdata = NULL; #endif -int __init +int __devinit setup_avm_pcipnp(struct IsdnCard *card) { u_int val, ver; diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index 3cf1f242178..87a630128a6 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -255,9 +255,9 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } -static struct pci_dev *dev_a4t __initdata = NULL; +static struct pci_dev *dev_a4t __devinitdata = NULL; -int __init +int __devinit setup_bkm_a4t(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 15681f3e73b..dae090a9a48 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -260,7 +260,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) return (0); } -static int __init +static int __devinit sct_alloc_io(u_int adr, u_int len) { if (!request_region(adr, len, "scitel")) { @@ -272,16 +272,16 @@ sct_alloc_io(u_int adr, u_int len) return(0); } -static struct pci_dev *dev_a8 __initdata = NULL; -static u16 sub_vendor_id __initdata = 0; -static u16 sub_sys_id __initdata = 0; -static u_char pci_bus __initdata = 0; -static u_char pci_device_fn __initdata = 0; -static u_char pci_irq __initdata = 0; +static struct pci_dev *dev_a8 __devinitdata = NULL; +static u16 sub_vendor_id __devinitdata = 0; +static u16 sub_sys_id __devinitdata = 0; +static u_char pci_bus __devinitdata = 0; +static u_char pci_device_fn __devinitdata = 0; +static u_char pci_irq __devinitdata = 0; #endif /* CONFIG_PCI */ -int __init +int __devinit setup_sct_quadro(struct IsdnCard *card) { #ifdef CONFIG_PCI diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 5333be5d2c4..e10350360f2 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1875,7 +1875,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if) #ifdef CONFIG_PCI #include -static struct pci_device_id hisax_pci_tbl[] __initdata = { +static struct pci_device_id hisax_pci_tbl[] __devinitdata = { #ifdef CONFIG_HISAX_FRITZPCI {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID}, #endif diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 323a02ef384..e294fa3918f 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -887,13 +887,13 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_diva __initdata = NULL; -static struct pci_dev *dev_diva_u __initdata = NULL; -static struct pci_dev *dev_diva201 __initdata = NULL; -static struct pci_dev *dev_diva202 __initdata = NULL; +static struct pci_dev *dev_diva __devinitdata = NULL; +static struct pci_dev *dev_diva_u __devinitdata = NULL; +static struct pci_dev *dev_diva201 __devinitdata = NULL; +static struct pci_dev *dev_diva202 __devinitdata = NULL; #ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] __initdata = { +static struct isapnp_device_id diva_ids[] __devinitdata = { { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), (unsigned long) "Diva picola" }, @@ -915,12 +915,12 @@ static struct isapnp_device_id diva_ids[] __initdata = { { 0, } }; -static struct isapnp_device_id *ipid __initdata = &diva_ids[0]; +static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_diva(struct IsdnCard *card) { int bytecnt = 8; diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c index 8fcbe2e7d76..76c7d29d1b2 100644 --- a/drivers/isdn/hisax/enternow_pci.c +++ b/drivers/isdn/hisax/enternow_pci.c @@ -301,10 +301,10 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) } -static struct pci_dev *dev_netjet __initdata = NULL; +static struct pci_dev *dev_netjet __devinitdata = NULL; /* called by config.c */ -int __init +int __devinit setup_enternow_pci(struct IsdnCard *card) { int bytecnt; diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 3e7d9230358..fe293726777 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -484,7 +484,7 @@ reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) return 1; } -static int __init +static int __devinit setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) { printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n"); @@ -532,9 +532,9 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) return (0); } -static struct pci_dev *dev_tel __initdata = NULL; +static struct pci_dev *dev_tel __devinitdata = NULL; -static int __init +static int __devinit setup_gazelpci(struct IsdnCardState *cs) { u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0; @@ -621,7 +621,7 @@ setup_gazelpci(struct IsdnCardState *cs) return (0); } -int __init +int __devinit setup_gazel(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 0f967b3df79..3a5ca8a68fc 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -1703,7 +1703,7 @@ hfc4s8s_module_init(void) /* driver module exit : */ /* release the HFC-4s/8s hardware */ /*************************************/ -static void +static void __exit hfc4s8s_module_exit(void) { pci_unregister_driver(&hfc4s8s_driver); diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 637a261c931..6360e821472 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs) { } -static unsigned int __init +static unsigned int *init_send_hfcd(int cnt) { int i, *send; @@ -1030,7 +1030,7 @@ static unsigned int __init return(send); } -void __init +void init2bds0(struct IsdnCardState *cs) { cs->setstack_d = setstack_hfcd; diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index c964539cc43..d0520ad3067 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs) return (0); } -static void __init +static void init_send(struct BCState *bcs) { int i; @@ -565,7 +565,7 @@ init_send(struct BCState *bcs) bcs->hw.hfc.send[i] = 0x1fff; } -void __init +void inithfc(struct IsdnCardState *cs) { init_send(&cs->bcs[0]); diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 7241e73879b..1df60ca9481 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1581,7 +1581,7 @@ hfcpci_bh(struct IsdnCardState *cs) /********************************/ /* called for card init message */ /********************************/ -static void __init +static void inithfcpci(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_2b; @@ -1638,11 +1638,11 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) /* this variable is used as card index when more than one cards are present */ -static struct pci_dev *dev_hfcpci __initdata = NULL; +static struct pci_dev *dev_hfcpci __devinitdata = NULL; #endif /* CONFIG_PCI */ -int __init +int __devinit setup_hfcpci(struct IsdnCard *card) { u_long flags; diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c index 86ab1c13f6b..4e7f472877e 100644 --- a/drivers/isdn/hisax/hfcscard.c +++ b/drivers/isdn/hisax/hfcscard.c @@ -139,7 +139,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) } #ifdef __ISAPNP__ -static struct isapnp_device_id hfc_ids[] __initdata = { +static struct isapnp_device_id hfc_ids[] __devinitdata = { { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), (unsigned long) "Acer P10" }, @@ -164,11 +164,11 @@ static struct isapnp_device_id hfc_ids[] __initdata = { { 0, } }; -static struct isapnp_device_id *ipid __initdata = &hfc_ids[0]; +static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_hfcs(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index c615752b96a..2cf7b665609 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -24,10 +24,10 @@ #define DBUSY_TIMER_VALUE 80 #define ARCOFI_USE 0 -static char *ICCVer[] __initdata = +static char *ICCVer[] = {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; -void __init +void ICCVersion(struct IsdnCardState *cs, char *s) { int val; @@ -613,7 +613,7 @@ dbusy_timer_handler(struct IsdnCardState *cs) } } -void __init +void initicc(struct IsdnCardState *cs) { cs->setstack_d = setstack_icc; @@ -646,7 +646,7 @@ initicc(struct IsdnCardState *cs) ph_command(cs, ICC_CMD_DI); } -void __init +void clear_pending_icc_ints(struct IsdnCardState *cs) { int val, eval; diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h index b3bb3d5de53..e7f593967e4 100644 --- a/drivers/isdn/hisax/icc.h +++ b/drivers/isdn/hisax/icc.h @@ -65,7 +65,7 @@ #define ICC_IND_AIL 0xE #define ICC_IND_DC 0xF -extern void __init ICCVersion(struct IsdnCardState *cs, char *s); +extern void ICCVersion(struct IsdnCardState *cs, char *s); extern void initicc(struct IsdnCardState *cs); extern void icc_interrupt(struct IsdnCardState *cs, u_char val); extern void clear_pending_icc_ints(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index df5fc92a89b..00afd553890 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -38,8 +38,8 @@ static void dbusy_timer_handler(struct IsdnCardState *cs); static void dch_empty_fifo(struct IsdnCardState *cs, int count); static void dch_fill_fifo(struct IsdnCardState *cs); static inline void dch_int(struct IsdnCardState *cs); -static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs); -static void __devinit dch_init(struct IsdnCardState *cs); +static void dch_setstack(struct PStack *st, struct IsdnCardState *cs); +static void dch_init(struct IsdnCardState *cs); static void bch_l2l1(struct PStack *st, int pr, void *arg); static void bch_empty_fifo(struct BCState *bcs, int count); static void bch_fill_fifo(struct BCState *bcs); @@ -48,8 +48,8 @@ static void bch_mode(struct BCState *bcs, int mode, int bc); static void bch_close_state(struct BCState *bcs); static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); static int bch_setstack(struct PStack *st, struct BCState *bcs); -static void __devinit bch_init(struct IsdnCardState *cs, int hscx); -static void __init clear_pending_ints(struct IsdnCardState *cs); +static void bch_init(struct IsdnCardState *cs, int hscx); +static void clear_pending_ints(struct IsdnCardState *cs); //---------------------------------------------------------- // Issue Layer 1 command to chip @@ -408,7 +408,7 @@ dch_int(struct IsdnCardState *cs) //---------------------------------------------------------- //---------------------------------------------------------- -static void __devinit +static void dch_setstack(struct PStack *st, struct IsdnCardState *cs) { st->l1.l1hw = dch_l2l1; @@ -416,7 +416,7 @@ dch_setstack(struct PStack *st, struct IsdnCardState *cs) //---------------------------------------------------------- //---------------------------------------------------------- -static void __devinit +static void dch_init(struct IsdnCardState *cs) { printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); @@ -823,7 +823,7 @@ bch_setstack(struct PStack *st, struct BCState *bcs) //---------------------------------------------------------- //---------------------------------------------------------- -static void __devinit +static void bch_init(struct IsdnCardState *cs, int hscx) { cs->bcs[hscx].BC_SetStack = bch_setstack; @@ -861,7 +861,7 @@ interrupt_ipacx(struct IsdnCardState *cs) //---------------------------------------------------------- // Clears chip interrupt status //---------------------------------------------------------- -static void __init +static void clear_pending_ints(struct IsdnCardState *cs) { int ista; @@ -883,7 +883,7 @@ clear_pending_ints(struct IsdnCardState *cs) // Does chip configuration work // Work to do depends on bit mask in part //---------------------------------------------------------- -void __init +void init_ipacx(struct IsdnCardState *cs, int part) { if (part &1) { // initialise chip diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c index 33747afc984..715a1a8cd69 100644 --- a/drivers/isdn/hisax/isurf.c +++ b/drivers/isdn/hisax/isurf.c @@ -196,10 +196,10 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { } #ifdef __ISAPNP__ -static struct pnp_card *pnp_c __initdata = NULL; +static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_isurf(struct IsdnCard *card) { int ver; diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c index 908a7e14442..39717506c67 100644 --- a/drivers/isdn/hisax/ix1_micro.c +++ b/drivers/isdn/hisax/ix1_micro.c @@ -210,7 +210,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) } #ifdef __ISAPNP__ -static struct isapnp_device_id itk_ids[] __initdata = { +static struct isapnp_device_id itk_ids[] __devinitdata = { { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), (unsigned long) "ITK micro 2" }, @@ -220,12 +220,12 @@ static struct isapnp_device_id itk_ids[] __initdata = { { 0, } }; -static struct isapnp_device_id *ipid __initdata = &itk_ids[0]; +static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0]; static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_ix1micro(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index 2659fecc267..43d61d1bc5b 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -19,7 +19,7 @@ #include -int __init +int JadeVersion(struct IsdnCardState *cs, char *s) { int ver,i; @@ -253,7 +253,7 @@ setstack_jade(struct PStack *st, struct BCState *bcs) return (0); } -void __init +void clear_pending_jade_ints(struct IsdnCardState *cs) { int val; @@ -279,7 +279,7 @@ clear_pending_jade_ints(struct IsdnCardState *cs) cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); } -void __init +void initjade(struct IsdnCardState *cs) { cs->bcs[0].BC_SetStack = setstack_jade; diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c index fe11f226b28..8c82519593a 100644 --- a/drivers/isdn/hisax/mic.c +++ b/drivers/isdn/hisax/mic.c @@ -189,7 +189,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -int __init +int __devinit setup_mic(struct IsdnCard *card) { int bytecnt; diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 47a47ef0968..38f648f9b0e 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -909,7 +909,7 @@ setstack_tiger(struct PStack *st, struct BCState *bcs) } -void __init +void inittiger(struct IsdnCardState *cs) { if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c index 79a97b1c381..489022bdef7 100644 --- a/drivers/isdn/hisax/niccy.c +++ b/drivers/isdn/hisax/niccy.c @@ -232,12 +232,12 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *niccy_dev __initdata = NULL; +static struct pci_dev *niccy_dev __devinitdata = NULL; #ifdef __ISAPNP__ static struct pnp_card *pnp_c __devinitdata = NULL; #endif -int __init +int __devinit setup_niccy(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index e5b900a6fa0..80025fd890f 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -148,9 +148,9 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_netjet __initdata = NULL; +static struct pci_dev *dev_netjet __devinitdata = NULL; -int __init +int __devinit setup_netjet_s(struct IsdnCard *card) { int bytecnt,cfg; diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c index 7002b09936d..37497162d53 100644 --- a/drivers/isdn/hisax/nj_u.c +++ b/drivers/isdn/hisax/nj_u.c @@ -128,9 +128,9 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_netjet __initdata = NULL; +static struct pci_dev *dev_netjet __devinitdata = NULL; -int __init +int __devinit setup_netjet_u(struct IsdnCard *card) { int bytecnt; diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c index 7b63085ea6e..e76042d323e 100644 --- a/drivers/isdn/hisax/s0box.c +++ b/drivers/isdn/hisax/s0box.c @@ -211,7 +211,7 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -int __init +int __devinit setup_s0box(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c index 821776e1561..d943d365890 100644 --- a/drivers/isdn/hisax/saphir.c +++ b/drivers/isdn/hisax/saphir.c @@ -241,7 +241,7 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) } -int __init +int __devinit setup_saphir(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c index cdf35dc564c..a49b694eb73 100644 --- a/drivers/isdn/hisax/sportster.c +++ b/drivers/isdn/hisax/sportster.c @@ -184,7 +184,7 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static int __init +static int __devinit get_io_range(struct IsdnCardState *cs) { int i, j, adr; @@ -209,7 +209,7 @@ get_io_range(struct IsdnCardState *cs) } } -int __init +int __devinit setup_sportster(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c index a2b1816af37..e94dc6f5bd6 100644 --- a/drivers/isdn/hisax/teleint.c +++ b/drivers/isdn/hisax/teleint.c @@ -261,7 +261,7 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -int __init +int __devinit setup_TeleInt(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c index 2b7df8f9823..f94af0930a1 100644 --- a/drivers/isdn/hisax/teles0.c +++ b/drivers/isdn/hisax/teles0.c @@ -265,7 +265,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -int __init +int __devinit setup_teles0(struct IsdnCard *card) { u_char val; diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c index 9382cdf04d8..dca446865f2 100644 --- a/drivers/isdn/hisax/telespci.c +++ b/drivers/isdn/hisax/telespci.c @@ -284,9 +284,9 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); } -static struct pci_dev *dev_tel __initdata = NULL; +static struct pci_dev *dev_tel __devinitdata = NULL; -int __init +int __devinit setup_telespci(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 6c68419c05f..0595293b865 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -44,11 +44,11 @@ static const char *w6692_revision = "$Revision: 1.18.2.4 $"; #define DBUSY_TIMER_VALUE 80 -static char *W6692Ver[] __initdata = +static char *W6692Ver[] = {"W6692 V00", "W6692 V01", "W6692 V10", "W6692 V11"}; -static void __init +static void W6692Version(struct IsdnCardState *cs, char *s) { int val; @@ -897,7 +897,7 @@ static void resetW6692(struct IsdnCardState *cs) } } -static void __init initW6692(struct IsdnCardState *cs, int part) +static void initW6692(struct IsdnCardState *cs, int part) { if (part & 1) { cs->setstack_d = setstack_W6692; @@ -992,9 +992,9 @@ w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg) static int id_idx ; -static struct pci_dev *dev_w6692 __initdata = NULL; +static struct pci_dev *dev_w6692 __devinitdata = NULL; -int __init +int __devinit setup_w6692(struct IsdnCard *card) { struct IsdnCardState *cs = card->cs; -- cgit v1.2.3 From a8f340e394ff30b79ab5b03c67ab4c94b2ac3646 Mon Sep 17 00:00:00 2001 From: Jon Smirl Date: Mon, 10 Jul 2006 04:44:12 -0700 Subject: [PATCH] vt: Remove VT-specific declarations and definitions from tty.h MAX_NR_CONSOLES, fg_console, want_console and last_console are more of a function of the VT layer than the TTY one. Moving these to vt.h and vt_kern.h allows all of the framebuffer and VT console drivers to remove their dependency on tty.h. [akpm@osdl.org: fix alpha build] Signed-off-by: Jon Smirl Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/process.c | 1 + arch/parisc/kernel/pdc_cons.c | 2 ++ drivers/video/68328fb.c | 1 - drivers/video/S3triofb.c | 1 - drivers/video/amifb.c | 1 - drivers/video/arcfb.c | 1 - drivers/video/asiliantfb.c | 1 - drivers/video/atafb.c | 1 - drivers/video/aty/aty128fb.c | 1 - drivers/video/aty/radeon_base.c | 1 - drivers/video/chipsfb.c | 1 - drivers/video/cirrusfb.c | 1 - drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 1 - drivers/video/console/mdacon.c | 1 - drivers/video/console/newport_con.c | 1 - drivers/video/console/promcon.c | 1 - drivers/video/console/softcursor.c | 1 - drivers/video/console/sticon.c | 1 - drivers/video/console/vgacon.c | 1 - drivers/video/controlfb.c | 1 - drivers/video/cyber2000fb.c | 1 - drivers/video/cyberfb.c | 1 - drivers/video/dnfb.c | 1 - drivers/video/epson1355fb.c | 1 - drivers/video/fbcmap.c | 1 - drivers/video/fbmem.c | 2 +- drivers/video/fbmon.c | 1 - drivers/video/g364fb.c | 1 - drivers/video/geode/gx1fb_core.c | 1 - drivers/video/geode/gxfb_core.c | 1 - drivers/video/hgafb.c | 1 - drivers/video/hitfb.c | 1 - drivers/video/hpfb.c | 1 - drivers/video/i810/i810_main.c | 1 - drivers/video/igafb.c | 1 - drivers/video/imacfb.c | 2 +- drivers/video/imsttfb.c | 1 - drivers/video/intelfb/intelfbdrv.c | 2 +- drivers/video/intelfb/intelfbhw.c | 1 - drivers/video/kyro/fbdev.c | 1 - drivers/video/macfb.c | 1 - drivers/video/matrox/matroxfb_base.h | 1 - drivers/video/maxinefb.c | 1 - drivers/video/modedb.c | 1 - drivers/video/neofb.c | 1 - drivers/video/nvidia/nvidia.c | 1 - drivers/video/offb.c | 1 - drivers/video/platinumfb.c | 1 - drivers/video/pm2fb.c | 1 - drivers/video/pm3fb.c | 1 - drivers/video/pmag-aa-fb.c | 1 - drivers/video/pvr2fb.c | 1 - drivers/video/q40fb.c | 1 - drivers/video/retz3fb.c | 1 - drivers/video/riva/fbdev.c | 1 - drivers/video/s3c2410fb.c | 1 - drivers/video/savage/savagefb_driver.c | 1 - drivers/video/sis/sis_main.c | 6 ++++++ drivers/video/skeletonfb.c | 1 - drivers/video/sun3fb.c | 1 - drivers/video/tdfxfb.c | 1 - drivers/video/tgafb.c | 1 - drivers/video/tx3912fb.c | 1 - drivers/video/valkyriefb.c | 1 - drivers/video/vesafb.c | 2 +- drivers/video/vfb.c | 1 - drivers/video/vga16fb.c | 2 +- drivers/video/virgefb.c | 1 - include/linux/console_struct.h | 1 + include/linux/fb.h | 1 - include/linux/tty.h | 11 ----------- include/linux/vt.h | 10 ++++++++++ include/linux/vt_kern.h | 1 + 74 files changed, 26 insertions(+), 78 deletions(-) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 41ebf51a107..b3a8a298036 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index ce78f412ff2..aab05767427 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -89,6 +89,8 @@ static int pdc_console_setup(struct console *co, char *options) } #if defined(CONFIG_PDC_CONSOLE) +#include + static struct tty_driver * pdc_console_device (struct console *c, int *index) { extern struct tty_driver console_driver; diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 78488bb41ae..0dda73da862 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c index e714e8449c1..afd146f5f68 100644 --- a/drivers/video/S3triofb.c +++ b/drivers/video/S3triofb.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index f9bc9f777e7..f1ba54f4fc3 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index fd95c2dbd4f..70dd8115a4d 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index eaeaf4d1a09..1fd22f460b0 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index e69ab65f784..5831893bf7a 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 72c58910947..1006f125fcc 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 51b78f8de94..8d85fc58142 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 0e465c80ef2..eba9d93ae36 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 7355da09c72..daf43f535a0 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 878707a0439..7c8eeeb30a4 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 94e9f7069be..390439b3d89 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -64,7 +64,6 @@ #include #include #include /* MSch: for IRQ probe */ -#include #include #include #include diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index c89f90edf8a..52ed12b12ac 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 03041311711..7fa1afeae8d 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c index 5cd5e114d1e..b78eac63459 100644 --- a/drivers/video/console/promcon.c +++ b/drivers/video/console/promcon.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index 3957fc7523e..557c563e4ae 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 45c4f227e56..45586aaabd1 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -37,7 +37,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 05735ff4e9c..7f1f0e7a5b2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index acdd6a103db..8cc6c0e2d27 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 2e2924957d8..aae6d9c26e8 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c index a3e189f90a7..c40e72dafb0 100644 --- a/drivers/video/cyberfb.c +++ b/drivers/video/cyberfb.c @@ -81,7 +81,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 5abd3cb0067..b083ea7e9c6 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index f0a621ecc28..737257d278f 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 1f98392a43b..e8b135f3d80 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 33034f81114..4fc9df426c1 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 3ccfff715a5..de93139ccbb 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -26,7 +26,6 @@ * for more details. * */ -#include #include #include #include diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c index 605d1a13202..1b981b63567 100644 --- a/drivers/video/g364fb.c +++ b/drivers/video/g364fb.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 4d3a8871d3d..bcf9cea54d8 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 5ef12a3dfa5..0d3643fc629 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 4e39035cf33..fb9e6722854 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 01864767450..4cc6b454265 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index abd920a663a..91cf3b577d1 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index fbe8a2c4b04..a6ca02f2156 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index 8a0c2d3d380..67f384f8675 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index cdbae173d69..ff233b84dec 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -15,9 +15,9 @@ #include #include #include +#include #include #include -#include #include diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 5f393d985b1..5715b8ad0dd 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 3f39d84015f..06af89d44a0 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -113,7 +113,6 @@ #include #include #include -#include #include #include #include @@ -122,6 +121,7 @@ #include #include #include +#include #include diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 3b78a57924f..2a9322f9cfd 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c index 2fdbe9b2b04..f0d614a80f1 100644 --- a/drivers/video/kyro/fbdev.c +++ b/drivers/video/kyro/fbdev.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index e6cbd9de944..80a04380716 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index b95779b57c0..9c25c2f7966 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index f85421bf7cb..38c8d38de4f 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index ff5454601e2..d1267904c28 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -12,7 +12,6 @@ */ #include -#include #include #include diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 773855a311e..59a6f5fa5ae 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index b02d6033cc0..ef58c382550 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 71ce1fa45cf..ce5f3031b99 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 450e802e0aa..983be3ec234 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 49a203e1591..a560a222382 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 0e0f977b05e..1d81ef47efd 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c index d92f352211e..68ca3cc4077 100644 --- a/drivers/video/pmag-aa-fb.c +++ b/drivers/video/pmag-aa-fb.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 4a1e0e85692..940ba2be55e 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index fc91dbf896d..48536c3e58a 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c index 5e2c64f622c..cf41ff17764 100644 --- a/drivers/video/retz3fb.c +++ b/drivers/video/retz3fb.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 2788655e6e7..baf494cecc1 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index f461eb10cc7..ad3bdd6f1ac 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -76,7 +76,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 4729af477fb..461e094e7b4 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index b848ca7db7f..f8dfabd73b0 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -44,7 +44,13 @@ #include #include #include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #include +#else +#include +#endif + #include #include #include diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 67f429e9318..bb96cb65fda 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c index e046e20f02b..f80356dfa8e 100644 --- a/drivers/video/sun3fb.c +++ b/drivers/video/sun3fb.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 239b1496874..689ce0270b8 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 6c2c78ab982..94fde625a6c 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c index d904da44e1a..07389ba01ef 100644 --- a/drivers/video/tx3912fb.c +++ b/drivers/video/tx3912fb.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 1d76c035050..47f27924a7d 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 5718924b677..2196448396e 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -13,13 +13,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include