1493d26c5SEd Maste /*
2493d26c5SEd Maste * aQuantia Corporation Network Driver
3493d26c5SEd Maste * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4493d26c5SEd Maste *
5493d26c5SEd Maste * Redistribution and use in source and binary forms, with or without
6493d26c5SEd Maste * modification, are permitted provided that the following conditions
7493d26c5SEd Maste * are met:
8493d26c5SEd Maste *
9493d26c5SEd Maste * (1) Redistributions of source code must retain the above
10493d26c5SEd Maste * copyright notice, this list of conditions and the following
11493d26c5SEd Maste * disclaimer.
12493d26c5SEd Maste *
13493d26c5SEd Maste * (2) Redistributions in binary form must reproduce the above
14493d26c5SEd Maste * copyright notice, this list of conditions and the following
15493d26c5SEd Maste * disclaimer in the documentation and/or other materials provided
16493d26c5SEd Maste * with the distribution.
17493d26c5SEd Maste *
18493d26c5SEd Maste * (3)The name of the author may not be used to endorse or promote
19493d26c5SEd Maste * products derived from this software without specific prior
20493d26c5SEd Maste * written permission.
21493d26c5SEd Maste *
22493d26c5SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23493d26c5SEd Maste * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24493d26c5SEd Maste * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25493d26c5SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26493d26c5SEd Maste * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27493d26c5SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28493d26c5SEd Maste * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29493d26c5SEd Maste * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30493d26c5SEd Maste * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31493d26c5SEd Maste * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32493d26c5SEd Maste * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33493d26c5SEd Maste */
34493d26c5SEd Maste
35493d26c5SEd Maste #include <sys/cdefs.h>
36493d26c5SEd Maste __FBSDID("$FreeBSD$");
37493d26c5SEd Maste
38493d26c5SEd Maste #include <sys/param.h>
39493d26c5SEd Maste #include <sys/kernel.h>
40493d26c5SEd Maste #include <sys/socket.h>
41493d26c5SEd Maste #include <sys/bitstring.h>
42493d26c5SEd Maste #include <net/if.h>
43493d26c5SEd Maste #include <net/if_media.h>
44493d26c5SEd Maste #include <net/if_var.h>
45493d26c5SEd Maste #include <net/if_dl.h>
46493d26c5SEd Maste #include <net/ethernet.h>
47493d26c5SEd Maste #include <net/iflib.h>
48493d26c5SEd Maste
49493d26c5SEd Maste #include "aq_device.h"
50493d26c5SEd Maste
51493d26c5SEd Maste #include "aq_fw.h"
52493d26c5SEd Maste #include "aq_dbg.h"
53493d26c5SEd Maste
54493d26c5SEd Maste #define AQ_HW_SUPPORT_SPEED(softc, s) ((softc)->link_speeds & s)
55493d26c5SEd Maste
aq_mediastatus_update(aq_dev_t * aq_dev,u32 link_speed,const struct aq_hw_fc_info * fc_neg)56493d26c5SEd Maste void aq_mediastatus_update(aq_dev_t *aq_dev, u32 link_speed, const struct aq_hw_fc_info *fc_neg)
57493d26c5SEd Maste {
58493d26c5SEd Maste struct aq_hw *hw = &aq_dev->hw;
59493d26c5SEd Maste
60493d26c5SEd Maste aq_dev->media_active = 0;
61493d26c5SEd Maste if (fc_neg->fc_rx)
62493d26c5SEd Maste aq_dev->media_active |= IFM_ETH_RXPAUSE;
63493d26c5SEd Maste if (fc_neg->fc_tx)
64493d26c5SEd Maste aq_dev->media_active |= IFM_ETH_TXPAUSE;
65493d26c5SEd Maste
66493d26c5SEd Maste switch(link_speed) {
67493d26c5SEd Maste case 100:
68493d26c5SEd Maste aq_dev->media_active |= IFM_100_TX | IFM_FDX;
69493d26c5SEd Maste break;
70493d26c5SEd Maste
71493d26c5SEd Maste case 1000:
72493d26c5SEd Maste aq_dev->media_active |= IFM_1000_T | IFM_FDX;
73493d26c5SEd Maste break;
74493d26c5SEd Maste
75493d26c5SEd Maste case 2500:
76493d26c5SEd Maste aq_dev->media_active |= IFM_2500_T | IFM_FDX;
77493d26c5SEd Maste break;
78493d26c5SEd Maste
79493d26c5SEd Maste case 5000:
80493d26c5SEd Maste aq_dev->media_active |= IFM_5000_T | IFM_FDX;
81493d26c5SEd Maste break;
82493d26c5SEd Maste
83493d26c5SEd Maste case 10000:
84493d26c5SEd Maste aq_dev->media_active |= IFM_10G_T | IFM_FDX;
85493d26c5SEd Maste break;
86493d26c5SEd Maste
87493d26c5SEd Maste case 0:
88493d26c5SEd Maste default:
89493d26c5SEd Maste aq_dev->media_active |= IFM_NONE;
90493d26c5SEd Maste break;
91493d26c5SEd Maste }
92493d26c5SEd Maste
93493d26c5SEd Maste if (hw->link_rate == aq_fw_speed_auto)
94493d26c5SEd Maste aq_dev->media_active |= IFM_AUTO;
95493d26c5SEd Maste }
96493d26c5SEd Maste
aq_mediastatus(if_t ifp,struct ifmediareq * ifmr)97*4756f5ffSOlivier Cochard void aq_mediastatus(if_t ifp, struct ifmediareq *ifmr)
98493d26c5SEd Maste {
99*4756f5ffSOlivier Cochard aq_dev_t *aq_dev = iflib_get_softc(if_getsoftc(ifp));
100493d26c5SEd Maste
101493d26c5SEd Maste ifmr->ifm_active = IFM_ETHER;
102493d26c5SEd Maste ifmr->ifm_status = IFM_AVALID;
103493d26c5SEd Maste
104493d26c5SEd Maste if (aq_dev->linkup)
105493d26c5SEd Maste ifmr->ifm_status |= IFM_ACTIVE;
106493d26c5SEd Maste
107493d26c5SEd Maste ifmr->ifm_active |= aq_dev->media_active;
108493d26c5SEd Maste }
109493d26c5SEd Maste
aq_mediachange(if_t ifp)110*4756f5ffSOlivier Cochard int aq_mediachange(if_t ifp)
111493d26c5SEd Maste {
112*4756f5ffSOlivier Cochard aq_dev_t *aq_dev = iflib_get_softc(if_getsoftc(ifp));
113493d26c5SEd Maste struct aq_hw *hw = &aq_dev->hw;
114*4756f5ffSOlivier Cochard int old_media_rate = if_getbaudrate(ifp);
115493d26c5SEd Maste int old_link_speed = hw->link_rate;
116493d26c5SEd Maste struct ifmedia *ifm = iflib_get_media(aq_dev->ctx);
117493d26c5SEd Maste int user_media = IFM_SUBTYPE(ifm->ifm_media);
118493d26c5SEd Maste uint64_t media_rate;
119493d26c5SEd Maste
120493d26c5SEd Maste AQ_DBG_ENTERA("media 0x%x", user_media);
121493d26c5SEd Maste
122493d26c5SEd Maste if (!(ifm->ifm_media & IFM_ETHER)) {
123493d26c5SEd Maste device_printf(aq_dev->dev, "%s(): aq_dev interface - bad media: 0x%X", __FUNCTION__, ifm->ifm_media);
124493d26c5SEd Maste return (0); // should never happen
125493d26c5SEd Maste }
126493d26c5SEd Maste
127493d26c5SEd Maste switch (user_media) {
128493d26c5SEd Maste case IFM_AUTO: // auto-select media
129493d26c5SEd Maste hw->link_rate = aq_fw_speed_auto;
130493d26c5SEd Maste media_rate = -1;
131493d26c5SEd Maste break;
132493d26c5SEd Maste
133493d26c5SEd Maste case IFM_NONE: // disable media
134493d26c5SEd Maste media_rate = 0;
135493d26c5SEd Maste hw->link_rate = 0;
136493d26c5SEd Maste iflib_link_state_change(aq_dev->ctx, LINK_STATE_DOWN, 0);
137493d26c5SEd Maste break;
138493d26c5SEd Maste
139493d26c5SEd Maste case IFM_100_TX:
140493d26c5SEd Maste hw->link_rate = aq_fw_100M;
141493d26c5SEd Maste media_rate = 100 * 1000;
142493d26c5SEd Maste break;
143493d26c5SEd Maste
144493d26c5SEd Maste case IFM_1000_T:
145493d26c5SEd Maste hw->link_rate = aq_fw_1G;
146493d26c5SEd Maste media_rate = 1000 * 1000;
147493d26c5SEd Maste break;
148493d26c5SEd Maste
149493d26c5SEd Maste case IFM_2500_T:
150493d26c5SEd Maste hw->link_rate = aq_fw_2G5;
151493d26c5SEd Maste media_rate = 2500 * 1000;
152493d26c5SEd Maste break;
153493d26c5SEd Maste
154493d26c5SEd Maste case IFM_5000_T:
155493d26c5SEd Maste hw->link_rate = aq_fw_5G;
156493d26c5SEd Maste media_rate = 5000 * 1000;
157493d26c5SEd Maste break;
158493d26c5SEd Maste
159493d26c5SEd Maste case IFM_10G_T:
160493d26c5SEd Maste hw->link_rate = aq_fw_10G;
161493d26c5SEd Maste media_rate = 10000 * 1000;
162493d26c5SEd Maste break;
163493d26c5SEd Maste
164493d26c5SEd Maste default: // should never happen
165493d26c5SEd Maste aq_log_error("unknown media: 0x%X", user_media);
166493d26c5SEd Maste return (0);
167493d26c5SEd Maste }
168493d26c5SEd Maste hw->fc.fc_rx = (ifm->ifm_media & IFM_ETH_RXPAUSE) ? 1 : 0;
169493d26c5SEd Maste hw->fc.fc_tx = (ifm->ifm_media & IFM_ETH_TXPAUSE) ? 1 : 0;
170493d26c5SEd Maste
171493d26c5SEd Maste /* In down state just remember new link speed */
172*4756f5ffSOlivier Cochard if (!(if_getflags(ifp) & IFF_UP))
173493d26c5SEd Maste return (0);
174493d26c5SEd Maste
175493d26c5SEd Maste if ((media_rate != old_media_rate) || (hw->link_rate != old_link_speed)) {
176493d26c5SEd Maste // re-initialize hardware with new parameters
177493d26c5SEd Maste aq_hw_set_link_speed(hw, hw->link_rate);
178493d26c5SEd Maste }
179493d26c5SEd Maste
180493d26c5SEd Maste AQ_DBG_EXIT(0);
181493d26c5SEd Maste return (0);
182493d26c5SEd Maste }
183493d26c5SEd Maste
aq_add_media_types(aq_dev_t * aq_dev,int media_link_speed)184493d26c5SEd Maste static void aq_add_media_types(aq_dev_t *aq_dev, int media_link_speed)
185493d26c5SEd Maste {
186493d26c5SEd Maste ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX, 0, NULL);
187493d26c5SEd Maste ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
188493d26c5SEd Maste IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE, 0, NULL);
189493d26c5SEd Maste ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
190493d26c5SEd Maste IFM_ETH_RXPAUSE, 0, NULL);
191493d26c5SEd Maste ifmedia_add(aq_dev->media, IFM_ETHER | media_link_speed | IFM_FDX |
192493d26c5SEd Maste IFM_ETH_TXPAUSE, 0, NULL);
193493d26c5SEd Maste }
aq_initmedia(aq_dev_t * aq_dev)194493d26c5SEd Maste void aq_initmedia(aq_dev_t *aq_dev)
195493d26c5SEd Maste {
196493d26c5SEd Maste AQ_DBG_ENTER();
197493d26c5SEd Maste
198493d26c5SEd Maste // ifconfig eth0 none
199493d26c5SEd Maste ifmedia_add(aq_dev->media, IFM_ETHER | IFM_NONE, 0, NULL);
200493d26c5SEd Maste
201493d26c5SEd Maste // ifconfig eth0 auto
202493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_AUTO);
203493d26c5SEd Maste
204493d26c5SEd Maste if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_100M))
205493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_100_TX);
206493d26c5SEd Maste if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_1G))
207493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_1000_T);
208493d26c5SEd Maste if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_2G5))
209493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_2500_T);
210493d26c5SEd Maste if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_5G))
211493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_5000_T);
212493d26c5SEd Maste if (AQ_HW_SUPPORT_SPEED(aq_dev, AQ_LINK_10G))
213493d26c5SEd Maste aq_add_media_types(aq_dev, IFM_10G_T);
214493d26c5SEd Maste
215493d26c5SEd Maste // link is initially autoselect
216493d26c5SEd Maste ifmedia_set(aq_dev->media, IFM_ETHER | IFM_AUTO | IFM_FDX | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE);
217493d26c5SEd Maste
218493d26c5SEd Maste AQ_DBG_EXIT(0);
219493d26c5SEd Maste }
220