Bug Summary

File:dev/mii/mii_physubr.c
Warning:line 182, column 9
Although the value stored to 'bmsr' is used in the enclosing expression, the value is never actually read from 'bmsr'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mii_physubr.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/mii/mii_physubr.c
1/* $OpenBSD: mii_physubr.c,v 1.46 2020/01/15 00:14:47 cheloha Exp $ */
2/* $NetBSD: mii_physubr.c,v 1.20 2001/04/13 23:30:09 thorpej Exp $ */
3
4/*-
5 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * Subroutines common to all PHYs.
36 */
37
38#include <sys/param.h>
39#include <sys/device.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/socket.h>
43#include <sys/errno.h>
44
45#include <net/if.h>
46#include <net/if_var.h>
47#include <net/if_media.h>
48
49#include <dev/mii/mii.h>
50#include <dev/mii/miivar.h>
51
52/*
53 * Media to register setting conversion table. Order matters.
54 * XXX 802.3 doesn't specify ANAR or ANLPAR bits for 1000base.
55 */
56const struct mii_media mii_media_table[] = {
57 /* None */
58 { BMCR_ISO0x0400, ANAR_CSMA0x0001, 0 },
59 /* 10baseT */
60 { BMCR_S100x0000, ANAR_CSMA0x0001|ANAR_100x0020, 0 },
61 /* 10baseT-FDX */
62 { BMCR_S100x0000|BMCR_FDX0x0100, ANAR_CSMA0x0001|ANAR_10_FD0x0040, 0 },
63 /* 100baseT4 */
64 { BMCR_S1000x2000, ANAR_CSMA0x0001|ANAR_T40x0200, 0 },
65 /* 100baseTX */
66 { BMCR_S1000x2000, ANAR_CSMA0x0001|ANAR_TX0x0080, 0 },
67 /* 100baseTX-FDX */
68 { BMCR_S1000x2000|BMCR_FDX0x0100, ANAR_CSMA0x0001|ANAR_TX_FD0x0100, 0 },
69 /* 1000baseX */
70 { BMCR_S10000x0040, ANAR_CSMA0x0001, 0 },
71 /* 1000baseX-FDX */
72 { BMCR_S10000x0040|BMCR_FDX0x0100, ANAR_CSMA0x0001, 0 },
73 /* 1000baseT */
74 { BMCR_S10000x0040, ANAR_CSMA0x0001, GTCR_ADV_1000THDX0x0100 },
75 /* 1000baseT-FDX */
76 { BMCR_S10000x0040|BMCR_FDX0x0100, ANAR_CSMA0x0001, GTCR_ADV_1000TFDX0x0200 },
77};
78
79void
80mii_phy_setmedia(struct mii_softc *sc)
81{
82 struct mii_data *mii = sc->mii_pdata;
83 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
84 int bmcr, anar, gtcr;
85
86 if (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL) == IFM_AUTO0ULL) {
87 if ((PHY_READ(sc, MII_BMCR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00))
& BMCR_AUTOEN0x1000) == 0 ||
88 (sc->mii_flags & MIIF_FORCEANEG0x0400))
89 (void) mii_phy_auto(sc, 1);
90 return;
91 }
92
93 /*
94 * Table index is stored in the media entry.
95 */
96#ifdef DIAGNOSTIC1
97 if (ife->ifm_data >= MII_NMEDIA10)
98 panic("mii_phy_setmedia");
99#endif
100
101 anar = mii_media_table[ife->ifm_data].mm_anar;
102 bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
103 gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
104
105 if (mii->mii_media.ifm_media & IFM_ETH_MASTER0x0000000000010000ULL) {
106 switch (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL)) {
107 case IFM_1000_T16:
108 gtcr |= GTCR_MAN_MS0x1000|GTCR_ADV_MS0x0800;
109 break;
110
111 default:
112 panic("mii_phy_setmedia: MASTER on wrong media");
113 }
114 }
115
116 if (ife->ifm_media & IFM_LOOP0x0000800000000000ULL)
117 bmcr |= BMCR_LOOP0x4000;
118
119 PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x04), (anar))
;
120 PHY_WRITE(sc, MII_BMCR, bmcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00), (bmcr))
;
121 if (sc->mii_flags & MIIF_HAVE_GTCR0x0040)
122 PHY_WRITE(sc, MII_100T2CR, gtcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x09), (gtcr))
;
123}
124
125int
126mii_phy_auto(struct mii_softc *sc, int waitfor)
127{
128 int bmsr, i;
129
130 if ((sc->mii_flags & MIIF_DOINGAUTO0x0008) == 0) {
131 /*
132 * Check for 1000BASE-X. Autonegotiation is a bit
133 * different on such devices.
134 */
135 if (sc->mii_flags & MIIF_IS_1000X0x0080) {
136 uint16_t anar = 0;
137
138 if (sc->mii_extcapabilities & EXTSR_1000XFDX0x8000)
139 anar |= ANAR_X_FD0x0020;
140 if (sc->mii_extcapabilities & EXTSR_1000XHDX0x4000)
141 anar |= ANAR_X_HD0x0040;
142
143 if (sc->mii_flags & MIIF_DOPAUSE0x0100 &&
144 sc->mii_extcapabilities & EXTSR_1000XFDX0x8000)
145 anar |= ANAR_X_PAUSE_TOWARDS(3 << 7);
146
147 PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x04), (anar))
;
148 } else {
149 uint16_t anar;
150
151 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities)(((sc->mii_capabilities) & (0x8000|0x4000|0x2000| 0x1000
|0x0800|0x0400|0x0200)) >> 6)
|
152 ANAR_CSMA0x0001;
153 /*
154 * Most 100baseTX PHY's only support symmetric
155 * PAUSE, so we don't advertise asymmetric
156 * PAUSE unless we also have 1000baseT capability.
157 */
158 if (sc->mii_flags & MIIF_DOPAUSE0x0100) {
159 if (sc->mii_capabilities & BMSR_100TXFDX0x4000)
160 anar |= ANAR_FC0x0400;
161 if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000)
162 anar |= ANAR_PAUSE_TOWARDS(3 << 10);
163 }
164 PHY_WRITE(sc, MII_ANAR, anar)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x04), (anar))
;
165 if (sc->mii_flags & MIIF_HAVE_GTCR0x0040) {
166 uint16_t gtcr = 0;
167
168 if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000)
169 gtcr |= GTCR_ADV_1000TFDX0x0200;
170 if (sc->mii_extcapabilities & EXTSR_1000THDX0x1000)
171 gtcr |= GTCR_ADV_1000THDX0x0100;
172
173 PHY_WRITE(sc, MII_100T2CR, gtcr)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x09), (gtcr))
;
174 }
175 }
176 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00), (0x1000 | 0x0200))
;
177 }
178
179 if (waitfor) {
180 /* Wait 500ms for it to complete. */
181 for (i = 0; i < 500; i++) {
182 if ((bmsr = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x01))
) & BMSR_ACOMP0x0020)
Although the value stored to 'bmsr' is used in the enclosing expression, the value is never actually read from 'bmsr'
183 return (0);
184 delay(1000)(*delay_func)(1000);
185 }
186
187 /*
188 * Don't need to worry about clearing MIIF_DOINGAUTO.
189 * If that's set, a timeout is pending, and it will
190 * clear the flag.
191 */
192 return (EIO5);
193 }
194
195 /*
196 * Just let it finish asynchronously. This is for the benefit of
197 * the tick handler driving autonegotiation. Don't want 500ms
198 * delays all the time while the system is running!
199 */
200 if (sc->mii_flags & MIIF_AUTOTSLEEP0x0010) {
201 sc->mii_flags |= MIIF_DOINGAUTO0x0008;
202 tsleep_nsec(&sc->mii_flags, PZERO22, "miiaut", MSEC_TO_NSEC(500));
203 mii_phy_auto_timeout(sc);
204 } else if ((sc->mii_flags & MIIF_DOINGAUTO0x0008) == 0) {
205 sc->mii_flags |= MIIF_DOINGAUTO0x0008;
206 timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
207 timeout_add_msec(&sc->mii_phy_timo, 500);
208 }
209 return (EJUSTRETURN-2);
210}
211
212void
213mii_phy_auto_timeout(void *arg)
214{
215 struct mii_softc *sc = arg;
216 int s, bmsr;
217
218 if ((sc->mii_dev.dv_flags & DVF_ACTIVE0x0001) == 0)
219 return;
220
221 s = splnet()splraise(0x4);
222 sc->mii_flags &= ~MIIF_DOINGAUTO0x0008;
223 bmsr = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x01))
;
224
225 /* Update the media status. */
226 (void) PHY_SERVICE(sc, sc->mii_pdata, MII_POLLSTAT)(*(sc)->mii_funcs->pf_service)((sc), (sc->mii_pdata)
, (3))
;
227 splx(s)spllower(s);
228}
229
230int
231mii_phy_tick(struct mii_softc *sc)
232{
233 struct mii_data *mii = sc->mii_pdata;
234 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
235 int reg;
236
237 /* Just bail now if the interface is down. */
238 if ((mii->mii_ifp->if_flags & IFF_UP0x1) == 0)
239 return (EJUSTRETURN-2);
240
241 /*
242 * If we're not doing autonegotiation, we don't need to do
243 * any extra work here. However, we need to check the link
244 * status so we can generate an announcement if the status
245 * changes.
246 */
247 if (IFM_SUBTYPE(ife->ifm_media)((ife->ifm_media) & 0x00000000000000ffULL) != IFM_AUTO0ULL)
248 return (0);
249
250 /* Read the status register twice; BMSR_LINK is latch-low. */
251 reg = PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x01))
| PHY_READ(sc, MII_BMSR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x01))
;
252 if (reg & BMSR_LINK0x0004) {
253 /*
254 * See above.
255 */
256 return (0);
257 }
258
259 /*
260 * Only retry autonegotiation every mii_anegticks seconds.
261 */
262 if (!sc->mii_anegticks)
263 sc->mii_anegticks = MII_ANEGTICKS5;
264
265 if (++sc->mii_ticks <= sc->mii_anegticks)
266 return (EJUSTRETURN-2);
267
268 sc->mii_ticks = 0;
269 PHY_RESET(sc)(*(sc)->mii_funcs->pf_reset)((sc));
270
271 if (mii_phy_auto(sc, 0) == EJUSTRETURN-2)
272 return (EJUSTRETURN-2);
273
274 /*
275 * Might need to generate a status message if autonegotiation
276 * failed.
277 */
278 return (0);
279}
280
281void
282mii_phy_reset(struct mii_softc *sc)
283{
284 int reg, i;
285
286 if (sc->mii_flags & MIIF_NOISOLATE0x0002)
287 reg = BMCR_RESET0x8000;
288 else
289 reg = BMCR_RESET0x8000 | BMCR_ISO0x0400;
290 PHY_WRITE(sc, MII_BMCR, reg)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00), (reg))
;
291
292 /*
293 * It is best to allow a little time for the reset to settle
294 * in before we start polling the BMCR again. Notably, the
295 * DP83840A manual states that there should be a 500us delay
296 * between asserting software reset and attempting MII serial
297 * operations. Also, a DP83815 can get into a bad state on
298 * cable removal and reinsertion if we do not delay here.
299 */
300 delay(500)(*delay_func)(500);
301
302 /* Wait another 100ms for it to complete. */
303 for (i = 0; i < 100; i++) {
304 reg = PHY_READ(sc, MII_BMCR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00))
;
305 if ((reg & BMCR_RESET0x8000) == 0)
306 break;
307 delay(1000)(*delay_func)(1000);
308 }
309
310 if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE0x0002) == 0))
311 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO)(*(sc)->mii_pdata->mii_writereg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x00), (reg | 0x0400))
;
312}
313
314void
315mii_phy_down(struct mii_softc *sc)
316{
317 if (sc->mii_flags & MIIF_DOINGAUTO0x0008) {
318 sc->mii_flags &= ~MIIF_DOINGAUTO0x0008;
319 timeout_del(&sc->mii_phy_timo);
320 }
321}
322
323
324void
325mii_phy_status(struct mii_softc *sc)
326{
327 PHY_STATUS(sc)(*(sc)->mii_funcs->pf_status)((sc));
328}
329
330void
331mii_phy_update(struct mii_softc *sc, int cmd)
332{
333 struct mii_data *mii = sc->mii_pdata;
334 struct ifnet *ifp = mii->mii_ifp;
335 int announce, s;
336
337 if (sc->mii_media_active != mii->mii_media_active ||
338 sc->mii_media_status != mii->mii_media_status ||
339 cmd == MII_MEDIACHG2) {
340 announce = mii_phy_statusmsg(sc);
341 (*mii->mii_statchg)(sc->mii_dev.dv_parent);
342 sc->mii_media_active = mii->mii_media_active;
343 sc->mii_media_status = mii->mii_media_status;
344
345 if (announce) {
346 s = splnet()splraise(0x4);
347 if_link_state_change(ifp);
348 splx(s)spllower(s);
349 }
350 }
351}
352
353int
354mii_phy_statusmsg(struct mii_softc *sc)
355{
356 struct mii_data *mii = sc->mii_pdata;
357 struct ifnet *ifp = mii->mii_ifp;
358 u_int64_t baudrate;
359 int link_state, announce = 0;
360
361 if (mii->mii_media_status & IFM_AVALID0x0000000000000001ULL) {
362 if (mii->mii_media_status & IFM_ACTIVE0x0000000000000002ULL) {
363 if (mii->mii_media_active & IFM_FDX0x0000010000000000ULL)
364 link_state = LINK_STATE_FULL_DUPLEX6;
365 else
366 link_state = LINK_STATE_HALF_DUPLEX5;
367 } else
368 link_state = LINK_STATE_DOWN2;
369 } else
370 link_state = LINK_STATE_UNKNOWN0;
371
372 baudrate = ifmedia_baudrate(mii->mii_media_active);
373
374 if (link_state != ifp->if_link_stateif_data.ifi_link_state) {
375 ifp->if_link_stateif_data.ifi_link_state = link_state;
376 /*
377 * XXX Right here we'd like to notify protocols
378 * XXX that the link status has changed, so that
379 * XXX e.g. Duplicate Address Detection can restart.
380 */
381 announce = 1;
382 }
383
384 if (baudrate != ifp->if_baudrateif_data.ifi_baudrate) {
385 ifp->if_baudrateif_data.ifi_baudrate = baudrate;
386 announce = 1;
387 }
388
389 return (announce);
390}
391
392/*
393 * Initialize generic PHY media based on BMSR, called when a PHY is
394 * attached.
395 */
396void
397mii_phy_add_media(struct mii_softc *sc)
398{
399 struct mii_data *mii = sc->mii_pdata;
400
401#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL((void *)0))
402
403 if ((sc->mii_flags & MIIF_NOISOLATE0x0002) == 0)
404 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst)((0x0000000000000100ULL) | (2ULL) | (0) | ((uint64_t)(sc->
mii_inst) << 56))
,
405 MII_MEDIA_NONE0);
406
407 if (sc->mii_capabilities & BMSR_10THDX0x0800) {
408 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst)((0x0000000000000100ULL) | (3) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
,
409 MII_MEDIA_10_T1);
410 }
411 if (sc->mii_capabilities & BMSR_10TFDX0x1000) {
412 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst)((0x0000000000000100ULL) | (3) | (0x0000010000000000ULL) | ((
uint64_t)(sc->mii_inst) << 56))
,
413 MII_MEDIA_10_T_FDX2);
414 }
415 if (sc->mii_capabilities & BMSR_100TXHDX0x2000) {
416 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst)((0x0000000000000100ULL) | (6) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
,
417 MII_MEDIA_100_TX4);
418 }
419 if (sc->mii_capabilities & BMSR_100TXFDX0x4000) {
420 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst)((0x0000000000000100ULL) | (6) | (0x0000010000000000ULL) | ((
uint64_t)(sc->mii_inst) << 56))
,
421 MII_MEDIA_100_TX_FDX5);
422 }
423 if (sc->mii_capabilities & BMSR_100T40x8000) {
424 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst)((0x0000000000000100ULL) | (8) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
,
425 MII_MEDIA_100_T43);
426 }
427 if (sc->mii_extcapabilities & EXTSR_MEDIAMASK(0x8000|0x4000| 0x2000|0x1000)) {
428 /*
429 * XXX Right now only handle 1000SX and 1000TX. Need
430 * XXX to handle 1000LX and 1000CX some how.
431 */
432 if (sc->mii_extcapabilities & EXTSR_1000XHDX0x4000) {
433 sc->mii_anegticks = MII_ANEGTICKS_GIGE10;
434 sc->mii_flags |= MIIF_IS_1000X0x0080;
435 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,((0x0000000000000100ULL) | (11) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
436 sc->mii_inst)((0x0000000000000100ULL) | (11) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
, MII_MEDIA_1000_X6);
437 }
438 if (sc->mii_extcapabilities & EXTSR_1000XFDX0x8000) {
439 sc->mii_anegticks = MII_ANEGTICKS_GIGE10;
440 sc->mii_flags |= MIIF_IS_1000X0x0080;
441 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,((0x0000000000000100ULL) | (11) | (0x0000010000000000ULL) | (
(uint64_t)(sc->mii_inst) << 56))
442 sc->mii_inst)((0x0000000000000100ULL) | (11) | (0x0000010000000000ULL) | (
(uint64_t)(sc->mii_inst) << 56))
, MII_MEDIA_1000_X_FDX7);
443 }
444
445 /*
446 * 1000baseT media needs to be able to manipulate
447 * master/slave mode. We set IFM_ETH_MASTER in
448 * the "don't care mask" and filter it out when
449 * the media is set.
450 *
451 * All 1000baseT PHYs have a 1000baseT control register.
452 */
453 if (sc->mii_extcapabilities & EXTSR_1000THDX0x1000) {
454 sc->mii_anegticks = MII_ANEGTICKS_GIGE10;
455 sc->mii_flags |= MIIF_HAVE_GTCR0x0040;
456 mii->mii_media.ifm_mask |= IFM_ETH_MASTER0x0000000000010000ULL;
457 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,((0x0000000000000100ULL) | (16) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
458 sc->mii_inst)((0x0000000000000100ULL) | (16) | (0) | ((uint64_t)(sc->mii_inst
) << 56))
, MII_MEDIA_1000_T8);
459 }
460 if (sc->mii_extcapabilities & EXTSR_1000TFDX0x2000) {
461 sc->mii_anegticks = MII_ANEGTICKS_GIGE10;
462 sc->mii_flags |= MIIF_HAVE_GTCR0x0040;
463 mii->mii_media.ifm_mask |= IFM_ETH_MASTER0x0000000000010000ULL;
464 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,((0x0000000000000100ULL) | (16) | (0x0000010000000000ULL) | (
(uint64_t)(sc->mii_inst) << 56))
465 sc->mii_inst)((0x0000000000000100ULL) | (16) | (0x0000010000000000ULL) | (
(uint64_t)(sc->mii_inst) << 56))
, MII_MEDIA_1000_T_FDX9);
466 }
467 }
468
469 if (sc->mii_capabilities & BMSR_ANEG0x0008) {
470 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst)((0x0000000000000100ULL) | (0ULL) | (0) | ((uint64_t)(sc->
mii_inst) << 56))
,
471 MII_NMEDIA10); /* intentionally invalid index */
472 }
473#undef ADD
474}
475
476void
477mii_phy_delete_media(struct mii_softc *sc)
478{
479 struct mii_data *mii = sc->mii_pdata;
480
481 ifmedia_delete_instance(&mii->mii_media, sc->mii_inst);
482}
483
484int
485mii_phy_detach(struct device *self, int flags)
486{
487 struct mii_softc *sc = (void *) self;
488
489 if (sc->mii_flags & MIIF_DOINGAUTO0x0008)
490 timeout_del(&sc->mii_phy_timo);
491
492 mii_phy_delete_media(sc);
493
494 return (0);
495}
496
497const struct mii_phydesc *
498mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd)
499{
500
501 for (; mpd->mpd_name != NULL((void *)0); mpd++) {
502 if (MII_OUI(ma->mii_id1, ma->mii_id2)(((ma->mii_id1) << 6) | ((ma->mii_id2) >> 10
))
== mpd->mpd_oui &&
503 MII_MODEL(ma->mii_id2)(((ma->mii_id2) & 0x03f0) >> 4) == mpd->mpd_model)
504 return (mpd);
505 }
506 return (NULL((void *)0));
507}
508
509/*
510 * Return the flow control status flag from MII_ANAR & MII_ANLPAR.
511 */
512uint64_t
513mii_phy_flowstatus(struct mii_softc *sc)
514{
515 int anar, anlpar;
516
517 if ((sc->mii_flags & MIIF_DOPAUSE0x0100) == 0)
518 return (0);
519
520 anar = PHY_READ(sc, MII_ANAR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x04))
;
521 anlpar = PHY_READ(sc, MII_ANLPAR)(*(sc)->mii_pdata->mii_readreg)((sc)->mii_dev.dv_parent
, (sc)->mii_phy, (0x05))
;
522
523 /* For 1000baseX, the bits are in a different location. */
524 if (sc->mii_flags & MIIF_IS_1000X0x0080) {
525 anar <<= 3;
526 anlpar <<= 3;
527 }
528
529 if ((anar & ANAR_PAUSE_SYM(1 << 10)) & (anlpar & ANLPAR_PAUSE_SYM(1 << 10)))
530 return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL);
531
532 if ((anar & ANAR_PAUSE_SYM(1 << 10)) == 0) {
533 if ((anar & ANAR_PAUSE_ASYM(2 << 10)) &&
534 ((anlpar & ANLPAR_PAUSE_TOWARDS(3 << 10)) == ANLPAR_PAUSE_TOWARDS(3 << 10)))
535 return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL);
536 else
537 return (0);
538 }
539
540 if ((anar & ANAR_PAUSE_ASYM(2 << 10)) == 0) {
541 if (anlpar & ANLPAR_PAUSE_SYM(1 << 10))
542 return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL);
543 else
544 return (0);
545 }
546
547 switch ((anlpar & ANLPAR_PAUSE_TOWARDS(3 << 10))) {
548 case ANLPAR_PAUSE_NONE(0 << 10):
549 return (0);
550
551 case ANLPAR_PAUSE_ASYM(2 << 10):
552 return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL);
553
554 default:
555 return (IFM_FLOW0x0000040000000000ULL|IFM_ETH_RXPAUSE0x0000000000020000ULL|IFM_ETH_TXPAUSE0x0000000000040000ULL);
556 }
557 /* NOTREACHED */
558}
559
560/*
561 * Given an ifmedia word, return the corresponding ANAR value.
562 */
563int
564mii_anar(uint64_t media)
565{
566 int rv;
567
568 switch (media & (IFM_TMASK0x00000000000000ffULL|IFM_NMASK0x000000000000ff00ULL|IFM_FDX0x0000010000000000ULL)) {
569 case IFM_ETHER0x0000000000000100ULL|IFM_10_T3:
570 rv = ANAR_100x0020|ANAR_CSMA0x0001;
571 break;
572 case IFM_ETHER0x0000000000000100ULL|IFM_10_T3|IFM_FDX0x0000010000000000ULL:
573 rv = ANAR_10_FD0x0040|ANAR_CSMA0x0001;
574 break;
575 case IFM_ETHER0x0000000000000100ULL|IFM_100_TX6:
576 rv = ANAR_TX0x0080|ANAR_CSMA0x0001;
577 break;
578 case IFM_ETHER0x0000000000000100ULL|IFM_100_TX6|IFM_FDX0x0000010000000000ULL:
579 rv = ANAR_TX_FD0x0100|ANAR_CSMA0x0001;
580 break;
581 case IFM_ETHER0x0000000000000100ULL|IFM_100_T48:
582 rv = ANAR_T40x0200|ANAR_CSMA0x0001;
583 break;
584 default:
585 rv = 0;
586 break;
587 }
588
589 return (rv);
590}