xref: /freebsd/sys/dev/aq/aq_media.c (revision 4756f5ff8f10cdda925cab60c0b66606698e49ee)
1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   (1) Redistributions of source code must retain the above
10  *   copyright notice, this list of conditions and the following
11  *   disclaimer.
12  *
13  *   (2) Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following
15  *   disclaimer in the documentation and/or other materials provided
16  *   with the distribution.
17  *
18  *   (3)The name of the author may not be used to endorse or promote
19  *   products derived from this software without specific prior
20  *   written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/bitstring.h>
42 #include <net/if.h>
43 #include <net/if_media.h>
44 #include <net/if_var.h>
45 #include <net/if_dl.h>
46 #include <net/ethernet.h>
47 #include <net/iflib.h>
48 
49 #include "aq_device.h"
50 
51 #include "aq_fw.h"
52 #include "aq_dbg.h"
53 
54 #define	AQ_HW_SUPPORT_SPEED(softc, s) ((softc)->link_speeds & s)
55 
aq_mediastatus_update(aq_dev_t * aq_dev,u32 link_speed,const struct aq_hw_fc_info * fc_neg)56 void aq_mediastatus_update(aq_dev_t *aq_dev, u32 link_speed, const struct aq_hw_fc_info *fc_neg)
57 {
58 	struct aq_hw *hw = &aq_dev->hw;
59 
60 	aq_dev->media_active = 0;
61 	if (fc_neg->fc_rx)
62 	    aq_dev->media_active |= IFM_ETH_RXPAUSE;
63 	if (fc_neg->fc_tx)
64 	    aq_dev->media_active |= IFM_ETH_TXPAUSE;
65 
66 	switch(link_speed) {
67 	case 100:
68 		aq_dev->media_active |= IFM_100_TX | IFM_FDX;
69 	break;
70 
71 	case 1000:
72 		aq_dev->media_active |= IFM_1000_T | IFM_FDX;
73 	break;
74 
75 	case 2500:
76 		aq_dev->media_active |= IFM_2500_T | IFM_FDX;
77 	break;
78 
79 	case 5000:
80 		aq_dev->media_active |= IFM_5000_T | IFM_FDX;
81 	break;
82 
83 	case 10000:
84 		aq_dev->media_active |= IFM_10G_T | IFM_FDX;
85 	break;
86 
87 	case 0:
88 	default:
89 		aq_dev->media_active |= IFM_NONE;
90 	break;
91 	}
92 
93 	if (hw->link_rate == aq_fw_speed_auto)
94 		aq_dev->media_active |= IFM_AUTO;
95 }
96 
aq_mediastatus(if_t ifp,struct ifmediareq * ifmr)97 void aq_mediastatus(if_t ifp, struct ifmediareq *ifmr)
98 {
99 	aq_dev_t *aq_dev = iflib_get_softc(if_getsoftc(ifp));
100 
101 	ifmr->ifm_active = IFM_ETHER;
102 	ifmr->ifm_status = IFM_AVALID;
103 
104 	if (aq_dev->linkup)
105 		ifmr->ifm_status |= IFM_ACTIVE;
106 
107 	ifmr->ifm_active |= aq_dev->media_active;
108 }
109 
aq_mediachange(if_t ifp)110 int aq_mediachange(if_t ifp)
111 {
112 	aq_dev_t          *aq_dev = iflib_get_softc(if_getsoftc(ifp));
113 	struct aq_hw      *hw = &aq_dev->hw;
114 	int                old_media_rate = if_getbaudrate(ifp);
115 	int                old_link_speed = hw->link_rate;
116 	struct ifmedia    *ifm = iflib_get_media(aq_dev->ctx);
117 	int                user_media = IFM_SUBTYPE(ifm->ifm_media);
118 	uint64_t           media_rate;
119 
120 	AQ_DBG_ENTERA("media 0x%x", user_media);
121 
122 	if (!(ifm->ifm_media & IFM_ETHER)) {
123 		device_printf(aq_dev->dev, "%s(): aq_dev interface - bad media: 0x%X", __FUNCTION__, ifm->ifm_media);
124 		return (0);    // should never happen
125 	}
126 
127 	switch (user_media) {
128 	case IFM_AUTO: // auto-select media
129 		hw->link_rate = aq_fw_speed_auto;
130 		media_rate = -1;
131 	break;
132 
133 	case IFM_NONE: // disable media
134 		media_rate = 0;
135 		hw->link_rate = 0;
136 		iflib_link_state_change(aq_dev->ctx, LINK_STATE_DOWN,  0);
137 	break;
138 
139 	case IFM_100_TX:
140 		hw->link_rate = aq_fw_100M;
141 		media_rate = 100 * 1000;
142 	break;
143 
144 	case IFM_1000_T:
145 		hw->link_rate = aq_fw_1G;
146 		media_rate = 1000 * 1000;
147 	break;
148 
149 	case IFM_2500_T:
150 		hw->link_rate = aq_fw_2G5;
151 		media_rate = 2500 * 1000;
152 	break;
153 
154 	case IFM_5000_T:
155 		hw->link_rate = aq_fw_5G;
156 		media_rate = 5000 * 1000;
157 	break;
158 
159 	case IFM_10G_T:
160 		hw->link_rate = aq_fw_10G;
161 		media_rate = 10000 * 1000;
162 	break;
163 
164 	default:            // should never happen
165 		aq_log_error("unknown media: 0x%X", user_media);
166 		return (0);
167 	}
168 	hw->fc.fc_rx = (ifm->ifm_media & IFM_ETH_RXPAUSE) ? 1 : 0;
169 	hw->fc.fc_tx = (ifm->ifm_media & IFM_ETH_TXPAUSE) ? 1 : 0;
170 
171 	/* In down state just remember new link speed */
172 	if (!(if_getflags(ifp) & IFF_UP))
173 		return (0);
174 
175 	if ((media_rate != old_media_rate) || (hw->link_rate != old_link_speed)) {
176 		// re-initialize hardware with new parameters
177 		aq_hw_set_link_speed(hw, hw->link_rate);
178 	}
179 
180 	AQ_DBG_EXIT(0);
181 	return (0);
182 }
183 
aq_add_media_types(aq_dev_t * aq_dev,int media_link_speed)184 static void aq_add_media_types(aq_dev_t *aq_dev, int media_link_speed)
185 {
186 	ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX, 0, NULL);
187 	ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
188 		IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE, 0, NULL);
189 	ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
190 		IFM_ETH_RXPAUSE, 0, NULL);
191 	ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
192 		IFM_ETH_TXPAUSE, 0, NULL);
193 }
aq_initmedia(aq_dev_t * aq_dev)194 void aq_initmedia(aq_dev_t *aq_dev)
195 {
196 	AQ_DBG_ENTER();
197 
198 	// ifconfig eth0 none
199 	ifmedia_add(aq_dev->media, IFM_ETHER | IFM_NONE, 0, NULL);
200 
201 	// ifconfig eth0 auto
202 	aq_add_media_types(aq_dev, IFM_AUTO);
203 
204 	if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_100M))
205 		aq_add_media_types(aq_dev, IFM_100_TX);
206 	if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_1G))
207 		aq_add_media_types(aq_dev, IFM_1000_T);
208 	if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_2G5))
209 		aq_add_media_types(aq_dev, IFM_2500_T);
210 	if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_5G))
211 		aq_add_media_types(aq_dev, IFM_5000_T);
212 	if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_10G))
213 		aq_add_media_types(aq_dev, IFM_10G_T);
214 
215 	// link is initially autoselect
216 	ifmedia_set(aq_dev->media, IFM_ETHER | IFM_AUTO | IFM_FDX | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE);
217 
218 	AQ_DBG_EXIT(0);
219 }
220