diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-02-06 13:45:39 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-07 18:49:59 -0500 |
commit | e3173832d7be8f62a181a1888a65f0a3dc58c2e0 (patch) | |
tree | 195129acd8ec02c265e7a8152f311cafaede1be5 /drivers/net/sky2.c | |
parent | dde6d43d060bf0e0f38c66f76908e460db3bf0d8 (diff) |
sky2: add Wake On Lan support
Adds basic magic packet wake on lan support to the sky2 driver.
Note: initial WOL value is based on BIOS settings.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 208 |
1 files changed, 181 insertions, 27 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bf1abf034d8a..f4c0bc19b005 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -567,6 +567,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2) | |||
567 | spin_unlock_bh(&sky2->phy_lock); | 567 | spin_unlock_bh(&sky2->phy_lock); |
568 | } | 568 | } |
569 | 569 | ||
570 | /* Put device in state to listen for Wake On Lan */ | ||
571 | static void sky2_wol_init(struct sky2_port *sky2) | ||
572 | { | ||
573 | struct sky2_hw *hw = sky2->hw; | ||
574 | unsigned port = sky2->port; | ||
575 | enum flow_control save_mode; | ||
576 | u16 ctrl; | ||
577 | u32 reg1; | ||
578 | |||
579 | /* Bring hardware out of reset */ | ||
580 | sky2_write16(hw, B0_CTST, CS_RST_CLR); | ||
581 | sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); | ||
582 | |||
583 | sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); | ||
584 | sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); | ||
585 | |||
586 | /* Force to 10/100 | ||
587 | * sky2_reset will re-enable on resume | ||
588 | */ | ||
589 | save_mode = sky2->flow_mode; | ||
590 | ctrl = sky2->advertising; | ||
591 | |||
592 | sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); | ||
593 | sky2->flow_mode = FC_NONE; | ||
594 | sky2_phy_power(hw, port, 1); | ||
595 | sky2_phy_reinit(sky2); | ||
596 | |||
597 | sky2->flow_mode = save_mode; | ||
598 | sky2->advertising = ctrl; | ||
599 | |||
600 | /* Set GMAC to no flow control and auto update for speed/duplex */ | ||
601 | gma_write16(hw, port, GM_GP_CTRL, | ||
602 | GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| | ||
603 | GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); | ||
604 | |||
605 | /* Set WOL address */ | ||
606 | memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), | ||
607 | sky2->netdev->dev_addr, ETH_ALEN); | ||
608 | |||
609 | /* Turn on appropriate WOL control bits */ | ||
610 | sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); | ||
611 | ctrl = 0; | ||
612 | if (sky2->wol & WAKE_PHY) | ||
613 | ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; | ||
614 | else | ||
615 | ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; | ||
616 | |||
617 | if (sky2->wol & WAKE_MAGIC) | ||
618 | ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; | ||
619 | else | ||
620 | ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; | ||
621 | |||
622 | ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; | ||
623 | sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); | ||
624 | |||
625 | /* Turn on legacy PCI-Express PME mode */ | ||
626 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); | ||
627 | reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); | ||
628 | reg1 |= PCI_Y2_PME_LEGACY; | ||
629 | sky2_pci_write32(hw, PCI_DEV_REG1, reg1); | ||
630 | sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); | ||
631 | |||
632 | /* block receiver */ | ||
633 | sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); | ||
634 | |||
635 | } | ||
636 | |||
570 | static void sky2_mac_init(struct sky2_hw *hw, unsigned port) | 637 | static void sky2_mac_init(struct sky2_hw *hw, unsigned port) |
571 | { | 638 | { |
572 | struct sky2_port *sky2 = netdev_priv(hw->dev[port]); | 639 | struct sky2_port *sky2 = netdev_priv(hw->dev[port]); |
@@ -2404,11 +2471,9 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) | |||
2404 | } | 2471 | } |
2405 | 2472 | ||
2406 | 2473 | ||
2407 | static int sky2_reset(struct sky2_hw *hw) | 2474 | static int __devinit sky2_init(struct sky2_hw *hw) |
2408 | { | 2475 | { |
2409 | u16 status; | ||
2410 | u8 t8; | 2476 | u8 t8; |
2411 | int i; | ||
2412 | 2477 | ||
2413 | sky2_write8(hw, B0_CTST, CS_RST_CLR); | 2478 | sky2_write8(hw, B0_CTST, CS_RST_CLR); |
2414 | 2479 | ||
@@ -2429,6 +2494,22 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2429 | return -EOPNOTSUPP; | 2494 | return -EOPNOTSUPP; |
2430 | } | 2495 | } |
2431 | 2496 | ||
2497 | hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); | ||
2498 | hw->ports = 1; | ||
2499 | t8 = sky2_read8(hw, B2_Y2_HW_RES); | ||
2500 | if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { | ||
2501 | if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) | ||
2502 | ++hw->ports; | ||
2503 | } | ||
2504 | |||
2505 | return 0; | ||
2506 | } | ||
2507 | |||
2508 | static void sky2_reset(struct sky2_hw *hw) | ||
2509 | { | ||
2510 | u16 status; | ||
2511 | int i; | ||
2512 | |||
2432 | /* disable ASF */ | 2513 | /* disable ASF */ |
2433 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { | 2514 | if (hw->chip_id <= CHIP_ID_YUKON_EC) { |
2434 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); | 2515 | sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); |
@@ -2453,14 +2534,6 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2453 | sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); | 2534 | sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); |
2454 | 2535 | ||
2455 | 2536 | ||
2456 | hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); | ||
2457 | hw->ports = 1; | ||
2458 | t8 = sky2_read8(hw, B2_Y2_HW_RES); | ||
2459 | if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { | ||
2460 | if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) | ||
2461 | ++hw->ports; | ||
2462 | } | ||
2463 | |||
2464 | sky2_power_on(hw); | 2537 | sky2_power_on(hw); |
2465 | 2538 | ||
2466 | for (i = 0; i < hw->ports; i++) { | 2539 | for (i = 0; i < hw->ports; i++) { |
@@ -2544,7 +2617,37 @@ static int sky2_reset(struct sky2_hw *hw) | |||
2544 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); | 2617 | sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); |
2545 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); | 2618 | sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); |
2546 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); | 2619 | sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); |
2620 | } | ||
2621 | |||
2622 | static inline u8 sky2_wol_supported(const struct sky2_hw *hw) | ||
2623 | { | ||
2624 | return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; | ||
2625 | } | ||
2626 | |||
2627 | static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
2628 | { | ||
2629 | const struct sky2_port *sky2 = netdev_priv(dev); | ||
2630 | |||
2631 | wol->supported = sky2_wol_supported(sky2->hw); | ||
2632 | wol->wolopts = sky2->wol; | ||
2633 | } | ||
2634 | |||
2635 | static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
2636 | { | ||
2637 | struct sky2_port *sky2 = netdev_priv(dev); | ||
2638 | struct sky2_hw *hw = sky2->hw; | ||
2547 | 2639 | ||
2640 | if (wol->wolopts & ~sky2_wol_supported(sky2->hw)) | ||
2641 | return -EOPNOTSUPP; | ||
2642 | |||
2643 | sky2->wol = wol->wolopts; | ||
2644 | |||
2645 | if (hw->chip_id == CHIP_ID_YUKON_EC_U) | ||
2646 | sky2_write32(hw, B0_CTST, sky2->wol | ||
2647 | ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); | ||
2648 | |||
2649 | if (!netif_running(dev)) | ||
2650 | sky2_wol_init(sky2); | ||
2548 | return 0; | 2651 | return 0; |
2549 | } | 2652 | } |
2550 | 2653 | ||
@@ -3156,7 +3259,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
3156 | static const struct ethtool_ops sky2_ethtool_ops = { | 3259 | static const struct ethtool_ops sky2_ethtool_ops = { |
3157 | .get_settings = sky2_get_settings, | 3260 | .get_settings = sky2_get_settings, |
3158 | .set_settings = sky2_set_settings, | 3261 | .set_settings = sky2_set_settings, |
3159 | .get_drvinfo = sky2_get_drvinfo, | 3262 | .get_drvinfo = sky2_get_drvinfo, |
3263 | .get_wol = sky2_get_wol, | ||
3264 | .set_wol = sky2_set_wol, | ||
3160 | .get_msglevel = sky2_get_msglevel, | 3265 | .get_msglevel = sky2_get_msglevel, |
3161 | .set_msglevel = sky2_set_msglevel, | 3266 | .set_msglevel = sky2_set_msglevel, |
3162 | .nway_reset = sky2_nway_reset, | 3267 | .nway_reset = sky2_nway_reset, |
@@ -3186,7 +3291,8 @@ static const struct ethtool_ops sky2_ethtool_ops = { | |||
3186 | 3291 | ||
3187 | /* Initialize network device */ | 3292 | /* Initialize network device */ |
3188 | static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, | 3293 | static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, |
3189 | unsigned port, int highmem) | 3294 | unsigned port, |
3295 | int highmem, int wol) | ||
3190 | { | 3296 | { |
3191 | struct sky2_port *sky2; | 3297 | struct sky2_port *sky2; |
3192 | struct net_device *dev = alloc_etherdev(sizeof(*sky2)); | 3298 | struct net_device *dev = alloc_etherdev(sizeof(*sky2)); |
@@ -3234,6 +3340,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, | |||
3234 | sky2->speed = -1; | 3340 | sky2->speed = -1; |
3235 | sky2->advertising = sky2_supported_modes(hw); | 3341 | sky2->advertising = sky2_supported_modes(hw); |
3236 | sky2->rx_csum = 1; | 3342 | sky2->rx_csum = 1; |
3343 | sky2->wol = wol; | ||
3237 | 3344 | ||
3238 | spin_lock_init(&sky2->phy_lock); | 3345 | spin_lock_init(&sky2->phy_lock); |
3239 | sky2->tx_pending = TX_DEF_PENDING; | 3346 | sky2->tx_pending = TX_DEF_PENDING; |
@@ -3336,12 +3443,24 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) | |||
3336 | return err; | 3443 | return err; |
3337 | } | 3444 | } |
3338 | 3445 | ||
3446 | static int __devinit pci_wake_enabled(struct pci_dev *dev) | ||
3447 | { | ||
3448 | int pm = pci_find_capability(dev, PCI_CAP_ID_PM); | ||
3449 | u16 value; | ||
3450 | |||
3451 | if (!pm) | ||
3452 | return 0; | ||
3453 | if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value)) | ||
3454 | return 0; | ||
3455 | return value & PCI_PM_CTRL_PME_ENABLE; | ||
3456 | } | ||
3457 | |||
3339 | static int __devinit sky2_probe(struct pci_dev *pdev, | 3458 | static int __devinit sky2_probe(struct pci_dev *pdev, |
3340 | const struct pci_device_id *ent) | 3459 | const struct pci_device_id *ent) |
3341 | { | 3460 | { |
3342 | struct net_device *dev; | 3461 | struct net_device *dev; |
3343 | struct sky2_hw *hw; | 3462 | struct sky2_hw *hw; |
3344 | int err, using_dac = 0; | 3463 | int err, using_dac = 0, wol_default; |
3345 | 3464 | ||
3346 | err = pci_enable_device(pdev); | 3465 | err = pci_enable_device(pdev); |
3347 | if (err) { | 3466 | if (err) { |
@@ -3378,6 +3497,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3378 | } | 3497 | } |
3379 | } | 3498 | } |
3380 | 3499 | ||
3500 | wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0; | ||
3501 | |||
3381 | err = -ENOMEM; | 3502 | err = -ENOMEM; |
3382 | hw = kzalloc(sizeof(*hw), GFP_KERNEL); | 3503 | hw = kzalloc(sizeof(*hw), GFP_KERNEL); |
3383 | if (!hw) { | 3504 | if (!hw) { |
@@ -3413,7 +3534,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3413 | if (!hw->st_le) | 3534 | if (!hw->st_le) |
3414 | goto err_out_iounmap; | 3535 | goto err_out_iounmap; |
3415 | 3536 | ||
3416 | err = sky2_reset(hw); | 3537 | err = sky2_init(hw); |
3417 | if (err) | 3538 | if (err) |
3418 | goto err_out_iounmap; | 3539 | goto err_out_iounmap; |
3419 | 3540 | ||
@@ -3422,7 +3543,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3422 | pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], | 3543 | pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], |
3423 | hw->chip_id, hw->chip_rev); | 3544 | hw->chip_id, hw->chip_rev); |
3424 | 3545 | ||
3425 | dev = sky2_init_netdev(hw, 0, using_dac); | 3546 | sky2_reset(hw); |
3547 | |||
3548 | dev = sky2_init_netdev(hw, 0, using_dac, wol_default); | ||
3426 | if (!dev) { | 3549 | if (!dev) { |
3427 | err = -ENOMEM; | 3550 | err = -ENOMEM; |
3428 | goto err_out_free_pci; | 3551 | goto err_out_free_pci; |
@@ -3457,7 +3580,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, | |||
3457 | if (hw->ports > 1) { | 3580 | if (hw->ports > 1) { |
3458 | struct net_device *dev1; | 3581 | struct net_device *dev1; |
3459 | 3582 | ||
3460 | dev1 = sky2_init_netdev(hw, 1, using_dac); | 3583 | dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default); |
3461 | if (!dev1) { | 3584 | if (!dev1) { |
3462 | printk(KERN_WARNING PFX | 3585 | printk(KERN_WARNING PFX |
3463 | "allocation of second port failed\n"); | 3586 | "allocation of second port failed\n"); |
@@ -3544,23 +3667,29 @@ static void __devexit sky2_remove(struct pci_dev *pdev) | |||
3544 | static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) | 3667 | static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) |
3545 | { | 3668 | { |
3546 | struct sky2_hw *hw = pci_get_drvdata(pdev); | 3669 | struct sky2_hw *hw = pci_get_drvdata(pdev); |
3547 | int i; | 3670 | int i, wol = 0; |
3548 | 3671 | ||
3549 | del_timer_sync(&hw->idle_timer); | 3672 | del_timer_sync(&hw->idle_timer); |
3550 | netif_poll_disable(hw->dev[0]); | 3673 | netif_poll_disable(hw->dev[0]); |
3551 | 3674 | ||
3552 | for (i = 0; i < hw->ports; i++) { | 3675 | for (i = 0; i < hw->ports; i++) { |
3553 | struct net_device *dev = hw->dev[i]; | 3676 | struct net_device *dev = hw->dev[i]; |
3677 | struct sky2_port *sky2 = netdev_priv(dev); | ||
3554 | 3678 | ||
3555 | if (netif_running(dev)) { | 3679 | if (netif_running(dev)) |
3556 | sky2_down(dev); | 3680 | sky2_down(dev); |
3557 | netif_device_detach(dev); | 3681 | |
3558 | } | 3682 | if (sky2->wol) |
3683 | sky2_wol_init(sky2); | ||
3684 | |||
3685 | wol |= sky2->wol; | ||
3559 | } | 3686 | } |
3560 | 3687 | ||
3561 | sky2_write32(hw, B0_IMSK, 0); | 3688 | sky2_write32(hw, B0_IMSK, 0); |
3562 | sky2_power_aux(hw); | 3689 | sky2_power_aux(hw); |
3690 | |||
3563 | pci_save_state(pdev); | 3691 | pci_save_state(pdev); |
3692 | pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); | ||
3564 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 3693 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); |
3565 | 3694 | ||
3566 | return 0; | 3695 | return 0; |
@@ -3580,18 +3709,13 @@ static int sky2_resume(struct pci_dev *pdev) | |||
3580 | goto out; | 3709 | goto out; |
3581 | 3710 | ||
3582 | pci_enable_wake(pdev, PCI_D0, 0); | 3711 | pci_enable_wake(pdev, PCI_D0, 0); |
3583 | 3712 | sky2_reset(hw); | |
3584 | err = sky2_reset(hw); | ||
3585 | if (err) | ||
3586 | goto out; | ||
3587 | 3713 | ||
3588 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); | 3714 | sky2_write32(hw, B0_IMSK, Y2_IS_BASE); |
3589 | 3715 | ||
3590 | for (i = 0; i < hw->ports; i++) { | 3716 | for (i = 0; i < hw->ports; i++) { |
3591 | struct net_device *dev = hw->dev[i]; | 3717 | struct net_device *dev = hw->dev[i]; |
3592 | if (netif_running(dev)) { | 3718 | if (netif_running(dev)) { |
3593 | netif_device_attach(dev); | ||
3594 | |||
3595 | err = sky2_up(dev); | 3719 | err = sky2_up(dev); |
3596 | if (err) { | 3720 | if (err) { |
3597 | printk(KERN_ERR PFX "%s: could not up: %d\n", | 3721 | printk(KERN_ERR PFX "%s: could not up: %d\n", |
@@ -3612,6 +3736,35 @@ out: | |||
3612 | } | 3736 | } |
3613 | #endif | 3737 | #endif |
3614 | 3738 | ||
3739 | static void sky2_shutdown(struct pci_dev *pdev) | ||
3740 | { | ||
3741 | struct sky2_hw *hw = pci_get_drvdata(pdev); | ||
3742 | int i, wol = 0; | ||
3743 | |||
3744 | del_timer_sync(&hw->idle_timer); | ||
3745 | netif_poll_disable(hw->dev[0]); | ||
3746 | |||
3747 | for (i = 0; i < hw->ports; i++) { | ||
3748 | struct net_device *dev = hw->dev[i]; | ||
3749 | struct sky2_port *sky2 = netdev_priv(dev); | ||
3750 | |||
3751 | if (sky2->wol) { | ||
3752 | wol = 1; | ||
3753 | sky2_wol_init(sky2); | ||
3754 | } | ||
3755 | } | ||
3756 | |||
3757 | if (wol) | ||
3758 | sky2_power_aux(hw); | ||
3759 | |||
3760 | pci_enable_wake(pdev, PCI_D3hot, wol); | ||
3761 | pci_enable_wake(pdev, PCI_D3cold, wol); | ||
3762 | |||
3763 | pci_disable_device(pdev); | ||
3764 | pci_set_power_state(pdev, PCI_D3hot); | ||
3765 | |||
3766 | } | ||
3767 | |||
3615 | static struct pci_driver sky2_driver = { | 3768 | static struct pci_driver sky2_driver = { |
3616 | .name = DRV_NAME, | 3769 | .name = DRV_NAME, |
3617 | .id_table = sky2_id_table, | 3770 | .id_table = sky2_id_table, |
@@ -3621,6 +3774,7 @@ static struct pci_driver sky2_driver = { | |||
3621 | .suspend = sky2_suspend, | 3774 | .suspend = sky2_suspend, |
3622 | .resume = sky2_resume, | 3775 | .resume = sky2_resume, |
3623 | #endif | 3776 | #endif |
3777 | .shutdown = sky2_shutdown, | ||
3624 | }; | 3778 | }; |
3625 | 3779 | ||
3626 | static int __init sky2_init_module(void) | 3780 | static int __init sky2_init_module(void) |