aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshemminger@osdl.org <shemminger@osdl.org>2005-09-27 18:03:00 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-28 11:52:57 -0400
commit5afa0a9cfb79556f45c02957e71a2ac48a5bb6a1 (patch)
tree2043649c5061090b3603d3b48f861fddf7ca7255
parentd1f1370863f7fa3d76dc7d7779debdda854a5a60 (diff)
[PATCH] sky2: explicit set power state
Add better power management, and power down the chip on device removal Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--drivers/net/sky2.c156
-rw-r--r--drivers/net/sky2.h1
2 files changed, 112 insertions, 45 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 6d9c1db8896e..1d00cdcdaa67 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -175,6 +175,91 @@ ready:
175 return gma_read16(hw, port, GM_SMI_DATA); 175 return gma_read16(hw, port, GM_SMI_DATA);
176} 176}
177 177
178static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
179{
180 u16 power_control;
181 u32 reg1;
182 int vaux;
183 int ret = 0;
184
185 pr_debug("sky2_set_power_state %d\n", state);
186 sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
187
188 pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_PMC, &power_control);
189 vaux = (sky2_read8(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
190 (power_control & PCI_PM_CAP_PME_D3cold);
191
192 pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_CTRL, &power_control);
193
194 power_control |= PCI_PM_CTRL_PME_STATUS;
195 power_control &= ~(PCI_PM_CTRL_STATE_MASK);
196
197 switch (state) {
198 case PCI_D0:
199 /* switch power to VCC (WA for VAUX problem) */
200 sky2_write8(hw, B0_POWER_CTRL,
201 PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
202
203 /* disable Core Clock Division, */
204 sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
205
206 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
207 /* enable bits are inverted */
208 sky2_write8(hw, B2_Y2_CLK_GATE,
209 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
210 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
211 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
212 else
213 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
214
215 /* Turn off phy power saving */
216 pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg1);
217 reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
218
219 /* looks like this xl is back asswards .. */
220 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) {
221 reg1 |= PCI_Y2_PHY1_COMA;
222 if (hw->ports > 1)
223 reg1 |= PCI_Y2_PHY2_COMA;
224 }
225 pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1);
226 break;
227
228 case PCI_D3hot:
229 case PCI_D3cold:
230 /* Turn on phy power saving */
231 pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg1);
232 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
233 reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
234 else
235 reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
236 pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1);
237
238 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
239 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
240 else
241 /* enable bits are inverted */
242 sky2_write8(hw, B2_Y2_CLK_GATE,
243 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
244 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
245 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
246
247 /* switch power to VAUX */
248 if (vaux && state != PCI_D3cold)
249 sky2_write8(hw, B0_POWER_CTRL,
250 (PC_VAUX_ENA | PC_VCC_ENA |
251 PC_VAUX_ON | PC_VCC_OFF));
252 break;
253 default:
254 printk(KERN_ERR PFX "Unknown power state %d\n", state);
255 ret = -1;
256 }
257
258 pci_write_config_byte(hw->pdev, hw->pm_cap + PCI_PM_CTRL, power_control);
259 sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
260 return ret;
261}
262
178static void sky2_phy_reset(struct sky2_hw *hw, unsigned port) 263static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
179{ 264{
180 u16 reg; 265 u16 reg;
@@ -1869,7 +1954,7 @@ static inline u32 sky2_us2clk(const struct sky2_hw *hw, u32 us)
1869 1954
1870static int sky2_reset(struct sky2_hw *hw) 1955static int sky2_reset(struct sky2_hw *hw)
1871{ 1956{
1872 u32 ctst, power; 1957 u32 ctst;
1873 u16 status; 1958 u16 status;
1874 u8 t8, pmd_type; 1959 u8 t8, pmd_type;
1875 int i; 1960 int i;
@@ -1927,33 +2012,7 @@ static int sky2_reset(struct sky2_hw *hw)
1927 } 2012 }
1928 hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; 2013 hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
1929 2014
1930 /* switch power to VCC (WA for VAUX problem) */ 2015 sky2_set_power_state(hw, PCI_D0);
1931 sky2_write8(hw, B0_POWER_CTRL,
1932 PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
1933
1934 /* disable Core Clock Division, */
1935 sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
1936
1937 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
1938 /* enable bits are inverted */
1939 sky2_write8(hw, B2_Y2_CLK_GATE,
1940 Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
1941 Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
1942 Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
1943 else
1944 sky2_write8(hw, B2_Y2_CLK_GATE, 0);
1945
1946 /* Turn off phy power saving */
1947 pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &power);
1948 power &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
1949
1950 /* looks like this xl is back asswards .. */
1951 if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) {
1952 power |= PCI_Y2_PHY1_COMA;
1953 if (hw->ports > 1)
1954 power |= PCI_Y2_PHY2_COMA;
1955 }
1956 pci_write_config_dword(hw->pdev, PCI_DEV_REG1, power);
1957 2016
1958 for (i = 0; i < hw->ports; i++) { 2017 for (i = 0; i < hw->ports; i++) {
1959 sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); 2018 sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2714,7 +2773,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
2714{ 2773{
2715 struct net_device *dev, *dev1 = NULL; 2774 struct net_device *dev, *dev1 = NULL;
2716 struct sky2_hw *hw; 2775 struct sky2_hw *hw;
2717 int err, using_dac = 0; 2776 int err, pm_cap, using_dac = 0;
2718 2777
2719 err = pci_enable_device(pdev); 2778 err = pci_enable_device(pdev);
2720 if (err) { 2779 if (err) {
@@ -2732,6 +2791,15 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
2732 2791
2733 pci_set_master(pdev); 2792 pci_set_master(pdev);
2734 2793
2794 /* Find power-management capability. */
2795 pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
2796 if (pm_cap == 0) {
2797 printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
2798 "aborting.\n");
2799 err = -EIO;
2800 goto err_out_free_regions;
2801 }
2802
2735 if (sizeof(dma_addr_t) > sizeof(u32)) { 2803 if (sizeof(dma_addr_t) > sizeof(u32)) {
2736 err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); 2804 err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
2737 if (!err) 2805 if (!err)
@@ -2775,6 +2843,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
2775 pci_name(pdev)); 2843 pci_name(pdev));
2776 goto err_out_free_hw; 2844 goto err_out_free_hw;
2777 } 2845 }
2846 hw->pm_cap = pm_cap;
2778 2847
2779 err = sky2_reset(hw); 2848 err = sky2_reset(hw);
2780 if (err) 2849 if (err)
@@ -2861,8 +2930,10 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
2861 unregister_netdev(dev0); 2930 unregister_netdev(dev0);
2862 2931
2863 sky2_write32(hw, B0_IMSK, 0); 2932 sky2_write32(hw, B0_IMSK, 0);
2933 sky2_set_power_state(hw, PCI_D3hot);
2864 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); 2934 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
2865 sky2_write8(hw, B0_CTST, CS_RST_SET); 2935 sky2_write8(hw, B0_CTST, CS_RST_SET);
2936 sky2_read8(hw, B0_CTST);
2866 2937
2867 free_irq(pdev->irq, hw); 2938 free_irq(pdev->irq, hw);
2868 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); 2939 pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
@@ -2874,6 +2945,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
2874 free_netdev(dev0); 2945 free_netdev(dev0);
2875 iounmap(hw->regs); 2946 iounmap(hw->regs);
2876 kfree(hw); 2947 kfree(hw);
2948
2877 pci_set_drvdata(pdev, NULL); 2949 pci_set_drvdata(pdev, NULL);
2878} 2950}
2879 2951
@@ -2881,28 +2953,21 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
2881static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) 2953static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
2882{ 2954{
2883 struct sky2_hw *hw = pci_get_drvdata(pdev); 2955 struct sky2_hw *hw = pci_get_drvdata(pdev);
2884 int i, wol = 0; 2956 int i;
2885 2957
2886 for (i = 0; i < 2; i++) { 2958 for (i = 0; i < 2; i++) {
2887 struct net_device *dev = hw->dev[i]; 2959 struct net_device *dev = hw->dev[i];
2888 2960
2889 if (dev) { 2961 if (dev) {
2890 struct sky2_port *sky2 = netdev_priv(dev); 2962 if (!netif_running(dev))
2891 if (netif_running(dev)) { 2963 continue;
2892 netif_carrier_off(dev); 2964
2893 sky2_down(dev); 2965 sky2_down(dev);
2894 }
2895 netif_device_detach(dev); 2966 netif_device_detach(dev);
2896 wol |= sky2->wol;
2897 } 2967 }
2898 } 2968 }
2899 2969
2900 pci_save_state(pdev); 2970 return sky2_set_power_state(hw, pci_choose_state(pdev, state));
2901 pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
2902 pci_disable_device(pdev);
2903 pci_set_power_state(pdev, pci_choose_state(pdev, state));
2904
2905 return 0;
2906} 2971}
2907 2972
2908static int sky2_resume(struct pci_dev *pdev) 2973static int sky2_resume(struct pci_dev *pdev)
@@ -2910,18 +2975,19 @@ static int sky2_resume(struct pci_dev *pdev)
2910 struct sky2_hw *hw = pci_get_drvdata(pdev); 2975 struct sky2_hw *hw = pci_get_drvdata(pdev);
2911 int i; 2976 int i;
2912 2977
2913 pci_set_power_state(pdev, PCI_D0);
2914 pci_restore_state(pdev); 2978 pci_restore_state(pdev);
2915 pci_enable_wake(pdev, PCI_D0, 0); 2979 pci_enable_wake(pdev, PCI_D0, 0);
2980 sky2_set_power_state(hw, PCI_D0);
2916 2981
2917 sky2_reset(hw); 2982 sky2_reset(hw);
2918 2983
2919 for (i = 0; i < 2; i++) { 2984 for (i = 0; i < 2; i++) {
2920 struct net_device *dev = hw->dev[i]; 2985 struct net_device *dev = hw->dev[i];
2921 if (dev) { 2986 if (dev) {
2922 netif_device_attach(dev); 2987 if (netif_running(dev)) {
2923 if (netif_running(dev)) 2988 netif_device_attach(dev);
2924 sky2_up(dev); 2989 sky2_up(dev);
2990 }
2925 } 2991 }
2926 } 2992 }
2927 return 0; 2993 return 0;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index ac91d91f130b..b1acdc606f31 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1854,6 +1854,7 @@ struct sky2_hw {
1854 u32 intr_mask; 1854 u32 intr_mask;
1855 struct net_device *dev[2]; 1855 struct net_device *dev[2];
1856 1856
1857 int pm_cap;
1857 u8 chip_id; 1858 u8 chip_id;
1858 u8 chip_rev; 1859 u8 chip_rev;
1859 u8 copper; 1860 u8 copper;