xref: /freebsd/sys/dev/ixgbe/if_ix_mdio.c (revision cfec995c87f39e59c80554b85625b4aaa8ddf8db)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "opt_inet.h"
28 #include "opt_inet6.h"
29 #include "opt_rss.h"
30 
31 #include "ixgbe.h"
32 #include "mdio_if.h"
33 #include "ixgbe_sriov.h"
34 #include "ifdi_if.h"
35 #include "if_ix_mdio_hw.h"
36 #include "if_ix_mdio.h"
37 
38 #include <dev/mdio/mdio.h>
39 
40 /**
41  * @brief Return if the given ixgbe chipset supports clause 22 MDIO bus access.
42  *
43  * Although technically all of the ixgbe chipsets support an MDIO
44  * bus interface, there's a bunch of factors controlling whether
45  * this should be exposed for external control.
46  *
47  * This functionr returns true if it supports an MDIO bus and
48  * clause 22 transactions.
49  */
50 static bool
ixgbe_has_mdio_bus_clause22(struct ixgbe_hw * hw)51 ixgbe_has_mdio_bus_clause22(struct ixgbe_hw *hw)
52 {
53 	switch (hw->device_id) {
54 	case IXGBE_DEV_ID_X550EM_A_KR:
55 	case IXGBE_DEV_ID_X550EM_A_KR_L:
56 	case IXGBE_DEV_ID_X550EM_A_SFP_N:
57 	case IXGBE_DEV_ID_X550EM_A_SGMII:
58 	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
59 	case IXGBE_DEV_ID_X550EM_A_10G_T:
60 	case IXGBE_DEV_ID_X550EM_A_SFP:
61 	case IXGBE_DEV_ID_X550EM_A_1G_T:
62 	case IXGBE_DEV_ID_X550EM_A_1G_T_L:
63 		return (true);
64 	}
65 	return (false);
66 }
67 
68 
69 
70 /**
71  * @brief Initiate a clause-22 MDIO read transfer.
72  *
73  * Note this is only officially supported for a small subset
74  * of NICs, notably the X552/X553 devices.  This must not be
75  * called for other chipsets.
76  */
77 int
ixgbe_mdio_readreg_c22(device_t dev,int phy,int reg)78 ixgbe_mdio_readreg_c22(device_t dev, int phy, int reg)
79 {
80 	if_ctx_t ctx = device_get_softc(dev);
81 	struct sx *iflib_ctx_lock = iflib_ctx_lock_get(ctx);
82 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
83 	struct ixgbe_hw *hw = &sc->hw;
84 	uint16_t val = 0;
85 	int32_t ret = 0;
86 
87 	if (! ixgbe_has_mdio_bus_clause22(hw))
88 		return (-1);
89 
90 	sx_xlock(iflib_ctx_lock);
91 	ret = ixgbe_read_mdio_c22(hw, phy, reg, &val);
92 	if (ret != IXGBE_SUCCESS) {
93 		device_printf(dev, "%s: read_mdi_22 failed (%d)\n",
94 		    __func__, ret);
95 		sx_xunlock(iflib_ctx_lock);
96 		return (-1);
97 	}
98 	sx_xunlock(iflib_ctx_lock);
99 	return (val);
100 }
101 
102 /**
103  * @brief Initiate a clause-22 MDIO write transfer.
104  *
105  * Note this is only officially supported for a small subset
106  * of NICs, notably the X552/X553 devices.  This must not be
107  * called for other chipsets.
108  */
109 int
ixgbe_mdio_writereg_c22(device_t dev,int phy,int reg,int data)110 ixgbe_mdio_writereg_c22(device_t dev, int phy, int reg, int data)
111 {
112 	if_ctx_t ctx = device_get_softc(dev);
113 	struct sx *iflib_ctx_lock = iflib_ctx_lock_get(ctx);
114 	struct ixgbe_softc *sc = iflib_get_softc(ctx);
115 	struct ixgbe_hw *hw = &sc->hw;
116 	int32_t ret;
117 
118 	if (! ixgbe_has_mdio_bus_clause22(hw))
119 		return (-1);
120 
121 	sx_xlock(iflib_ctx_lock);
122 	ret = ixgbe_write_mdio_c22(hw, phy, reg, data);
123 	if (ret != IXGBE_SUCCESS) {
124 		device_printf(dev, "%s: write_mdi_22 failed (%d)\n",
125 		    __func__, ret);
126 		sx_xunlock(iflib_ctx_lock);
127 		return (-1);
128 	}
129 	sx_xunlock(iflib_ctx_lock);
130 	return (0);
131 }
132 
133 /**
134  * @brief Attach the MDIO bus if one exists.
135  */
136 void
ixgbe_mdio_attach(struct ixgbe_softc * sc)137 ixgbe_mdio_attach(struct ixgbe_softc *sc)
138 {
139 	struct ixgbe_hw *hw = &sc->hw;
140 	int enable_mdio = 0;
141 
142 	/*
143 	 * This explicitly needs to be enabled regardless of whether
144 	 * the device / instance supports an external MDIO bus.
145 	 */
146 	if (resource_int_value(device_get_name(sc->dev),
147 	    device_get_unit(sc->dev), "enable_mdio", &enable_mdio) == 0) {
148 		if (enable_mdio == 0)
149 			return;
150 	} else
151 		return;
152 
153 	if (! ixgbe_has_mdio_bus_clause22(hw))
154 		return;
155 
156 	device_add_child(sc->dev, "mdio", DEVICE_UNIT_ANY);
157 	bus_attach_children(sc->dev);
158 }
159