Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/axgbe/if_axgbe.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2016,2017 SoftIron Inc. | * Copyright (c) 2016,2017 SoftIron Inc. | ||||
* All rights reserved. | * Copyright (c) 2020 Advanced Micro Devices, Inc. | ||||
* | * | ||||
* This software was developed by Andrew Turner under | * This software was developed by Andrew Turner under | ||||
* the sponsorship of SoftIron Inc. | * the sponsorship of SoftIron Inc. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | static struct resource_spec mac_spec[] = { | ||||
{ SYS_RES_IRQ, 1, RF_ACTIVE }, | { SYS_RES_IRQ, 1, RF_ACTIVE }, | ||||
{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, | { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, | ||||
{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, | { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, | ||||
{ SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, | { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, | ||||
{ SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, | { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, | ||||
{ -1, 0 } | { -1, 0 } | ||||
}; | }; | ||||
static struct xgbe_version_data xgbe_v1 = { | |||||
.init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v1, | |||||
.xpcs_access = XGBE_XPCS_ACCESS_V1, | |||||
.tx_max_fifo_size = 81920, | |||||
.rx_max_fifo_size = 81920, | |||||
.tx_tstamp_workaround = 1, | |||||
}; | |||||
MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); | MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); | ||||
static void | static void | ||||
axgbe_init(void *p) | axgbe_init(void *p) | ||||
{ | { | ||||
struct axgbe_softc *sc; | struct axgbe_softc *sc; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
sc = p; | sc = p; | ||||
ifp = sc->prv.netdev; | ifp = sc->prv.netdev; | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
return; | return; | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
} | } | ||||
static int | static int | ||||
axgbe_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) | axgbe_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) | ||||
{ | { | ||||
struct axgbe_softc *sc = ifp->if_softc; | struct axgbe_softc *sc = ifp->if_softc; | ||||
struct ifreq *ifr = (struct ifreq *)data; | struct ifreq *ifr = (struct ifreq *)data; | ||||
int error; | int error = 0; | ||||
switch(command) { | switch(command) { | ||||
case SIOCSIFMTU: | case SIOCSIFMTU: | ||||
if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO) | if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO) | ||||
error = EINVAL; | error = EINVAL; | ||||
else | /* TODO - change it to iflib way */ | ||||
error = xgbe_change_mtu(ifp, ifr->ifr_mtu); | |||||
break; | break; | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
error = 0; | error = 0; | ||||
break; | break; | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
error = ifmedia_ioctl(ifp, ifr, &sc->media, command); | error = ifmedia_ioctl(ifp, ifr, &sc->media, command); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | axgbe_attach(device_t dev) | ||||
phandle_t node, phy_node; | phandle_t node, phy_node; | ||||
struct resource *mac_res[11]; | struct resource *mac_res[11]; | ||||
struct resource *phy_res[4]; | struct resource *phy_res[4]; | ||||
ssize_t len; | ssize_t len; | ||||
int error, i, j; | int error, i, j; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->prv.vdata = &xgbe_v1; | |||||
node = ofw_bus_get_node(dev); | node = ofw_bus_get_node(dev); | ||||
if (OF_getencprop(node, "phy-handle", &phy_handle, | if (OF_getencprop(node, "phy-handle", &phy_handle, | ||||
sizeof(phy_handle)) <= 0) { | sizeof(phy_handle)) <= 0) { | ||||
phy_node = node; | phy_node = node; | ||||
if (bus_alloc_resources(dev, mac_spec, mac_res)) { | if (bus_alloc_resources(dev, mac_spec, mac_res)) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"could not allocate phy resources\n"); | "could not allocate phy resources\n"); | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | if (ifp == NULL) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
sc->prv.dev = dev; | sc->prv.dev = dev; | ||||
sc->prv.dmat = bus_get_dma_tag(dev); | sc->prv.dmat = bus_get_dma_tag(dev); | ||||
sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full | | sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full | | ||||
ADVERTISED_1000baseKX_Full; | ADVERTISED_1000baseKX_Full; | ||||
/* | /* | ||||
* Read the needed properties from the phy node. | * Read the needed properties from the phy node. | ||||
*/ | */ | ||||
/* This is documented as optional, but Linux requires it */ | /* This is documented as optional, but Linux requires it */ | ||||
if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, | if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, | ||||
sizeof(sc->prv.speed_set)) <= 0) { | sizeof(sc->prv.speed_set)) <= 0) { | ||||
device_printf(dev, "%s property is missing\n", | device_printf(dev, "%s property is missing\n", | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (error > 0) { | ||||
sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; | sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; | ||||
sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; | sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; | ||||
sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; | sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; | ||||
} | } | ||||
/* Check if the NIC is DMA coherent */ | /* Check if the NIC is DMA coherent */ | ||||
sc->prv.coherent = OF_hasprop(node, "dma-coherent"); | sc->prv.coherent = OF_hasprop(node, "dma-coherent"); | ||||
if (sc->prv.coherent) { | if (sc->prv.coherent) { | ||||
sc->prv.axdomain = XGBE_DMA_OS_AXDOMAIN; | sc->prv.arcr = XGBE_DMA_OS_ARCR; | ||||
sc->prv.arcache = XGBE_DMA_OS_ARCACHE; | sc->prv.awcr = XGBE_DMA_OS_AWCR; | ||||
sc->prv.awcache = XGBE_DMA_OS_AWCACHE; | |||||
} else { | } else { | ||||
sc->prv.axdomain = XGBE_DMA_SYS_AXDOMAIN; | sc->prv.arcr = XGBE_DMA_SYS_ARCR; | ||||
sc->prv.arcache = XGBE_DMA_SYS_ARCACHE; | sc->prv.awcr = XGBE_DMA_SYS_AWCR; | ||||
sc->prv.awcache = XGBE_DMA_SYS_AWCACHE; | |||||
} | } | ||||
/* Create the lock & workqueues */ | /* Create the lock & workqueues */ | ||||
spin_lock_init(&sc->prv.xpcs_lock); | spin_lock_init(&sc->prv.xpcs_lock); | ||||
sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK, | sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK, | ||||
taskqueue_thread_enqueue, &sc->prv.dev_workqueue); | taskqueue_thread_enqueue, &sc->prv.dev_workqueue); | ||||
taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET, | taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET, | ||||
"axgbe taskq"); | "axgbe taskq"); | ||||
/* Set the needed pointers */ | /* Set the needed pointers */ | ||||
xgbe_init_function_ptrs_phy(&sc->prv.phy_if); | xgbe_init_function_ptrs_phy(&sc->prv.phy_if); | ||||
xgbe_init_function_ptrs_dev(&sc->prv.hw_if); | xgbe_init_function_ptrs_dev(&sc->prv.hw_if); | ||||
xgbe_init_function_ptrs_desc(&sc->prv.desc_if); | xgbe_init_function_ptrs_desc(&sc->prv.desc_if); | ||||
sc->prv.vdata->init_function_ptrs_phy_impl(&sc->prv.phy_if); | |||||
/* Reset the hardware */ | /* Reset the hardware */ | ||||
sc->prv.hw_if.exit(&sc->prv); | sc->prv.hw_if.exit(&sc->prv); | ||||
/* Read the hardware features */ | /* Read the hardware features */ | ||||
xgbe_get_all_hw_features(&sc->prv); | xgbe_get_all_hw_features(&sc->prv); | ||||
/* Set default values */ | /* Set default values */ | ||||
sc->prv.pblx8 = DMA_PBL_X8_ENABLE; | |||||
sc->prv.tx_desc_count = XGBE_TX_DESC_CNT; | sc->prv.tx_desc_count = XGBE_TX_DESC_CNT; | ||||
sc->prv.tx_sf_mode = MTL_TSF_ENABLE; | sc->prv.tx_sf_mode = MTL_TSF_ENABLE; | ||||
sc->prv.tx_threshold = MTL_TX_THRESHOLD_64; | sc->prv.tx_threshold = MTL_TX_THRESHOLD_64; | ||||
sc->prv.tx_pbl = DMA_PBL_16; | |||||
sc->prv.tx_osp_mode = DMA_OSP_ENABLE; | sc->prv.tx_osp_mode = DMA_OSP_ENABLE; | ||||
sc->prv.rx_desc_count = XGBE_RX_DESC_CNT; | sc->prv.rx_desc_count = XGBE_RX_DESC_CNT; | ||||
sc->prv.rx_sf_mode = MTL_RSF_DISABLE; | sc->prv.rx_sf_mode = MTL_RSF_DISABLE; | ||||
sc->prv.rx_threshold = MTL_RX_THRESHOLD_64; | sc->prv.rx_threshold = MTL_RX_THRESHOLD_64; | ||||
sc->prv.rx_pbl = DMA_PBL_16; | sc->prv.pbl = DMA_PBL_128; | ||||
sc->prv.pause_autoneg = 1; | sc->prv.pause_autoneg = 1; | ||||
sc->prv.tx_pause = 1; | sc->prv.tx_pause = 1; | ||||
sc->prv.rx_pause = 1; | sc->prv.rx_pause = 1; | ||||
sc->prv.phy_speed = SPEED_UNKNOWN; | sc->prv.phy_speed = SPEED_UNKNOWN; | ||||
sc->prv.power_down = 0; | sc->prv.power_down = 0; | ||||
/* TODO: Limit to min(ncpus, hw rings) */ | /* TODO: Limit to min(ncpus, hw rings) */ | ||||
sc->prv.tx_ring_count = 1; | sc->prv.tx_ring_count = 1; | ||||
sc->prv.tx_q_count = 1; | sc->prv.tx_q_count = 1; | ||||
sc->prv.rx_ring_count = 1; | sc->prv.rx_ring_count = 1; | ||||
sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt; | sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt; | ||||
/* Init the PHY */ | /* Init the PHY */ | ||||
sc->prv.phy_if.phy_init(&sc->prv); | sc->prv.phy_if.phy_init(&sc->prv); | ||||
/* Set the coalescing */ | /* Set the coalescing */ | ||||
xgbe_init_rx_coalesce(&sc->prv); | xgbe_init_rx_coalesce(&sc->prv); | ||||
xgbe_init_tx_coalesce(&sc->prv); | xgbe_init_tx_coalesce(&sc->prv); | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_init = axgbe_init; | ifp->if_init = axgbe_init; | ||||
ifp->if_softc = sc; | ifp->if_softc = sc; | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ||||
ifp->if_ioctl = axgbe_ioctl; | ifp->if_ioctl = axgbe_ioctl; | ||||
ifp->if_transmit = xgbe_xmit; | /* TODO - change it to iflib way */ | ||||
ifp->if_qflush = axgbe_qflush; | ifp->if_qflush = axgbe_qflush; | ||||
ifp->if_get_counter = axgbe_get_counter; | ifp->if_get_counter = axgbe_get_counter; | ||||
/* TODO: Support HW offload */ | /* TODO: Support HW offload */ | ||||
ifp->if_capabilities = 0; | ifp->if_capabilities = 0; | ||||
ifp->if_capenable = 0; | ifp->if_capenable = 0; | ||||
ifp->if_hwassist = 0; | ifp->if_hwassist = 0; | ||||
ether_ifattach(ifp, sc->mac_addr); | ether_ifattach(ifp, sc->mac_addr); | ||||
ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change, | ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change, | ||||
axgbe_media_status); | axgbe_media_status); | ||||
#ifdef notyet | #ifdef notyet | ||||
ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ||||
#endif | #endif | ||||
ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL); | ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL); | ||||
ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ||||
ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); | ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); | ||||
set_bit(XGBE_DOWN, &sc->prv.dev_state); | set_bit(XGBE_DOWN, &sc->prv.dev_state); | ||||
if (xgbe_open(ifp) < 0) { | /* TODO - change it to iflib way */ | ||||
device_printf(dev, "ndo_open failed\n"); | |||||
return (ENXIO); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static device_method_t axgbe_methods[] = { | static device_method_t axgbe_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, axgbe_probe), | DEVMETHOD(device_probe, axgbe_probe), | ||||
DEVMETHOD(device_attach, axgbe_attach), | DEVMETHOD(device_attach, axgbe_attach), | ||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
static devclass_t axgbe_devclass; | static devclass_t axgbe_devclass; | ||||
DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods, | DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods, | ||||
sizeof(struct axgbe_softc)); | sizeof(struct axgbe_softc)); | ||||
DRIVER_MODULE(axgbe, simplebus, axgbe_driver, axgbe_devclass, 0, 0); | DRIVER_MODULE(axa, simplebus, axgbe_driver, axgbe_devclass, 0, 0); | ||||
static struct ofw_compat_data phy_compat_data[] = { | static struct ofw_compat_data phy_compat_data[] = { | ||||
{ "amd,xgbe-phy-seattle-v1a", true }, | { "amd,xgbe-phy-seattle-v1a", true }, | ||||
{ NULL, false } | { NULL, false } | ||||
}; | }; | ||||
static int | static int | ||||
axgbephy_probe(device_t dev) | axgbephy_probe(device_t dev) | ||||
{ | { | ||||
Show All 18 Lines | axgbephy_attach(device_t dev) | ||||
return (0); | return (0); | ||||
} | } | ||||
static device_method_t axgbephy_methods[] = { | static device_method_t axgbephy_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, axgbephy_probe), | DEVMETHOD(device_probe, axgbephy_probe), | ||||
DEVMETHOD(device_attach, axgbephy_attach), | DEVMETHOD(device_attach, axgbephy_attach), | ||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
static devclass_t axgbephy_devclass; | static devclass_t axgbephy_devclass; | ||||
DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0); | DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0); | ||||
EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass, | EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass, | ||||
0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); | 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); |