ix: implement sfp+ module attach interrupt handling

2012-12-13 Thread Mike Belopuhov
first this allows you to connect the sfp+ cable after boot
and correctly identify and use it, secondly it allows you
(supposedly as i've only tested two different types of
direct attach cables, i.e. different phys) to switch between
copper and fiber w/o rebooting.

SDP1 interrupt processing is not enabled because i can't
test it.

code from the intel driver (except for handling the bad hp
cable correctly -- and that's b not a for those who have
any idea what i'm talking about).

OK?

diff --git sys/dev/pci/if_ix.c sys/dev/pci/if_ix.c
index 8c3f817..414d54f 100644
--- sys/dev/pci/if_ix.c
+++ sys/dev/pci/if_ix.c
@@ -145,6 +145,8 @@ voidixgbe_setup_vlan_hw_support(struct ix_softc *);
 /* Support for pluggable optic modules */
 intixgbe_sfp_probe(struct ix_softc *);
 void   ixgbe_setup_optics(struct ix_softc *);
+void   ixgbe_handle_mod(struct ix_softc *);
+void   ixgbe_handle_msf(struct ix_softc *);
 
 /* Legacy (single vector interrupt handler */
 intixgbe_legacy_irq(void *);
@@ -928,12 +930,6 @@ ixgbe_legacy_irq(void *arg)
return (0);
}
 
-   if (ifp-if_flags  IFF_RUNNING) {
-   ixgbe_rxeof(que);
-   ixgbe_txeof(txr);
-   refill = 1;
-   }
-
/* Check for fan failure */
if ((hw-phy.media_type == ixgbe_media_type_copper) 
(reg_eicr  IXGBE_EICR_GPI_SDP1)) {
@@ -958,6 +954,28 @@ ixgbe_legacy_irq(void *arg)
timeout_add_sec(sc-timer, 1);
}
 
+   if (hw-mac.type != ixgbe_mac_82598EB) {
+   if (reg_eicr  IXGBE_EICR_GPI_SDP2) {
+   /* Clear the interrupt */
+   IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
+   ixgbe_handle_mod(sc);
+   }
+#if 0
+   else if ((hw-phy.media_type != ixgbe_media_type_copper) 
+   (reg_eicr  IXGBE_EICR_GPI_SDP1)) {
+   /* Clear the interrupt */
+   IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+   ixgbe_handle_msf(sc);
+   }
+#endif
+   }
+
+   if (ifp-if_flags  IFF_RUNNING) {
+   ixgbe_rxeof(que);
+   ixgbe_txeof(txr);
+   refill = 1;
+   }
+
if (refill) {
if (ixgbe_rxfill(que-rxr)) {
/* Advance the Rx Queue Tail Pointer */
@@ -3408,6 +3426,53 @@ out:
return (result);
 }
 
+/*
+ * SFP module interrupts handler
+ */
+void
+ixgbe_handle_mod(struct ix_softc *sc)
+{
+   struct ixgbe_hw *hw = sc-hw;
+   uint32_t err;
+
+   err = hw-phy.ops.identify_sfp(hw);
+   if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+   printf(%s: Unsupported SFP+ module type was detected!\n,
+   sc-dev.dv_xname);
+   return;
+   }
+   err = hw-mac.ops.setup_sfp(hw);
+   if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+   printf(%s: Setup failure - unsupported SFP+ module type!\n,
+   sc-dev.dv_xname);
+   return;
+   }
+   return (ixgbe_handle_msf(sc));
+}
+
+
+/*
+ * MSF (multispeed fiber) interrupts handler
+ */
+void
+ixgbe_handle_msf(struct ix_softc *sc)
+{
+   struct ixgbe_hw *hw = sc-hw;
+   uint32_t autoneg;
+   int negotiate;
+
+   /* XXX: must be changeable in ixgbe_media_change */
+   autoneg = IXGBE_LINK_SPEED_100_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL |
+ IXGBE_LINK_SPEED_10GB_FULL;
+   if ((!autoneg)  (hw-mac.ops.get_link_capabilities))
+   hw-mac.ops.get_link_capabilities(hw, autoneg, negotiate);
+   if (hw-mac.ops.setup_link)
+   hw-mac.ops.setup_link(hw, autoneg, negotiate, TRUE);
+   /* Set the optics type so system reports correctly */
+   ixgbe_setup_optics(sc);
+}
+
 /**
  *
  *  Update the board statistics counters.
diff --git sys/dev/pci/ixgbe_82599.c sys/dev/pci/ixgbe_82599.c
index 350ddc7..e91579d 100644
--- sys/dev/pci/ixgbe_82599.c
+++ sys/dev/pci/ixgbe_82599.c
@@ -1350,6 +1350,11 @@ sfp_check:
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
else if (comp_codes_10g  IXGBE_SFF_10GBASELR_CAPABLE)
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+   else if (comp_codes_10g 
+   (IXGBE_SFF_DA_PASSIVE_CABLE | IXGBE_SFF_DA_BAD_HP_CABLE))
+   physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
+   else if (comp_codes_10g  IXGBE_SFF_DA_ACTIVE_CABLE)
+   physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
else if (comp_codes_1g  IXGBE_SFF_1GBASET_CAPABLE)
physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T;
break;



Re: ix: implement sfp+ module attach interrupt handling

2012-12-13 Thread Mike Belopuhov
On Thu, Dec 13, 2012 at 20:49 +0100, Mike Belopuhov wrote:
 first this allows you to connect the sfp+ cable after boot
 and correctly identify and use it, secondly it allows you
 (supposedly as i've only tested two different types of
 direct attach cables, i.e. different phys) to switch between
 copper and fiber w/o rebooting.
 
 SDP1 interrupt processing is not enabled because i can't
 test it.
 
 code from the intel driver (except for handling the bad hp
 cable correctly -- and that's b not a for those who have
 any idea what i'm talking about).
 
 OK?
 

a bit better arrangement of code + use change autoneg to use
hw-phy.autoneg_advertised like FreeBSD does.  in this case
it should be set properly.

forgot to mention that diff only affects 82599 and only when
interface is up (since interrupts must be enabled).

diff --git sys/dev/pci/if_ix.c sys/dev/pci/if_ix.c
index 8c3f817..337f789 100644
--- sys/dev/pci/if_ix.c
+++ sys/dev/pci/if_ix.c
@@ -145,6 +145,8 @@ voidixgbe_setup_vlan_hw_support(struct ix_softc *);
 /* Support for pluggable optic modules */
 intixgbe_sfp_probe(struct ix_softc *);
 void   ixgbe_setup_optics(struct ix_softc *);
+void   ixgbe_handle_mod(struct ix_softc *);
+void   ixgbe_handle_msf(struct ix_softc *);
 
 /* Legacy (single vector interrupt handler */
 intixgbe_legacy_irq(void *);
@@ -928,12 +930,6 @@ ixgbe_legacy_irq(void *arg)
return (0);
}
 
-   if (ifp-if_flags  IFF_RUNNING) {
-   ixgbe_rxeof(que);
-   ixgbe_txeof(txr);
-   refill = 1;
-   }
-
/* Check for fan failure */
if ((hw-phy.media_type == ixgbe_media_type_copper) 
(reg_eicr  IXGBE_EICR_GPI_SDP1)) {
@@ -958,6 +954,28 @@ ixgbe_legacy_irq(void *arg)
timeout_add_sec(sc-timer, 1);
}
 
+   if (hw-mac.type != ixgbe_mac_82598EB) {
+   if (reg_eicr  IXGBE_EICR_GPI_SDP2) {
+   /* Clear the interrupt */
+   IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
+   ixgbe_handle_mod(sc);
+   }
+#if 0
+   else if ((hw-phy.media_type != ixgbe_media_type_copper) 
+   (reg_eicr  IXGBE_EICR_GPI_SDP1)) {
+   /* Clear the interrupt */
+   IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+   ixgbe_handle_msf(sc);
+   }
+#endif
+   }
+
+   if (ifp-if_flags  IFF_RUNNING) {
+   ixgbe_rxeof(que);
+   ixgbe_txeof(txr);
+   refill = 1;
+   }
+
if (refill) {
if (ixgbe_rxfill(que-rxr)) {
/* Advance the Rx Queue Tail Pointer */
@@ -3408,6 +3426,50 @@ out:
return (result);
 }
 
+/*
+ * SFP module interrupts handler
+ */
+void
+ixgbe_handle_mod(struct ix_softc *sc)
+{
+   struct ixgbe_hw *hw = sc-hw;
+   uint32_t err;
+
+   err = hw-phy.ops.identify_sfp(hw);
+   if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+   printf(%s: Unsupported SFP+ module type was detected!\n,
+   sc-dev.dv_xname);
+   return;
+   }
+   err = hw-mac.ops.setup_sfp(hw);
+   if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+   printf(%s: Setup failure - unsupported SFP+ module type!\n,
+   sc-dev.dv_xname);
+   return;
+   }
+   /* Set the optics type so system reports correctly */
+   ixgbe_setup_optics(sc);
+   return (ixgbe_handle_msf(sc));
+}
+
+
+/*
+ * MSF (multispeed fiber) interrupts handler
+ */
+void
+ixgbe_handle_msf(struct ix_softc *sc)
+{
+   struct ixgbe_hw *hw = sc-hw;
+   uint32_t autoneg;
+   int negotiate;
+
+   autoneg = hw-phy.autoneg_advertised;
+   if ((!autoneg)  (hw-mac.ops.get_link_capabilities))
+   hw-mac.ops.get_link_capabilities(hw, autoneg, negotiate);
+   if (hw-mac.ops.setup_link)
+   hw-mac.ops.setup_link(hw, autoneg, negotiate, TRUE);
+}
+
 /**
  *
  *  Update the board statistics counters.
diff --git sys/dev/pci/ixgbe_82599.c sys/dev/pci/ixgbe_82599.c
index 350ddc7..e91579d 100644
--- sys/dev/pci/ixgbe_82599.c
+++ sys/dev/pci/ixgbe_82599.c
@@ -1350,6 +1350,11 @@ sfp_check:
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
else if (comp_codes_10g  IXGBE_SFF_10GBASELR_CAPABLE)
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+   else if (comp_codes_10g 
+   (IXGBE_SFF_DA_PASSIVE_CABLE | IXGBE_SFF_DA_BAD_HP_CABLE))
+   physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
+   else if (comp_codes_10g  IXGBE_SFF_DA_ACTIVE_CABLE)
+   physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
else if (comp_codes_1g  IXGBE_SFF_1GBASET_CAPABLE)