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