ixgbe: add MDIO bus support

This works enough to let me see the marvell switch on the MDIO bus.

It uses clause 22, which ixgbe's existing MDIO code doesn't currently
support, so it's implemented in a new source file.

Since mdio(4) is now required, add it where appropriate to GENERIC kernels.

Reviewed by:	kbowling
Differential Revision:	https://reviews.freebsd.org/D50128
This commit is contained in:
Adrian Chadd committed 2026-04-17 10:11:42 -07:00
1 parent eb0279550d
commit cfec995c87
9 files changed
+432 -2

No files matched your search

+3
View File
@@ -229,6 +229,9 @@ device ppi # Parallel port interface device
device puc # Multi I/O cards and multi-channel UARTs
# MDIO bus for Ethernet NICs that directly expose the MDIO bus
device mdio
# PCI/PCI-X/PCIe Ethernet NICs that use iflib infrastructure
device iflib
device em # Intel PRO/1000 Gigabit Ethernet Family
+3
View File
@@ -1997,6 +1997,9 @@ device vr # VIA Rhine, Rhine II
device vte # DM&P Vortex86 RDC R6040 Fast Ethernet
device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'')
# MDIO bus for Ethernet NICs that directly expose the MDIO bus
device mdio
# PCI/PCI-X/PCIe Ethernet NICs that use iflib infrastructure
device iflib
device em # Intel Pro/1000 Gigabit Ethernet
+4
View File
@@ -2300,6 +2300,10 @@ dev/ixgbe/if_ix.c optional ix inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP"
dev/ixgbe/if_ixv.c optional ixv inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe -DSMP"
dev/ixgbe/if_ix_mdio.c optional ix inet mdio \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/if_ix_mdio_hw.c optional ix inet mdio \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/if_bypass.c optional ix inet \
compile-with "${NORMAL_C} -I$S/dev/ixgbe"
dev/ixgbe/if_fdir.c optional ix inet | ixv inet \
+14 -1
View File
@@ -36,10 +36,14 @@
#include "opt_rss.h"
#include "ixgbe.h"
#include "mdio_if.h"
#include "ixgbe_sriov.h"
#include "ifdi_if.h"
#include "if_ix_mdio_hw.h"
#include "if_ix_mdio.h"
#include <net/netmap.h>
#include <dev/mdio/mdio.h>
#include <dev/netmap/netmap_kern.h>
/************************************************************************
@@ -298,6 +302,10 @@ static device_method_t ix_methods[] = {
DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
#endif /* PCI_IOV */
DEVMETHOD(bus_add_child, device_add_child_ordered),
DEVMETHOD(mdio_readreg, ixgbe_mdio_readreg_c22),
DEVMETHOD(mdio_writereg, ixgbe_mdio_writereg_c22),
DEVMETHOD_END
};
@@ -305,11 +313,13 @@ static driver_t ix_driver = {
"ix", ix_methods, sizeof(struct ixgbe_softc),
};
DRIVER_MODULE(ix, pci, ix_driver, 0, 0);
DRIVER_MODULE(mdio, ix, mdio_driver, 0, 0); /* needs to happen before ix */
DRIVER_MODULE_ORDERED(ix, pci, ix_driver, NULL, NULL, SI_ORDER_ANY); /* needs to be last */
IFLIB_PNP_INFO(pci, ix_driver, ixgbe_vendor_info_array);
MODULE_DEPEND(ix, pci, 1, 1, 1);
MODULE_DEPEND(ix, ether, 1, 1, 1);
MODULE_DEPEND(ix, iflib, 1, 1, 1);
MODULE_DEPEND(ix, mdio, 1, 1, 1);
static device_method_t ixgbe_if_methods[] = {
DEVMETHOD(ifdi_attach_pre, ixgbe_if_attach_pre),
@@ -1274,6 +1284,9 @@ ixgbe_if_attach_post(if_ctx_t ctx)
/* Add sysctls */
ixgbe_add_device_sysctls(ctx);
/* Add MDIO bus if required / supported */
ixgbe_mdio_attach(sc);
/* Init recovery mode timer and state variable */
if (sc->feat_en & IXGBE_FEATURE_RECOVERY_MODE) {
sc->recovery_mode = 0;
+158
View File
@@ -0,0 +1,158 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_rss.h"
#include "ixgbe.h"
#include "mdio_if.h"
#include "ixgbe_sriov.h"
#include "ifdi_if.h"
#include "if_ix_mdio_hw.h"
#include "if_ix_mdio.h"
#include <dev/mdio/mdio.h>
/**
* @brief Return if the given ixgbe chipset supports clause 22 MDIO bus access.
*
* Although technically all of the ixgbe chipsets support an MDIO
* bus interface, there's a bunch of factors controlling whether
* this should be exposed for external control.
*
* This functionr returns true if it supports an MDIO bus and
* clause 22 transactions.
*/
static bool
ixgbe_has_mdio_bus_clause22(struct ixgbe_hw *hw)
{
switch (hw->device_id) {
case IXGBE_DEV_ID_X550EM_A_KR:
case IXGBE_DEV_ID_X550EM_A_KR_L:
case IXGBE_DEV_ID_X550EM_A_SFP_N:
case IXGBE_DEV_ID_X550EM_A_SGMII:
case IXGBE_DEV_ID_X550EM_A_SGMII_L:
case IXGBE_DEV_ID_X550EM_A_10G_T:
case IXGBE_DEV_ID_X550EM_A_SFP:
case IXGBE_DEV_ID_X550EM_A_1G_T:
case IXGBE_DEV_ID_X550EM_A_1G_T_L:
return (true);
}
return (false);
}
/**
* @brief Initiate a clause-22 MDIO read transfer.
*
* Note this is only officially supported for a small subset
* of NICs, notably the X552/X553 devices. This must not be
* called for other chipsets.
*/
int
ixgbe_mdio_readreg_c22(device_t dev, int phy, int reg)
{
if_ctx_t ctx = device_get_softc(dev);
struct sx *iflib_ctx_lock = iflib_ctx_lock_get(ctx);
struct ixgbe_softc *sc = iflib_get_softc(ctx);
struct ixgbe_hw *hw = &sc->hw;
uint16_t val = 0;
int32_t ret = 0;
if (! ixgbe_has_mdio_bus_clause22(hw))
return (-1);
sx_xlock(iflib_ctx_lock);
ret = ixgbe_read_mdio_c22(hw, phy, reg, &val);
if (ret != IXGBE_SUCCESS) {
device_printf(dev, "%s: read_mdi_22 failed (%d)\n",
__func__, ret);
sx_xunlock(iflib_ctx_lock);
return (-1);
}
sx_xunlock(iflib_ctx_lock);
return (val);
}
/**
* @brief Initiate a clause-22 MDIO write transfer.
*
* Note this is only officially supported for a small subset
* of NICs, notably the X552/X553 devices. This must not be
* called for other chipsets.
*/
int
ixgbe_mdio_writereg_c22(device_t dev, int phy, int reg, int data)
{
if_ctx_t ctx = device_get_softc(dev);
struct sx *iflib_ctx_lock = iflib_ctx_lock_get(ctx);
struct ixgbe_softc *sc = iflib_get_softc(ctx);
struct ixgbe_hw *hw = &sc->hw;
int32_t ret;
if (! ixgbe_has_mdio_bus_clause22(hw))
return (-1);
sx_xlock(iflib_ctx_lock);
ret = ixgbe_write_mdio_c22(hw, phy, reg, data);
if (ret != IXGBE_SUCCESS) {
device_printf(dev, "%s: write_mdi_22 failed (%d)\n",
__func__, ret);
sx_xunlock(iflib_ctx_lock);
return (-1);
}
sx_xunlock(iflib_ctx_lock);
return (0);
}
/**
* @brief Attach the MDIO bus if one exists.
*/
void
ixgbe_mdio_attach(struct ixgbe_softc *sc)
{
struct ixgbe_hw *hw = &sc->hw;
int enable_mdio = 0;
/*
* This explicitly needs to be enabled regardless of whether
* the device / instance supports an external MDIO bus.
*/
if (resource_int_value(device_get_name(sc->dev),
device_get_unit(sc->dev), "enable_mdio", &enable_mdio) == 0) {
if (enable_mdio == 0)
return;
} else
return;
if (! ixgbe_has_mdio_bus_clause22(hw))
return;
device_add_child(sc->dev, "mdio", DEVICE_UNIT_ANY);
bus_attach_children(sc->dev);
}
+34
View File
@@ -0,0 +1,34 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _IF_IX_MDIO_H_
#define _IF_IX_MDIO_H_
int ixgbe_mdio_readreg_c22(device_t, int, int);
int ixgbe_mdio_writereg_c22(device_t, int, int, int);
void ixgbe_mdio_attach(struct ixgbe_softc *);
#endif /* _IF_IX_MDIO_H */
+181
View File
@@ -0,0 +1,181 @@
/******************************************************************************
SPDX-License-Identifier: BSD-3-Clause
Copyright (c) 2001-2024, Intel Corporation
All rights reserved.
Copyright (c) 2026 Adrian Chadd <adrian@FreeBSD.org>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#include "ixgbe_api.h"
#include "ixgbe_common.h"
#include "ixgbe_phy.h"
#include "if_ix_mdio_hw.h"
/*
* These routines are separate from the rest of ixgbe for now to make merging
* easier.
*/
static s32
ixgbe_read_mdio_unlocked_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 *phy_data)
{
u32 i, data, command;
/* Setup and write the read command */
command = (reg << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(phy << IXGBE_MSCA_PHY_ADDR_SHIFT) |
IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_READ_AUTOINC |
IXGBE_MSCA_MDI_COMMAND;
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/* Check every 10 usec to see if the access completed.
* The MDI Command bit will clear when the operation is
* complete
*/
for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
usec_delay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if (!(command & IXGBE_MSCA_MDI_COMMAND))
break;
}
if (command & IXGBE_MSCA_MDI_COMMAND)
return IXGBE_ERR_PHY;
/* Read operation is complete. Get the data from MSRWD */
data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
*phy_data = (u16)data;
return IXGBE_SUCCESS;
}
static s32
ixgbe_write_mdio_unlocked_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 phy_data)
{
u32 i, command;
/* Put the data in the MDI single read and write data register*/
IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
/* Setup and write the write command */
command = (reg << IXGBE_MSCA_DEV_TYPE_SHIFT) |
(phy << IXGBE_MSCA_PHY_ADDR_SHIFT) |
IXGBE_MSCA_OLD_PROTOCOL | IXGBE_MSCA_WRITE |
IXGBE_MSCA_MDI_COMMAND;
IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
/* Check every 10 usec to see if the access completed.
* The MDI Command bit will clear when the operation is
* complete
*/
for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
usec_delay(10);
command = IXGBE_READ_REG(hw, IXGBE_MSCA);
if (!(command & IXGBE_MSCA_MDI_COMMAND))
break;
}
if (command & IXGBE_MSCA_MDI_COMMAND)
return IXGBE_ERR_PHY;
return IXGBE_SUCCESS;
}
/*
* Return true if the MAC is an X55x backplane.
*
* These have a single MDIO PHY semaphore (PHY0) and also require the
* token semaphore.
*/
static bool
ixgbe_check_mdio_is_x550em(struct ixgbe_hw *hw)
{
switch (hw->device_id) {
case IXGBE_DEV_ID_X550EM_A_KR:
case IXGBE_DEV_ID_X550EM_A_KR_L:
case IXGBE_DEV_ID_X550EM_A_SFP_N:
case IXGBE_DEV_ID_X550EM_A_SGMII:
case IXGBE_DEV_ID_X550EM_A_SGMII_L:
case IXGBE_DEV_ID_X550EM_A_10G_T:
case IXGBE_DEV_ID_X550EM_A_SFP:
case IXGBE_DEV_ID_X550EM_A_1G_T:
case IXGBE_DEV_ID_X550EM_A_1G_T_L:
return true;
default:
return false;
}
}
s32
ixgbe_read_mdio_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 *phy_data)
{
u32 gssr = hw->phy.phy_semaphore_mask;
s32 ret;
if (ixgbe_check_mdio_is_x550em(hw))
gssr |= IXGBE_GSSR_PHY0_SM | IXGBE_GSSR_TOKEN_SM;
if (hw->mac.ops.acquire_swfw_sync(hw, gssr)) {
*phy_data = -1;
return IXGBE_ERR_TIMEOUT;
}
ret = ixgbe_read_mdio_unlocked_c22(hw, phy, reg, phy_data);
if (ret != IXGBE_SUCCESS)
*phy_data = -1;
hw->mac.ops.release_swfw_sync(hw, gssr);
return ret;
}
s32
ixgbe_write_mdio_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 data)
{
u32 gssr = hw->phy.phy_semaphore_mask;
s32 ret;
if (ixgbe_check_mdio_is_x550em(hw))
gssr |= IXGBE_GSSR_PHY0_SM | IXGBE_GSSR_TOKEN_SM;
if (hw->mac.ops.acquire_swfw_sync(hw, gssr))
return IXGBE_ERR_TIMEOUT;
ret = ixgbe_write_mdio_unlocked_c22(hw, phy, reg, data);
hw->mac.ops.release_swfw_sync(hw, gssr);
return ret;
}
+33
View File
@@ -0,0 +1,33 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2026 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _IF_IX_MDIO_HW_H_
#define _IF_IX_MDIO_HW_H_
s32 ixgbe_read_mdio_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 *phy_data);
s32 ixgbe_write_mdio_c22(struct ixgbe_hw *hw, u16 phy, u16 reg, u16 data);
#endif /* _IF_IX_MDIO_HW_H_ */
+2 -1
View File
@@ -1,9 +1,10 @@
.PATH: ${SRCTOP}/sys/dev/ixgbe
KMOD = if_ix
SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h ifdi_if.h
SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h ifdi_if.h mdio_if.h
SRCS += opt_inet.h opt_inet6.h opt_rss.h
SRCS += if_ix.c if_bypass.c if_fdir.c if_sriov.c ix_txrx.c ixgbe_osdep.c
SRCS += if_ix_mdio.c if_ix_mdio_hw.c
# Shared source
SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c
SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c