diff options
Diffstat (limited to 'drivers/net/sky2.c')
| -rw-r--r-- | drivers/net/sky2.c | 186 |
1 files changed, 141 insertions, 45 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f8b973a04b65..cae2edf23004 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
| @@ -23,12 +23,6 @@ | |||
| 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | /* | ||
| 27 | * TOTEST | ||
| 28 | * - speed setting | ||
| 29 | * - suspend/resume | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/config.h> | 26 | #include <linux/config.h> |
| 33 | #include <linux/crc32.h> | 27 | #include <linux/crc32.h> |
| 34 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
| @@ -57,7 +51,7 @@ | |||
| 57 | #include "sky2.h" | 51 | #include "sky2.h" |
| 58 | 52 | ||
| 59 | #define DRV_NAME "sky2" | 53 | #define DRV_NAME "sky2" |
| 60 | #define DRV_VERSION "0.13" | 54 | #define DRV_VERSION "0.15" |
| 61 | #define PFX DRV_NAME " " | 55 | #define PFX DRV_NAME " " |
| 62 | 56 | ||
| 63 | /* | 57 | /* |
| @@ -102,6 +96,10 @@ static int copybreak __read_mostly = 256; | |||
| 102 | module_param(copybreak, int, 0); | 96 | module_param(copybreak, int, 0); |
| 103 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); | 97 | MODULE_PARM_DESC(copybreak, "Receive copy threshold"); |
| 104 | 98 | ||
| 99 | static int disable_msi = 0; | ||
| 100 | module_param(disable_msi, int, 0); | ||
| 101 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
| 102 | |||
| 105 | static const struct pci_device_id sky2_id_table[] = { | 103 | static const struct pci_device_id sky2_id_table[] = { |
| 106 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, | 104 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, |
| 107 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, | 105 | { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, |
| @@ -198,7 +196,7 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) | |||
| 198 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 196 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
| 199 | 197 | ||
| 200 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_PMC, &power_control); | 198 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_PMC, &power_control); |
| 201 | vaux = (sky2_read8(hw, B0_CTST) & Y2_VAUX_AVAIL) && | 199 | vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) && |
| 202 | (power_control & PCI_PM_CAP_PME_D3cold); | 200 | (power_control & PCI_PM_CAP_PME_D3cold); |
| 203 | 201 | ||
| 204 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_CTRL, &power_control); | 202 | pci_read_config_word(hw->pdev, hw->pm_cap + PCI_PM_CTRL, &power_control); |
| @@ -1834,6 +1832,8 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
| 1834 | u16 hwidx; | 1832 | u16 hwidx; |
| 1835 | u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS }; | 1833 | u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS }; |
| 1836 | 1834 | ||
| 1835 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); | ||
| 1836 | |||
| 1837 | hwidx = sky2_read16(hw, STAT_PUT_IDX); | 1837 | hwidx = sky2_read16(hw, STAT_PUT_IDX); |
| 1838 | BUG_ON(hwidx >= STATUS_RING_SIZE); | 1838 | BUG_ON(hwidx >= STATUS_RING_SIZE); |
| 1839 | rmb(); | 1839 | rmb(); |
| @@ -1913,12 +1913,10 @@ static int sky2_poll(struct net_device *dev0, int *budget) | |||
| 1913 | } | 1913 | } |
| 1914 | 1914 | ||
| 1915 | exit_loop: | 1915 | exit_loop: |
| 1916 | sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); | ||
| 1917 | |||
| 1918 | sky2_tx_check(hw, 0, tx_done[0]); | 1916 | sky2_tx_check(hw, 0, tx_done[0]); |
| 1919 | sky2_tx_check(hw, 1, tx_done[1]); | 1917 | sky2_tx_check(hw, 1, tx_done[1]); |
| 1920 | 1918 | ||
| 1921 | if (sky2_read16(hw, STAT_PUT_IDX) == hw->st_idx) { | 1919 | if (likely(work_done < to_do)) { |
| 1922 | /* need to restart TX timer */ | 1920 | /* need to restart TX timer */ |
| 1923 | if (is_ec_a1(hw)) { | 1921 | if (is_ec_a1(hw)) { |
| 1924 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); | 1922 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); |
| @@ -2141,14 +2139,12 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) | |||
| 2141 | 2139 | ||
| 2142 | static int sky2_reset(struct sky2_hw *hw) | 2140 | static int sky2_reset(struct sky2_hw *hw) |
| 2143 | { | 2141 | { |
| 2144 | u32 ctst; | ||
| 2145 | u16 status; | 2142 | u16 status; |
| 2146 | u8 t8, pmd_type; | 2143 | u8 t8, pmd_type; |
| 2147 | int i; | 2144 | int i, err; |
| 2148 | |||
| 2149 | ctst = sky2_read32(hw, B0_CTST); | ||
| 2150 | 2145 | ||
| 2151 | sky2_write8(hw, B0_CTST, CS_RST_CLR); | 2146 | sky2_write8(hw, B0_CTST, CS_RST_CLR); |
| 2147 | |||
| 2152 | hw->chip_id = sky2_read8(hw, B2_CHIP_ID); | 2148 | hw->chip_id = sky2_read8(hw, B2_CHIP_ID); |
| 2153 | if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { | 2149 | if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { |
| 2154 | printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", | 2150 | printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", |
| @@ -2156,12 +2152,6 @@ static int sky2_reset(struct sky2_hw *hw) | |||
| 2156 | return -EOPNOTSUPP; | 2152 | return -EOPNOTSUPP; |
| 2157 | } | 2153 | } |
| 2158 | 2154 | ||
| 2159 | /* ring for status responses */ | ||
| 2160 | hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, | ||
| 2161 | &hw->st_dma); | ||
| 2162 | if (!hw->st_le) | ||
| 2163 | return -ENOMEM; | ||
| 2164 | |||
| 2165 | /* disable ASF */ | 2155 | /* disable ASF */ |
| 2166 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { | 2156 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { |
| 2167 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); | 2157 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); |
| @@ -2173,19 +2163,24 @@ static int sky2_reset(struct sky2_hw *hw) | |||
| 2173 | sky2_write8(hw, B0_CTST, CS_RST_CLR); | 2163 | sky2_write8(hw, B0_CTST, CS_RST_CLR); |
| 2174 | 2164 | ||
| 2175 | /* clear PCI errors, if any */ | 2165 | /* clear PCI errors, if any */ |
| 2176 | pci_read_config_word(hw->pdev, PCI_STATUS, &status); | 2166 | err = pci_read_config_word(hw->pdev, PCI_STATUS, &status); |
| 2167 | if (err) | ||
| 2168 | goto pci_err; | ||
| 2169 | |||
| 2177 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | 2170 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); |
| 2178 | pci_write_config_word(hw->pdev, PCI_STATUS, | 2171 | err = pci_write_config_word(hw->pdev, PCI_STATUS, |
| 2179 | status | PCI_STATUS_ERROR_BITS); | 2172 | status | PCI_STATUS_ERROR_BITS); |
| 2173 | if (err) | ||
| 2174 | goto pci_err; | ||
| 2180 | 2175 | ||
| 2181 | sky2_write8(hw, B0_CTST, CS_MRST_CLR); | 2176 | sky2_write8(hw, B0_CTST, CS_MRST_CLR); |
| 2182 | 2177 | ||
| 2183 | /* clear any PEX errors */ | 2178 | /* clear any PEX errors */ |
| 2184 | if (is_pciex(hw)) { | 2179 | if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) { |
| 2185 | u16 lstat; | 2180 | err = pci_write_config_dword(hw->pdev, PEX_UNC_ERR_STAT, |
| 2186 | pci_write_config_dword(hw->pdev, PEX_UNC_ERR_STAT, | 2181 | 0xffffffffUL); |
| 2187 | 0xffffffffUL); | 2182 | if (err) |
| 2188 | pci_read_config_word(hw->pdev, PEX_LNK_STAT, &lstat); | 2183 | goto pci_err; |
| 2189 | } | 2184 | } |
| 2190 | 2185 | ||
| 2191 | pmd_type = sky2_read8(hw, B2_PMD_TYP); | 2186 | pmd_type = sky2_read8(hw, B2_PMD_TYP); |
| @@ -2297,6 +2292,14 @@ static int sky2_reset(struct sky2_hw *hw) | |||
| 2297 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | 2292 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); |
| 2298 | 2293 | ||
| 2299 | return 0; | 2294 | return 0; |
| 2295 | |||
| 2296 | pci_err: | ||
| 2297 | /* This is to catch a BIOS bug workaround where | ||
| 2298 | * mmconfig table doesn't have other buses. | ||
| 2299 | */ | ||
| 2300 | printk(KERN_ERR PFX "%s: can't access PCI config space\n", | ||
| 2301 | pci_name(hw->pdev)); | ||
| 2302 | return err; | ||
| 2300 | } | 2303 | } |
| 2301 | 2304 | ||
| 2302 | static u32 sky2_supported_modes(const struct sky2_hw *hw) | 2305 | static u32 sky2_supported_modes(const struct sky2_hw *hw) |
| @@ -2551,19 +2554,24 @@ static struct net_device_stats *sky2_get_stats(struct net_device *dev) | |||
| 2551 | static int sky2_set_mac_address(struct net_device *dev, void *p) | 2554 | static int sky2_set_mac_address(struct net_device *dev, void *p) |
| 2552 | { | 2555 | { |
| 2553 | struct sky2_port *sky2 = netdev_priv(dev); | 2556 | struct sky2_port *sky2 = netdev_priv(dev); |
| 2554 | struct sockaddr *addr = p; | 2557 | struct sky2_hw *hw = sky2->hw; |
| 2558 | unsigned port = sky2->port; | ||
| 2559 | const struct sockaddr *addr = p; | ||
| 2555 | 2560 | ||
| 2556 | if (!is_valid_ether_addr(addr->sa_data)) | 2561 | if (!is_valid_ether_addr(addr->sa_data)) |
| 2557 | return -EADDRNOTAVAIL; | 2562 | return -EADDRNOTAVAIL; |
| 2558 | 2563 | ||
| 2559 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 2564 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
| 2560 | memcpy_toio(sky2->hw->regs + B2_MAC_1 + sky2->port * 8, | 2565 | memcpy_toio(hw->regs + B2_MAC_1 + port * 8, |
| 2561 | dev->dev_addr, ETH_ALEN); | 2566 | dev->dev_addr, ETH_ALEN); |
| 2562 | memcpy_toio(sky2->hw->regs + B2_MAC_2 + sky2->port * 8, | 2567 | memcpy_toio(hw->regs + B2_MAC_2 + port * 8, |
| 2563 | dev->dev_addr, ETH_ALEN); | 2568 | dev->dev_addr, ETH_ALEN); |
| 2564 | 2569 | ||
| 2565 | if (netif_running(dev)) | 2570 | /* virtual address for data */ |
| 2566 | sky2_phy_reinit(sky2); | 2571 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); |
| 2572 | |||
| 2573 | /* physical address: used for pause frames */ | ||
| 2574 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); | ||
| 2567 | 2575 | ||
| 2568 | return 0; | 2576 | return 0; |
| 2569 | } | 2577 | } |
| @@ -2843,7 +2851,7 @@ static int sky2_set_coalesce(struct net_device *dev, | |||
| 2843 | if (ecmd->rx_coalesce_usecs_irq == 0) | 2851 | if (ecmd->rx_coalesce_usecs_irq == 0) |
| 2844 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_STOP); | 2852 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_STOP); |
| 2845 | else { | 2853 | else { |
| 2846 | sky2_write32(hw, STAT_TX_TIMER_INI, | 2854 | sky2_write32(hw, STAT_ISR_TIMER_INI, |
| 2847 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs_irq)); | 2855 | sky2_us2clk(hw, ecmd->rx_coalesce_usecs_irq)); |
| 2848 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | 2856 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); |
| 2849 | } | 2857 | } |
| @@ -3055,6 +3063,61 @@ static void __devinit sky2_show_addr(struct net_device *dev) | |||
| 3055 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); | 3063 | dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); |
| 3056 | } | 3064 | } |
| 3057 | 3065 | ||
| 3066 | /* Handle software interrupt used during MSI test */ | ||
| 3067 | static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id, | ||
| 3068 | struct pt_regs *regs) | ||
| 3069 | { | ||
| 3070 | struct sky2_hw *hw = dev_id; | ||
| 3071 | u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2); | ||
| 3072 | |||
| 3073 | if (status == 0) | ||
| 3074 | return IRQ_NONE; | ||
| 3075 | |||
| 3076 | if (status & Y2_IS_IRQ_SW) { | ||
| 3077 | sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); | ||
| 3078 | hw->msi = 1; | ||
| 3079 | } | ||
| 3080 | sky2_write32(hw, B0_Y2_SP_ICR, 2); | ||
| 3081 | |||
| 3082 | sky2_read32(hw, B0_IMSK); | ||
| 3083 | return IRQ_HANDLED; | ||
| 3084 | } | ||
| 3085 | |||
| 3086 | /* Test interrupt path by forcing a a software IRQ */ | ||
| 3087 | static int __devinit sky2_test_msi(struct sky2_hw *hw) | ||
| 3088 | { | ||
| 3089 | struct pci_dev *pdev = hw->pdev; | ||
| 3090 | int i, err; | ||
| 3091 | |||
| 3092 | sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); | ||
| 3093 | |||
| 3094 | err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw); | ||
| 3095 | if (err) { | ||
| 3096 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", | ||
| 3097 | pci_name(pdev), pdev->irq); | ||
| 3098 | return err; | ||
| 3099 | } | ||
| 3100 | |||
| 3101 | sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); | ||
| 3102 | wmb(); | ||
| 3103 | |||
| 3104 | for (i = 0; i < 10; i++) { | ||
| 3105 | barrier(); | ||
| 3106 | if (hw->msi) | ||
| 3107 | goto found; | ||
| 3108 | mdelay(1); | ||
| 3109 | } | ||
| 3110 | |||
| 3111 | err = -EOPNOTSUPP; | ||
| 3112 | sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); | ||
| 3113 | found: | ||
| 3114 | sky2_write32(hw, B0_IMSK, 0); | ||
| 3115 | |||
| 3116 | free_irq(pdev->irq, hw); | ||
| 3117 | |||
| 3118 | return err; | ||
| 3119 | } | ||
| 3120 | |||
| 3058 | static int __devinit sky2_probe(struct pci_dev *pdev, | 3121 | static int __devinit sky2_probe(struct pci_dev *pdev, |
| 3059 | const struct pci_device_id *ent) | 3122 | const struct pci_device_id *ent) |
| 3060 | { | 3123 | { |
| @@ -3135,6 +3198,12 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
| 3135 | } | 3198 | } |
| 3136 | hw->pm_cap = pm_cap; | 3199 | hw->pm_cap = pm_cap; |
| 3137 | 3200 | ||
| 3201 | /* ring for status responses */ | ||
| 3202 | hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES, | ||
| 3203 | &hw->st_dma); | ||
| 3204 | if (!hw->st_le) | ||
| 3205 | goto err_out_iounmap; | ||
| 3206 | |||
| 3138 | err = sky2_reset(hw); | 3207 | err = sky2_reset(hw); |
| 3139 | if (err) | 3208 | if (err) |
| 3140 | goto err_out_iounmap; | 3209 | goto err_out_iounmap; |
| @@ -3169,7 +3238,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
| 3169 | } | 3238 | } |
| 3170 | } | 3239 | } |
| 3171 | 3240 | ||
| 3172 | err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); | 3241 | if (!disable_msi && pci_enable_msi(pdev) == 0) { |
| 3242 | err = sky2_test_msi(hw); | ||
| 3243 | if (err == -EOPNOTSUPP) { | ||
| 3244 | /* MSI test failed, go back to INTx mode */ | ||
| 3245 | printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " | ||
| 3246 | "switching to INTx mode. Please report this failure to " | ||
| 3247 | "the PCI maintainer and include system chipset information.\n", | ||
| 3248 | pci_name(pdev)); | ||
| 3249 | pci_disable_msi(pdev); | ||
| 3250 | } | ||
| 3251 | else if (err) | ||
| 3252 | goto err_out_unregister; | ||
| 3253 | } | ||
| 3254 | |||
| 3255 | err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, | ||
| 3256 | DRV_NAME, hw); | ||
| 3173 | if (err) { | 3257 | if (err) { |
| 3174 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", | 3258 | printk(KERN_ERR PFX "%s: cannot assign irq %d\n", |
| 3175 | pci_name(pdev), pdev->irq); | 3259 | pci_name(pdev), pdev->irq); |
| @@ -3184,6 +3268,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
| 3184 | return 0; | 3268 | return 0; |
| 3185 | 3269 | ||
| 3186 | err_out_unregister: | 3270 | err_out_unregister: |
| 3271 | if (hw->msi) | ||
| 3272 | pci_disable_msi(pdev); | ||
| 3187 | if (dev1) { | 3273 | if (dev1) { |
| 3188 | unregister_netdev(dev1); | 3274 | unregister_netdev(dev1); |
| 3189 | free_netdev(dev1); | 3275 | free_netdev(dev1); |
| @@ -3226,6 +3312,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) | |||
| 3226 | sky2_read8(hw, B0_CTST); | 3312 | sky2_read8(hw, B0_CTST); |
| 3227 | 3313 | ||
| 3228 | free_irq(pdev->irq, hw); | 3314 | free_irq(pdev->irq, hw); |
| 3315 | if (hw->msi) | ||
| 3316 | pci_disable_msi(pdev); | ||
| 3229 | pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); | 3317 | pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); |
| 3230 | pci_release_regions(pdev); | 3318 | pci_release_regions(pdev); |
| 3231 | pci_disable_device(pdev); | 3319 | pci_disable_device(pdev); |
| @@ -3263,25 +3351,33 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) | |||
| 3263 | static int sky2_resume(struct pci_dev *pdev) | 3351 | static int sky2_resume(struct pci_dev *pdev) |
| 3264 | { | 3352 | { |
| 3265 | struct sky2_hw *hw = pci_get_drvdata(pdev); | 3353 | struct sky2_hw *hw = pci_get_drvdata(pdev); |
| 3266 | int i; | 3354 | int i, err; |
| 3267 | 3355 | ||
| 3268 | pci_restore_state(pdev); | 3356 | pci_restore_state(pdev); |
| 3269 | pci_enable_wake(pdev, PCI_D0, 0); | 3357 | pci_enable_wake(pdev, PCI_D0, 0); |
| 3270 | sky2_set_power_state(hw, PCI_D0); | 3358 | err = sky2_set_power_state(hw, PCI_D0); |
| 3359 | if (err) | ||
| 3360 | goto out; | ||
| 3271 | 3361 | ||
| 3272 | sky2_reset(hw); | 3362 | err = sky2_reset(hw); |
| 3363 | if (err) | ||
| 3364 | goto out; | ||
| 3273 | 3365 | ||
| 3274 | for (i = 0; i < 2; i++) { | 3366 | for (i = 0; i < 2; i++) { |
| 3275 | struct net_device *dev = hw->dev[i]; | 3367 | struct net_device *dev = hw->dev[i]; |
| 3276 | if (dev) { | 3368 | if (dev && netif_running(dev)) { |
| 3277 | if (netif_running(dev)) { | 3369 | netif_device_attach(dev); |
| 3278 | netif_device_attach(dev); | 3370 | err = sky2_up(dev); |
| 3279 | if (sky2_up(dev)) | 3371 | if (err) { |
| 3280 | dev_close(dev); | 3372 | printk(KERN_ERR PFX "%s: could not up: %d\n", |
| 3373 | dev->name, err); | ||
| 3374 | dev_close(dev); | ||
| 3375 | break; | ||
| 3281 | } | 3376 | } |
| 3282 | } | 3377 | } |
| 3283 | } | 3378 | } |
| 3284 | return 0; | 3379 | out: |
| 3380 | return err; | ||
| 3285 | } | 3381 | } |
| 3286 | #endif | 3382 | #endif |
| 3287 | 3383 | ||
