Lines Matching +full:mac +full:- +full:clk +full:- +full:rx

1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2007-2008 Avionic Design Development GmbH
6 * Copyright (C) 2008-2009 Avionic Design GmbH
8 * Written by Thierry Reding <thierry.reding@avionic-design.de>
11 #include <linux/dma-mapping.h>
13 #include <linux/clk.h>
64 #define MODER_NBO (1 << 8) /* no back-off */
152 /* RX buffer descriptor */
154 #define RX_BD_CRC (1 << 1) /* RX CRC error */
177 * struct ethoc - driver-private device structure
193 * @clk: clock
220 struct clk *clk; member
228 * struct ethoc_bd - buffer descriptor
239 if (dev->big_endian) in ethoc_read()
240 return ioread32be(dev->iobase + offset); in ethoc_read()
242 return ioread32(dev->iobase + offset); in ethoc_read()
247 if (dev->big_endian) in ethoc_write()
248 iowrite32be(data, dev->iobase + offset); in ethoc_write()
250 iowrite32(data, dev->iobase + offset); in ethoc_write()
257 bd->stat = ethoc_read(dev, offset + 0); in ethoc_read_bd()
258 bd->addr = ethoc_read(dev, offset + 4); in ethoc_read_bd()
265 ethoc_write(dev, offset + 0, bd->stat); in ethoc_write_bd()
266 ethoc_write(dev, offset + 4, bd->addr); in ethoc_write_bd()
308 dev->cur_tx = 0; in ethoc_init_ring()
309 dev->dty_tx = 0; in ethoc_init_ring()
310 dev->cur_rx = 0; in ethoc_init_ring()
312 ethoc_write(dev, TX_BD_NUM, dev->num_tx); in ethoc_init_ring()
317 vma = dev->membase; in ethoc_init_ring()
319 for (i = 0; i < dev->num_tx; i++) { in ethoc_init_ring()
320 if (i == dev->num_tx - 1) in ethoc_init_ring()
326 dev->vma[i] = vma; in ethoc_init_ring()
332 for (i = 0; i < dev->num_rx; i++) { in ethoc_init_ring()
333 if (i == dev->num_rx - 1) in ethoc_init_ring()
336 ethoc_write_bd(dev, dev->num_tx + i, &bd); in ethoc_init_ring()
339 dev->vma[dev->num_tx + i] = vma; in ethoc_init_ring()
361 /* set full-duplex mode */ in ethoc_reset()
376 struct net_device *netdev = dev->netdev; in ethoc_update_rx_stats()
379 if (bd->stat & RX_BD_TL) { in ethoc_update_rx_stats()
380 dev_err(&netdev->dev, "RX: frame too long\n"); in ethoc_update_rx_stats()
381 netdev->stats.rx_length_errors++; in ethoc_update_rx_stats()
385 if (bd->stat & RX_BD_SF) { in ethoc_update_rx_stats()
386 dev_err(&netdev->dev, "RX: frame too short\n"); in ethoc_update_rx_stats()
387 netdev->stats.rx_length_errors++; in ethoc_update_rx_stats()
391 if (bd->stat & RX_BD_DN) { in ethoc_update_rx_stats()
392 dev_err(&netdev->dev, "RX: dribble nibble\n"); in ethoc_update_rx_stats()
393 netdev->stats.rx_frame_errors++; in ethoc_update_rx_stats()
396 if (bd->stat & RX_BD_CRC) { in ethoc_update_rx_stats()
397 dev_err(&netdev->dev, "RX: wrong CRC\n"); in ethoc_update_rx_stats()
398 netdev->stats.rx_crc_errors++; in ethoc_update_rx_stats()
402 if (bd->stat & RX_BD_OR) { in ethoc_update_rx_stats()
403 dev_err(&netdev->dev, "RX: overrun\n"); in ethoc_update_rx_stats()
404 netdev->stats.rx_over_errors++; in ethoc_update_rx_stats()
408 if (bd->stat & RX_BD_MISS) in ethoc_update_rx_stats()
409 netdev->stats.rx_missed_errors++; in ethoc_update_rx_stats()
411 if (bd->stat & RX_BD_LC) { in ethoc_update_rx_stats()
412 dev_err(&netdev->dev, "RX: late collision\n"); in ethoc_update_rx_stats()
413 netdev->stats.collisions++; in ethoc_update_rx_stats()
429 entry = priv->num_tx + priv->cur_rx; in ethoc_rx()
435 * risk missing the packet as the RX interrupt won't in ethoc_rx()
449 size -= 4; /* strip the CRC */ in ethoc_rx()
453 void *src = priv->vma[entry]; in ethoc_rx()
455 skb->protocol = eth_type_trans(skb, dev); in ethoc_rx()
456 dev->stats.rx_packets++; in ethoc_rx()
457 dev->stats.rx_bytes += size; in ethoc_rx()
461 dev_warn(&dev->dev, in ethoc_rx()
462 "low on memory - packet dropped\n"); in ethoc_rx()
464 dev->stats.rx_dropped++; in ethoc_rx()
473 if (++priv->cur_rx == priv->num_rx) in ethoc_rx()
474 priv->cur_rx = 0; in ethoc_rx()
482 struct net_device *netdev = dev->netdev; in ethoc_update_tx_stats()
484 if (bd->stat & TX_BD_LC) { in ethoc_update_tx_stats()
485 dev_err(&netdev->dev, "TX: late collision\n"); in ethoc_update_tx_stats()
486 netdev->stats.tx_window_errors++; in ethoc_update_tx_stats()
489 if (bd->stat & TX_BD_RL) { in ethoc_update_tx_stats()
490 dev_err(&netdev->dev, "TX: retransmit limit\n"); in ethoc_update_tx_stats()
491 netdev->stats.tx_aborted_errors++; in ethoc_update_tx_stats()
494 if (bd->stat & TX_BD_UR) { in ethoc_update_tx_stats()
495 dev_err(&netdev->dev, "TX: underrun\n"); in ethoc_update_tx_stats()
496 netdev->stats.tx_fifo_errors++; in ethoc_update_tx_stats()
499 if (bd->stat & TX_BD_CS) { in ethoc_update_tx_stats()
500 dev_err(&netdev->dev, "TX: carrier sense lost\n"); in ethoc_update_tx_stats()
501 netdev->stats.tx_carrier_errors++; in ethoc_update_tx_stats()
504 if (bd->stat & TX_BD_STATS) in ethoc_update_tx_stats()
505 netdev->stats.tx_errors++; in ethoc_update_tx_stats()
507 netdev->stats.collisions += (bd->stat >> 4) & 0xf; in ethoc_update_tx_stats()
508 netdev->stats.tx_bytes += bd->stat >> 16; in ethoc_update_tx_stats()
509 netdev->stats.tx_packets++; in ethoc_update_tx_stats()
521 entry = priv->dty_tx & (priv->num_tx-1); in ethoc_tx()
525 if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) { in ethoc_tx()
536 (priv->dty_tx == priv->cur_tx)) in ethoc_tx()
541 priv->dty_tx++; in ethoc_tx()
544 if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2)) in ethoc_tx()
576 dev_dbg(&dev->dev, "packet dropped\n"); in ethoc_interrupt()
577 dev->stats.rx_dropped++; in ethoc_interrupt()
583 napi_schedule(&priv->napi); in ethoc_interrupt()
592 u8 *mac = (u8 *)addr; in ethoc_get_mac_address() local
596 mac[2] = (reg >> 24) & 0xff; in ethoc_get_mac_address()
597 mac[3] = (reg >> 16) & 0xff; in ethoc_get_mac_address()
598 mac[4] = (reg >> 8) & 0xff; in ethoc_get_mac_address()
599 mac[5] = (reg >> 0) & 0xff; in ethoc_get_mac_address()
602 mac[0] = (reg >> 8) & 0xff; in ethoc_get_mac_address()
603 mac[1] = (reg >> 0) & 0xff; in ethoc_get_mac_address()
614 rx_work_done = ethoc_rx(priv->netdev, budget); in ethoc_poll()
615 tx_work_done = ethoc_tx(priv->netdev, budget); in ethoc_poll()
627 struct ethoc *priv = bus->priv; in ethoc_mdio_read()
644 return -EBUSY; in ethoc_mdio_read()
649 struct ethoc *priv = bus->priv; in ethoc_mdio_write()
666 return -EBUSY; in ethoc_mdio_write()
672 struct phy_device *phydev = dev->phydev; in ethoc_mdio_poll()
676 if (priv->old_link != phydev->link) { in ethoc_mdio_poll()
678 priv->old_link = phydev->link; in ethoc_mdio_poll()
681 if (priv->old_duplex != phydev->duplex) { in ethoc_mdio_poll()
683 priv->old_duplex = phydev->duplex; in ethoc_mdio_poll()
690 if (phydev->duplex == DUPLEX_FULL) in ethoc_mdio_poll()
705 if (priv->phy_id != -1) in ethoc_mdio_probe()
706 phy = mdiobus_get_phy(priv->mdio, priv->phy_id); in ethoc_mdio_probe()
708 phy = phy_find_first(priv->mdio); in ethoc_mdio_probe()
711 return dev_err_probe(&dev->dev, -ENXIO, "no PHY found\n"); in ethoc_mdio_probe()
713 priv->old_duplex = -1; in ethoc_mdio_probe()
714 priv->old_link = -1; in ethoc_mdio_probe()
719 return dev_err_probe(&dev->dev, err, "could not attach to PHY\n"); in ethoc_mdio_probe()
731 ret = request_irq(dev->irq, ethoc_interrupt, IRQF_SHARED, in ethoc_open()
732 dev->name, dev); in ethoc_open()
736 napi_enable(&priv->napi); in ethoc_open()
738 ethoc_init_ring(priv, dev->mem_start); in ethoc_open()
742 dev_dbg(&dev->dev, " resuming queue\n"); in ethoc_open()
745 dev_dbg(&dev->dev, " starting queue\n"); in ethoc_open()
749 priv->old_link = -1; in ethoc_open()
750 priv->old_duplex = -1; in ethoc_open()
752 phy_start(dev->phydev); in ethoc_open()
755 dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n", in ethoc_open()
756 dev->base_addr, dev->mem_start, dev->mem_end); in ethoc_open()
766 napi_disable(&priv->napi); in ethoc_stop()
768 if (dev->phydev) in ethoc_stop()
769 phy_stop(dev->phydev); in ethoc_stop()
772 free_irq(dev->irq, dev); in ethoc_stop()
787 return -EINVAL; in ethoc_ioctl()
790 if (mdio->phy_id >= PHY_MAX_ADDR) in ethoc_ioctl()
791 return -ERANGE; in ethoc_ioctl()
793 phy = mdiobus_get_phy(priv->mdio, mdio->phy_id); in ethoc_ioctl()
795 return -ENODEV; in ethoc_ioctl()
797 phy = dev->phydev; in ethoc_ioctl()
805 const unsigned char *mac = dev->dev_addr; in ethoc_do_set_mac_address() local
808 ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) | in ethoc_do_set_mac_address()
809 (mac[4] << 8) | (mac[5] << 0)); in ethoc_do_set_mac_address()
810 ethoc_write(priv, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0)); in ethoc_do_set_mac_address()
817 if (!is_valid_ether_addr(addr->sa_data)) in ethoc_set_mac_address()
818 return -EADDRNOTAVAIL; in ethoc_set_mac_address()
819 eth_hw_addr_set(dev, addr->sa_data); in ethoc_set_mac_address()
832 if (dev->flags & IFF_LOOPBACK) in ethoc_set_multicast_list()
838 if (dev->flags & IFF_BROADCAST) in ethoc_set_multicast_list()
844 if (dev->flags & IFF_PROMISC) in ethoc_set_multicast_list()
852 if (dev->flags & IFF_ALLMULTI) { in ethoc_set_multicast_list()
857 u32 crc = ether_crc(ETH_ALEN, ha->addr); in ethoc_set_multicast_list()
869 return -ENOSYS; in ethoc_change_mtu()
877 ethoc_interrupt(dev->irq, dev); in ethoc_tx_timeout()
888 dev->stats.tx_errors++; in ethoc_start_xmit()
892 if (unlikely(skb->len > ETHOC_BUFSIZ)) { in ethoc_start_xmit()
893 dev->stats.tx_errors++; in ethoc_start_xmit()
897 entry = priv->cur_tx % priv->num_tx; in ethoc_start_xmit()
898 spin_lock_irq(&priv->lock); in ethoc_start_xmit()
899 priv->cur_tx++; in ethoc_start_xmit()
902 if (unlikely(skb->len < ETHOC_ZLEN)) in ethoc_start_xmit()
907 dest = priv->vma[entry]; in ethoc_start_xmit()
908 memcpy_toio(dest, skb->data, skb->len); in ethoc_start_xmit()
911 bd.stat |= TX_BD_LEN(skb->len); in ethoc_start_xmit()
917 if (priv->cur_tx == (priv->dty_tx + priv->num_tx)) { in ethoc_start_xmit()
918 dev_dbg(&dev->dev, "stopping queue\n"); in ethoc_start_xmit()
922 spin_unlock_irq(&priv->lock); in ethoc_start_xmit()
942 regs->version = 0; in ethoc_get_regs()
954 ring->rx_max_pending = priv->num_bd - 1; in ethoc_get_ringparam()
955 ring->rx_mini_max_pending = 0; in ethoc_get_ringparam()
956 ring->rx_jumbo_max_pending = 0; in ethoc_get_ringparam()
957 ring->tx_max_pending = priv->num_bd - 1; in ethoc_get_ringparam()
959 ring->rx_pending = priv->num_rx; in ethoc_get_ringparam()
960 ring->rx_mini_pending = 0; in ethoc_get_ringparam()
961 ring->rx_jumbo_pending = 0; in ethoc_get_ringparam()
962 ring->tx_pending = priv->num_tx; in ethoc_get_ringparam()
972 if (ring->tx_pending < 1 || ring->rx_pending < 1 || in ethoc_set_ringparam()
973 ring->tx_pending + ring->rx_pending > priv->num_bd) in ethoc_set_ringparam()
974 return -EINVAL; in ethoc_set_ringparam()
975 if (ring->rx_mini_pending || ring->rx_jumbo_pending) in ethoc_set_ringparam()
976 return -EINVAL; in ethoc_set_ringparam()
982 synchronize_irq(dev->irq); in ethoc_set_ringparam()
985 priv->num_tx = rounddown_pow_of_two(ring->tx_pending); in ethoc_set_ringparam()
986 priv->num_rx = ring->rx_pending; in ethoc_set_ringparam()
987 ethoc_init_ring(priv, dev->mem_start); in ethoc_set_ringparam()
1021 * ethoc_probe - initialize OpenCores ethernet MAC
1033 struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev); in ethoc_probe()
1034 u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0; in ethoc_probe()
1039 ret = -ENOMEM; in ethoc_probe()
1043 SET_NETDEV_DEV(netdev, &pdev->dev); in ethoc_probe()
1049 dev_err(&pdev->dev, "cannot obtain I/O memory space\n"); in ethoc_probe()
1050 ret = -ENXIO; in ethoc_probe()
1054 mmio = devm_request_mem_region(&pdev->dev, res->start, in ethoc_probe()
1055 resource_size(res), res->name); in ethoc_probe()
1057 dev_err(&pdev->dev, "cannot request I/O memory space\n"); in ethoc_probe()
1058 ret = -ENXIO; in ethoc_probe()
1062 netdev->base_addr = mmio->start; in ethoc_probe()
1067 mem = devm_request_mem_region(&pdev->dev, res->start, in ethoc_probe()
1068 resource_size(res), res->name); in ethoc_probe()
1070 dev_err(&pdev->dev, "cannot request memory space\n"); in ethoc_probe()
1071 ret = -ENXIO; in ethoc_probe()
1075 netdev->mem_start = mem->start; in ethoc_probe()
1076 netdev->mem_end = mem->end; in ethoc_probe()
1085 netdev->irq = ret; in ethoc_probe()
1087 /* setup driver-private data */ in ethoc_probe()
1089 priv->netdev = netdev; in ethoc_probe()
1091 priv->iobase = devm_ioremap(&pdev->dev, netdev->base_addr, in ethoc_probe()
1093 if (!priv->iobase) { in ethoc_probe()
1094 dev_err(&pdev->dev, "cannot remap I/O memory space\n"); in ethoc_probe()
1095 ret = -ENXIO; in ethoc_probe()
1099 if (netdev->mem_end) { in ethoc_probe()
1100 priv->membase = devm_ioremap(&pdev->dev, in ethoc_probe()
1101 netdev->mem_start, resource_size(mem)); in ethoc_probe()
1102 if (!priv->membase) { in ethoc_probe()
1103 dev_err(&pdev->dev, "cannot remap memory space\n"); in ethoc_probe()
1104 ret = -ENXIO; in ethoc_probe()
1109 priv->membase = dmam_alloc_coherent(&pdev->dev, in ethoc_probe()
1110 buffer_size, (void *)&netdev->mem_start, in ethoc_probe()
1112 if (!priv->membase) { in ethoc_probe()
1113 dev_err(&pdev->dev, "cannot allocate %dB buffer\n", in ethoc_probe()
1115 ret = -ENOMEM; in ethoc_probe()
1118 netdev->mem_end = netdev->mem_start + buffer_size; in ethoc_probe()
1121 priv->big_endian = pdata ? pdata->big_endian : in ethoc_probe()
1122 of_device_is_big_endian(pdev->dev.of_node); in ethoc_probe()
1124 /* calculate the number of TX/RX buffers, maximum 128 supported */ in ethoc_probe()
1126 128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ); in ethoc_probe()
1128 ret = -ENODEV; in ethoc_probe()
1131 priv->num_bd = num_bd; in ethoc_probe()
1133 priv->num_tx = rounddown_pow_of_two(num_bd >> 1); in ethoc_probe()
1134 priv->num_rx = num_bd - priv->num_tx; in ethoc_probe()
1136 dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n", in ethoc_probe()
1137 priv->num_tx, priv->num_rx); in ethoc_probe()
1139 priv->vma = devm_kcalloc(&pdev->dev, num_bd, sizeof(void *), in ethoc_probe()
1141 if (!priv->vma) { in ethoc_probe()
1142 ret = -ENOMEM; in ethoc_probe()
1146 /* Allow the platform setup code to pass in a MAC address. */ in ethoc_probe()
1148 eth_hw_addr_set(netdev, pdata->hwaddr); in ethoc_probe()
1149 priv->phy_id = pdata->phy_id; in ethoc_probe()
1151 of_get_ethdev_address(pdev->dev.of_node, netdev); in ethoc_probe()
1152 priv->phy_id = -1; in ethoc_probe()
1155 /* Check that the given MAC address is valid. If it isn't, read the in ethoc_probe()
1156 * current MAC from the controller. in ethoc_probe()
1158 if (!is_valid_ether_addr(netdev->dev_addr)) { in ethoc_probe()
1165 /* Check the MAC again for validity, if it still isn't choose and in ethoc_probe()
1168 if (!is_valid_ether_addr(netdev->dev_addr)) in ethoc_probe()
1175 struct clk *clk = devm_clk_get(&pdev->dev, NULL); in ethoc_probe() local
1177 if (!IS_ERR(clk)) { in ethoc_probe()
1178 priv->clk = clk; in ethoc_probe()
1179 clk_prepare_enable(clk); in ethoc_probe()
1180 eth_clkfreq = clk_get_rate(clk); in ethoc_probe()
1188 dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv); in ethoc_probe()
1195 priv->mdio = mdiobus_alloc(); in ethoc_probe()
1196 if (!priv->mdio) { in ethoc_probe()
1197 ret = -ENOMEM; in ethoc_probe()
1201 priv->mdio->name = "ethoc-mdio"; in ethoc_probe()
1202 snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%d", in ethoc_probe()
1203 priv->mdio->name, pdev->id); in ethoc_probe()
1204 priv->mdio->read = ethoc_mdio_read; in ethoc_probe()
1205 priv->mdio->write = ethoc_mdio_write; in ethoc_probe()
1206 priv->mdio->priv = priv; in ethoc_probe()
1208 ret = mdiobus_register(priv->mdio); in ethoc_probe()
1210 dev_err(&netdev->dev, "failed to register MDIO bus\n"); in ethoc_probe()
1216 dev_err(&netdev->dev, "failed to probe MDIO bus\n"); in ethoc_probe()
1221 netdev->netdev_ops = &ethoc_netdev_ops; in ethoc_probe()
1222 netdev->watchdog_timeo = ETHOC_TIMEOUT; in ethoc_probe()
1223 netdev->features |= 0; in ethoc_probe()
1224 netdev->ethtool_ops = &ethoc_ethtool_ops; in ethoc_probe()
1227 netif_napi_add(netdev, &priv->napi, ethoc_poll); in ethoc_probe()
1229 spin_lock_init(&priv->lock); in ethoc_probe()
1233 dev_err(&netdev->dev, "failed to register interface\n"); in ethoc_probe()
1240 netif_napi_del(&priv->napi); in ethoc_probe()
1242 mdiobus_unregister(priv->mdio); in ethoc_probe()
1244 mdiobus_free(priv->mdio); in ethoc_probe()
1246 clk_disable_unprepare(priv->clk); in ethoc_probe()
1254 * ethoc_remove - shutdown OpenCores ethernet MAC
1263 netif_napi_del(&priv->napi); in ethoc_remove()
1264 phy_disconnect(netdev->phydev); in ethoc_remove()
1266 if (priv->mdio) { in ethoc_remove()
1267 mdiobus_unregister(priv->mdio); in ethoc_remove()
1268 mdiobus_free(priv->mdio); in ethoc_remove()
1270 clk_disable_unprepare(priv->clk); in ethoc_remove()
1279 return -ENOSYS; in ethoc_suspend()
1284 return -ENOSYS; in ethoc_resume()
1310 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
1311 MODULE_DESCRIPTION("OpenCores Ethernet MAC driver");