summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarybchik <arybchik@FreeBSD.org>2015-05-21 09:15:19 +0000
committerarybchik <arybchik@FreeBSD.org>2015-05-21 09:15:19 +0000
commitdb9589182b524f024f29cb27de0a6a2c5ed228e1 (patch)
tree92948b969615f1e783a03beedc02e0f6a5e6d67f
parent41bc1c612cdd4b49d7bf664228cff576eb924b0e (diff)
downloadFreeBSD-src-db9589182b524f024f29cb27de0a6a2c5ed228e1.zip
FreeBSD-src-db9589182b524f024f29cb27de0a6a2c5ed228e1.tar.gz
MFC: r283007
sfxge: avoid usage of ifm_data The driver uses ifm_data to save capabilities mask calculated during initialization when supported phy modes are discovered. The patch simply calculates it when either media or options are changed. Sponsored by: Solarflare Communications, Inc.
-rw-r--r--sys/dev/sfxge/sfxge_port.c132
1 files changed, 107 insertions, 25 deletions
diff --git a/sys/dev/sfxge/sfxge_port.c b/sys/dev/sfxge/sfxge_port.c
index 8afb1dc..aaf3da0 100644
--- a/sys/dev/sfxge/sfxge_port.c
+++ b/sys/dev/sfxge/sfxge_port.c
@@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
#include "sfxge.h"
+static int sfxge_phy_cap_mask(struct sfxge_softc *, int, uint32_t *);
+
static int
sfxge_mac_stat_update(struct sfxge_softc *sc)
{
@@ -381,6 +383,7 @@ sfxge_port_start(struct sfxge_softc *sc)
efx_nic_t *enp;
size_t pdu;
int rc;
+ uint32_t phy_cap_mask;
port = &sc->port;
enp = sc->enp;
@@ -421,10 +424,13 @@ sfxge_port_start(struct sfxge_softc *sc)
if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
goto fail3;
- if ((rc = efx_phy_adv_cap_set(sc->enp, sc->media.ifm_cur->ifm_data))
- != 0)
+ if ((rc = sfxge_phy_cap_mask(sc, sc->media.ifm_cur->ifm_media,
+ &phy_cap_mask)) != 0)
goto fail4;
+ if ((rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask)) != 0)
+ goto fail5;
+
port->init_state = SFXGE_PORT_STARTED;
/* Single poll in case there were missing initial events */
@@ -433,6 +439,7 @@ sfxge_port_start(struct sfxge_softc *sc)
return (0);
+fail5:
fail4:
(void)efx_mac_drain(enp, B_TRUE);
fail3:
@@ -676,12 +683,95 @@ sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
SFXGE_ADAPTER_UNLOCK(sc);
}
+static efx_phy_cap_type_t
+sfxge_link_mode_to_phy_cap(efx_link_mode_t mode)
+{
+ switch (mode) {
+ case EFX_LINK_10HDX:
+ return (EFX_PHY_CAP_10HDX);
+ case EFX_LINK_10FDX:
+ return (EFX_PHY_CAP_10FDX);
+ case EFX_LINK_100HDX:
+ return (EFX_PHY_CAP_100HDX);
+ case EFX_LINK_100FDX:
+ return (EFX_PHY_CAP_100FDX);
+ case EFX_LINK_1000HDX:
+ return (EFX_PHY_CAP_1000HDX);
+ case EFX_LINK_1000FDX:
+ return (EFX_PHY_CAP_1000FDX);
+ case EFX_LINK_10000FDX:
+ return (EFX_PHY_CAP_10000FDX);
+ default:
+ EFSYS_ASSERT(B_FALSE);
+ return (EFX_PHY_CAP_INVALID);
+ }
+}
+
+static int
+sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask)
+{
+ efx_phy_media_type_t medium_type;
+ boolean_t mode_found = B_FALSE;
+ uint32_t cap_mask, mode_cap_mask;
+ efx_link_mode_t mode;
+ efx_phy_cap_type_t phy_cap;
+
+ efx_phy_media_type_get(sc->enp, &medium_type);
+ if (medium_type >= nitems(sfxge_link_mode)) {
+ if_printf(sc->ifnet, "unexpected media type %d\n", medium_type);
+ return (EINVAL);
+ }
+
+ efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
+
+ for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) {
+ if (ifmedia == sfxge_link_mode[medium_type][mode]) {
+ mode_found = B_TRUE;
+ break;
+ }
+ }
+
+ if (!mode_found) {
+ /*
+ * If media is not in the table, it must be IFM_AUTO.
+ */
+ KASSERT((cap_mask & (1 << EFX_PHY_CAP_AN)) &&
+ ifmedia == (IFM_ETHER | IFM_AUTO),
+ ("%s: no mode for media %d", __func__, ifmedia));
+ *phy_cap_mask = (cap_mask & ~(1 << EFX_PHY_CAP_ASYM));
+ return (0);
+ }
+
+ phy_cap = sfxge_link_mode_to_phy_cap(mode);
+ if (phy_cap == EFX_PHY_CAP_INVALID) {
+ if_printf(sc->ifnet,
+ "cannot map link mode %d to phy capability\n",
+ mode);
+ return (EINVAL);
+ }
+
+ mode_cap_mask = (1 << phy_cap);
+ mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
+#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
+ if (ifmedia & IFM_ETH_RXPAUSE)
+ mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
+ if (!(ifmedia & IFM_ETH_TXPAUSE))
+ mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_ASYM);
+#else
+ mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
+#endif
+
+ *phy_cap_mask = mode_cap_mask;
+ return (0);
+}
+
static int
sfxge_media_change(struct ifnet *ifp)
{
struct sfxge_softc *sc;
struct ifmedia_entry *ifm;
int rc;
+ uint32_t phy_cap_mask;
sc = ifp->if_softc;
ifm = sc->media.ifm_cur;
@@ -697,7 +787,10 @@ sfxge_media_change(struct ifnet *ifp)
if (rc != 0)
goto out;
- rc = efx_phy_adv_cap_set(sc->enp, ifm->ifm_data);
+ if ((rc = sfxge_phy_cap_mask(sc, ifm->ifm_media, &phy_cap_mask)) != 0)
+ goto out;
+
+ rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask);
out:
SFXGE_ADAPTER_UNLOCK(sc);
@@ -709,6 +802,7 @@ int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
efx_phy_media_type_t medium_type;
uint32_t cap_mask, mode_cap_mask;
efx_link_mode_t mode;
+ efx_phy_cap_type_t phy_cap;
int mode_ifm, best_mode_ifm = 0;
int rc;
@@ -739,41 +833,30 @@ int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
efx_phy_media_type_get(sc->enp, &medium_type);
efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
- EFX_STATIC_ASSERT(EFX_LINK_10HDX == EFX_PHY_CAP_10HDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_10FDX == EFX_PHY_CAP_10FDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_100HDX == EFX_PHY_CAP_100HDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_100FDX == EFX_PHY_CAP_100FDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_1000HDX == EFX_PHY_CAP_1000HDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_1000FDX == EFX_PHY_CAP_1000FDX + 1);
- EFX_STATIC_ASSERT(EFX_LINK_10000FDX == EFX_PHY_CAP_10000FDX + 1);
+ for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) {
+ phy_cap = sfxge_link_mode_to_phy_cap(mode);
+ if (phy_cap == EFX_PHY_CAP_INVALID)
+ continue;
- for (mode = EFX_LINK_10HDX; mode <= EFX_LINK_10000FDX; mode++) {
- mode_cap_mask = 1 << (mode - 1);
+ mode_cap_mask = (1 << phy_cap);
mode_ifm = sfxge_link_mode[medium_type][mode];
if ((cap_mask & mode_cap_mask) && mode_ifm) {
- mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
-
-#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
/* No flow-control */
- ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
+ ifmedia_add(&sc->media, mode_ifm, 0, NULL);
+#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
/* Respond-only. If using AN, we implicitly
* offer symmetric as well, but that doesn't
* mean we *have* to generate pause frames.
*/
- mode_cap_mask |= cap_mask & ((1 << EFX_PHY_CAP_PAUSE) |
- (1 << EFX_PHY_CAP_ASYM));
mode_ifm |= IFM_ETH_RXPAUSE;
- ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
+ ifmedia_add(&sc->media, mode_ifm, 0, NULL);
/* Symmetric */
- mode_cap_mask &= ~(1 << EFX_PHY_CAP_ASYM);
mode_ifm |= IFM_ETH_TXPAUSE;
-#else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
- mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
+ ifmedia_add(&sc->media, mode_ifm, 0, NULL);
#endif
- ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
/* Link modes are numbered in order of speed,
* so assume the last one available is the best.
@@ -785,8 +868,7 @@ int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
if (cap_mask & (1 << EFX_PHY_CAP_AN)) {
/* Add autoselect mode. */
mode_ifm = IFM_ETHER | IFM_AUTO;
- ifmedia_add(&sc->media, mode_ifm,
- cap_mask & ~(1 << EFX_PHY_CAP_ASYM), NULL);
+ ifmedia_add(&sc->media, mode_ifm, 0, NULL);
best_mode_ifm = mode_ifm;
}
OpenPOWER on IntegriCloud