From ff772b27e5f65c1a186e9f0741f0d00ef7002799 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Fri, 9 May 2008 22:12:06 -0500 Subject: atl1: add PHY power save mode Using vendor-provided magic, add code to enter power save mode on the PHY. We'll need this for suspend and wake-on-lan. Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 19 ++++++++----------- drivers/net/atlx/atlx.h | 3 +++ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 0afe522b8f7..3beb44e80ba 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -638,21 +638,18 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) } /* - *TODO: do something or get rid of this + * Force the PHY into power saving mode using vendor magic. */ #ifdef CONFIG_PM -static s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) +static void atl1_phy_enter_power_saving(struct atl1_hw *hw) { -/* s32 ret_val; - * u16 phy_data; - */ + atl1_write_phy_reg(hw, MII_DBG_ADDR, 0); + atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E); + atl1_write_phy_reg(hw, MII_DBG_ADDR, 2); + atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000); + atl1_write_phy_reg(hw, MII_DBG_ADDR, 3); + atl1_write_phy_reg(hw, MII_DBG_DATA, 0); -/* - ret_val = atl1_write_phy_reg(hw, ...); - ret_val = atl1_write_phy_reg(hw, ...); - .... -*/ - return 0; } #endif diff --git a/drivers/net/atlx/atlx.h b/drivers/net/atlx/atlx.h index 3be7c09734d..96721881ad6 100644 --- a/drivers/net/atlx/atlx.h +++ b/drivers/net/atlx/atlx.h @@ -460,6 +460,9 @@ MODULE_VERSION(ATLX_DRIVER_VERSION); #define MII_ATLX_PSSR_100MBS 0x4000 /* 01=100Mbs */ #define MII_ATLX_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ +#define MII_DBG_ADDR 0x1D +#define MII_DBG_DATA 0x1E + /* PCI Command Register Bit Definitions */ #define PCI_REG_COMMAND 0x04 /* PCI Command Register */ #define CMD_IO_SPACE 0x0001 -- cgit v1.2.3 From 08e0f1dc8388b3e134c714672c59edc2a7059430 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Fri, 9 May 2008 22:12:07 -0500 Subject: atl1: fix broken suspend and resume Fix atl1_suspend() and atl1_resume() so they actually work. We'll use the suspend function for wake-on-lan in addition to just suspending. Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 125 +++++++++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 45 deletions(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 3beb44e80ba..12fb3e5529d 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2781,64 +2781,93 @@ static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) struct atl1_hw *hw = &adapter->hw; u32 ctrl = 0; u32 wufc = adapter->wol; + u32 val; + int retval; + u16 speed; + u16 duplex; netif_device_detach(netdev); if (netif_running(netdev)) atl1_down(adapter); + retval = pci_save_state(pdev); + if (retval) + return retval; + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); - if (ctrl & BMSR_LSTATUS) + val = ctrl & BMSR_LSTATUS; + if (val) wufc &= ~ATLX_WUFC_LNKC; - /* reduce speed to 10/100M */ - if (wufc) { - atl1_phy_enter_power_saving(hw); - /* if resume, let driver to re- setup link */ - hw->phy_configured = false; - atl1_set_mac_addr(hw); - atlx_set_multi(netdev); + if (val && wufc) { + val = atl1_get_speed_and_duplex(hw, &speed, &duplex); + if (val) { + if (netif_msg_ifdown(adapter)) + dev_printk(KERN_DEBUG, &pdev->dev, + "error getting speed/duplex\n"); + goto disable_wol; + } ctrl = 0; - /* turn on magic packet wol */ - if (wufc & ATLX_WUFC_MAG) - ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; - /* turn on Link change WOL */ - if (wufc & ATLX_WUFC_LNKC) - ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + /* enable magic packet WOL */ + if (wufc & ATLX_WUFC_MAG) + ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); - - /* turn on all-multi mode if wake on multicast is enabled */ - ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); - ctrl &= ~MAC_CTRL_DBG; - ctrl &= ~MAC_CTRL_PROMIS_EN; - if (wufc & ATLX_WUFC_MC) - ctrl |= MAC_CTRL_MC_ALL_EN; - else - ctrl &= ~MAC_CTRL_MC_ALL_EN; - - /* turn on broadcast mode if wake on-BC is enabled */ - if (wufc & ATLX_WUFC_BC) + ioread32(hw->hw_addr + REG_WOL_CTRL); + + /* configure the mac */ + ctrl = MAC_CTRL_RX_EN; + ctrl |= ((u32)((speed == SPEED_1000) ? MAC_CTRL_SPEED_1000 : + MAC_CTRL_SPEED_10_100) << MAC_CTRL_SPEED_SHIFT); + if (duplex == FULL_DUPLEX) + ctrl |= MAC_CTRL_DUPLX; + ctrl |= (((u32)adapter->hw.preamble_len & + MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + if (adapter->vlgrp) + ctrl |= MAC_CTRL_RMV_VLAN; + if (wufc & ATLX_WUFC_MAG) ctrl |= MAC_CTRL_BC_EN; - else - ctrl &= ~MAC_CTRL_BC_EN; - - /* enable RX */ - ctrl |= MAC_CTRL_RX_EN; iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } else { - iowrite32(0, hw->hw_addr + REG_WOL_CTRL); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + ioread32(hw->hw_addr + REG_MAC_CTRL); + + /* poke the PHY */ + ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); + ioread32(hw->hw_addr + REG_PCIE_PHYMISC); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + goto exit; } - pci_save_state(pdev); + if (!val && wufc) { + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); + ioread32(hw->hw_addr + REG_WOL_CTRL); + iowrite32(0, hw->hw_addr + REG_MAC_CTRL); + ioread32(hw->hw_addr + REG_MAC_CTRL); + hw->phy_configured = false; + pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); + goto exit; + } + +disable_wol: + iowrite32(0, hw->hw_addr + REG_WOL_CTRL); + ioread32(hw->hw_addr + REG_WOL_CTRL); + ctrl = ioread32(hw->hw_addr + REG_PCIE_PHYMISC); + ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; + iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); + ioread32(hw->hw_addr + REG_PCIE_PHYMISC); + atl1_phy_enter_power_saving(hw); + hw->phy_configured = false; + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); +exit: + if (netif_running(netdev)) + pci_disable_msi(adapter->pdev); pci_disable_device(pdev); - - pci_set_power_state(pdev, PCI_D3hot); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } @@ -2852,20 +2881,26 @@ static int atl1_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - /* FIXME: check and handle */ err = pci_enable_device(pdev); + if (err) { + if (netif_msg_ifup(adapter)) + dev_printk(KERN_DEBUG, &pdev->dev, + "error enabling pci device\n"); + return err; + } + + pci_set_master(pdev); + iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); - iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); - atl1_reset(adapter); + atl1_reset_hw(&adapter->hw); + adapter->cmb.cmb->int_stats = 0; if (netif_running(netdev)) atl1_up(adapter); netif_device_attach(netdev); - atl1_via_workaround(adapter); - return 0; } #else -- cgit v1.2.3 From bf455a2247c6abe7d0debfbf2974514b5144ed4d Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Fri, 9 May 2008 22:12:08 -0500 Subject: atl1: add shutdown callback Add a shutdown callback that points to atl1_suspend(). This, along with a working suspend function, fixes wake-on-lan. Tested-by: Per Olofsson Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 12fb3e5529d..b7092a330f5 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -36,7 +36,6 @@ * A very incomplete list of things that need to be dealt with: * * TODO: - * Wake on LAN. * Add more ethtool functions. * Fix abstruse irq enable/disable condition described here: * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 @@ -2908,6 +2907,13 @@ static int atl1_resume(struct pci_dev *pdev) #define atl1_resume NULL #endif +static void atl1_shutdown(struct pci_dev *pdev) +{ +#ifdef CONFIG_PM + atl1_suspend(pdev, PMSG_SUSPEND); +#endif +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void atl1_poll_controller(struct net_device *netdev) { @@ -3154,7 +3160,8 @@ static struct pci_driver atl1_driver = { .probe = atl1_probe, .remove = __devexit_p(atl1_remove), .suspend = atl1_suspend, - .resume = atl1_resume + .resume = atl1_resume, + .shutdown = atl1_shutdown }; /* -- cgit v1.2.3 From e8f720fdec08daa669f46c8d76da0714f6872ccc Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Fri, 9 May 2008 22:12:09 -0500 Subject: atl1: bump version number atl1-2.1.3. Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 2 +- drivers/net/atlx/atl1.h | 2 +- drivers/net/atlx/atlx.c | 2 +- drivers/net/atlx/atlx.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index b7092a330f5..9c2394d4942 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1,7 +1,7 @@ /* * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. * Copyright(c) 2006 - 2007 Chris Snook - * Copyright(c) 2006 Jay Cliburn + * Copyright(c) 2006 - 2008 Jay Cliburn * * Derived from Intel e1000 driver * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h index 51893d66eae..a5015b14a42 100644 --- a/drivers/net/atlx/atl1.h +++ b/drivers/net/atlx/atl1.h @@ -1,7 +1,7 @@ /* * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. * Copyright(c) 2006 - 2007 Chris Snook - * Copyright(c) 2006 Jay Cliburn + * Copyright(c) 2006 - 2008 Jay Cliburn * * Derived from Intel e1000 driver * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c index f06b854e250..b3e7fcf0f6e 100644 --- a/drivers/net/atlx/atlx.c +++ b/drivers/net/atlx/atlx.c @@ -2,7 +2,7 @@ * * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. * Copyright(c) 2006 - 2007 Chris Snook - * Copyright(c) 2006 Jay Cliburn + * Copyright(c) 2006 - 2008 Jay Cliburn * Copyright(c) 2007 Atheros Corporation. All rights reserved. * * Derived from Intel e1000 driver diff --git a/drivers/net/atlx/atlx.h b/drivers/net/atlx/atlx.h index 96721881ad6..297a03da6b7 100644 --- a/drivers/net/atlx/atlx.h +++ b/drivers/net/atlx/atlx.h @@ -2,7 +2,7 @@ * * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. * Copyright(c) 2006 - 2007 Chris Snook - * Copyright(c) 2006 Jay Cliburn + * Copyright(c) 2006 - 2008 Jay Cliburn * Copyright(c) 2007 Atheros Corporation. All rights reserved. * * Derived from Intel e1000 driver @@ -29,7 +29,7 @@ #include #include -#define ATLX_DRIVER_VERSION "2.1.1" +#define ATLX_DRIVER_VERSION "2.1.3" MODULE_AUTHOR("Xiong Huang , \ Chris Snook , Jay Cliburn "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4ec7ffa2df247054d422b48148ad82369a45e986 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 21 May 2008 06:32:11 +0100 Subject: misc drivers/net endianness noise Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/net/atlx/atl1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9c2394d4942..6e4c80d41b0 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2135,7 +2135,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, return -1; } - if (skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); real_len = (((unsigned char *)iph - skb->data) + -- cgit v1.2.3 From aefdbf1a3b832a580a50cf3d1dcbb717be7cbdbe Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 23 May 2008 02:00:25 +0400 Subject: atl1: fix 4G memory corruption bug When using 4+ GB RAM and SWIOTLB is active, the driver corrupts memory by writing an skb after the relevant DMA page has been unmapped. Although this doesn't happen when *not* using bounce buffers, clearing the pointer to the DMA page after unmapping it fixes the problem. http://marc.info/?t=120861317000005&r=2&w=2 Signed-off-by: Alexey Dobriyan Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 9c2394d4942..79325c4fb54 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2023,6 +2023,7 @@ rrd_ok: /* Good Receive */ pci_unmap_page(adapter->pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; skb = buffer_info->skb; length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); -- cgit v1.2.3 From ae6b4d9ab6129467415801f30e487bc141a3f471 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Sun, 1 Jun 2008 16:57:11 -0500 Subject: atl1: fix suspend regression Using vendor magic to force the PHY into power save mode breaks suspend. It isn't needed anyway, so remove it. Tested-by: Avuton Olrich Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 6ddc911e7d1..99e0b4cdc56 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -636,22 +636,6 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) return atl1_write_phy_reg(hw, 30, 0); } -/* - * Force the PHY into power saving mode using vendor magic. - */ -#ifdef CONFIG_PM -static void atl1_phy_enter_power_saving(struct atl1_hw *hw) -{ - atl1_write_phy_reg(hw, MII_DBG_ADDR, 0); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E); - atl1_write_phy_reg(hw, MII_DBG_ADDR, 2); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000); - atl1_write_phy_reg(hw, MII_DBG_ADDR, 3); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0); - -} -#endif - /* * Resets the PHY and make all config validate * hw - Struct containing variables accessed by shared code @@ -2860,7 +2844,6 @@ disable_wol: ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); ioread32(hw->hw_addr + REG_PCIE_PHYMISC); - atl1_phy_enter_power_saving(hw); hw->phy_configured = false; pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); exit: -- cgit v1.2.3 From 58c7821c4264a7ddd6f0c31c5caaf393b3897f10 Mon Sep 17 00:00:00 2001 From: Radu Cristescu Date: Thu, 12 Jun 2008 17:04:54 -0500 Subject: atl1: relax eeprom mac address error check The atl1 driver tries to determine the MAC address thusly: - If an EEPROM exists, read the MAC address from EEPROM and validate it. - If an EEPROM doesn't exist, try to read a MAC address from SPI flash. - If that fails, try to read a MAC address directly from the MAC Station Address register. - If that fails, assign a random MAC address provided by the kernel. We now have a report of a system fitted with an EEPROM containing all zeros where we expect the MAC address to be, and we currently handle this as an error condition. Turns out, on this system the BIOS writes a valid MAC address to the NIC's MAC Station Address register, but we never try to read it because we return an error when we find the all- zeros address in EEPROM. This patch relaxes the error check and continues looking for a MAC address even if it finds an illegal one in EEPROM. Signed-off-by: Radu Cristescu Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/atlx') diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 99e0b4cdc56..3c798ae5c34 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -471,7 +471,6 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); return 0; } - return 1; } /* see if SPI FLAGS exist ? */ -- cgit v1.2.3