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/bitstring.h>
40 #include <sys/kernel.h>
41 #include <sys/socket.h>
42 #include <net/ethernet.h>
43 #include <net/if.h>
44 #include <net/if_media.h>
45 #include <net/if_var.h>
46 #include <net/if_dl.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
56 void
aq_mediastatus_update(aq_dev_t * aq_dev,uint32_t link_speed,const struct aq_hw_fc_info * fc_neg)57 aq_mediastatus_update(aq_dev_t *aq_dev, uint32_t link_speed,
58 const struct aq_hw_fc_info *fc_neg)
59 {
60 struct aq_hw *hw = &aq_dev->hw;
61
62 aq_dev->media_active = 0;
63 if (fc_neg->fc_rx)
64 aq_dev->media_active |= IFM_ETH_RXPAUSE;
65 if (fc_neg->fc_tx)
66 aq_dev->media_active |= IFM_ETH_TXPAUSE;
67
68 switch(link_speed) {
69 case 100:
70 aq_dev->media_active |= IFM_100_TX | IFM_FDX;
71 break;
72 case 1000:
73 aq_dev->media_active |= IFM_1000_T | IFM_FDX;
74 break;
75 case 2500:
76 aq_dev->media_active |= IFM_2500_T | IFM_FDX;
77 break;
78 case 5000:
79 aq_dev->media_active |= IFM_5000_T | IFM_FDX;
80 break;
81 case 10000:
82 aq_dev->media_active |= IFM_10G_T | IFM_FDX;
83 break;
84 case 0:
85 default:
86 aq_dev->media_active |= IFM_NONE;
87 break;
88 }
89
90 if (hw->link_rate == aq_fw_speed_auto)
91 aq_dev->media_active |= IFM_AUTO;
92 }
93
94 void
aq_mediastatus(if_t ifp,struct ifmediareq * ifmr)95 aq_mediastatus(if_t ifp, struct ifmediareq *ifmr)
96 {
97 aq_dev_t *aq_dev = iflib_get_softc(if_getsoftc(ifp));
98
99 ifmr->ifm_active = IFM_ETHER;
100 ifmr->ifm_status = IFM_AVALID;
101
102 if (aq_dev->linkup)
103 ifmr->ifm_status |= IFM_ACTIVE;
104
105 ifmr->ifm_active |= aq_dev->media_active;
106 }
107
108 int
aq_mediachange(if_t ifp)109 aq_mediachange(if_t ifp)
110 {
111 aq_dev_t *aq_dev = iflib_get_softc(if_getsoftc(ifp));
112 struct aq_hw *hw = &aq_dev->hw;
113 int old_media_rate = if_getbaudrate(ifp);
114 int old_link_speed = hw->link_rate;
115 struct ifmedia *ifm = iflib_get_media(aq_dev->ctx);
116 int user_media = IFM_SUBTYPE(ifm->ifm_media);
117 uint64_t media_rate;
118
119 AQ_DBG_ENTERA("media 0x%x", user_media);
120
121 if (!(ifm->ifm_media & IFM_ETHER)) {
122 device_printf(aq_dev->dev,
123 "%s(): aq_dev interface - bad media: 0x%X", __FUNCTION__,
124 ifm->ifm_media);
125 return (0); // should never happen
126 }
127
128 switch (user_media) {
129 case IFM_AUTO: // auto-select media
130 hw->link_rate = aq_fw_speed_auto;
131 media_rate = -1;
132 break;
133
134 case IFM_NONE: // disable media
135 media_rate = 0;
136 hw->link_rate = 0;
137 iflib_link_state_change(aq_dev->ctx, LINK_STATE_DOWN, 0);
138 break;
139
140 case IFM_100_TX:
141 hw->link_rate = aq_fw_100M;
142 media_rate = 100 * 1000;
143 break;
144
145 case IFM_1000_T:
146 hw->link_rate = aq_fw_1G;
147 media_rate = 1000 * 1000;
148 break;
149
150 case IFM_2500_T:
151 hw->link_rate = aq_fw_2G5;
152 media_rate = 2500 * 1000;
153 break;
154
155 case IFM_5000_T:
156 hw->link_rate = aq_fw_5G;
157 media_rate = 5000 * 1000;
158 break;
159
160 case IFM_10G_T:
161 hw->link_rate = aq_fw_10G;
162 media_rate = 10000 * 1000;
163 break;
164
165 default: // should never happen
166 aq_log_error("unknown media: 0x%X", user_media);
167 return (0);
168 }
169 hw->fc.fc_rx = (ifm->ifm_media & IFM_ETH_RXPAUSE) ? 1 : 0;
170 hw->fc.fc_tx = (ifm->ifm_media & IFM_ETH_TXPAUSE) ? 1 : 0;
171
172 /* In down state just remember new link speed */
173 if (!(if_getflags(ifp) & IFF_UP))
174 return (0);
175
176 if ((media_rate != old_media_rate) ||
177 (hw->link_rate != old_link_speed)) {
178 // re-initialize hardware with new parameters
179 aq_hw_set_link_speed(hw, hw->link_rate);
180 }
181
182 AQ_DBG_EXIT(0);
183 return (0);
184 }
185
186 static void
aq_add_media_types(aq_dev_t * aq_dev,int media_link_speed)187 aq_add_media_types(aq_dev_t *aq_dev, int media_link_speed)
188 {
189 ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX, 0,
190 NULL);
191 ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
192 IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE, 0, NULL);
193 ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
194 IFM_ETH_RXPAUSE, 0, NULL);
195 ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
196 IFM_ETH_TXPAUSE, 0, NULL);
197 }
198 void
aq_initmedia(aq_dev_t * aq_dev)199 aq_initmedia(aq_dev_t *aq_dev)
200 {
201 AQ_DBG_ENTER();
202
203 // ifconfig eth0 none
204 ifmedia_add(aq_dev->media, IFM_ETHER | IFM_NONE, 0, NULL);
205
206 // ifconfig eth0 auto
207 aq_add_media_types(aq_dev, IFM_AUTO);
208
209 if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_100M))
210 aq_add_media_types(aq_dev, IFM_100_TX);
211 if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_1G))
212 aq_add_media_types(aq_dev, IFM_1000_T);
213 if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_2G5))
214 aq_add_media_types(aq_dev, IFM_2500_T);
215 if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_5G))
216 aq_add_media_types(aq_dev, IFM_5000_T);
217 if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_10G))
218 aq_add_media_types(aq_dev, IFM_10G_T);
219
220 // link is initially autoselect
221 ifmedia_set(aq_dev->media,
222 IFM_ETHER | IFM_AUTO | IFM_FDX | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE);
223
224 AQ_DBG_EXIT(0);
225 }
226