From 9999e48639b3cecb08ffb37358bcba3b48161b29 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 08:50:17 +0000 Subject: [PATCH] add ax88772_rst --- kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_uio.c | 432 +++++++++++++++++++----------------------------------- 1 files changed, 152 insertions(+), 280 deletions(-) diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_uio.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_uio.c index b241bd9..11ec4b7 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_uio.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_uio.c @@ -16,7 +16,6 @@ #include <linux/interrupt.h> #include <linux/ip.h> #include <linux/tcp.h> -#include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/if_ether.h> #include <linux/crc32.h> @@ -45,14 +44,14 @@ #define DRIVER_NAME "rockchip_gmac_uio_drv" #define DRIVER_VERSION "0.1" -#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16) #define TC_DEFAULT 64 -#define DEFAULT_BUFSIZE 1536 -#define STMMAC_RX_COPYBREAK 256 - -static int buf_sz = DEFAULT_BUFSIZE; static int tc = TC_DEFAULT; + +#define DEFAULT_BUFSIZE 1536 +static int buf_sz = DEFAULT_BUFSIZE; + +#define STMMAC_RX_COPYBREAK 256 /** * rockchip_gmac_uio_pdev_info @@ -120,11 +119,11 @@ /* Free DMA regions of consistent memory previously allocated */ if (!priv->extend_desc) - dma_free_coherent(priv->device, - DMA_RX_SIZE * sizeof(struct dma_desc), + dma_free_coherent(priv->device, priv->dma_rx_size * + sizeof(struct dma_desc), rx_q->dma_rx, rx_q->dma_rx_phy); else - dma_free_coherent(priv->device, DMA_RX_SIZE * + dma_free_coherent(priv->device, priv->dma_rx_size * sizeof(struct dma_extended_desc), rx_q->dma_erx, rx_q->dma_rx_phy); } @@ -142,16 +141,23 @@ /* Free TX queue resources */ for (queue = 0; queue < tx_count; queue++) { struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; + size_t size; + void *addr; - /* Free DMA regions of consistent memory previously allocated */ - if (!priv->extend_desc) - dma_free_coherent(priv->device, - DMA_TX_SIZE * sizeof(struct dma_desc), - tx_q->dma_tx, tx_q->dma_tx_phy); - else - dma_free_coherent(priv->device, DMA_TX_SIZE * - sizeof(struct dma_extended_desc), - tx_q->dma_etx, tx_q->dma_tx_phy); + if (priv->extend_desc) { + size = sizeof(struct dma_extended_desc); + addr = tx_q->dma_etx; + } else if (tx_q->tbs & STMMAC_TBS_AVAIL) { + size = sizeof(struct dma_edesc); + addr = tx_q->dma_entx; + } else { + size = sizeof(struct dma_desc); + addr = tx_q->dma_tx; + } + + size *= priv->dma_tx_size; + + dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); } } @@ -173,26 +179,20 @@ for (queue = 0; queue < rx_count; queue++) { struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; - rx_q->queue_index = queue; - rx_q->priv_data = priv; - if (priv->extend_desc) { - rx_q->dma_erx = dma_zalloc_coherent(priv->device, - DMA_RX_SIZE * - sizeof(struct - dma_extended_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); - if (!rx_q->dma_erx) - goto err_dma; - - } else { - rx_q->dma_rx = dma_zalloc_coherent(priv->device, - DMA_RX_SIZE * - sizeof(struct - dma_desc), + rx_q->dma_erx = dma_alloc_coherent(priv->device, + priv->dma_rx_size * + sizeof(struct dma_extended_desc), &rx_q->dma_rx_phy, GFP_KERNEL); + if (!rx_q->dma_erx) + goto err_dma; + } else { + rx_q->dma_rx = dma_alloc_coherent(priv->device, + priv->dma_rx_size * + sizeof(struct dma_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); if (!rx_q->dma_rx) goto err_dma; } @@ -223,36 +223,38 @@ /* TX queues buffers and DMA */ for (queue = 0; queue < tx_count; queue++) { struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; + size_t size; + void *addr; tx_q->queue_index = queue; tx_q->priv_data = priv; - if (priv->extend_desc) { - tx_q->dma_etx = dma_zalloc_coherent(priv->device, - DMA_TX_SIZE * - sizeof(struct - dma_extended_desc), - &tx_q->dma_tx_phy, - GFP_KERNEL); - if (!tx_q->dma_etx) - goto err_dma; - } else { - tx_q->dma_tx = dma_zalloc_coherent(priv->device, - DMA_TX_SIZE * - sizeof(struct - dma_desc), - &tx_q->dma_tx_phy, - GFP_KERNEL); - if (!tx_q->dma_tx) - goto err_dma; - } + if (priv->extend_desc) + size = sizeof(struct dma_extended_desc); + else if (tx_q->tbs & STMMAC_TBS_AVAIL) + size = sizeof(struct dma_edesc); + else + size = sizeof(struct dma_desc); + + size *= priv->dma_tx_size; + + addr = dma_alloc_coherent(priv->device, size, + &tx_q->dma_tx_phy, GFP_KERNEL); + if (!addr) + goto err_dma; + + if (priv->extend_desc) + tx_q->dma_etx = addr; + else if (tx_q->tbs & STMMAC_TBS_AVAIL) + tx_q->dma_entx = addr; + else + tx_q->dma_tx = addr; } return 0; err_dma: uio_free_dma_tx_desc_resources(priv); - return ret; } @@ -291,121 +293,6 @@ } /** - * uio_hw_fix_mac_speed - callback for speed selection - * @priv: driver private structure - * Description: on some platforms (e.g. ST), some HW system configuration - * registers have to be set according to the link speed negotiated. - */ -static inline void uio_hw_fix_mac_speed(struct stmmac_priv *priv) -{ - struct net_device *ndev = priv->dev; - struct phy_device *phydev = ndev->phydev; - - if (likely(priv->plat->fix_mac_speed)) - priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed); -} - -/** - * uio_mac_flow_ctrl - Configure flow control in all queues - * @priv: driver private structure - * Description: It is used for configuring the flow control in all queues - */ -static void uio_mac_flow_ctrl(struct stmmac_priv *priv, u32 duplex) -{ - u32 tx_cnt = priv->plat->tx_queues_to_use; - - stmmac_flow_ctrl(priv, priv->hw, duplex, priv->flow_ctrl, - priv->pause, tx_cnt); -} - -/** - * uio_adjust_link - adjusts the link parameters - * @dev: net device structure - * Description: this is the helper called by the physical abstraction layer - * drivers to communicate the phy link status. According the speed and duplex - * this driver can invoke registered glue-logic as well. - * It also invoke the eee initialization because it could happen when switch - * on different networks (that are eee capable). - */ -static void uio_adjust_link(struct net_device *dev) -{ - struct stmmac_priv *priv = netdev_priv(dev); - struct phy_device *phydev = dev->phydev; - bool new_state = false; - - if (!phydev) - return; - - mutex_lock(&priv->lock); - - if (phydev->link) { - u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); - - /* Now we make sure that we can be in full duplex mode. - * If not, we operate in half-duplex mode. - */ - if (phydev->duplex != priv->oldduplex) { - new_state = true; - if (!phydev->duplex) - ctrl &= ~priv->hw->link.duplex; - else - ctrl |= priv->hw->link.duplex; - priv->oldduplex = phydev->duplex; - } - /* Flow Control operation */ - if (phydev->pause) - uio_mac_flow_ctrl(priv, phydev->duplex); - - if (phydev->speed != priv->speed) { - new_state = true; - ctrl &= ~priv->hw->link.speed_mask; - switch (phydev->speed) { - case SPEED_1000: - ctrl |= priv->hw->link.speed1000; - break; - case SPEED_100: - ctrl |= priv->hw->link.speed100; - break; - case SPEED_10: - ctrl |= priv->hw->link.speed10; - break; - default: - netif_warn(priv, link, priv->dev, - "broken speed: %d\n", phydev->speed); - phydev->speed = SPEED_UNKNOWN; - break; - } - if (phydev->speed != SPEED_UNKNOWN) - uio_hw_fix_mac_speed(priv); - priv->speed = phydev->speed; - } - - writel(ctrl, priv->ioaddr + MAC_CTRL_REG); - - if (!priv->oldlink) { - new_state = true; - priv->oldlink = true; - } - } else if (priv->oldlink) { - new_state = true; - priv->oldlink = false; - priv->speed = SPEED_UNKNOWN; - priv->oldduplex = DUPLEX_UNKNOWN; - } - - if (new_state && netif_msg_link(priv)) - phy_print_status(phydev); - - mutex_unlock(&priv->lock); - - if (phydev->is_pseudo_fixed_link) - /* Stop PHY layer to call the hook to adjust the link in case - * of a switch is attached to the stmmac driver. - */ - phydev->irq = PHY_IGNORE_INTERRUPT; -} - -/** * rockchip_gmac_uio_init_phy - PHY initialization * @dev: net device structure * Description: it initializes the driver's PHY state, and attaches the PHY @@ -416,82 +303,38 @@ static int rockchip_gmac_uio_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); - u32 tx_cnt = priv->plat->tx_queues_to_use; - struct phy_device *phydev; - char phy_id_fmt[MII_BUS_ID_SIZE + 3]; - char bus_id[MII_BUS_ID_SIZE]; - int interface = priv->plat->interface; - int max_speed = priv->plat->max_speed; + struct device_node *node; + int ret; - priv->oldlink = false; - priv->speed = SPEED_UNKNOWN; - priv->oldduplex = DUPLEX_UNKNOWN; + node = priv->plat->phylink_node; - if (priv->plat->integrated_phy_power) - priv->plat->integrated_phy_power(priv->plat->bsp_priv, true); + if (node) + ret = phylink_of_phy_connect(priv->phylink, node, 0); - if (priv->mii) - stmmac_mdio_reset(priv->mii); + /* Some DT bindings do not set-up the PHY handle. Let's try to + * manually parse it + */ + if (!node || ret) { + int addr = priv->plat->phy_addr; + struct phy_device *phydev; - if (priv->plat->phy_node) { - phydev = of_phy_connect(dev, priv->plat->phy_node, - &uio_adjust_link, 0, interface); - } else { - snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", - priv->plat->bus_id); - - snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, - priv->plat->phy_addr); - netdev_dbg(priv->dev, "%s: trying to attach to %s\n", __func__, - phy_id_fmt); - - phydev = phy_connect(dev, phy_id_fmt, &uio_adjust_link, - interface); - } - - if (IS_ERR_OR_NULL(phydev)) { - netdev_err(priv->dev, "Could not attach to PHY\n"); - if (!phydev) + phydev = mdiobus_get_phy(priv->mii, addr); + if (!phydev) { + netdev_err(priv->dev, "no phy at addr %d\n", addr); return -ENODEV; + } - return PTR_ERR(phydev); + ret = phylink_connect_phy(priv->phylink, phydev); } - /* Stop Advertising 1000BASE Capability if interface is not GMII */ - if (interface == PHY_INTERFACE_MODE_MII || - interface == PHY_INTERFACE_MODE_RMII || - (max_speed < 1000 && max_speed > 0)) - phydev->advertising &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + if (!priv->plat->pmt) { + struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; - /* Half-duplex mode not supported with multiqueue - * half-duplex can only works with single queue - */ - if (tx_cnt > 1) - phydev->supported &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_100baseT_Half | - SUPPORTED_10baseT_Half); - - /* Broken HW is sometimes missing the pull-up resistor on the - * MDIO line, which results in reads to non-existent devices returning - * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent - * device as well. - * Note: phydev->phy_id is the result of reading the UID PHY registers. - */ - if (!priv->plat->phy_node && phydev->phy_id == 0) { - phy_disconnect(phydev); - return -ENODEV; + phylink_ethtool_get_wol(priv->phylink, &wol); + device_set_wakeup_capable(priv->device, !!wol.supported); } - /* uio_adjust_link will change this to PHY_IGNORE_INTERRUPT to avoid - * subsequent PHY polling, make sure we force a link transition if - * we have a UP/DOWN/UP transition - */ - if (phydev->is_pseudo_fixed_link) - phydev->irq = PHY_POLL; - - phy_attached_info(phydev); - return 0; + return ret; } /** @@ -545,7 +388,8 @@ rx_q->dma_rx_phy, chan); rx_q->rx_tail_addr = rx_q->dma_rx_phy + - (DMA_RX_SIZE * sizeof(struct dma_desc)); + (priv->dma_rx_size * + sizeof(struct dma_desc)); stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, chan); } @@ -574,12 +418,12 @@ /* set TX ring length */ for (chan = 0; chan < tx_channels_count; chan++) stmmac_set_tx_ring_len(priv, priv->ioaddr, - (DMA_TX_SIZE - 1), chan); + (priv->dma_tx_size - 1), chan); /* set RX ring length */ for (chan = 0; chan < rx_channels_count; chan++) stmmac_set_rx_ring_len(priv, priv->ioaddr, - (DMA_RX_SIZE - 1), chan); + (priv->dma_rx_size - 1), chan); } /** @@ -617,11 +461,11 @@ continue; stmmac_config_cbs(priv, priv->hw, - priv->plat->tx_queues_cfg[queue].send_slope, - priv->plat->tx_queues_cfg[queue].idle_slope, - priv->plat->tx_queues_cfg[queue].high_credit, - priv->plat->tx_queues_cfg[queue].low_credit, - queue); + priv->plat->tx_queues_cfg[queue].send_slope, + priv->plat->tx_queues_cfg[queue].idle_slope, + priv->plat->tx_queues_cfg[queue].high_credit, + priv->plat->tx_queues_cfg[queue].low_credit, + queue); } } @@ -703,6 +547,22 @@ } } +static void uio_mac_config_rss(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.rssen || !priv->plat->rss_en) { + priv->rss.enable = false; + return; + } + + if (priv->dev->features & NETIF_F_RXHASH) + priv->rss.enable = true; + else + priv->rss.enable = false; + + stmmac_rss_configure(priv, priv->hw, &priv->rss, + priv->plat->rx_queues_to_use); +} + /** * uio_mac_enable_rx_queues - Enable MAC rx queues * @priv: driver private structure @@ -764,14 +624,17 @@ /* Set RX routing */ if (rx_queues_count > 1) uio_mac_config_rx_queues_routing(priv); + + /* Receive Side Scaling */ + if (rx_queues_count > 1) + uio_mac_config_rss(priv); } static void uio_safety_feat_configuration(struct stmmac_priv *priv) { if (priv->dma_cap.asp) { netdev_info(priv->dev, "Enabling Safety Features\n"); - stmmac_safety_feat_config(priv, priv->ioaddr, - priv->dma_cap.asp); + stmmac_safety_feat_config(priv, priv->ioaddr, priv->dma_cap.asp); } else { netdev_info(priv->dev, "No Safety Features support found\n"); } @@ -840,26 +703,6 @@ } /** - * rockchip_gmac_uio_mmc_setup: setup the Mac Management Counters (MMC) - * @priv: driver private structure - * Description: this masks the MMC irq, in fact, the counters are managed in SW. - */ -static void rockchip_gmac_uio_mmc_setup(struct stmmac_priv *priv) -{ - unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | - MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; - - dwmac_mmc_intr_all_mask(priv->mmcaddr); - - if (priv->dma_cap.rmon) { - dwmac_mmc_ctrl(priv->mmcaddr, mode); - memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); - } else { - netdev_info(priv->dev, "No MAC Management Counters available\n"); - } -} - -/** * rockchip_gmac_uio_hw_setup - setup mac in a usable state. * @dev : pointer to the device structure. * @init_ptp: initialize PTP if set @@ -923,13 +766,29 @@ /* Set the HW DMA mode and the COE */ uio_dma_operation_mode(priv); - rockchip_gmac_uio_mmc_setup(priv); - if (priv->hw->pcs) stmmac_pcs_ctrl_ane(priv, priv->hw, 1, priv->hw->ps, 0); /* set TX and RX rings length */ uio_set_rings_length(priv); + + return 0; +} + +static int uio_set_bfsize(int mtu, int bufsize) +{ + int ret = bufsize; + + if (mtu >= BUF_SIZE_8KiB) + ret = BUF_SIZE_16KiB; + else if (mtu >= BUF_SIZE_4KiB) + ret = BUF_SIZE_8KiB; + else if (mtu >= BUF_SIZE_2KiB) + ret = BUF_SIZE_4KiB; + else if (mtu > DEFAULT_BUFSIZE) + ret = BUF_SIZE_2KiB; + else + ret = DEFAULT_BUFSIZE; return ret; } @@ -946,11 +805,12 @@ static int uio_open(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + int bfsize = 0; int ret; - if (priv->hw->pcs != STMMAC_PCS_RGMII && - priv->hw->pcs != STMMAC_PCS_TBI && - priv->hw->pcs != STMMAC_PCS_RTBI) { + if (priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI && + !priv->hw->xpcs) { ret = rockchip_gmac_uio_init_phy(dev); if (ret) { netdev_err(priv->dev, @@ -961,11 +821,24 @@ } /* Extra statistics */ - memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); priv->xstats.threshold = tc; - priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); + bfsize = stmmac_set_16kib_bfsize(priv, dev->mtu); + if (bfsize < 0) + bfsize = 0; + + if (bfsize < BUF_SIZE_16KiB) + bfsize = uio_set_bfsize(dev->mtu, priv->dma_buf_sz); + + priv->dma_buf_sz = bfsize; + buf_sz = bfsize; + priv->rx_copybreak = STMMAC_RX_COPYBREAK; + + if (!priv->dma_tx_size) + priv->dma_tx_size = DMA_DEFAULT_TX_SIZE; + if (!priv->dma_rx_size) + priv->dma_rx_size = DMA_DEFAULT_RX_SIZE; ret = uio_alloc_dma_desc_resources(priv); if (ret < 0) { @@ -980,16 +853,16 @@ goto init_error; } - if (dev->phydev) - phy_start(dev->phydev); + phylink_start(priv->phylink); + /* We may have called phylink_speed_down before */ + phylink_speed_up(priv->phylink); return 0; init_error: uio_free_dma_desc_resources(priv); dma_desc_error: - if (dev->phydev) - phy_disconnect(dev->phydev); + phylink_disconnect_phy(priv->phylink); return ret; } @@ -1091,12 +964,12 @@ uio->mem[1].name = "eth_rx_bd"; uio->mem[1].addr = priv->rx_queue[0].dma_rx_phy; - uio->mem[1].size = DMA_RX_SIZE * sizeof(struct dma_desc); + uio->mem[1].size = priv->dma_rx_size * sizeof(struct dma_desc); uio->mem[1].memtype = UIO_MEM_PHYS; uio->mem[2].name = "eth_tx_bd"; uio->mem[2].addr = priv->tx_queue[0].dma_tx_phy; - uio->mem[2].size = DMA_TX_SIZE * sizeof(struct dma_desc); + uio->mem[2].size = priv->dma_tx_size * sizeof(struct dma_desc); uio->mem[2].memtype = UIO_MEM_PHYS; uio->open = rockchip_gmac_uio_open; @@ -1148,7 +1021,7 @@ if (netdev) { rtnl_lock(); - dev_open(netdev); + dev_open(netdev, NULL); rtnl_unlock(); } @@ -1175,4 +1048,3 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("ROCKCHIP"); MODULE_DESCRIPTION("ROCKCHIP GMAC UIO Driver"); - -- Gitblit v1.6.2