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