Module Name:    src
Committed By:   martin
Date:           Tue Apr 28 15:44:07 UTC 2020

Modified Files:
        src/sys/dev/pci [netbsd-9]: if_mcx.c

Log Message:
Pull up following revision(s) (requested by jmcneill in ticket #858):

        sys/dev/pci/if_mcx.c: revision 1.13

mcx: sync with OpenBSD sys/dev/pci/if_mcx.c r1.44

1.44:
Fix typo which could lead into a double free

1.43:
Commands that create objects return a 24 bit object ID, so mask off the
high 8 bits of the value we extract, in case the firmware leaves junk there.
Hrvoje Popovski has seen this with newer firmware on a ConnectX 5 card,
which now works properly.

1.42:
Increase the completion queue size to prevent overflow.  Under reasonably
unlikely circumstances - lots of single-fragment packets being sent, a
significant number of packets being received, while the interrupt handler
was unable to process the completion queue - the completion queue could
overflow, which would result in the interface locking up.

1.41:
Check if we've reached the end of the current mailbox before writing past
the end of it, rather than after.  Now we can actually allocate queues
big enough to need multiple mailboxes.

1.40:
Don't call mcx_intr() from mcx_cmdq_poll(); this was a leftover from early
development that I forgot about, but turns out to be a potential race with
the actual interrupt handler.

1.39:
fix previous: use the correct offset for sq/rq creation, and don't
reset the mbox counter to 0 after calculating it.

1.38:
Add a helper function for writing physical addresses for queues into
command queue mailboxes, and use this for all queue setup commands.
Previously we just assumed the addresses would fit in the first mailbox,
which is currently true but may not be for much longer.

1.37:
(skipped)

1.36:
The event queue consumer counter also needs to be unsigned like the others.

1.35:
try to make if_baudrate look plausible.
this updates the eth proto capability map so it records the baudrate
against the different link types and their media, and then reads
it when the link state changes.

1.34:
(skipped)


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.9 -r1.1.2.10 src/sys/dev/pci/if_mcx.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_mcx.c
diff -u src/sys/dev/pci/if_mcx.c:1.1.2.9 src/sys/dev/pci/if_mcx.c:1.1.2.10
--- src/sys/dev/pci/if_mcx.c:1.1.2.9	Sun Mar  1 12:47:10 2020
+++ src/sys/dev/pci/if_mcx.c	Tue Apr 28 15:44:06 2020
@@ -1,5 +1,5 @@
-/*	$NetBSD: if_mcx.c,v 1.1.2.9 2020/03/01 12:47:10 martin Exp $ */
-/*	$OpenBSD: if_mcx.c,v 1.33 2019/09/12 04:23:59 jmatthew Exp $ */
+/*	$NetBSD: if_mcx.c,v 1.1.2.10 2020/04/28 15:44:06 martin Exp $ */
+/*	$OpenBSD: if_mcx.c,v 1.44 2020/04/24 07:28:37 mestre Exp $ */
 
 /*
  * Copyright (c) 2017 David Gwynne <d...@openbsd.org>
@@ -82,7 +82,7 @@
 
 /* queue sizes */
 #define MCX_LOG_EQ_SIZE		 6		/* one page */
-#define MCX_LOG_CQ_SIZE		 11
+#define MCX_LOG_CQ_SIZE		 12
 #define MCX_LOG_RQ_SIZE		 10
 #define MCX_LOG_SQ_SIZE		 11
 
@@ -154,33 +154,33 @@
 #define MCX_REG_PPCNT		0x5008
 #define MCX_REG_MCIA		0x9014
 
-#define MCX_ETHER_CAP_SGMII	(1 << 0)
-#define MCX_ETHER_CAP_1000_KX	(1 << 1)
-#define MCX_ETHER_CAP_10G_CX4	(1 << 2)
-#define MCX_ETHER_CAP_10G_KX4	(1 << 3)
-#define MCX_ETHER_CAP_10G_KR	(1 << 4)
-#define MCX_ETHER_CAP_20G_KR2	(1 << 5)
-#define MCX_ETHER_CAP_40G_CR4	(1 << 6)
-#define MCX_ETHER_CAP_40G_KR4	(1 << 7)
-#define MCX_ETHER_CAP_56G_R4	(1 << 8)
-#define MCX_ETHER_CAP_10G_CR	(1 << 12)
-#define MCX_ETHER_CAP_10G_SR	(1 << 13)
-#define MCX_ETHER_CAP_10G_LR	(1 << 14)
-#define MCX_ETHER_CAP_40G_SR4	(1 << 15)
-#define MCX_ETHER_CAP_40G_LR4	(1 << 16)
-#define MCX_ETHER_CAP_50G_SR2	(1 << 18)
-#define MCX_ETHER_CAP_100G_CR4	(1 << 20)
-#define MCX_ETHER_CAP_100G_SR4	(1 << 21)
-#define MCX_ETHER_CAP_100G_KR4	(1 << 22)
-#define MCX_ETHER_CAP_100G_LR4	(1 << 23)
-#define MCX_ETHER_CAP_100_TX	(1 << 24)
-#define MCX_ETHER_CAP_1000_T	(1 << 25)
-#define MCX_ETHER_CAP_10G_T	(1 << 26)
-#define MCX_ETHER_CAP_25G_CR	(1 << 27)
-#define MCX_ETHER_CAP_25G_KR	(1 << 28)
-#define MCX_ETHER_CAP_25G_SR	(1 << 29)
-#define MCX_ETHER_CAP_50G_CR2	(1 << 30)
-#define MCX_ETHER_CAP_50G_KR2	(1 << 31)
+#define MCX_ETHER_CAP_SGMII	0
+#define MCX_ETHER_CAP_1000_KX	1
+#define MCX_ETHER_CAP_10G_CX4	2
+#define MCX_ETHER_CAP_10G_KX4	3
+#define MCX_ETHER_CAP_10G_KR	4
+#define MCX_ETHER_CAP_20G_KR2	5
+#define MCX_ETHER_CAP_40G_CR4	6
+#define MCX_ETHER_CAP_40G_KR4	7
+#define MCX_ETHER_CAP_56G_R4	8
+#define MCX_ETHER_CAP_10G_CR	12
+#define MCX_ETHER_CAP_10G_SR	13
+#define MCX_ETHER_CAP_10G_LR	14
+#define MCX_ETHER_CAP_40G_SR4	15
+#define MCX_ETHER_CAP_40G_LR4	16
+#define MCX_ETHER_CAP_50G_SR2	18
+#define MCX_ETHER_CAP_100G_CR4	20
+#define MCX_ETHER_CAP_100G_SR4	21
+#define MCX_ETHER_CAP_100G_KR4	22
+#define MCX_ETHER_CAP_100G_LR4	23
+#define MCX_ETHER_CAP_100_TX	24
+#define MCX_ETHER_CAP_1000_T	25
+#define MCX_ETHER_CAP_10G_T	26
+#define MCX_ETHER_CAP_25G_CR	27
+#define MCX_ETHER_CAP_25G_KR	28
+#define MCX_ETHER_CAP_25G_SR	29
+#define MCX_ETHER_CAP_50G_CR2	30
+#define MCX_ETHER_CAP_50G_KR2	31
 
 #define MCX_PAGE_SHIFT		12
 #define MCX_PAGE_SIZE		(1 << MCX_PAGE_SHIFT)
@@ -1970,7 +1970,7 @@ struct mcx_softc {
 	struct mcx_dmamem	 sc_doorbell_mem;
 
 	int			 sc_eqn;
-	int			 sc_eq_cons;
+	uint32_t		 sc_eq_cons;
 	struct mcx_dmamem	 sc_eq_mem;
 	int			 sc_hardmtu;
 
@@ -2146,42 +2146,48 @@ static const struct {
 	{ PCI_VENDOR_MELLANOX,	PCI_PRODUCT_MELLANOX_MT28800 },
 };
 
-static const uint64_t mcx_eth_cap_map[] = {
-	IFM_1000_SGMII,
-	IFM_1000_KX,
-	IFM_10G_CX4,
-	IFM_10G_KX4,
-	IFM_10G_KR,
-	IFM_20G_KR2,
-	IFM_40G_CR4,
-	IFM_40G_KR4,
-	IFM_56G_R4,
-	0,
-	0,
-	0,
-	IFM_10G_CR1,
-	IFM_10G_SR,
-	IFM_10G_LR,
-	IFM_40G_SR4,
-	IFM_40G_LR4,
-	0,
-	IFM_50G_SR2,
-	0,
-	IFM_100G_CR4,
-	IFM_100G_SR4,
-	IFM_100G_KR4,
-	IFM_100G_LR4,
-	IFM_100_TX,
-	IFM_1000_T,
-	IFM_10G_T,
-	IFM_25G_CR,
-	IFM_25G_KR,
-	IFM_25G_SR,
-	IFM_50G_CR2,
-	IFM_50G_KR2
+struct mcx_eth_proto_capability {
+	uint64_t	cap_media;
+	uint64_t	cap_baudrate;
+};
+
+static const struct mcx_eth_proto_capability mcx_eth_cap_map[] = {
+	[MCX_ETHER_CAP_SGMII]		= { IFM_1000_SGMII,	IF_Gbps(1) },
+	[MCX_ETHER_CAP_1000_KX]		= { IFM_1000_KX,	IF_Gbps(1) },
+	[MCX_ETHER_CAP_10G_CX4]		= { IFM_10G_CX4,	IF_Gbps(10) },
+	[MCX_ETHER_CAP_10G_KX4]		= { IFM_10G_KX4,	IF_Gbps(10) },
+	[MCX_ETHER_CAP_10G_KR]		= { IFM_10G_KR,		IF_Gbps(10) },
+	[MCX_ETHER_CAP_20G_KR2]		= { IFM_20G_KR2,	IF_Gbps(20) },
+	[MCX_ETHER_CAP_40G_CR4]		= { IFM_40G_CR4,	IF_Gbps(40) },
+	[MCX_ETHER_CAP_40G_KR4]		= { IFM_40G_KR4,	IF_Gbps(40) },
+	[MCX_ETHER_CAP_56G_R4]		= { IFM_56G_R4,		IF_Gbps(56) },
+	[MCX_ETHER_CAP_10G_CR]		= { IFM_10G_CR1,	IF_Gbps(10) },
+	[MCX_ETHER_CAP_10G_SR]		= { IFM_10G_SR,		IF_Gbps(10) },
+	[MCX_ETHER_CAP_10G_LR]		= { IFM_10G_LR,		IF_Gbps(10) },
+	[MCX_ETHER_CAP_40G_SR4]		= { IFM_40G_SR4,	IF_Gbps(40) },
+	[MCX_ETHER_CAP_40G_LR4]		= { IFM_40G_LR4,	IF_Gbps(40) },
+	[MCX_ETHER_CAP_50G_SR2]		= { IFM_50G_SR2,	IF_Gbps(50) },
+	[MCX_ETHER_CAP_100G_CR4]	= { IFM_100G_CR4,	IF_Gbps(100) },
+	[MCX_ETHER_CAP_100G_SR4]	= { IFM_100G_SR4,	IF_Gbps(100) },
+	[MCX_ETHER_CAP_100G_KR4]	= { IFM_100G_KR4,	IF_Gbps(100) },
+	[MCX_ETHER_CAP_100G_LR4]	= { IFM_100G_LR4,	IF_Gbps(100) },
+	[MCX_ETHER_CAP_100_TX]		= { IFM_100_TX,		IF_Mbps(100) },
+	[MCX_ETHER_CAP_1000_T]		= { IFM_1000_T,		IF_Gbps(1) },
+	[MCX_ETHER_CAP_10G_T]		= { IFM_10G_T,		IF_Gbps(10) },
+	[MCX_ETHER_CAP_25G_CR]		= { IFM_25G_CR,		IF_Gbps(25) },
+	[MCX_ETHER_CAP_25G_KR]		= { IFM_25G_KR,		IF_Gbps(25) },
+	[MCX_ETHER_CAP_25G_SR]		= { IFM_25G_SR,		IF_Gbps(25) },
+	[MCX_ETHER_CAP_50G_CR2]		= { IFM_50G_CR2,	IF_Gbps(50) },
+	[MCX_ETHER_CAP_50G_KR2]		= { IFM_50G_KR2,	IF_Gbps(50) },
 };
 
 static int
+mcx_get_id(uint32_t val)
+{
+	return be32toh(val) & 0x00ffffff;
+}
+
+static int
 mcx_match(device_t parent, cfdata_t cf, void *aux)
 {
 	struct pci_attach_args *pa = aux;
@@ -2557,11 +2563,8 @@ mcx_cmdq_poll(struct mcx_softc *sc, stru
 		    0, MCX_DMA_LEN(&sc->sc_cmdq_mem), BUS_DMASYNC_POSTRW);
 
 		if ((cqe->cq_status & MCX_CQ_STATUS_OWN_MASK) ==
-		    MCX_CQ_STATUS_OWN_SW) {
-			if (sc->sc_eqn != 0)
-				mcx_intr(sc);
+		    MCX_CQ_STATUS_OWN_SW)
 			return (0);
-		}
 
 		delay(1000);
 	}
@@ -2873,6 +2876,30 @@ mcx_cmdq_mboxes_copyin(struct mcx_dmamem
 }
 
 static void
+mcx_cmdq_mboxes_pas(struct mcx_dmamem *mxm, int offset, int npages,
+    struct mcx_dmamem *buf)
+{
+	uint64_t *pas;
+	int mbox, mbox_pages, i;
+
+	mbox = offset / MCX_CMDQ_MAILBOX_DATASIZE;
+	offset %= MCX_CMDQ_MAILBOX_DATASIZE;
+
+	pas = mcx_cq_mbox_data(mcx_cq_mbox(mxm, mbox));
+	pas += (offset / sizeof(*pas));
+	mbox_pages = (MCX_CMDQ_MAILBOX_DATASIZE - offset) / sizeof(*pas);
+	for (i = 0; i < npages; i++) {
+		if (i == mbox_pages) {
+			mbox++;
+			pas = mcx_cq_mbox_data(mcx_cq_mbox(mxm, mbox));
+			mbox_pages += MCX_CMDQ_MAILBOX_DATASIZE / sizeof(*pas);
+		}
+		*pas = htobe64(MCX_DMA_DVA(buf) + (i * MCX_PAGE_SIZE));
+		pas++;
+	}
+}
+
+static void
 mcx_cmdq_mboxes_copyout(struct mcx_dmamem *mxm, int nmb, void *b, size_t len)
 {
 	uint8_t *buf = b;
@@ -3650,7 +3677,7 @@ mcx_alloc_uar(struct mcx_softc *sc)
 		return (-1);
 	}
 
-	sc->sc_uar = be32toh(out->cmd_uar);
+	sc->sc_uar = mcx_get_id(out->cmd_uar);
 
 	return (0);
 }
@@ -3709,11 +3736,7 @@ mcx_create_eq(struct mcx_softc *sc)
 	    (1ull << MCX_EVENT_TYPE_PAGE_REQUEST));
 
 	/* physical addresses follow the mailbox in data */
-	pas = (uint64_t *)(mbin + 1);
-	for (i = 0; i < npages; i++) {
-		pas[i] = htobe64(MCX_DMA_DVA(&sc->sc_eq_mem) +
-		    (i * MCX_PAGE_SIZE));
-	}
+	mcx_cmdq_mboxes_pas(&mxm, sizeof(*mbin), npages, &sc->sc_eq_mem);
 	mcx_cmdq_mboxes_sign(&mxm, howmany(insize, MCX_CMDQ_MAILBOX_DATASIZE));
 	mcx_cmdq_post(sc, cqe, 0);
 
@@ -3735,7 +3758,7 @@ mcx_create_eq(struct mcx_softc *sc)
 		goto free;
 	}
 
-	sc->sc_eqn = be32toh(out->cmd_eqn);
+	sc->sc_eqn = mcx_get_id(out->cmd_eqn);
 	mcx_arm_eq(sc);
 free:
 	mcx_dmamem_free(sc, &mxm);
@@ -3775,7 +3798,7 @@ mcx_alloc_pd(struct mcx_softc *sc)
 		return (-1);
 	}
 
-	sc->sc_pd = be32toh(out->cmd_pd);
+	sc->sc_pd = mcx_get_id(out->cmd_pd);
 	return (0);
 }
 
@@ -3813,7 +3836,7 @@ mcx_alloc_tdomain(struct mcx_softc *sc)
 		return (-1);
 	}
 
-	sc->sc_tdomain = be32toh(out->cmd_tdomain);
+	sc->sc_tdomain = mcx_get_id(out->cmd_tdomain);
 	return (0);
 }
 
@@ -4002,10 +4025,7 @@ mcx_create_cq(struct mcx_softc *sc, int 
 	    MCX_CQ_DOORBELL_OFFSET + (MCX_CQ_DOORBELL_SIZE * sc->sc_num_cq));
 
 	/* physical addresses follow the mailbox in data */
-	pas = (uint64_t *)(mbin + 1);
-	for (i = 0; i < npages; i++) {
-		pas[i] = htobe64(MCX_DMA_DVA(&cq->cq_mem) + (i * MCX_PAGE_SIZE));
-	}
+	mcx_cmdq_mboxes_pas(&mxm, sizeof(*mbin), npages, &cq->cq_mem);
 	mcx_cmdq_post(sc, cmde, 0);
 
 	error = mcx_cmdq_poll(sc, cmde, 1000);
@@ -4026,7 +4046,7 @@ mcx_create_cq(struct mcx_softc *sc, int 
 		goto free;
 	}
 
-	cq->cq_n = be32toh(out->cmd_cqn);
+	cq->cq_n = mcx_get_id(out->cmd_cqn);
 	cq->cq_cons = 0;
 	cq->cq_count = 0;
 	cq->cq_doorbell = (void *)((uint8_t *)MCX_DMA_KVA(&sc->sc_doorbell_mem) +
@@ -4093,7 +4113,7 @@ mcx_create_rq(struct mcx_softc *sc, int 
 	int error;
 	uint64_t *pas;
 	uint8_t *doorbell;
-	int insize, npages, paslen, i, token;
+	int insize, npages, paslen, token;
 
 	npages = howmany((1 << MCX_LOG_RQ_SIZE) * sizeof(struct mcx_rq_entry),
 	    MCX_PAGE_SIZE);
@@ -4133,11 +4153,7 @@ mcx_create_rq(struct mcx_softc *sc, int 
 	mbin->rq_wq.wq_log_size = MCX_LOG_RQ_SIZE;
 
 	/* physical addresses follow the mailbox in data */
-	pas = (uint64_t *)(mbin + 1);
-	for (i = 0; i < npages; i++) {
-		pas[i] = htobe64(MCX_DMA_DVA(&sc->sc_rq_mem) +
-		    (i * MCX_PAGE_SIZE));
-	}
+	mcx_cmdq_mboxes_pas(&mxm, sizeof(*mbin) + 0x10, npages, &sc->sc_rq_mem);
 	mcx_cmdq_post(sc, cqe, 0);
 
 	error = mcx_cmdq_poll(sc, cqe, 1000);
@@ -4158,7 +4174,7 @@ mcx_create_rq(struct mcx_softc *sc, int 
 		goto free;
 	}
 
-	sc->sc_rqn = be32toh(out->cmd_rqn);
+	sc->sc_rqn = mcx_get_id(out->cmd_rqn);
 
 	doorbell = MCX_DMA_KVA(&sc->sc_doorbell_mem);
 	sc->sc_rx_doorbell = (uint32_t *)(doorbell + MCX_RQ_DOORBELL_OFFSET);
@@ -4309,7 +4325,7 @@ mcx_create_tir(struct mcx_softc *sc)
 		goto free;
 	}
 
-	sc->sc_tirn = be32toh(out->cmd_tirn);
+	sc->sc_tirn = mcx_get_id(out->cmd_tirn);
 free:
 	mcx_dmamem_free(sc, &mxm);
 	return (error);
@@ -4366,7 +4382,7 @@ mcx_create_sq(struct mcx_softc *sc, int 
 	int error;
 	uint64_t *pas;
 	uint8_t *doorbell;
-	int insize, npages, paslen, i, token;
+	int insize, npages, paslen, token;
 
 	npages = howmany((1 << MCX_LOG_SQ_SIZE) * sizeof(struct mcx_sq_entry),
 	    MCX_PAGE_SIZE);
@@ -4409,11 +4425,7 @@ mcx_create_sq(struct mcx_softc *sc, int 
 	mbin->sq_wq.wq_log_size = MCX_LOG_SQ_SIZE;
 
 	/* physical addresses follow the mailbox in data */
-	pas = (uint64_t *)(mbin + 1);
-	for (i = 0; i < npages; i++) {
-		pas[i] = htobe64(MCX_DMA_DVA(&sc->sc_sq_mem) +
-		    (i * MCX_PAGE_SIZE));
-	}
+	mcx_cmdq_mboxes_pas(&mxm, sizeof(*mbin) + 0x10, npages, &sc->sc_sq_mem);
 	mcx_cmdq_post(sc, cqe, 0);
 
 	error = mcx_cmdq_poll(sc, cqe, 1000);
@@ -4434,7 +4446,7 @@ mcx_create_sq(struct mcx_softc *sc, int 
 		goto free;
 	}
 
-	sc->sc_sqn = be32toh(out->cmd_sqn);
+	sc->sc_sqn = mcx_get_id(out->cmd_sqn);
 
 	doorbell = MCX_DMA_KVA(&sc->sc_doorbell_mem);
 	sc->sc_tx_doorbell = (uint32_t *)(doorbell + MCX_SQ_DOORBELL_OFFSET + 4);
@@ -4583,7 +4595,7 @@ mcx_create_tis(struct mcx_softc *sc)
 		goto free;
 	}
 
-	sc->sc_tisn = be32toh(out->cmd_tisn);
+	sc->sc_tisn = mcx_get_id(out->cmd_tisn);
 free:
 	mcx_dmamem_free(sc, &mxm);
 	return (error);
@@ -4719,7 +4731,7 @@ mcx_create_flow_table(struct mcx_softc *
 		goto free;
 	}
 
-	sc->sc_flow_table_id = be32toh(out->cmd_table_id);
+	sc->sc_flow_table_id = mcx_get_id(out->cmd_table_id);
 free:
 	mcx_dmamem_free(sc, &mxm);
 	return (error);
@@ -4890,7 +4902,7 @@ mcx_create_flow_group(struct mcx_softc *
 		goto free;
 	}
 
-	sc->sc_flow_group_id[group] = be32toh(out->cmd_group_id);
+	sc->sc_flow_group_id[group] = mcx_get_id(out->cmd_group_id);
 	sc->sc_flow_group_size[group] = size;
 	sc->sc_flow_group_start[group] = start;
 
@@ -6136,7 +6148,7 @@ mcx_init(struct ifnet *ifp)
 	return 0;
 destroy_tx_slots:
 	mcx_free_slots(sc, sc->sc_tx_slots, i, (1 << MCX_LOG_SQ_SIZE));
-	sc->sc_rx_slots = NULL;
+	sc->sc_tx_slots = NULL;
 
 	i = (1 << MCX_LOG_RQ_SIZE);
 destroy_rx_slots:
@@ -6530,9 +6542,15 @@ mcx_media_add_types(struct mcx_softc *sc
 
 	proto_cap = be32toh(ptys.rp_eth_proto_cap);
 	for (i = 0; i < __arraycount(mcx_eth_cap_map); i++) {
-		if ((proto_cap & (1U << i)) && (mcx_eth_cap_map[i] != 0))
-			ifmedia_add(&sc->sc_media, IFM_ETHER |
-			    mcx_eth_cap_map[i], 0, NULL);
+		const struct mcx_eth_proto_capability *cap;
+		if (!ISSET(proto_cap, 1U << i))
+			continue;
+
+		cap = &mcx_eth_cap_map[i];
+		if (cap->cap_media == 0)
+			continue;
+
+		ifmedia_add(&sc->sc_media, IFM_ETHER | cap->cap_media, 0, NULL);
 	}
 }
 
@@ -6542,7 +6560,7 @@ mcx_media_status(struct ifnet *ifp, stru
 	struct mcx_softc *sc = (struct mcx_softc *)ifp->if_softc;
 	struct mcx_reg_ptys ptys;
 	int i;
-	uint32_t /* proto_cap, */ proto_oper;
+	uint32_t proto_oper;
 	uint64_t media_oper;
 
 	memset(&ptys, 0, sizeof(ptys));
@@ -6555,14 +6573,19 @@ mcx_media_status(struct ifnet *ifp, stru
 		return;
 	}
 
-	/* proto_cap = be32toh(ptys.rp_eth_proto_cap); */
 	proto_oper = be32toh(ptys.rp_eth_proto_oper);
 
 	media_oper = 0;
+
 	for (i = 0; i < __arraycount(mcx_eth_cap_map); i++) {
-		if (proto_oper & (1U << i)) {
-			media_oper = mcx_eth_cap_map[i];
-		}
+		const struct mcx_eth_proto_capability *cap;
+		if (!ISSET(proto_oper, 1U << i))
+			continue;
+
+		cap = &mcx_eth_cap_map[i];
+
+		if (cap->cap_media != 0)
+			media_oper = cap->cap_media;
 	}
 
 	ifmr->ifm_status = IFM_AVALID;
@@ -6605,7 +6628,10 @@ mcx_media_change(struct ifnet *ifp)
 		/* map media type */
 		media = 0;
 		for (i = 0; i < __arraycount(mcx_eth_cap_map); i++) {
-			if (mcx_eth_cap_map[i] ==
+			const struct mcx_eth_proto_capability *cap;
+
+			cap = &mcx_eth_cap_map[i];
+			if (cap->cap_media ==
 			    IFM_SUBTYPE(sc->sc_media.ifm_media)) {
 				media = (1 << i);
 				break;
@@ -6654,18 +6680,41 @@ mcx_port_change(struct work *wk, void *x
 {
 	struct mcx_softc *sc = xsc;
 	struct ifnet *ifp = &sc->sc_ec.ec_if;
-	struct mcx_reg_paos paos;
+	struct mcx_reg_paos paos = {
+		.rp_local_port = 1,
+	};
+	struct mcx_reg_ptys ptys = {
+		.rp_local_port = 1,
+		.rp_proto_mask = MCX_REG_PTYS_PROTO_MASK_ETH,
+	};
 	int link_state = LINK_STATE_DOWN;
-	struct ifmediareq ifmr;
 
-	memset(&paos, 0, sizeof(paos));
-	paos.rp_local_port = 1;
 	if (mcx_access_hca_reg(sc, MCX_REG_PAOS, MCX_REG_OP_READ, &paos,
 	    sizeof(paos)) == 0) {
 		if (paos.rp_oper_status == MCX_REG_PAOS_OPER_STATUS_UP)
 			link_state = LINK_STATE_UP;
-		mcx_media_status(ifp, &ifmr);
-		ifp->if_baudrate = ifmedia_baudrate(ifmr.ifm_active);
+	}
+
+	if (mcx_access_hca_reg(sc, MCX_REG_PTYS, MCX_REG_OP_READ, &ptys,
+	    sizeof(ptys)) == 0) {
+		uint32_t proto_oper = be32toh(ptys.rp_eth_proto_oper);
+		uint64_t baudrate = 0;
+		unsigned int i;
+
+		for (i = 0; i < __arraycount(mcx_eth_cap_map); i++) {
+			const struct mcx_eth_proto_capability *cap;
+			if (!ISSET(proto_oper, 1U << i))
+				continue;
+
+			cap = &mcx_eth_cap_map[i];
+			if (cap->cap_baudrate == 0)
+				continue;
+
+			baudrate = cap->cap_baudrate;
+			break;
+		}
+
+		ifp->if_baudrate = baudrate;
 	}
 
 	if (link_state != ifp->if_link_state) {

Reply via email to