aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ixgbe/ixgbe_main.c
diff options
context:
space:
mode:
authorDonald Skidmore <donald.c.skidmore@intel.com>2008-11-21 00:11:42 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-21 00:11:42 -0500
commitc4900be053d376dfe4f603d000aa5e4c60745dec (patch)
treef5658e8d4f2345e0f15346020fe3aeb2adb48905 /drivers/net/ixgbe/ixgbe_main.c
parent859ee3c43812051e21816c6d6d4cc04fb7ce9b2e (diff)
ixgbe: add SFP+ driver support
This patch adds support for SFP+ PHY in the following device ID's (10DB, 10F1, 10E1). These SFP+ PHY's are accessed via an I2C interface so the patch also includes functions to support this. Another feature of note is that the PHY is pluggable and some rearchitecting was needed to support this. Signed-off-by: Donald Skidmore <donald.c.skidmore@intel.com> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_main.c')
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c94
1 files changed, 91 insertions, 3 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 91dde9cdab6..6620397a1fb 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -74,8 +74,14 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
74 board_82598 }, 74 board_82598 },
75 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), 75 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
76 board_82598 }, 76 board_82598 },
77 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT),
78 board_82598 },
79 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM),
80 board_82598 },
77 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), 81 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR),
78 board_82598 }, 82 board_82598 },
83 {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM),
84 board_82598 },
79 85
80 /* required last entry */ 86 /* required last entry */
81 {0, } 87 {0, }
@@ -2680,6 +2686,57 @@ err_alloc_queues:
2680} 2686}
2681 2687
2682/** 2688/**
2689 * ixgbe_sfp_timer - worker thread to find a missing module
2690 * @data: pointer to our adapter struct
2691 **/
2692static void ixgbe_sfp_timer(unsigned long data)
2693{
2694 struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
2695
2696 /* Do the sfp_timer outside of interrupt context due to the
2697 * delays that sfp+ detection requires
2698 */
2699 schedule_work(&adapter->sfp_task);
2700}
2701
2702/**
2703 * ixgbe_sfp_task - worker thread to find a missing module
2704 * @work: pointer to work_struct containing our data
2705 **/
2706static void ixgbe_sfp_task(struct work_struct *work)
2707{
2708 struct ixgbe_adapter *adapter = container_of(work,
2709 struct ixgbe_adapter,
2710 sfp_task);
2711 struct ixgbe_hw *hw = &adapter->hw;
2712
2713 if ((hw->phy.type == ixgbe_phy_nl) &&
2714 (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
2715 s32 ret = hw->phy.ops.identify_sfp(hw);
2716 if (ret)
2717 goto reschedule;
2718 ret = hw->phy.ops.reset(hw);
2719 if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
2720 DPRINTK(PROBE, ERR, "failed to initialize because an "
2721 "unsupported SFP+ module type was detected.\n"
2722 "Reload the driver after installing a "
2723 "supported module.\n");
2724 unregister_netdev(adapter->netdev);
2725 } else {
2726 DPRINTK(PROBE, INFO, "detected SFP+: %d\n",
2727 hw->phy.sfp_type);
2728 }
2729 /* don't need this routine any more */
2730 clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
2731 }
2732 return;
2733reschedule:
2734 if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
2735 mod_timer(&adapter->sfp_timer,
2736 round_jiffies(jiffies + (2 * HZ)));
2737}
2738
2739/**
2683 * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) 2740 * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
2684 * @adapter: board private structure to initialize 2741 * @adapter: board private structure to initialize
2685 * 2742 *
@@ -4006,11 +4063,31 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
4006 4063
4007 /* PHY */ 4064 /* PHY */
4008 memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); 4065 memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
4009 /* phy->sfp_type = ixgbe_sfp_type_unknown; */ 4066 hw->phy.sfp_type = ixgbe_sfp_type_unknown;
4067
4068 /* set up this timer and work struct before calling get_invariants
4069 * which might start the timer
4070 */
4071 init_timer(&adapter->sfp_timer);
4072 adapter->sfp_timer.function = &ixgbe_sfp_timer;
4073 adapter->sfp_timer.data = (unsigned long) adapter;
4074
4075 INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
4010 4076
4011 err = ii->get_invariants(hw); 4077 err = ii->get_invariants(hw);
4012 if (err) 4078 if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
4079 /* start a kernel thread to watch for a module to arrive */
4080 set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
4081 mod_timer(&adapter->sfp_timer,
4082 round_jiffies(jiffies + (2 * HZ)));
4083 err = 0;
4084 } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
4085 DPRINTK(PROBE, ERR, "failed to load because an "
4086 "unsupported SFP+ module type was detected.\n");
4013 goto err_hw_init; 4087 goto err_hw_init;
4088 } else if (err) {
4089 goto err_hw_init;
4090 }
4014 4091
4015 /* setup the private structure */ 4092 /* setup the private structure */
4016 err = ixgbe_sw_init(adapter); 4093 err = ixgbe_sw_init(adapter);
@@ -4144,6 +4221,9 @@ err_hw_init:
4144err_sw_init: 4221err_sw_init:
4145 ixgbe_reset_interrupt_capability(adapter); 4222 ixgbe_reset_interrupt_capability(adapter);
4146err_eeprom: 4223err_eeprom:
4224 clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
4225 del_timer_sync(&adapter->sfp_timer);
4226 cancel_work_sync(&adapter->sfp_task);
4147 iounmap(hw->hw_addr); 4227 iounmap(hw->hw_addr);
4148err_ioremap: 4228err_ioremap:
4149 free_netdev(netdev); 4229 free_netdev(netdev);
@@ -4170,8 +4250,15 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
4170 struct ixgbe_adapter *adapter = netdev_priv(netdev); 4250 struct ixgbe_adapter *adapter = netdev_priv(netdev);
4171 4251
4172 set_bit(__IXGBE_DOWN, &adapter->state); 4252 set_bit(__IXGBE_DOWN, &adapter->state);
4253 /* clear the module not found bit to make sure the worker won't
4254 * reschedule
4255 */
4256 clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
4173 del_timer_sync(&adapter->watchdog_timer); 4257 del_timer_sync(&adapter->watchdog_timer);
4174 4258
4259 del_timer_sync(&adapter->sfp_timer);
4260 cancel_work_sync(&adapter->watchdog_task);
4261 cancel_work_sync(&adapter->sfp_task);
4175 flush_scheduled_work(); 4262 flush_scheduled_work();
4176 4263
4177#ifdef CONFIG_IXGBE_DCA 4264#ifdef CONFIG_IXGBE_DCA
@@ -4182,7 +4269,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
4182 } 4269 }
4183 4270
4184#endif 4271#endif
4185 unregister_netdev(netdev); 4272 if (netdev->reg_state == NETREG_REGISTERED)
4273 unregister_netdev(netdev);
4186 4274
4187 ixgbe_reset_interrupt_capability(adapter); 4275 ixgbe_reset_interrupt_capability(adapter);
4188 4276