From 748ce18c34badaa2d87dae60ca7a7925c545cf0a Mon Sep 17 00:00:00 2001 From: jmatthew Date: Thu, 11 Apr 2024 05:30:55 +0000 Subject: [PATCH] Add support for media types from the extended ethernet capabilities fields. If none of the regular ethernet capabilities are present, check the extended capabilities. Since we only report that the link is active if there's a detected media type, this isn't just a cosmetic change. Joerg Streckfuss reported that a gigabit SFP didn't work in a ConnectX-6 Lx, and tested that this change makes it work. ok dlg@ --- sys/dev/pci/if_mcx.c | 101 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/sys/dev/pci/if_mcx.c b/sys/dev/pci/if_mcx.c index 9108423827d..c4a83a68edb 100644 --- a/sys/dev/pci/if_mcx.c +++ b/sys/dev/pci/if_mcx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mcx.c,v 1.111 2023/11/10 15:51:20 bluhm Exp $ */ +/* $OpenBSD: if_mcx.c,v 1.112 2024/04/11 05:30:55 jmatthew Exp $ */ /* * Copyright (c) 2017 David Gwynne @@ -199,6 +199,19 @@ CTASSERT(MCX_MAX_QUEUES * MCX_WQ_DOORBELL_STRIDE < #define MCX_ETHER_CAP_50G_CR2 30 #define MCX_ETHER_CAP_50G_KR2 31 +#define MCX_ETHER_EXT_CAP_SGMII_100 0 +#define MCX_ETHER_EXT_CAP_1000_X 1 +#define MCX_ETHER_EXT_CAP_5G_R 3 +#define MCX_ETHER_EXT_CAP_XAUI 4 +#define MCX_ETHER_EXT_CAP_XLAUI 5 +#define MCX_ETHER_EXT_CAP_25G_AUI1 6 +#define MCX_ETHER_EXT_CAP_50G_AUI2 7 +#define MCX_ETHER_EXT_CAP_50G_AUI1 8 +#define MCX_ETHER_EXT_CAP_CAUI4 9 +#define MCX_ETHER_EXT_CAP_100G_AUI2 10 +#define MCX_ETHER_EXT_CAP_200G_AUI4 12 +#define MCX_ETHER_EXT_CAP_400G_AUI8 15 + #define MCX_MAX_CQE 32 #define MCX_CMD_QUERY_HCA_CAP 0x100 @@ -406,11 +419,14 @@ struct mcx_reg_ptys { uint8_t rp_reserved2; uint8_t rp_proto_mask; #define MCX_REG_PTYS_PROTO_MASK_ETH (1 << 2) - uint8_t rp_reserved3[8]; + uint8_t rp_reserved3[4]; + uint32_t rp_ext_eth_proto_cap; uint32_t rp_eth_proto_cap; - uint8_t rp_reserved4[8]; + uint8_t rp_reserved4[4]; + uint32_t rp_ext_eth_proto_admin; uint32_t rp_eth_proto_admin; - uint8_t rp_reserved5[8]; + uint8_t rp_reserved5[4]; + uint32_t rp_ext_eth_proto_oper; uint32_t rp_eth_proto_oper; uint8_t rp_reserved6[24]; } __packed __aligned(4); @@ -2691,6 +2707,21 @@ static const struct mcx_eth_proto_capability mcx_eth_cap_map[] = { [MCX_ETHER_CAP_50G_KR2] = { IFM_50G_KR2, IF_Gbps(50) }, }; +static const struct mcx_eth_proto_capability mcx_ext_eth_cap_map[] = { + [MCX_ETHER_EXT_CAP_SGMII_100] = { IFM_100_FX, IF_Mbps(100) }, + [MCX_ETHER_EXT_CAP_1000_X] = { IFM_1000_SX, IF_Gbps(1) }, + [MCX_ETHER_EXT_CAP_5G_R] = { IFM_5000_T, IF_Gbps(5) }, + [MCX_ETHER_EXT_CAP_XAUI] = { IFM_10G_SFI, IF_Gbps(10) }, + [MCX_ETHER_EXT_CAP_XLAUI] = { IFM_40G_XLPPI, IF_Gbps(40) }, + [MCX_ETHER_EXT_CAP_25G_AUI1] = { 0 /*IFM_25G_AUI*/, IF_Gbps(25) }, + [MCX_ETHER_EXT_CAP_50G_AUI2] = { 0 /*IFM_50G_AUI*/, IF_Gbps(50) }, + [MCX_ETHER_EXT_CAP_50G_AUI1] = { 0 /*IFM_50G_AUI*/, IF_Gbps(50) }, + [MCX_ETHER_EXT_CAP_CAUI4] = { 0 /*IFM_100G_AUI*/, IF_Gbps(100) }, + [MCX_ETHER_EXT_CAP_100G_AUI2] = { 0 /*IFM_100G_AUI*/, IF_Gbps(100) }, + [MCX_ETHER_EXT_CAP_200G_AUI4] = { 0 /*IFM_200G_AUI*/, IF_Gbps(200) }, + [MCX_ETHER_EXT_CAP_400G_AUI8] = { 0 /*IFM_400G_AUI*/, IF_Gbps(400) }, +}; + static int mcx_get_id(uint32_t val) { @@ -7956,6 +7987,19 @@ mcx_media_add_types(struct mcx_softc *sc) ifmedia_add(&sc->sc_media, IFM_ETHER | cap->cap_media, 0, NULL); } + + proto_cap = betoh32(ptys.rp_ext_eth_proto_cap); + for (i = 0; i < nitems(mcx_ext_eth_cap_map); i++) { + const struct mcx_eth_proto_capability *cap; + if (!ISSET(proto_cap, 1 << i)) + continue; + + cap = &mcx_ext_eth_cap_map[i]; + if (cap->cap_media == 0) + continue; + + ifmedia_add(&sc->sc_media, IFM_ETHER | cap->cap_media, 0, NULL); + } } static void @@ -7965,6 +8009,7 @@ mcx_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) struct mcx_reg_ptys ptys; int i; uint32_t proto_oper; + uint32_t ext_proto_oper; uint64_t media_oper; memset(&ptys, 0, sizeof(ptys)); @@ -7979,6 +8024,7 @@ mcx_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) } proto_oper = betoh32(ptys.rp_eth_proto_oper); + ext_proto_oper = betoh32(ptys.rp_ext_eth_proto_oper); media_oper = 0; @@ -7993,8 +8039,21 @@ mcx_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) media_oper = cap->cap_media; } + if (media_oper == 0) { + for (i = 0; i < nitems(mcx_ext_eth_cap_map); i++) { + const struct mcx_eth_proto_capability *cap; + if (!ISSET(ext_proto_oper, 1 << i)) + continue; + + cap = &mcx_ext_eth_cap_map[i]; + + if (cap->cap_media != 0) + media_oper = cap->cap_media; + } + } + ifmr->ifm_status = IFM_AVALID; - if (proto_oper != 0) { + if ((proto_oper | ext_proto_oper) != 0) { ifmr->ifm_status |= IFM_ACTIVE; ifmr->ifm_active = IFM_ETHER | IFM_AUTO | media_oper; /* txpause, rxpause, duplex? */ @@ -8010,6 +8069,7 @@ mcx_media_change(struct ifnet *ifp) struct mcx_reg_ptys ptys; struct mcx_reg_paos paos; uint32_t media; + uint32_t ext_media; int i, error; if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) @@ -8032,6 +8092,7 @@ mcx_media_change(struct ifnet *ifp) } media = betoh32(ptys.rp_eth_proto_cap); + ext_media = betoh32(ptys.rp_ext_eth_proto_cap); } else { /* map media type */ media = 0; @@ -8045,6 +8106,17 @@ mcx_media_change(struct ifnet *ifp) break; } } + + for (i = 0; i < nitems(mcx_ext_eth_cap_map); i++) { + const struct mcx_eth_proto_capability *cap; + + cap = &mcx_ext_eth_cap_map[i]; + if (cap->cap_media == + IFM_SUBTYPE(sc->sc_media.ifm_media)) { + media = (1 << i); + break; + } + } } /* disable the port */ @@ -8063,6 +8135,7 @@ mcx_media_change(struct ifnet *ifp) ptys.rp_local_port = 1; ptys.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH; ptys.rp_eth_proto_admin = htobe32(media); + ptys.rp_ext_eth_proto_admin = htobe32(ext_media); if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_WRITE, &ptys, sizeof(ptys), MCX_CMDQ_SLOT_IOCTL) != 0) { printf("%s: unable to set port media type/speed\n", @@ -8107,10 +8180,11 @@ mcx_port_change(void *xsc) if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ, &ptys, sizeof(ptys), slot) == 0) { uint32_t proto_oper = betoh32(ptys.rp_eth_proto_oper); + uint32_t ext_proto_oper = betoh32(ptys.rp_ext_eth_proto_oper); uint64_t baudrate = 0; unsigned int i; - if (proto_oper != 0) + if ((proto_oper | ext_proto_oper) != 0) link_state = LINK_STATE_FULL_DUPLEX; for (i = 0; i < nitems(mcx_eth_cap_map); i++) { @@ -8126,6 +8200,21 @@ mcx_port_change(void *xsc) break; } + if (baudrate == 0) { + for (i = 0; i < nitems(mcx_ext_eth_cap_map); i++) { + const struct mcx_eth_proto_capability *cap; + if (!ISSET(ext_proto_oper, 1 << i)) + continue; + + cap = &mcx_ext_eth_cap_map[i]; + if (cap->cap_baudrate == 0) + continue; + + baudrate = cap->cap_baudrate; + break; + } + } + ifp->if_baudrate = baudrate; } -- 2.20.1