staticvoid icssg_config_sr1(struct prueth *prueth, struct prueth_emac *emac, int slice)
{ struct icssg_sr1_config config; void __iomem *va; int i, index;
memset(&config, 0, sizeof(config));
config.addr_lo = cpu_to_le32(lower_32_bits(prueth->msmcram.pa));
config.addr_hi = cpu_to_le32(upper_32_bits(prueth->msmcram.pa));
config.rx_flow_id = cpu_to_le32(emac->rx_flow_id_base); /* flow id for host port */
config.rx_mgr_flow_id = cpu_to_le32(emac->rx_mgm_flow_id_base); /* for mgm ch */
config.rand_seed = cpu_to_le32(get_random_u32());
for (i = PRUETH_EMAC_BUF_POOL_START_SR1; i < PRUETH_NUM_BUF_POOLS_SR1; i++) {
index = i - PRUETH_EMAC_BUF_POOL_START_SR1;
config.tx_buf_sz[i] = cpu_to_le32(emac_egress_buf_pool_size[index]);
}
va = prueth->shram.va + slice * ICSSG_CONFIG_OFFSET_SLICE1;
memcpy_toio(va, &config, sizeof(config));
val = icssg_rgmii_get_speed(prueth->miig_rt, slice); /* firmware expects speed settings in bit 2-1 */
val <<= 1;
cmd |= val;
val = icssg_rgmii_get_fullduplex(prueth->miig_rt, slice); /* firmware expects full duplex settings in bit 3 */
val <<= 3;
cmd |= val;
emac_send_command_sr1(emac, cmd);
}
/* called back by PHY layer if there is change in link state of hw port*/ staticvoid emac_adjust_link_sr1(struct net_device *ndev)
{ struct prueth_emac *emac = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; struct prueth *prueth = emac->prueth; bool new_state = false; unsignedlong flags;
if (phydev->link) { /* check the mode of operation - full/half duplex */ if (phydev->duplex != emac->duplex) {
new_state = true;
emac->duplex = phydev->duplex;
} if (phydev->speed != emac->speed) {
new_state = true;
emac->speed = phydev->speed;
} if (!emac->link) {
new_state = true;
emac->link = 1;
}
} elseif (emac->link) {
new_state = true;
emac->link = 0;
/* f/w should support 100 & 1000 */
emac->speed = SPEED_1000;
/* half duplex may not be supported by f/w */
emac->duplex = DUPLEX_FULL;
}
if (new_state) {
phy_print_status(phydev);
/* update RGMII and MII configuration based on PHY negotiated *values
*/ if (emac->link) { /* Set the RGMII cfg for gig en and full duplex */
icssg_update_rgmii_cfg(prueth->miig_rt, emac);
/* update the Tx IPG based on 100M/1G speed */
spin_lock_irqsave(&emac->lock, flags);
icssg_config_ipg(emac);
spin_unlock_irqrestore(&emac->lock, flags);
icssg_config_set_speed_sr1(emac);
}
}
if (emac->link) { /* reactivate the transmit queue */
netif_tx_wake_all_queues(ndev);
} else {
netif_tx_stop_all_queues(ndev);
prueth_cleanup_tx_ts(emac);
}
}
if (!emac->half_duplex) {
dev_dbg(prueth->dev, "half duplex mode is not supported\n");
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
}
/* Remove 100Mbits half-duplex due to RGMII misreporting connection
* as full duplex */
phy_remove_link_mode(ndev->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
/* Notify the stack of the actual queue counts. */
ret = netif_set_real_num_tx_queues(ndev, num_data_chn); if (ret) {
dev_err(dev, "cannot set real number of tx queues\n"); return ret;
}
init_completion(&emac->cmd_complete);
ret = prueth_init_tx_chns(emac); if (ret) {
dev_err(dev, "failed to init tx channel: %d\n", ret); return ret;
}
max_rx_flows = PRUETH_MAX_RX_FLOWS_SR1;
ret = prueth_init_rx_chns(emac, &emac->rx_chns, "rx",
max_rx_flows, PRUETH_MAX_RX_DESC); if (ret) {
dev_err(dev, "failed to init rx channel: %d\n", ret); goto cleanup_tx;
}
ret = prueth_init_rx_chns(emac, &emac->rx_mgm_chn, "rxmgm",
PRUETH_MAX_RX_MGM_FLOWS_SR1,
PRUETH_MAX_RX_MGM_DESC_SR1); if (ret) {
dev_err(dev, "failed to init rx mgmt channel: %d\n",
ret); goto cleanup_rx;
}
ret = prueth_ndev_add_tx_napi(emac); if (ret) goto cleanup_rx_mgm;
/* we use only the highest priority flow for now i.e. @irq[3] */
rx_flow = PRUETH_RX_FLOW_DATA_SR1;
ret = request_irq(emac->rx_chns.irq[rx_flow], prueth_rx_irq,
IRQF_TRIGGER_HIGH, dev_name(dev), emac); if (ret) {
dev_err(dev, "unable to request RX IRQ\n"); goto cleanup_napi;
}
ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_RESPONSE_SR1],
NULL, prueth_rx_mgm_rsp_thread,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
dev_name(dev), emac); if (ret) {
dev_err(dev, "unable to request RX Management RSP IRQ\n"); goto free_rx_irq;
}
ret = request_threaded_irq(emac->rx_mgm_chn.irq[PRUETH_RX_MGM_FLOW_TIMESTAMP_SR1],
NULL, prueth_rx_mgm_ts_thread_sr1,
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
dev_name(dev), emac); if (ret) {
dev_err(dev, "unable to request RX Management TS IRQ\n"); goto free_rx_mgm_rsp_irq;
}
/* reset and start PRU firmware */
ret = prueth_emac_start(prueth, emac); if (ret) goto free_rx_mgmt_ts_irq;
atomic_set(&emac->tdown_cnt, emac->tx_ch_num); /* ensure new tdown_cnt value is visible */
smp_mb__after_atomic(); /* tear down and disable UDMA channels */
reinit_completion(&emac->tdown_complete); for (i = 0; i < emac->tx_ch_num; i++)
k3_udma_glue_tdown_tx_chn(emac->tx_chns[i].tx_chn, false);
ret = wait_for_completion_timeout(&emac->tdown_complete,
msecs_to_jiffies(1000)); if (!ret)
netdev_err(ndev, "tx teardown timeout\n");
prueth_reset_tx_chan(emac, emac->tx_ch_num, true); for (i = 0; i < emac->tx_ch_num; i++)
napi_disable(&emac->tx_chns[i].napi_tx);
if (promisc) {
icssg_class_promiscuous_sr1(prueth->miig_rt, slice); return;
}
if (allmulti) {
icssg_class_default(prueth->miig_rt, slice, 1, true); return;
}
icssg_class_default(prueth->miig_rt, slice, 0, true); if (!netdev_mc_empty(ndev)) { /* program multicast address list into Classifier */
icssg_class_add_mcast_sr1(prueth->miig_rt, slice, ndev);
}
}
ret = pruss_request_mem_region(prueth->pruss,
port == PRUETH_PORT_MII0 ?
PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,
&emac->dram); if (ret) {
dev_err(prueth->dev, "unable to get DRAM: %d\n", ret);
ret = -ENOMEM; goto free_wq;
}
/* SR1.0 uses a dedicated high priority channel *tosendcommandstothefirmware
*/
emac->tx_ch_num = 2;
emac->phy_node = of_parse_phandle(eth_node, "phy-handle", 0); if (!emac->phy_node && !of_phy_is_fixed_link(eth_node)) {
dev_err(prueth->dev, "couldn't find phy-handle\n");
ret = -ENODEV; goto free;
} elseif (of_phy_is_fixed_link(eth_node)) {
ret = of_phy_register_fixed_link(eth_node); if (ret) {
ret = dev_err_probe(prueth->dev, ret, "failed to register fixed-link phy\n"); goto free;
}
emac->phy_node = eth_node;
}
ret = of_get_phy_mode(eth_node, &emac->phy_if); if (ret) {
dev_err(prueth->dev, "could not get phy-mode property\n"); goto free;
}
if (emac->phy_if != PHY_INTERFACE_MODE_MII &&
!phy_interface_mode_is_rgmii(emac->phy_if)) {
dev_err(prueth->dev, "PHY mode unsupported %s\n", phy_modes(emac->phy_if));
ret = -EINVAL; goto free;
}
/* AM65 SR2.0 has TX Internal delay always enabled by hardware *anditisnotpossibletodisableTXInternaldelay.Thebelow *switchcaseblockdescribeshowwehandledifferentphymodes *basedonhardwarerestriction.
*/ switch (emac->phy_if) { case PHY_INTERFACE_MODE_RGMII_ID:
emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID; break; case PHY_INTERFACE_MODE_RGMII_TXID:
emac->phy_if = PHY_INTERFACE_MODE_RGMII; break; case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_RXID:
dev_err(prueth->dev, "RGMII mode without TX delay is not supported");
ret = -EINVAL; goto free; default: break;
}
/* get mac address from DT and set private and netdev addr */
ret = of_get_ethdev_address(eth_node, ndev); if (!is_valid_ether_addr(ndev->dev_addr)) {
eth_hw_addr_random(ndev);
dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n",
port, ndev->dev_addr);
}
ether_addr_copy(emac->mac_addr, ndev->dev_addr);
if (strcmp(eth_node->name, "port")) continue;
ret = of_property_read_u32(eth_node, "reg", ®); if (ret < 0) {
dev_err(dev, "%pOF error reading port_id %d\n",
eth_node, ret);
}
of_node_get(eth_node);
if (reg == 0) {
eth0_node = eth_node; if (!of_device_is_available(eth0_node)) {
of_node_put(eth0_node);
eth0_node = NULL;
}
} elseif (reg == 1) {
eth1_node = eth_node; if (!of_device_is_available(eth1_node)) {
of_node_put(eth1_node);
eth1_node = NULL;
}
} else {
dev_err(dev, "port reg should be 0 or 1\n");
}
}
of_node_put(eth_ports_node);
/* At least one node must be present and available else we fail */ if (!eth0_node && !eth1_node) {
dev_err(dev, "neither port0 nor port1 node available\n"); return -ENODEV;
}
if (eth0_node == eth1_node) {
dev_err(dev, "port0 and port1 can't have same reg\n");
of_node_put(eth0_node); return -ENODEV;
}
prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-g-rt"); if (IS_ERR(prueth->miig_rt)) {
dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n"); return -ENODEV;
}
prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); if (IS_ERR(prueth->mii_rt)) {
dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n"); return -ENODEV;
}
if (eth0_node) {
ret = prueth_get_cores(prueth, ICSS_SLICE0, true); if (ret) goto put_cores;
}
if (eth1_node) {
ret = prueth_get_cores(prueth, ICSS_SLICE1, true); if (ret) goto put_cores;
}
pruss = pruss_get(eth0_node ?
prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]); if (IS_ERR(pruss)) {
ret = PTR_ERR(pruss);
dev_err(dev, "unable to get pruss handle\n"); goto put_cores;
}
prueth->pruss = pruss;
ret = pruss_request_mem_region(pruss, PRUSS_MEM_SHRD_RAM2,
&prueth->shram); if (ret) {
dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n", ret); goto put_pruss;
}
prueth->sram_pool = of_gen_pool_get(np, "sram", 0); if (!prueth->sram_pool) {
dev_err(dev, "unable to get SRAM pool\n");
ret = -ENODEV;
/* register the network devices */ if (eth0_node) {
ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); if (ret) {
dev_err(dev, "can't register netdev for port MII0\n"); goto netdev_exit;
}
if (eth1_node) {
ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); if (ret) {
dev_err(dev, "can't register netdev for port MII1\n"); goto netdev_unregister;
}
for (i = 0; i < PRUETH_NUM_MACS; i++) { if (!prueth->registered_netdevs[i]) continue;
phy_stop(prueth->emac[i]->ndev->phydev);
phy_disconnect(prueth->emac[i]->ndev->phydev);
prueth->emac[i]->ndev->phydev = NULL;
unregister_netdev(prueth->registered_netdevs[i]);
}
for (i = 0; i < PRUETH_NUM_MACS; i++) {
eth_node = prueth->eth_node[i]; if (!eth_node) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.