1671 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Texas Instruments ICSSG Ethernet Driver4 *5 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/6 *7 */8 9#include <linux/bitops.h>10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/dma-mapping.h>13#include <linux/dma/ti-cppi5.h>14#include <linux/etherdevice.h>15#include <linux/genalloc.h>16#include <linux/if_hsr.h>17#include <linux/if_vlan.h>18#include <linux/interrupt.h>19#include <linux/io-64-nonatomic-hi-lo.h>20#include <linux/kernel.h>21#include <linux/mfd/syscon.h>22#include <linux/module.h>23#include <linux/of.h>24#include <linux/of_mdio.h>25#include <linux/of_net.h>26#include <linux/platform_device.h>27#include <linux/phy.h>28#include <linux/property.h>29#include <linux/remoteproc/pruss.h>30#include <linux/regmap.h>31#include <linux/remoteproc.h>32#include <net/switchdev.h>33 34#include "icssg_prueth.h"35#include "icssg_mii_rt.h"36#include "icssg_switchdev.h"37#include "../k3-cppi-desc-pool.h"38 39#define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"40 41#define DEFAULT_VID 142#define DEFAULT_PORT_MASK 143#define DEFAULT_UNTAG_MASK 144 45#define NETIF_PRUETH_HSR_OFFLOAD_FEATURES (NETIF_F_HW_HSR_FWD | \46 NETIF_F_HW_HSR_DUP | \47 NETIF_F_HW_HSR_TAG_INS | \48 NETIF_F_HW_HSR_TAG_RM)49 50/* CTRLMMR_ICSSG_RGMII_CTRL register bits */51#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)52 53static int emac_get_tx_ts(struct prueth_emac *emac,54 struct emac_tx_ts_response *rsp)55{56 struct prueth *prueth = emac->prueth;57 int slice = prueth_emac_slice(emac);58 int addr;59 60 addr = icssg_queue_pop(prueth, slice == 0 ?61 ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1);62 if (addr < 0)63 return addr;64 65 memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));66 /* return buffer back for to pool */67 icssg_queue_push(prueth, slice == 0 ?68 ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr);69 70 return 0;71}72 73static void tx_ts_work(struct prueth_emac *emac)74{75 struct skb_shared_hwtstamps ssh;76 struct emac_tx_ts_response tsr;77 struct sk_buff *skb;78 int ret = 0;79 u32 hi_sw;80 u64 ns;81 82 /* There may be more than one pending requests */83 while (1) {84 ret = emac_get_tx_ts(emac, &tsr);85 if (ret) /* nothing more */86 break;87 88 if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS ||89 !emac->tx_ts_skb[tsr.cookie]) {90 netdev_err(emac->ndev, "Invalid TX TS cookie 0x%x\n",91 tsr.cookie);92 break;93 }94 95 skb = emac->tx_ts_skb[tsr.cookie];96 emac->tx_ts_skb[tsr.cookie] = NULL; /* free slot */97 if (!skb) {98 netdev_err(emac->ndev, "Driver Bug! got NULL skb\n");99 break;100 }101 102 hi_sw = readl(emac->prueth->shram.va +103 TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET);104 ns = icssg_ts_to_ns(hi_sw, tsr.hi_ts, tsr.lo_ts,105 IEP_DEFAULT_CYCLE_TIME_NS);106 107 memset(&ssh, 0, sizeof(ssh));108 ssh.hwtstamp = ns_to_ktime(ns);109 110 skb_tstamp_tx(skb, &ssh);111 dev_consume_skb_any(skb);112 113 if (atomic_dec_and_test(&emac->tx_ts_pending)) /* no more? */114 break;115 }116}117 118static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id)119{120 struct prueth_emac *emac = dev_id;121 122 /* currently only TX timestamp is being returned */123 tx_ts_work(emac);124 125 return IRQ_HANDLED;126}127 128static struct icssg_firmwares icssg_hsr_firmwares[] = {129 {130 .pru = "ti-pruss/am65x-sr2-pru0-pruhsr-fw.elf",131 .rtu = "ti-pruss/am65x-sr2-rtu0-pruhsr-fw.elf",132 .txpru = "ti-pruss/am65x-sr2-txpru0-pruhsr-fw.elf",133 },134 {135 .pru = "ti-pruss/am65x-sr2-pru1-pruhsr-fw.elf",136 .rtu = "ti-pruss/am65x-sr2-rtu1-pruhsr-fw.elf",137 .txpru = "ti-pruss/am65x-sr2-txpru1-pruhsr-fw.elf",138 }139};140 141static struct icssg_firmwares icssg_switch_firmwares[] = {142 {143 .pru = "ti-pruss/am65x-sr2-pru0-prusw-fw.elf",144 .rtu = "ti-pruss/am65x-sr2-rtu0-prusw-fw.elf",145 .txpru = "ti-pruss/am65x-sr2-txpru0-prusw-fw.elf",146 },147 {148 .pru = "ti-pruss/am65x-sr2-pru1-prusw-fw.elf",149 .rtu = "ti-pruss/am65x-sr2-rtu1-prusw-fw.elf",150 .txpru = "ti-pruss/am65x-sr2-txpru1-prusw-fw.elf",151 }152};153 154static struct icssg_firmwares icssg_emac_firmwares[] = {155 {156 .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",157 .rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",158 .txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",159 },160 {161 .pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf",162 .rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",163 .txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",164 }165};166 167static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)168{169 struct icssg_firmwares *firmwares;170 struct device *dev = prueth->dev;171 int slice, ret;172 173 if (prueth->is_switch_mode)174 firmwares = icssg_switch_firmwares;175 else if (prueth->is_hsr_offload_mode)176 firmwares = icssg_hsr_firmwares;177 else178 firmwares = icssg_emac_firmwares;179 180 slice = prueth_emac_slice(emac);181 if (slice < 0) {182 netdev_err(emac->ndev, "invalid port\n");183 return -EINVAL;184 }185 186 ret = icssg_config(prueth, emac, slice);187 if (ret)188 return ret;189 190 ret = rproc_set_firmware(prueth->pru[slice], firmwares[slice].pru);191 ret = rproc_boot(prueth->pru[slice]);192 if (ret) {193 dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);194 return -EINVAL;195 }196 197 ret = rproc_set_firmware(prueth->rtu[slice], firmwares[slice].rtu);198 ret = rproc_boot(prueth->rtu[slice]);199 if (ret) {200 dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);201 goto halt_pru;202 }203 204 ret = rproc_set_firmware(prueth->txpru[slice], firmwares[slice].txpru);205 ret = rproc_boot(prueth->txpru[slice]);206 if (ret) {207 dev_err(dev, "failed to boot TX_PRU%d: %d\n", slice, ret);208 goto halt_rtu;209 }210 211 emac->fw_running = 1;212 return 0;213 214halt_rtu:215 rproc_shutdown(prueth->rtu[slice]);216 217halt_pru:218 rproc_shutdown(prueth->pru[slice]);219 220 return ret;221}222 223/* called back by PHY layer if there is change in link state of hw port*/224static void emac_adjust_link(struct net_device *ndev)225{226 struct prueth_emac *emac = netdev_priv(ndev);227 struct phy_device *phydev = ndev->phydev;228 struct prueth *prueth = emac->prueth;229 bool new_state = false;230 unsigned long flags;231 232 if (phydev->link) {233 /* check the mode of operation - full/half duplex */234 if (phydev->duplex != emac->duplex) {235 new_state = true;236 emac->duplex = phydev->duplex;237 }238 if (phydev->speed != emac->speed) {239 new_state = true;240 emac->speed = phydev->speed;241 }242 if (!emac->link) {243 new_state = true;244 emac->link = 1;245 }246 } else if (emac->link) {247 new_state = true;248 emac->link = 0;249 250 /* f/w should support 100 & 1000 */251 emac->speed = SPEED_1000;252 253 /* half duplex may not be supported by f/w */254 emac->duplex = DUPLEX_FULL;255 }256 257 if (new_state) {258 phy_print_status(phydev);259 260 /* update RGMII and MII configuration based on PHY negotiated261 * values262 */263 if (emac->link) {264 if (emac->duplex == DUPLEX_HALF)265 icssg_config_half_duplex(emac);266 /* Set the RGMII cfg for gig en and full duplex */267 icssg_update_rgmii_cfg(prueth->miig_rt, emac);268 269 /* update the Tx IPG based on 100M/1G speed */270 spin_lock_irqsave(&emac->lock, flags);271 icssg_config_ipg(emac);272 spin_unlock_irqrestore(&emac->lock, flags);273 icssg_config_set_speed(emac);274 icssg_set_port_state(emac, ICSSG_EMAC_PORT_FORWARD);275 276 } else {277 icssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);278 }279 }280 281 if (emac->link) {282 /* reactivate the transmit queue */283 netif_tx_wake_all_queues(ndev);284 } else {285 netif_tx_stop_all_queues(ndev);286 prueth_cleanup_tx_ts(emac);287 }288}289 290static enum hrtimer_restart emac_rx_timer_callback(struct hrtimer *timer)291{292 struct prueth_emac *emac =293 container_of(timer, struct prueth_emac, rx_hrtimer);294 int rx_flow = PRUETH_RX_FLOW_DATA;295 296 enable_irq(emac->rx_chns.irq[rx_flow]);297 return HRTIMER_NORESTART;298}299 300static int emac_phy_connect(struct prueth_emac *emac)301{302 struct prueth *prueth = emac->prueth;303 struct net_device *ndev = emac->ndev;304 /* connect PHY */305 ndev->phydev = of_phy_connect(emac->ndev, emac->phy_node,306 &emac_adjust_link, 0,307 emac->phy_if);308 if (!ndev->phydev) {309 dev_err(prueth->dev, "couldn't connect to phy %s\n",310 emac->phy_node->full_name);311 return -ENODEV;312 }313 314 if (!emac->half_duplex) {315 dev_dbg(prueth->dev, "half duplex mode is not supported\n");316 phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);317 phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);318 }319 320 /* remove unsupported modes */321 phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);322 phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Pause_BIT);323 phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);324 325 if (emac->phy_if == PHY_INTERFACE_MODE_MII)326 phy_set_max_speed(ndev->phydev, SPEED_100);327 328 return 0;329}330 331static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts)332{333 u32 hi_rollover_count, hi_rollover_count_r;334 struct prueth_emac *emac = clockops_data;335 struct prueth *prueth = emac->prueth;336 void __iomem *fw_hi_r_count_addr;337 void __iomem *fw_count_hi_addr;338 u32 iepcount_hi, iepcount_hi_r;339 unsigned long flags;340 u32 iepcount_lo;341 u64 ts = 0;342 343 fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET;344 fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET;345 346 local_irq_save(flags);347 do {348 iepcount_hi = icss_iep_get_count_hi(emac->iep);349 iepcount_hi += readl(fw_count_hi_addr);350 hi_rollover_count = readl(fw_hi_r_count_addr);351 ptp_read_system_prets(sts);352 iepcount_lo = icss_iep_get_count_low(emac->iep);353 ptp_read_system_postts(sts);354 355 iepcount_hi_r = icss_iep_get_count_hi(emac->iep);356 iepcount_hi_r += readl(fw_count_hi_addr);357 hi_rollover_count_r = readl(fw_hi_r_count_addr);358 } while ((iepcount_hi_r != iepcount_hi) ||359 (hi_rollover_count != hi_rollover_count_r));360 local_irq_restore(flags);361 362 ts = ((u64)hi_rollover_count) << 23 | iepcount_hi;363 ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo;364 365 return ts;366}367 368static void prueth_iep_settime(void *clockops_data, u64 ns)369{370 struct icssg_setclock_desc __iomem *sc_descp;371 struct prueth_emac *emac = clockops_data;372 struct icssg_setclock_desc sc_desc;373 u64 cyclecount;374 u32 cycletime;375 int timeout;376 377 if (!emac->fw_running)378 return;379 380 sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET;381 382 cycletime = IEP_DEFAULT_CYCLE_TIME_NS;383 cyclecount = ns / cycletime;384 385 memset(&sc_desc, 0, sizeof(sc_desc));386 sc_desc.margin = cycletime - 1000;387 sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0);388 sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32;389 sc_desc.iepcount_set = ns % cycletime;390 /* Count from 0 to (cycle time) - emac->iep->def_inc */391 sc_desc.CMP0_current = cycletime - emac->iep->def_inc;392 393 memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc));394 395 writeb(1, &sc_descp->request);396 397 timeout = 5; /* fw should take 2-3 ms */398 while (timeout--) {399 if (readb(&sc_descp->acknowledgment))400 return;401 402 usleep_range(500, 1000);403 }404 405 dev_err(emac->prueth->dev, "settime timeout\n");406}407 408static int prueth_perout_enable(void *clockops_data,409 struct ptp_perout_request *req, int on,410 u64 *cmp)411{412 struct prueth_emac *emac = clockops_data;413 u32 reduction_factor = 0, offset = 0;414 struct timespec64 ts;415 u64 current_cycle;416 u64 start_offset;417 u64 ns_period;418 419 if (!on)420 return 0;421 422 /* Any firmware specific stuff for PPS/PEROUT handling */423 ts.tv_sec = req->period.sec;424 ts.tv_nsec = req->period.nsec;425 ns_period = timespec64_to_ns(&ts);426 427 /* f/w doesn't support period less than cycle time */428 if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS)429 return -ENXIO;430 431 reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS;432 offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS;433 434 /* f/w requires at least 1uS within a cycle so CMP435 * can trigger after SYNC is enabled436 */437 if (offset < 5 * NSEC_PER_USEC)438 offset = 5 * NSEC_PER_USEC;439 440 /* if offset is close to cycle time then we will miss441 * the CMP event for last tick when IEP rolls over.442 * In normal mode, IEP tick is 4ns.443 * In slow compensation it could be 0ns or 8ns at444 * every slow compensation cycle.445 */446 if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8)447 offset = IEP_DEFAULT_CYCLE_TIME_NS - 8;448 449 /* we're in shadow mode so need to set upper 32-bits */450 *cmp = (u64)offset << 32;451 452 writel(reduction_factor, emac->prueth->shram.va +453 TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET);454 455 current_cycle = icssg_read_time(emac->prueth->shram.va +456 TIMESYNC_FW_WC_CYCLECOUNT_OFFSET);457 458 /* Rounding of current_cycle count to next second */459 start_offset = roundup(current_cycle, MSEC_PER_SEC);460 461 hi_lo_writeq(start_offset, emac->prueth->shram.va +462 TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET);463 464 return 0;465}466 467const struct icss_iep_clockops prueth_iep_clockops = {468 .settime = prueth_iep_settime,469 .gettime = prueth_iep_gettime,470 .perout_enable = prueth_perout_enable,471};472 473static int icssg_prueth_add_mcast(struct net_device *ndev, const u8 *addr)474{475 struct prueth_emac *emac = netdev_priv(ndev);476 int port_mask = BIT(emac->port_id);477 478 port_mask |= icssg_fdb_lookup(emac, addr, 0);479 icssg_fdb_add_del(emac, addr, 0, port_mask, true);480 icssg_vtbl_modify(emac, 0, port_mask, port_mask, true);481 482 return 0;483}484 485static int icssg_prueth_del_mcast(struct net_device *ndev, const u8 *addr)486{487 struct prueth_emac *emac = netdev_priv(ndev);488 int port_mask = BIT(emac->port_id);489 int other_port_mask;490 491 other_port_mask = port_mask ^ icssg_fdb_lookup(emac, addr, 0);492 493 icssg_fdb_add_del(emac, addr, 0, port_mask, false);494 icssg_vtbl_modify(emac, 0, port_mask, port_mask, false);495 496 if (other_port_mask) {497 icssg_fdb_add_del(emac, addr, 0, other_port_mask, true);498 icssg_vtbl_modify(emac, 0, other_port_mask, other_port_mask, true);499 }500 501 return 0;502}503 504static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)505{506 struct prueth_emac *emac = netdev_priv(ndev);507 struct prueth *prueth = emac->prueth;508 509 icssg_fdb_add_del(emac, addr, prueth->default_vlan,510 ICSSG_FDB_ENTRY_P0_MEMBERSHIP |511 ICSSG_FDB_ENTRY_P1_MEMBERSHIP |512 ICSSG_FDB_ENTRY_P2_MEMBERSHIP |513 ICSSG_FDB_ENTRY_BLOCK, true);514 515 icssg_vtbl_modify(emac, emac->port_vlan, BIT(emac->port_id),516 BIT(emac->port_id), true);517 return 0;518}519 520static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)521{522 struct prueth_emac *emac = netdev_priv(ndev);523 struct prueth *prueth = emac->prueth;524 525 icssg_fdb_add_del(emac, addr, prueth->default_vlan,526 ICSSG_FDB_ENTRY_P0_MEMBERSHIP |527 ICSSG_FDB_ENTRY_P1_MEMBERSHIP |528 ICSSG_FDB_ENTRY_P2_MEMBERSHIP |529 ICSSG_FDB_ENTRY_BLOCK, false);530 531 return 0;532}533 534/**535 * emac_ndo_open - EMAC device open536 * @ndev: network adapter device537 *538 * Called when system wants to start the interface.539 *540 * Return: 0 for a successful open, or appropriate error code541 */542static int emac_ndo_open(struct net_device *ndev)543{544 struct prueth_emac *emac = netdev_priv(ndev);545 int ret, i, num_data_chn = emac->tx_ch_num;546 struct prueth *prueth = emac->prueth;547 int slice = prueth_emac_slice(emac);548 struct device *dev = prueth->dev;549 int max_rx_flows;550 int rx_flow;551 552 /* clear SMEM and MSMC settings for all slices */553 if (!prueth->emacs_initialized) {554 memset_io(prueth->msmcram.va, 0, prueth->msmcram.size);555 memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS);556 }557 558 /* set h/w MAC as user might have re-configured */559 ether_addr_copy(emac->mac_addr, ndev->dev_addr);560 561 icssg_class_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);562 icssg_class_default(prueth->miig_rt, slice, 0, false);563 icssg_ft1_set_mac_addr(prueth->miig_rt, slice, emac->mac_addr);564 565 /* Notify the stack of the actual queue counts. */566 ret = netif_set_real_num_tx_queues(ndev, num_data_chn);567 if (ret) {568 dev_err(dev, "cannot set real number of tx queues\n");569 return ret;570 }571 572 init_completion(&emac->cmd_complete);573 ret = prueth_init_tx_chns(emac);574 if (ret) {575 dev_err(dev, "failed to init tx channel: %d\n", ret);576 return ret;577 }578 579 max_rx_flows = PRUETH_MAX_RX_FLOWS;580 ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx",581 max_rx_flows, PRUETH_MAX_RX_DESC);582 if (ret) {583 dev_err(dev, "failed to init rx channel: %d\n", ret);584 goto cleanup_tx;585 }586 587 ret = prueth_ndev_add_tx_napi(emac);588 if (ret)589 goto cleanup_rx;590 591 /* we use only the highest priority flow for now i.e. @irq[3] */592 rx_flow = PRUETH_RX_FLOW_DATA;593 ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq,594 IRQF_TRIGGER_HIGH, dev_name(dev), emac);595 if (ret) {596 dev_err(dev, "unable to request RX IRQ\n");597 goto cleanup_napi;598 }599 600 /* reset and start PRU firmware */601 ret = prueth_emac_start(prueth, emac);602 if (ret)603 goto free_rx_irq;604 605 icssg_mii_update_mtu(prueth->mii_rt, slice, ndev->max_mtu);606 607 if (!prueth->emacs_initialized) {608 ret = icss_iep_init(emac->iep, &prueth_iep_clockops,609 emac, IEP_DEFAULT_CYCLE_TIME_NS);610 }611 612 ret = request_threaded_irq(emac->tx_ts_irq, NULL, prueth_tx_ts_irq,613 IRQF_ONESHOT, dev_name(dev), emac);614 if (ret)615 goto stop;616 617 /* Prepare RX */618 ret = prueth_prepare_rx_chan(emac, &emac->rx_chns, PRUETH_MAX_PKT_SIZE);619 if (ret)620 goto free_tx_ts_irq;621 622 ret = k3_udma_glue_enable_rx_chn(emac->rx_chns.rx_chn);623 if (ret)624 goto reset_rx_chn;625 626 for (i = 0; i < emac->tx_ch_num; i++) {627 ret = k3_udma_glue_enable_tx_chn(emac->tx_chns[i].tx_chn);628 if (ret)629 goto reset_tx_chan;630 }631 632 /* Enable NAPI in Tx and Rx direction */633 for (i = 0; i < emac->tx_ch_num; i++)634 napi_enable(&emac->tx_chns[i].napi_tx);635 napi_enable(&emac->napi_rx);636 637 /* start PHY */638 phy_start(ndev->phydev);639 640 prueth->emacs_initialized++;641 642 queue_work(system_long_wq, &emac->stats_work.work);643 644 return 0;645 646reset_tx_chan:647 /* Since interface is not yet up, there is wouldn't be648 * any SKB for completion. So set false to free_skb649 */650 prueth_reset_tx_chan(emac, i, false);651reset_rx_chn:652 prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, false);653free_tx_ts_irq:654 free_irq(emac->tx_ts_irq, emac);655stop:656 prueth_emac_stop(emac);657free_rx_irq:658 free_irq(emac->rx_chns.irq[rx_flow], emac);659cleanup_napi:660 prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);661cleanup_rx:662 prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);663cleanup_tx:664 prueth_cleanup_tx_chns(emac);665 666 return ret;667}668 669/**670 * emac_ndo_stop - EMAC device stop671 * @ndev: network adapter device672 *673 * Called when system wants to stop or down the interface.674 *675 * Return: Always 0 (Success)676 */677static int emac_ndo_stop(struct net_device *ndev)678{679 struct prueth_emac *emac = netdev_priv(ndev);680 struct prueth *prueth = emac->prueth;681 int rx_flow = PRUETH_RX_FLOW_DATA;682 int max_rx_flows;683 int ret, i;684 685 /* inform the upper layers. */686 netif_tx_stop_all_queues(ndev);687 688 /* block packets from wire */689 if (ndev->phydev)690 phy_stop(ndev->phydev);691 692 icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac));693 694 if (emac->prueth->is_hsr_offload_mode)695 __dev_mc_unsync(ndev, icssg_prueth_hsr_del_mcast);696 else697 __dev_mc_unsync(ndev, icssg_prueth_del_mcast);698 699 atomic_set(&emac->tdown_cnt, emac->tx_ch_num);700 /* ensure new tdown_cnt value is visible */701 smp_mb__after_atomic();702 /* tear down and disable UDMA channels */703 reinit_completion(&emac->tdown_complete);704 for (i = 0; i < emac->tx_ch_num; i++)705 k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false);706 707 ret = wait_for_completion_timeout(&emac->tdown_complete,708 msecs_to_jiffies(1000));709 if (!ret)710 netdev_err(ndev, "tx teardown timeout\n");711 712 prueth_reset_tx_chan(emac, emac->tx_ch_num, true);713 for (i = 0; i < emac->tx_ch_num; i++) {714 napi_disable(&emac->tx_chns[i].napi_tx);715 hrtimer_cancel(&emac->tx_chns[i].tx_hrtimer);716 }717 718 max_rx_flows = PRUETH_MAX_RX_FLOWS;719 k3_udma_glue_tdown_rx_chn(emac->rx_chns.rx_chn, true);720 721 prueth_reset_rx_chan(&emac->rx_chns, max_rx_flows, true);722 723 napi_disable(&emac->napi_rx);724 hrtimer_cancel(&emac->rx_hrtimer);725 726 cancel_work_sync(&emac->rx_mode_work);727 728 /* Destroying the queued work in ndo_stop() */729 cancel_delayed_work_sync(&emac->stats_work);730 731 if (prueth->emacs_initialized == 1)732 icss_iep_exit(emac->iep);733 734 /* stop PRUs */735 prueth_emac_stop(emac);736 737 free_irq(emac->tx_ts_irq, emac);738 739 free_irq(emac->rx_chns.irq[rx_flow], emac);740 prueth_ndev_del_tx_napi(emac, emac->tx_ch_num);741 742 prueth_cleanup_rx_chns(emac, &emac->rx_chns, max_rx_flows);743 prueth_cleanup_tx_chns(emac);744 745 prueth->emacs_initialized--;746 747 return 0;748}749 750static void emac_ndo_set_rx_mode_work(struct work_struct *work)751{752 struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work);753 struct net_device *ndev = emac->ndev;754 bool promisc, allmulti;755 756 if (!netif_running(ndev))757 return;758 759 promisc = ndev->flags & IFF_PROMISC;760 allmulti = ndev->flags & IFF_ALLMULTI;761 icssg_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_DISABLE);762 icssg_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_DISABLE);763 764 if (promisc) {765 icssg_set_port_state(emac, ICSSG_EMAC_PORT_UC_FLOODING_ENABLE);766 icssg_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);767 return;768 }769 770 if (allmulti) {771 icssg_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE);772 return;773 }774 775 if (emac->prueth->is_hsr_offload_mode)776 __dev_mc_sync(ndev, icssg_prueth_hsr_add_mcast,777 icssg_prueth_hsr_del_mcast);778 else779 __dev_mc_sync(ndev, icssg_prueth_add_mcast,780 icssg_prueth_del_mcast);781}782 783/**784 * emac_ndo_set_rx_mode - EMAC set receive mode function785 * @ndev: The EMAC network adapter786 *787 * Called when system wants to set the receive mode of the device.788 *789 */790static void emac_ndo_set_rx_mode(struct net_device *ndev)791{792 struct prueth_emac *emac = netdev_priv(ndev);793 794 queue_work(emac->cmd_wq, &emac->rx_mode_work);795}796 797static netdev_features_t emac_ndo_fix_features(struct net_device *ndev,798 netdev_features_t features)799{800 /* hsr tag insertion offload and hsr dup offload are tightly coupled in801 * firmware implementation. Both these features need to be enabled /802 * disabled together.803 */804 if (!(ndev->features & (NETIF_F_HW_HSR_DUP | NETIF_F_HW_HSR_TAG_INS)))805 if ((features & NETIF_F_HW_HSR_DUP) ||806 (features & NETIF_F_HW_HSR_TAG_INS))807 features |= NETIF_F_HW_HSR_DUP |808 NETIF_F_HW_HSR_TAG_INS;809 810 if ((ndev->features & NETIF_F_HW_HSR_DUP) ||811 (ndev->features & NETIF_F_HW_HSR_TAG_INS))812 if (!(features & NETIF_F_HW_HSR_DUP) ||813 !(features & NETIF_F_HW_HSR_TAG_INS))814 features &= ~(NETIF_F_HW_HSR_DUP |815 NETIF_F_HW_HSR_TAG_INS);816 817 return features;818}819 820static const struct net_device_ops emac_netdev_ops = {821 .ndo_open = emac_ndo_open,822 .ndo_stop = emac_ndo_stop,823 .ndo_start_xmit = icssg_ndo_start_xmit,824 .ndo_set_mac_address = eth_mac_addr,825 .ndo_validate_addr = eth_validate_addr,826 .ndo_tx_timeout = icssg_ndo_tx_timeout,827 .ndo_set_rx_mode = emac_ndo_set_rx_mode,828 .ndo_eth_ioctl = icssg_ndo_ioctl,829 .ndo_get_stats64 = icssg_ndo_get_stats64,830 .ndo_get_phys_port_name = icssg_ndo_get_phys_port_name,831 .ndo_fix_features = emac_ndo_fix_features,832};833 834static int prueth_netdev_init(struct prueth *prueth,835 struct device_node *eth_node)836{837 int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES;838 struct prueth_emac *emac;839 struct net_device *ndev;840 enum prueth_port port;841 const char *irq_name;842 enum prueth_mac mac;843 844 port = prueth_node_port(eth_node);845 if (port == PRUETH_PORT_INVALID)846 return -EINVAL;847 848 mac = prueth_node_mac(eth_node);849 if (mac == PRUETH_MAC_INVALID)850 return -EINVAL;851 852 ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn);853 if (!ndev)854 return -ENOMEM;855 856 emac = netdev_priv(ndev);857 emac->prueth = prueth;858 emac->ndev = ndev;859 emac->port_id = port;860 emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq");861 if (!emac->cmd_wq) {862 ret = -ENOMEM;863 goto free_ndev;864 }865 INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work);866 867 INIT_DELAYED_WORK(&emac->stats_work, icssg_stats_work_handler);868 869 ret = pruss_request_mem_region(prueth->pruss,870 port == PRUETH_PORT_MII0 ?871 PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,872 &emac->dram);873 if (ret) {874 dev_err(prueth->dev, "unable to get DRAM: %d\n", ret);875 ret = -ENOMEM;876 goto free_wq;877 }878 879 emac->tx_ch_num = 1;880 881 irq_name = "tx_ts0";882 if (emac->port_id == PRUETH_PORT_MII1)883 irq_name = "tx_ts1";884 emac->tx_ts_irq = platform_get_irq_byname_optional(prueth->pdev, irq_name);885 if (emac->tx_ts_irq < 0) {886 ret = dev_err_probe(prueth->dev, emac->tx_ts_irq, "could not get tx_ts_irq\n");887 goto free;888 }889 890 SET_NETDEV_DEV(ndev, prueth->dev);891 spin_lock_init(&emac->lock);892 mutex_init(&emac->cmd_lock);893 894 emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0);895 if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) {896 dev_err(prueth->dev, "couldn't find phy-handle\n");897 ret = -ENODEV;898 goto free;899 } else if (of_phy_is_fixed_link(eth_node)) {900 ret = of_phy_register_fixed_link(eth_node);901 if (ret) {902 ret = dev_err_probe(prueth->dev, ret,903 "failed to register fixed-link phy\n");904 goto free;905 }906 907 emac->phy_node = eth_node;908 }909 910 ret = of_get_phy_mode(eth_node, &emac->phy_if);911 if (ret) {912 dev_err(prueth->dev, "could not get phy-mode property\n");913 goto free;914 }915 916 if (emac->phy_if != PHY_INTERFACE_MODE_MII &&917 !phy_interface_mode_is_rgmii(emac->phy_if)) {918 dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if));919 ret = -EINVAL;920 goto free;921 }922 923 /* AM65 SR2.0 has TX Internal delay always enabled by hardware924 * and it is not possible to disable TX Internal delay. The below925 * switch case block describes how we handle different phy modes926 * based on hardware restriction.927 */928 switch (emac->phy_if) {929 case PHY_INTERFACE_MODE_RGMII_ID:930 emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID;931 break;932 case PHY_INTERFACE_MODE_RGMII_TXID:933 emac->phy_if = PHY_INTERFACE_MODE_RGMII;934 break;935 case PHY_INTERFACE_MODE_RGMII:936 case PHY_INTERFACE_MODE_RGMII_RXID:937 dev_err(prueth->dev, "RGMII mode without TX delay is not supported");938 ret = -EINVAL;939 goto free;940 default:941 break;942 }943 944 /* get mac address from DT and set private and netdev addr */945 ret = of_get_ethdev_address(eth_node, ndev);946 if (!is_valid_ether_addr(ndev->dev_addr)) {947 eth_hw_addr_random(ndev);948 dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",949 port, ndev->dev_addr);950 }951 ether_addr_copy(emac->mac_addr, ndev->dev_addr);952 953 ndev->dev.of_node = eth_node;954 ndev->min_mtu = PRUETH_MIN_PKT_SIZE;955 ndev->max_mtu = PRUETH_MAX_MTU;956 ndev->netdev_ops = &emac_netdev_ops;957 ndev->ethtool_ops = &icssg_ethtool_ops;958 ndev->hw_features = NETIF_F_SG;959 ndev->features = ndev->hw_features;960 ndev->hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES;961 962 netif_napi_add(ndev, &emac->napi_rx, icssg_napi_rx_poll);963 hrtimer_init(&emac->rx_hrtimer, CLOCK_MONOTONIC,964 HRTIMER_MODE_REL_PINNED);965 emac->rx_hrtimer.function = &emac_rx_timer_callback;966 prueth->emac[mac] = emac;967 968 return 0;969 970free:971 pruss_release_mem_region(prueth->pruss, &emac->dram);972free_wq:973 destroy_workqueue(emac->cmd_wq);974free_ndev:975 emac->ndev = NULL;976 prueth->emac[mac] = NULL;977 free_netdev(ndev);978 979 return ret;980}981 982bool prueth_dev_check(const struct net_device *ndev)983{984 if (ndev->netdev_ops == &emac_netdev_ops && netif_running(ndev)) {985 struct prueth_emac *emac = netdev_priv(ndev);986 987 return emac->prueth->is_switch_mode;988 }989 990 return false;991}992 993static void prueth_offload_fwd_mark_update(struct prueth *prueth)994{995 int set_val = 0;996 int i;997 998 if (prueth->br_members == (BIT(PRUETH_PORT_MII0) | BIT(PRUETH_PORT_MII1)))999 set_val = 1;1000 1001 dev_dbg(prueth->dev, "set offload_fwd_mark %d\n", set_val);1002 1003 for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) {1004 struct prueth_emac *emac = prueth->emac[i];1005 1006 if (!emac || !emac->ndev)1007 continue;1008 1009 emac->offload_fwd_mark = set_val;1010 }1011}1012 1013static void prueth_emac_restart(struct prueth *prueth)1014{1015 struct prueth_emac *emac0 = prueth->emac[PRUETH_MAC0];1016 struct prueth_emac *emac1 = prueth->emac[PRUETH_MAC1];1017 1018 /* Detach the net_device for both PRUeth ports*/1019 if (netif_running(emac0->ndev))1020 netif_device_detach(emac0->ndev);1021 if (netif_running(emac1->ndev))1022 netif_device_detach(emac1->ndev);1023 1024 /* Disable both PRUeth ports */1025 icssg_set_port_state(emac0, ICSSG_EMAC_PORT_DISABLE);1026 icssg_set_port_state(emac1, ICSSG_EMAC_PORT_DISABLE);1027 1028 /* Stop both pru cores for both PRUeth ports*/1029 prueth_emac_stop(emac0);1030 prueth->emacs_initialized--;1031 prueth_emac_stop(emac1);1032 prueth->emacs_initialized--;1033 1034 /* Start both pru cores for both PRUeth ports */1035 prueth_emac_start(prueth, emac0);1036 prueth->emacs_initialized++;1037 prueth_emac_start(prueth, emac1);1038 prueth->emacs_initialized++;1039 1040 /* Enable forwarding for both PRUeth ports */1041 icssg_set_port_state(emac0, ICSSG_EMAC_PORT_FORWARD);1042 icssg_set_port_state(emac1, ICSSG_EMAC_PORT_FORWARD);1043 1044 /* Attache net_device for both PRUeth ports */1045 netif_device_attach(emac0->ndev);1046 netif_device_attach(emac1->ndev);1047}1048 1049static void icssg_change_mode(struct prueth *prueth)1050{1051 struct prueth_emac *emac;1052 int mac;1053 1054 prueth_emac_restart(prueth);1055 1056 for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) {1057 emac = prueth->emac[mac];1058 if (prueth->is_hsr_offload_mode) {1059 if (emac->ndev->features & NETIF_F_HW_HSR_TAG_RM)1060 icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE);1061 else1062 icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE);1063 }1064 1065 if (netif_running(emac->ndev)) {1066 icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,1067 ICSSG_FDB_ENTRY_P0_MEMBERSHIP |1068 ICSSG_FDB_ENTRY_P1_MEMBERSHIP |1069 ICSSG_FDB_ENTRY_P2_MEMBERSHIP |1070 ICSSG_FDB_ENTRY_BLOCK,1071 true);1072 icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,1073 BIT(emac->port_id) | DEFAULT_PORT_MASK,1074 BIT(emac->port_id) | DEFAULT_UNTAG_MASK,1075 true);1076 if (prueth->is_hsr_offload_mode)1077 icssg_vtbl_modify(emac, DEFAULT_VID,1078 DEFAULT_PORT_MASK,1079 DEFAULT_UNTAG_MASK, true);1080 icssg_set_pvid(prueth, emac->port_vlan, emac->port_id);1081 if (prueth->is_switch_mode)1082 icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);1083 }1084 }1085}1086 1087static int prueth_netdevice_port_link(struct net_device *ndev,1088 struct net_device *br_ndev,1089 struct netlink_ext_ack *extack)1090{1091 struct prueth_emac *emac = netdev_priv(ndev);1092 struct prueth *prueth = emac->prueth;1093 int err;1094 1095 if (!prueth->br_members) {1096 prueth->hw_bridge_dev = br_ndev;1097 } else {1098 /* This is adding the port to a second bridge, this is1099 * unsupported1100 */1101 if (prueth->hw_bridge_dev != br_ndev)1102 return -EOPNOTSUPP;1103 }1104 1105 err = switchdev_bridge_port_offload(br_ndev, ndev, emac,1106 &prueth->prueth_switchdev_nb,1107 &prueth->prueth_switchdev_bl_nb,1108 false, extack);1109 if (err)1110 return err;1111 1112 prueth->br_members |= BIT(emac->port_id);1113 1114 if (!prueth->is_switch_mode) {1115 if (prueth->br_members & BIT(PRUETH_PORT_MII0) &&1116 prueth->br_members & BIT(PRUETH_PORT_MII1)) {1117 prueth->is_switch_mode = true;1118 prueth->default_vlan = 1;1119 emac->port_vlan = prueth->default_vlan;1120 icssg_change_mode(prueth);1121 }1122 }1123 1124 prueth_offload_fwd_mark_update(prueth);1125 1126 return NOTIFY_DONE;1127}1128 1129static void prueth_netdevice_port_unlink(struct net_device *ndev)1130{1131 struct prueth_emac *emac = netdev_priv(ndev);1132 struct prueth *prueth = emac->prueth;1133 1134 prueth->br_members &= ~BIT(emac->port_id);1135 1136 if (prueth->is_switch_mode) {1137 prueth->is_switch_mode = false;1138 emac->port_vlan = 0;1139 prueth_emac_restart(prueth);1140 }1141 1142 prueth_offload_fwd_mark_update(prueth);1143 1144 if (!prueth->br_members)1145 prueth->hw_bridge_dev = NULL;1146}1147 1148static int prueth_hsr_port_link(struct net_device *ndev)1149{1150 struct prueth_emac *emac = netdev_priv(ndev);1151 struct prueth *prueth = emac->prueth;1152 struct prueth_emac *emac0;1153 struct prueth_emac *emac1;1154 1155 emac0 = prueth->emac[PRUETH_MAC0];1156 emac1 = prueth->emac[PRUETH_MAC1];1157 1158 if (prueth->is_switch_mode)1159 return -EOPNOTSUPP;1160 1161 prueth->hsr_members |= BIT(emac->port_id);1162 if (!prueth->is_hsr_offload_mode) {1163 if (prueth->hsr_members & BIT(PRUETH_PORT_MII0) &&1164 prueth->hsr_members & BIT(PRUETH_PORT_MII1)) {1165 if (!(emac0->ndev->features &1166 NETIF_PRUETH_HSR_OFFLOAD_FEATURES) &&1167 !(emac1->ndev->features &1168 NETIF_PRUETH_HSR_OFFLOAD_FEATURES))1169 return -EOPNOTSUPP;1170 prueth->is_hsr_offload_mode = true;1171 prueth->default_vlan = 1;1172 emac0->port_vlan = prueth->default_vlan;1173 emac1->port_vlan = prueth->default_vlan;1174 icssg_change_mode(prueth);1175 netdev_dbg(ndev, "Enabling HSR offload mode\n");1176 }1177 }1178 1179 return 0;1180}1181 1182static void prueth_hsr_port_unlink(struct net_device *ndev)1183{1184 struct prueth_emac *emac = netdev_priv(ndev);1185 struct prueth *prueth = emac->prueth;1186 struct prueth_emac *emac0;1187 struct prueth_emac *emac1;1188 1189 emac0 = prueth->emac[PRUETH_MAC0];1190 emac1 = prueth->emac[PRUETH_MAC1];1191 1192 prueth->hsr_members &= ~BIT(emac->port_id);1193 if (prueth->is_hsr_offload_mode) {1194 prueth->is_hsr_offload_mode = false;1195 emac0->port_vlan = 0;1196 emac1->port_vlan = 0;1197 prueth->hsr_dev = NULL;1198 prueth_emac_restart(prueth);1199 netdev_dbg(ndev, "Disabling HSR Offload mode\n");1200 }1201}1202 1203/* netdev notifier */1204static int prueth_netdevice_event(struct notifier_block *unused,1205 unsigned long event, void *ptr)1206{1207 struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);1208 struct net_device *ndev = netdev_notifier_info_to_dev(ptr);1209 struct netdev_notifier_changeupper_info *info;1210 struct prueth_emac *emac = netdev_priv(ndev);1211 struct prueth *prueth = emac->prueth;1212 int ret = NOTIFY_DONE;1213 1214 if (ndev->netdev_ops != &emac_netdev_ops)1215 return NOTIFY_DONE;1216 1217 switch (event) {1218 case NETDEV_CHANGEUPPER:1219 info = ptr;1220 1221 if ((ndev->features & NETIF_PRUETH_HSR_OFFLOAD_FEATURES) &&1222 is_hsr_master(info->upper_dev)) {1223 if (info->linking) {1224 if (!prueth->hsr_dev) {1225 prueth->hsr_dev = info->upper_dev;1226 icssg_class_set_host_mac_addr(prueth->miig_rt,1227 prueth->hsr_dev->dev_addr);1228 } else {1229 if (prueth->hsr_dev != info->upper_dev) {1230 netdev_dbg(ndev, "Both interfaces must be linked to same upper device\n");1231 return -EOPNOTSUPP;1232 }1233 }1234 prueth_hsr_port_link(ndev);1235 } else {1236 prueth_hsr_port_unlink(ndev);1237 }1238 }1239 1240 if (netif_is_bridge_master(info->upper_dev)) {1241 if (info->linking)1242 ret = prueth_netdevice_port_link(ndev, info->upper_dev, extack);1243 else1244 prueth_netdevice_port_unlink(ndev);1245 }1246 break;1247 default:1248 return NOTIFY_DONE;1249 }1250 1251 return notifier_from_errno(ret);1252}1253 1254static int prueth_register_notifiers(struct prueth *prueth)1255{1256 int ret = 0;1257 1258 prueth->prueth_netdevice_nb.notifier_call = &prueth_netdevice_event;1259 ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb);1260 if (ret) {1261 dev_err(prueth->dev, "can't register netdevice notifier\n");1262 return ret;1263 }1264 1265 ret = prueth_switchdev_register_notifiers(prueth);1266 if (ret)1267 unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);1268 1269 return ret;1270}1271 1272static void prueth_unregister_notifiers(struct prueth *prueth)1273{1274 prueth_switchdev_unregister_notifiers(prueth);1275 unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);1276}1277 1278static int prueth_probe(struct platform_device *pdev)1279{1280 struct device_node *eth_node, *eth_ports_node;1281 struct device_node *eth0_node = NULL;1282 struct device_node *eth1_node = NULL;1283 struct genpool_data_align gp_data = {1284 .align = SZ_64K,1285 };1286 struct device *dev = &pdev->dev;1287 struct device_node *np;1288 struct prueth *prueth;1289 struct pruss *pruss;1290 u32 msmc_ram_size;1291 int i, ret;1292 1293 np = dev->of_node;1294 1295 prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL);1296 if (!prueth)1297 return -ENOMEM;1298 1299 dev_set_drvdata(dev, prueth);1300 prueth->pdev = pdev;1301 prueth->pdata = *(const struct prueth_pdata *)device_get_match_data(dev);1302 1303 prueth->dev = dev;1304 eth_ports_node = of_get_child_by_name(np, "ethernet-ports");1305 if (!eth_ports_node)1306 return -ENOENT;1307 1308 for_each_child_of_node(eth_ports_node, eth_node) {1309 u32 reg;1310 1311 if (strcmp(eth_node->name, "port"))1312 continue;1313 ret = of_property_read_u32(eth_node, "reg", ®);1314 if (ret < 0) {1315 dev_err(dev, "%pOF error reading port_id %d\n",1316 eth_node, ret);1317 }1318 1319 of_node_get(eth_node);1320 1321 if (reg == 0) {1322 eth0_node = eth_node;1323 if (!of_device_is_available(eth0_node)) {1324 of_node_put(eth0_node);1325 eth0_node = NULL;1326 }1327 } else if (reg == 1) {1328 eth1_node = eth_node;1329 if (!of_device_is_available(eth1_node)) {1330 of_node_put(eth1_node);1331 eth1_node = NULL;1332 }1333 } else {1334 dev_err(dev, "port reg should be 0 or 1\n");1335 }1336 }1337 1338 of_node_put(eth_ports_node);1339 1340 /* At least one node must be present and available else we fail */1341 if (!eth0_node && !eth1_node) {1342 dev_err(dev, "neither port0 nor port1 node available\n");1343 return -ENODEV;1344 }1345 1346 if (eth0_node == eth1_node) {1347 dev_err(dev, "port0 and port1 can't have same reg\n");1348 of_node_put(eth0_node);1349 return -ENODEV;1350 }1351 1352 prueth->eth_node[PRUETH_MAC0] = eth0_node;1353 prueth->eth_node[PRUETH_MAC1] = eth1_node;1354 1355 prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt");1356 if (IS_ERR(prueth->miig_rt)) {1357 dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n");1358 return -ENODEV;1359 }1360 1361 prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt");1362 if (IS_ERR(prueth->mii_rt)) {1363 dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n");1364 return -ENODEV;1365 }1366 1367 prueth->pa_stats = syscon_regmap_lookup_by_phandle(np, "ti,pa-stats");1368 if (IS_ERR(prueth->pa_stats)) {1369 dev_err(dev, "couldn't get ti,pa-stats syscon regmap\n");1370 prueth->pa_stats = NULL;1371 }1372 1373 if (eth0_node) {1374 ret = prueth_get_cores(prueth, ICSS_SLICE0, false);1375 if (ret)1376 goto put_cores;1377 }1378 1379 if (eth1_node) {1380 ret = prueth_get_cores(prueth, ICSS_SLICE1, false);1381 if (ret)1382 goto put_cores;1383 }1384 1385 pruss = pruss_get(eth0_node ?1386 prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]);1387 if (IS_ERR(pruss)) {1388 ret = PTR_ERR(pruss);1389 dev_err(dev, "unable to get pruss handle\n");1390 goto put_cores;1391 }1392 1393 prueth->pruss = pruss;1394 1395 ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2,1396 &prueth->shram);1397 if (ret) {1398 dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret);1399 goto put_pruss;1400 }1401 1402 prueth->sram_pool = of_gen_pool_get(np, "sram", 0);1403 if (!prueth->sram_pool) {1404 dev_err(dev, "unable to get SRAM pool\n");1405 ret = -ENODEV;1406 1407 goto put_mem;1408 }1409 1410 msmc_ram_size = MSMC_RAM_SIZE;1411 prueth->is_switchmode_supported = prueth->pdata.switch_mode;1412 if (prueth->is_switchmode_supported)1413 msmc_ram_size = MSMC_RAM_SIZE_SWITCH_MODE;1414 1415 /* NOTE: FW bug needs buffer base to be 64KB aligned */1416 prueth->msmcram.va =1417 (void __iomem *)gen_pool_alloc_algo(prueth->sram_pool,1418 msmc_ram_size,1419 gen_pool_first_fit_align,1420 &gp_data);1421 1422 if (!prueth->msmcram.va) {1423 ret = -ENOMEM;1424 dev_err(dev, "unable to allocate MSMC resource\n");1425 goto put_mem;1426 }1427 prueth->msmcram.pa = gen_pool_virt_to_phys(prueth->sram_pool,1428 (unsigned long)prueth->msmcram.va);1429 prueth->msmcram.size = msmc_ram_size;1430 memset_io(prueth->msmcram.va, 0, msmc_ram_size);1431 dev_dbg(dev, "sram: pa %llx va %p size %zx\n", prueth->msmcram.pa,1432 prueth->msmcram.va, prueth->msmcram.size);1433 1434 prueth->iep0 = icss_iep_get_idx(np, 0);1435 if (IS_ERR(prueth->iep0)) {1436 ret = dev_err_probe(dev, PTR_ERR(prueth->iep0), "iep0 get failed\n");1437 prueth->iep0 = NULL;1438 goto free_pool;1439 }1440 1441 prueth->iep1 = icss_iep_get_idx(np, 1);1442 if (IS_ERR(prueth->iep1)) {1443 ret = dev_err_probe(dev, PTR_ERR(prueth->iep1), "iep1 get failed\n");1444 goto put_iep0;1445 }1446 1447 if (prueth->pdata.quirk_10m_link_issue) {1448 /* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX1449 * traffic.1450 */1451 icss_iep_init_fw(prueth->iep1);1452 }1453 1454 spin_lock_init(&prueth->vtbl_lock);1455 /* setup netdev interfaces */1456 if (eth0_node) {1457 ret = prueth_netdev_init(prueth, eth0_node);1458 if (ret) {1459 dev_err_probe(dev, ret, "netdev init %s failed\n",1460 eth0_node->name);1461 goto exit_iep;1462 }1463 1464 prueth->emac[PRUETH_MAC0]->half_duplex =1465 of_property_read_bool(eth0_node, "ti,half-duplex-capable");1466 1467 prueth->emac[PRUETH_MAC0]->iep = prueth->iep0;1468 }1469 1470 if (eth1_node) {1471 ret = prueth_netdev_init(prueth, eth1_node);1472 if (ret) {1473 dev_err_probe(dev, ret, "netdev init %s failed\n",1474 eth1_node->name);1475 goto netdev_exit;1476 }1477 1478 prueth->emac[PRUETH_MAC1]->half_duplex =1479 of_property_read_bool(eth1_node, "ti,half-duplex-capable");1480 1481 prueth->emac[PRUETH_MAC1]->iep = prueth->iep0;1482 }1483 1484 /* register the network devices */1485 if (eth0_node) {1486 ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev);1487 if (ret) {1488 dev_err(dev, "can't register netdev for port MII0");1489 goto netdev_exit;1490 }1491 1492 prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev;1493 1494 ret = emac_phy_connect(prueth->emac[PRUETH_MAC0]);1495 if (ret) {1496 dev_err(dev,1497 "can't connect to MII0 PHY, error -%d", ret);1498 goto netdev_unregister;1499 }1500 phy_attached_info(prueth->emac[PRUETH_MAC0]->ndev->phydev);1501 }1502 1503 if (eth1_node) {1504 ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev);1505 if (ret) {1506 dev_err(dev, "can't register netdev for port MII1");1507 goto netdev_unregister;1508 }1509 1510 prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev;1511 ret = emac_phy_connect(prueth->emac[PRUETH_MAC1]);1512 if (ret) {1513 dev_err(dev,1514 "can't connect to MII1 PHY, error %d", ret);1515 goto netdev_unregister;1516 }1517 phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);1518 }1519 1520 if (prueth->is_switchmode_supported) {1521 ret = prueth_register_notifiers(prueth);1522 if (ret)1523 goto netdev_unregister;1524 1525 sprintf(prueth->switch_id, "%s", dev_name(dev));1526 }1527 1528 dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",1529 (!eth0_node || !eth1_node) ? "single" : "dual");1530 1531 if (eth1_node)1532 of_node_put(eth1_node);1533 if (eth0_node)1534 of_node_put(eth0_node);1535 return 0;1536 1537netdev_unregister:1538 for (i = 0; i < PRUETH_NUM_MACS; i++) {1539 if (!prueth->registered_netdevs[i])1540 continue;1541 if (prueth->emac[i]->ndev->phydev) {1542 phy_disconnect(prueth->emac[i]->ndev->phydev);1543 prueth->emac[i]->ndev->phydev = NULL;1544 }1545 unregister_netdev(prueth->registered_netdevs[i]);1546 }1547 1548netdev_exit:1549 for (i = 0; i < PRUETH_NUM_MACS; i++) {1550 eth_node = prueth->eth_node[i];1551 if (!eth_node)1552 continue;1553 1554 prueth_netdev_exit(prueth, eth_node);1555 }1556 1557exit_iep:1558 if (prueth->pdata.quirk_10m_link_issue)1559 icss_iep_exit_fw(prueth->iep1);1560 icss_iep_put(prueth->iep1);1561 1562put_iep0:1563 icss_iep_put(prueth->iep0);1564 prueth->iep0 = NULL;1565 prueth->iep1 = NULL;1566 1567free_pool:1568 gen_pool_free(prueth->sram_pool,1569 (unsigned long)prueth->msmcram.va, msmc_ram_size);1570 1571put_mem:1572 pruss_release_mem_region(prueth->pruss, &prueth->shram);1573 1574put_pruss:1575 pruss_put(prueth->pruss);1576 1577put_cores:1578 if (eth1_node) {1579 prueth_put_cores(prueth, ICSS_SLICE1);1580 of_node_put(eth1_node);1581 }1582 1583 if (eth0_node) {1584 prueth_put_cores(prueth, ICSS_SLICE0);1585 of_node_put(eth0_node);1586 }1587 1588 return ret;1589}1590 1591static void prueth_remove(struct platform_device *pdev)1592{1593 struct prueth *prueth = platform_get_drvdata(pdev);1594 struct device_node *eth_node;1595 int i;1596 1597 prueth_unregister_notifiers(prueth);1598 1599 for (i = 0; i < PRUETH_NUM_MACS; i++) {1600 if (!prueth->registered_netdevs[i])1601 continue;1602 phy_stop(prueth->emac[i]->ndev->phydev);1603 phy_disconnect(prueth->emac[i]->ndev->phydev);1604 prueth->emac[i]->ndev->phydev = NULL;1605 unregister_netdev(prueth->registered_netdevs[i]);1606 }1607 1608 for (i = 0; i < PRUETH_NUM_MACS; i++) {1609 eth_node = prueth->eth_node[i];1610 if (!eth_node)1611 continue;1612 1613 prueth_netdev_exit(prueth, eth_node);1614 }1615 1616 if (prueth->pdata.quirk_10m_link_issue)1617 icss_iep_exit_fw(prueth->iep1);1618 1619 icss_iep_put(prueth->iep1);1620 icss_iep_put(prueth->iep0);1621 1622 gen_pool_free(prueth->sram_pool,1623 (unsigned long)prueth->msmcram.va,1624 MSMC_RAM_SIZE);1625 1626 pruss_release_mem_region(prueth->pruss, &prueth->shram);1627 1628 pruss_put(prueth->pruss);1629 1630 if (prueth->eth_node[PRUETH_MAC1])1631 prueth_put_cores(prueth, ICSS_SLICE1);1632 1633 if (prueth->eth_node[PRUETH_MAC0])1634 prueth_put_cores(prueth, ICSS_SLICE0);1635}1636 1637static const struct prueth_pdata am654_icssg_pdata = {1638 .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,1639 .quirk_10m_link_issue = 1,1640 .switch_mode = 1,1641};1642 1643static const struct prueth_pdata am64x_icssg_pdata = {1644 .fdqring_mode = K3_RINGACC_RING_MODE_RING,1645 .quirk_10m_link_issue = 1,1646 .switch_mode = 1,1647};1648 1649static const struct of_device_id prueth_dt_match[] = {1650 { .compatible = "ti,am654-icssg-prueth", .data = &am654_icssg_pdata },1651 { .compatible = "ti,am642-icssg-prueth", .data = &am64x_icssg_pdata },1652 { /* sentinel */ }1653};1654MODULE_DEVICE_TABLE(of, prueth_dt_match);1655 1656static struct platform_driver prueth_driver = {1657 .probe = prueth_probe,1658 .remove_new = prueth_remove,1659 .driver = {1660 .name = "icssg-prueth",1661 .of_match_table = prueth_dt_match,1662 .pm = &prueth_dev_pm_ops,1663 },1664};1665module_platform_driver(prueth_driver);1666 1667MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");1668MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>");1669MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver");1670MODULE_LICENSE("GPL");1671