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