|
|
|
|
@@ -241,8 +241,8 @@ static int am65_cpsw_nuss_ndo_slave_add_vid(struct net_device *ndev,
|
|
|
|
|
if (!vid)
|
|
|
|
|
unreg_mcast = port_mask;
|
|
|
|
|
dev_info(common->dev, "Adding vlan %d to vlan filter\n", vid);
|
|
|
|
|
ret = cpsw_ale_add_vlan(common->ale, vid, port_mask,
|
|
|
|
|
unreg_mcast, port_mask, 0);
|
|
|
|
|
ret = cpsw_ale_vlan_add_modify(common->ale, vid, port_mask,
|
|
|
|
|
unreg_mcast, port_mask, 0);
|
|
|
|
|
|
|
|
|
|
pm_runtime_put(common->dev);
|
|
|
|
|
return ret;
|
|
|
|
|
@@ -252,6 +252,7 @@ static int am65_cpsw_nuss_ndo_slave_kill_vid(struct net_device *ndev,
|
|
|
|
|
__be16 proto, u16 vid)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
|
|
|
|
|
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (!netif_running(ndev) || !vid)
|
|
|
|
|
@@ -264,14 +265,15 @@ static int am65_cpsw_nuss_ndo_slave_kill_vid(struct net_device *ndev,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_info(common->dev, "Removing vlan %d from vlan filter\n", vid);
|
|
|
|
|
ret = cpsw_ale_del_vlan(common->ale, vid, 0);
|
|
|
|
|
ret = cpsw_ale_del_vlan(common->ale, vid,
|
|
|
|
|
BIT(port->port_id) | ALE_PORT_HOST);
|
|
|
|
|
|
|
|
|
|
pm_runtime_put(common->dev);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_slave_set_promisc_2g(struct am65_cpsw_port *port,
|
|
|
|
|
bool promisc)
|
|
|
|
|
static void am65_cpsw_slave_set_promisc(struct am65_cpsw_port *port,
|
|
|
|
|
bool promisc)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_common *common = port->common;
|
|
|
|
|
|
|
|
|
|
@@ -296,7 +298,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev)
|
|
|
|
|
bool promisc;
|
|
|
|
|
|
|
|
|
|
promisc = !!(ndev->flags & IFF_PROMISC);
|
|
|
|
|
am65_cpsw_slave_set_promisc_2g(port, promisc);
|
|
|
|
|
am65_cpsw_slave_set_promisc(port, promisc);
|
|
|
|
|
|
|
|
|
|
if (promisc)
|
|
|
|
|
return;
|
|
|
|
|
@@ -373,7 +375,7 @@ static int am65_cpsw_nuss_rx_push(struct am65_cpsw_common *common,
|
|
|
|
|
|
|
|
|
|
cppi5_hdesc_init(desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT,
|
|
|
|
|
AM65_CPSW_NAV_PS_DATA_SIZE);
|
|
|
|
|
cppi5_hdesc_attach_buf(desc_rx, 0, 0, buf_dma, skb_tailroom(skb));
|
|
|
|
|
cppi5_hdesc_attach_buf(desc_rx, buf_dma, skb_tailroom(skb), buf_dma, skb_tailroom(skb));
|
|
|
|
|
swdata = cppi5_hdesc_get_swdata(desc_rx);
|
|
|
|
|
*((void **)swdata) = skb;
|
|
|
|
|
|
|
|
|
|
@@ -426,9 +428,7 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common,
|
|
|
|
|
writel(common->rx_flow_id_base,
|
|
|
|
|
host_p->port_base + AM65_CPSW_PORT0_REG_FLOW_ID_OFFSET);
|
|
|
|
|
/* en tx crc offload */
|
|
|
|
|
if (features & NETIF_F_HW_CSUM)
|
|
|
|
|
writel(AM65_CPSW_P0_REG_CTL_RX_CHECKSUM_EN,
|
|
|
|
|
host_p->port_base + AM65_CPSW_P0_REG_CTL);
|
|
|
|
|
writel(AM65_CPSW_P0_REG_CTL_RX_CHECKSUM_EN, host_p->port_base + AM65_CPSW_P0_REG_CTL);
|
|
|
|
|
|
|
|
|
|
am65_cpsw_nuss_set_p0_ptype(common);
|
|
|
|
|
|
|
|
|
|
@@ -629,13 +629,13 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
|
|
|
|
|
|
|
|
|
|
am65_cpsw_port_set_sl_mac(port, ndev->dev_addr);
|
|
|
|
|
|
|
|
|
|
if (port->slave.mac_only)
|
|
|
|
|
if (port->slave.mac_only) {
|
|
|
|
|
/* enable mac-only mode on port */
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_MACONLY, 1);
|
|
|
|
|
if (AM65_CPSW_IS_CPSW2G(common))
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_NOLEARN, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port_mask = BIT(port->port_id) | ALE_PORT_HOST;
|
|
|
|
|
cpsw_ale_add_ucast(common->ale, ndev->dev_addr,
|
|
|
|
|
@@ -767,7 +767,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (desc_dma & 0x1) {
|
|
|
|
|
if (cppi5_desc_is_tdcm(desc_dma)) {
|
|
|
|
|
dev_dbg(dev, "%s RX tdown flow: %u\n", __func__, flow_idx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -911,10 +911,57 @@ static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma)
|
|
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct sk_buff *
|
|
|
|
|
am65_cpsw_nuss_tx_compl_packet(struct am65_cpsw_tx_chn *tx_chn,
|
|
|
|
|
dma_addr_t desc_dma)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_ndev_priv *ndev_priv;
|
|
|
|
|
struct am65_cpsw_ndev_stats *stats;
|
|
|
|
|
struct cppi5_host_desc_t *desc_tx;
|
|
|
|
|
struct net_device *ndev;
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
void **swdata;
|
|
|
|
|
|
|
|
|
|
desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
|
|
|
|
|
desc_dma);
|
|
|
|
|
swdata = cppi5_hdesc_get_swdata(desc_tx);
|
|
|
|
|
skb = *(swdata);
|
|
|
|
|
am65_cpsw_nuss_xmit_free(tx_chn, tx_chn->common->dev, desc_tx);
|
|
|
|
|
|
|
|
|
|
ndev = skb->dev;
|
|
|
|
|
|
|
|
|
|
am65_cpts_tx_timestamp(tx_chn->common->cpts, skb);
|
|
|
|
|
|
|
|
|
|
ndev_priv = netdev_priv(ndev);
|
|
|
|
|
stats = this_cpu_ptr(ndev_priv->stats);
|
|
|
|
|
u64_stats_update_begin(&stats->syncp);
|
|
|
|
|
stats->tx_packets++;
|
|
|
|
|
stats->tx_bytes += skb->len;
|
|
|
|
|
u64_stats_update_end(&stats->syncp);
|
|
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_nuss_tx_wake(struct am65_cpsw_tx_chn *tx_chn, struct net_device *ndev,
|
|
|
|
|
struct netdev_queue *netif_txq)
|
|
|
|
|
{
|
|
|
|
|
if (netif_tx_queue_stopped(netif_txq)) {
|
|
|
|
|
/* Check whether the queue is stopped due to stalled
|
|
|
|
|
* tx dma, if the queue is stopped then wake the queue
|
|
|
|
|
* as we have free desc for tx
|
|
|
|
|
*/
|
|
|
|
|
__netif_tx_lock(netif_txq, smp_processor_id());
|
|
|
|
|
if (netif_running(ndev) &&
|
|
|
|
|
(k3_cppi_desc_pool_avail(tx_chn->desc_pool) >= MAX_SKB_FRAGS))
|
|
|
|
|
netif_tx_wake_queue(netif_txq);
|
|
|
|
|
|
|
|
|
|
__netif_tx_unlock(netif_txq);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
|
|
|
|
|
int chn, unsigned int budget)
|
|
|
|
|
{
|
|
|
|
|
struct cppi5_host_desc_t *desc_tx;
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct am65_cpsw_tx_chn *tx_chn;
|
|
|
|
|
struct netdev_queue *netif_txq;
|
|
|
|
|
@@ -923,41 +970,68 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
dma_addr_t desc_dma;
|
|
|
|
|
int res, num_tx = 0;
|
|
|
|
|
void **swdata;
|
|
|
|
|
|
|
|
|
|
tx_chn = &common->tx_chns[chn];
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
struct am65_cpsw_ndev_priv *ndev_priv;
|
|
|
|
|
struct am65_cpsw_ndev_stats *stats;
|
|
|
|
|
|
|
|
|
|
spin_lock(&tx_chn->lock);
|
|
|
|
|
res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);
|
|
|
|
|
spin_unlock(&tx_chn->lock);
|
|
|
|
|
if (res == -ENODATA)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (desc_dma & 0x1) {
|
|
|
|
|
if (cppi5_desc_is_tdcm(desc_dma)) {
|
|
|
|
|
if (atomic_dec_and_test(&common->tdown_cnt))
|
|
|
|
|
complete(&common->tdown_complete);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
|
|
|
|
|
desc_dma);
|
|
|
|
|
swdata = cppi5_hdesc_get_swdata(desc_tx);
|
|
|
|
|
skb = *(swdata);
|
|
|
|
|
am65_cpsw_nuss_xmit_free(tx_chn, dev, desc_tx);
|
|
|
|
|
skb = am65_cpsw_nuss_tx_compl_packet(tx_chn, desc_dma);
|
|
|
|
|
total_bytes = skb->len;
|
|
|
|
|
ndev = skb->dev;
|
|
|
|
|
napi_consume_skb(skb, budget);
|
|
|
|
|
num_tx++;
|
|
|
|
|
|
|
|
|
|
netif_txq = netdev_get_tx_queue(ndev, chn);
|
|
|
|
|
|
|
|
|
|
netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
|
|
|
|
|
|
|
|
|
|
am65_cpsw_nuss_tx_wake(tx_chn, ndev, netif_txq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(dev, "%s:%u pkt:%d\n", __func__, chn, num_tx);
|
|
|
|
|
|
|
|
|
|
return num_tx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
|
|
|
|
|
int chn, unsigned int budget)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct am65_cpsw_tx_chn *tx_chn;
|
|
|
|
|
struct netdev_queue *netif_txq;
|
|
|
|
|
unsigned int total_bytes = 0;
|
|
|
|
|
struct net_device *ndev;
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
dma_addr_t desc_dma;
|
|
|
|
|
int res, num_tx = 0;
|
|
|
|
|
|
|
|
|
|
tx_chn = &common->tx_chns[chn];
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
res = k3_udma_glue_pop_tx_chn(tx_chn->tx_chn, &desc_dma);
|
|
|
|
|
if (res == -ENODATA)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (cppi5_desc_is_tdcm(desc_dma)) {
|
|
|
|
|
if (atomic_dec_and_test(&common->tdown_cnt))
|
|
|
|
|
complete(&common->tdown_complete);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
skb = am65_cpsw_nuss_tx_compl_packet(tx_chn, desc_dma);
|
|
|
|
|
|
|
|
|
|
ndev = skb->dev;
|
|
|
|
|
|
|
|
|
|
am65_cpts_tx_timestamp(common->cpts, skb);
|
|
|
|
|
|
|
|
|
|
ndev_priv = netdev_priv(ndev);
|
|
|
|
|
stats = this_cpu_ptr(ndev_priv->stats);
|
|
|
|
|
u64_stats_update_begin(&stats->syncp);
|
|
|
|
|
stats->tx_packets++;
|
|
|
|
|
stats->tx_bytes += skb->len;
|
|
|
|
|
u64_stats_update_end(&stats->syncp);
|
|
|
|
|
|
|
|
|
|
total_bytes += skb->len;
|
|
|
|
|
napi_consume_skb(skb, budget);
|
|
|
|
|
num_tx++;
|
|
|
|
|
@@ -970,19 +1044,8 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
|
|
|
|
|
|
|
|
|
|
netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
|
|
|
|
|
|
|
|
|
|
if (netif_tx_queue_stopped(netif_txq)) {
|
|
|
|
|
/* Check whether the queue is stopped due to stalled tx dma,
|
|
|
|
|
* if the queue is stopped then wake the queue as
|
|
|
|
|
* we have free desc for tx
|
|
|
|
|
*/
|
|
|
|
|
__netif_tx_lock(netif_txq, smp_processor_id());
|
|
|
|
|
if (netif_running(ndev) &&
|
|
|
|
|
(k3_cppi_desc_pool_avail(tx_chn->desc_pool) >=
|
|
|
|
|
MAX_SKB_FRAGS))
|
|
|
|
|
netif_tx_wake_queue(netif_txq);
|
|
|
|
|
am65_cpsw_nuss_tx_wake(tx_chn, ndev, netif_txq);
|
|
|
|
|
|
|
|
|
|
__netif_tx_unlock(netif_txq);
|
|
|
|
|
}
|
|
|
|
|
dev_dbg(dev, "%s:%u pkt:%d\n", __func__, chn, num_tx);
|
|
|
|
|
|
|
|
|
|
return num_tx;
|
|
|
|
|
@@ -993,8 +1056,11 @@ static int am65_cpsw_nuss_tx_poll(struct napi_struct *napi_tx, int budget)
|
|
|
|
|
struct am65_cpsw_tx_chn *tx_chn = am65_cpsw_napi_to_tx_chn(napi_tx);
|
|
|
|
|
int num_tx;
|
|
|
|
|
|
|
|
|
|
num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, tx_chn->id,
|
|
|
|
|
budget);
|
|
|
|
|
if (AM65_CPSW_IS_CPSW2G(tx_chn->common))
|
|
|
|
|
num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id, budget);
|
|
|
|
|
else
|
|
|
|
|
num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, tx_chn->id, budget);
|
|
|
|
|
|
|
|
|
|
num_tx = min(num_tx, budget);
|
|
|
|
|
if (num_tx < budget) {
|
|
|
|
|
napi_complete(napi_tx);
|
|
|
|
|
@@ -1139,7 +1205,13 @@ done_tx:
|
|
|
|
|
|
|
|
|
|
cppi5_hdesc_set_pktlen(first_desc, pkt_len);
|
|
|
|
|
desc_dma = k3_cppi_desc_pool_virt2dma(tx_chn->desc_pool, first_desc);
|
|
|
|
|
ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
|
|
|
|
|
if (AM65_CPSW_IS_CPSW2G(common)) {
|
|
|
|
|
ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
|
|
|
|
|
} else {
|
|
|
|
|
spin_lock_bh(&tx_chn->lock);
|
|
|
|
|
ret = k3_udma_glue_push_tx_chn(tx_chn->tx_chn, first_desc, desc_dma);
|
|
|
|
|
spin_unlock_bh(&tx_chn->lock);
|
|
|
|
|
}
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "can't push desc %d\n", ret);
|
|
|
|
|
/* inform bql */
|
|
|
|
|
@@ -1369,32 +1441,7 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev,
|
|
|
|
|
stats->tx_dropped = dev->stats.tx_dropped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_ndo_slave_set_features(struct net_device *ndev,
|
|
|
|
|
netdev_features_t features)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
|
|
|
|
|
netdev_features_t changes = features ^ ndev->features;
|
|
|
|
|
struct am65_cpsw_host *host_p;
|
|
|
|
|
|
|
|
|
|
host_p = am65_common_get_host(common);
|
|
|
|
|
|
|
|
|
|
if (changes & NETIF_F_HW_CSUM) {
|
|
|
|
|
bool enable = !!(features & NETIF_F_HW_CSUM);
|
|
|
|
|
|
|
|
|
|
dev_info(common->dev, "Turn %s tx-checksum-ip-generic\n",
|
|
|
|
|
enable ? "ON" : "OFF");
|
|
|
|
|
if (enable)
|
|
|
|
|
writel(AM65_CPSW_P0_REG_CTL_RX_CHECKSUM_EN,
|
|
|
|
|
host_p->port_base + AM65_CPSW_P0_REG_CTL);
|
|
|
|
|
else
|
|
|
|
|
writel(0,
|
|
|
|
|
host_p->port_base + AM65_CPSW_P0_REG_CTL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct net_device_ops am65_cpsw_nuss_netdev_ops_2g = {
|
|
|
|
|
static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
|
|
|
|
|
.ndo_open = am65_cpsw_nuss_ndo_slave_open,
|
|
|
|
|
.ndo_stop = am65_cpsw_nuss_ndo_slave_stop,
|
|
|
|
|
.ndo_start_xmit = am65_cpsw_nuss_ndo_slave_xmit,
|
|
|
|
|
@@ -1406,7 +1453,6 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops_2g = {
|
|
|
|
|
.ndo_vlan_rx_add_vid = am65_cpsw_nuss_ndo_slave_add_vid,
|
|
|
|
|
.ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid,
|
|
|
|
|
.ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl,
|
|
|
|
|
.ndo_set_features = am65_cpsw_nuss_ndo_slave_set_features,
|
|
|
|
|
.ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -1417,7 +1463,6 @@ static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port)
|
|
|
|
|
if (!port->disabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
common->disabled_ports_mask |= BIT(port->port_id);
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
|
|
|
|
|
|
|
|
|
|
@@ -1496,6 +1541,7 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common)
|
|
|
|
|
snprintf(tx_chn->tx_chn_name,
|
|
|
|
|
sizeof(tx_chn->tx_chn_name), "tx%d", i);
|
|
|
|
|
|
|
|
|
|
spin_lock_init(&tx_chn->lock);
|
|
|
|
|
tx_chn->common = common;
|
|
|
|
|
tx_chn->id = i;
|
|
|
|
|
tx_chn->descs_num = max_desc_num;
|
|
|
|
|
@@ -1515,9 +1561,8 @@ static int am65_cpsw_nuss_init_tx_chns(struct am65_cpsw_common *common)
|
|
|
|
|
tx_chn->tx_chn_name,
|
|
|
|
|
&tx_cfg);
|
|
|
|
|
if (IS_ERR(tx_chn->tx_chn)) {
|
|
|
|
|
ret = PTR_ERR(tx_chn->tx_chn);
|
|
|
|
|
dev_err(dev, "Failed to request tx dma channel %d\n",
|
|
|
|
|
ret);
|
|
|
|
|
ret = dev_err_probe(dev, PTR_ERR(tx_chn->tx_chn),
|
|
|
|
|
"Failed to request tx dma channel\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1588,8 +1633,8 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
|
|
|
|
|
|
|
|
|
rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, "rx", &rx_cfg);
|
|
|
|
|
if (IS_ERR(rx_chn->rx_chn)) {
|
|
|
|
|
ret = PTR_ERR(rx_chn->rx_chn);
|
|
|
|
|
dev_err(dev, "Failed to request rx dma channel %d\n", ret);
|
|
|
|
|
ret = dev_err_probe(dev, PTR_ERR(rx_chn->rx_chn),
|
|
|
|
|
"Failed to request rx dma channel\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1606,7 +1651,6 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
|
|
|
|
};
|
|
|
|
|
struct k3_ring_cfg fdqring_cfg = {
|
|
|
|
|
.elm_size = K3_RINGACC_RING_ELSIZE_8,
|
|
|
|
|
.mode = K3_RINGACC_RING_MODE_MESSAGE,
|
|
|
|
|
.flags = K3_RINGACC_RING_SHARED,
|
|
|
|
|
};
|
|
|
|
|
struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = {
|
|
|
|
|
@@ -1620,6 +1664,7 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
|
|
|
|
|
rx_flow_cfg.ring_rxfdq0_id = fdqring_id;
|
|
|
|
|
rx_flow_cfg.rx_cfg.size = max_desc_num;
|
|
|
|
|
rx_flow_cfg.rxfdq_cfg.size = max_desc_num;
|
|
|
|
|
rx_flow_cfg.rxfdq_cfg.mode = common->pdata.fdqring_mode;
|
|
|
|
|
|
|
|
|
|
ret = k3_udma_glue_rx_flow_init(rx_chn->rx_chn,
|
|
|
|
|
i, &rx_flow_cfg);
|
|
|
|
|
@@ -1725,6 +1770,13 @@ static int am65_cpsw_init_cpts(struct am65_cpsw_common *common)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
common->cpts = cpts;
|
|
|
|
|
/* Forbid PM runtime if CPTS is running.
|
|
|
|
|
* K3 CPSWxG modules may completely lose context during ON->OFF
|
|
|
|
|
* transitions depending on integration.
|
|
|
|
|
* AM65x/J721E MCU CPSW2G: false
|
|
|
|
|
* J721E MAIN_CPSW9G: true
|
|
|
|
|
*/
|
|
|
|
|
pm_runtime_forbid(dev);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -1778,8 +1830,10 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
|
|
|
|
|
return PTR_ERR(port->slave.mac_sl);
|
|
|
|
|
|
|
|
|
|
port->disabled = !of_device_is_available(port_np);
|
|
|
|
|
if (port->disabled)
|
|
|
|
|
if (port->disabled) {
|
|
|
|
|
common->disabled_ports_mask |= BIT(port->port_id);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port->slave.ifphy = devm_of_phy_get(dev, port_np, NULL);
|
|
|
|
|
if (IS_ERR(port->slave.ifphy)) {
|
|
|
|
|
@@ -1795,12 +1849,10 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
|
|
|
|
|
/* get phy/link info */
|
|
|
|
|
if (of_phy_is_fixed_link(port_np)) {
|
|
|
|
|
ret = of_phy_register_fixed_link(port_np);
|
|
|
|
|
if (ret) {
|
|
|
|
|
if (ret != -EPROBE_DEFER)
|
|
|
|
|
dev_err(dev, "%pOF failed to register fixed-link phy: %d\n",
|
|
|
|
|
port_np, ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
if (ret)
|
|
|
|
|
return dev_err_probe(dev, ret,
|
|
|
|
|
"failed to register fixed-link phy %pOF\n",
|
|
|
|
|
port_np);
|
|
|
|
|
port->slave.phy_node = of_node_get(port_np);
|
|
|
|
|
} else {
|
|
|
|
|
port->slave.phy_node =
|
|
|
|
|
@@ -1833,6 +1885,12 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
|
|
|
|
|
}
|
|
|
|
|
of_node_put(node);
|
|
|
|
|
|
|
|
|
|
/* is there at least one ext.port */
|
|
|
|
|
if (!(~common->disabled_ports_mask & GENMASK(common->port_num, 1))) {
|
|
|
|
|
dev_err(dev, "No Ext. port are available\n");
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1843,14 +1901,18 @@ static void am65_cpsw_pcpu_stats_free(void *data)
|
|
|
|
|
free_percpu(stats);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common)
|
|
|
|
|
static int
|
|
|
|
|
am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_ndev_priv *ndev_priv;
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
port = am65_common_get_port(common, 1);
|
|
|
|
|
port = &common->ports[port_idx];
|
|
|
|
|
|
|
|
|
|
if (port->disabled)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* alloc netdev */
|
|
|
|
|
port->ndev = devm_alloc_etherdev_mqs(common->dev,
|
|
|
|
|
@@ -1879,7 +1941,7 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common)
|
|
|
|
|
port->ndev->features = port->ndev->hw_features |
|
|
|
|
|
NETIF_F_HW_VLAN_CTAG_FILTER;
|
|
|
|
|
port->ndev->vlan_features |= NETIF_F_SG;
|
|
|
|
|
port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops_2g;
|
|
|
|
|
port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops;
|
|
|
|
|
port->ndev->ethtool_ops = &am65_cpsw_ethtool_ops_slave;
|
|
|
|
|
|
|
|
|
|
/* Disable TX checksum offload by default due to HW bug */
|
|
|
|
|
@@ -1892,29 +1954,41 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common)
|
|
|
|
|
|
|
|
|
|
ret = devm_add_action_or_reset(dev, am65_cpsw_pcpu_stats_free,
|
|
|
|
|
ndev_priv->stats);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "Failed to add percpu stat free action %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "failed to add percpu stat free action %d\n", ret);
|
|
|
|
|
|
|
|
|
|
if (!common->dma_ndev)
|
|
|
|
|
common->dma_ndev = port->ndev;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_init_ndevs(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->port_num; i++) {
|
|
|
|
|
ret = am65_cpsw_nuss_init_port_ndev(common, i);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
netif_napi_add(port->ndev, &common->napi_rx,
|
|
|
|
|
netif_napi_add(common->dma_ndev, &common->napi_rx,
|
|
|
|
|
am65_cpsw_nuss_rx_poll, NAPI_POLL_WEIGHT);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_ndev_add_napi_2g(struct am65_cpsw_common *common)
|
|
|
|
|
static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int i, ret = 0;
|
|
|
|
|
|
|
|
|
|
port = am65_common_get_port(common, 1);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->tx_ch_num; i++) {
|
|
|
|
|
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
|
|
|
|
|
|
|
|
|
|
netif_tx_napi_add(port->ndev, &tx_chn->napi_tx,
|
|
|
|
|
netif_tx_napi_add(common->dma_ndev, &tx_chn->napi_tx,
|
|
|
|
|
am65_cpsw_nuss_tx_poll, NAPI_POLL_WEIGHT);
|
|
|
|
|
|
|
|
|
|
ret = devm_request_irq(dev, tx_chn->irq,
|
|
|
|
|
@@ -1932,16 +2006,27 @@ err:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_ndev_reg_2g(struct am65_cpsw_common *common)
|
|
|
|
|
static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->port_num; i++) {
|
|
|
|
|
port = &common->ports[i];
|
|
|
|
|
if (port->ndev)
|
|
|
|
|
unregister_netdev(port->ndev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int ret = 0, i;
|
|
|
|
|
|
|
|
|
|
port = am65_common_get_port(common, 1);
|
|
|
|
|
ret = am65_cpsw_nuss_ndev_add_napi_2g(common);
|
|
|
|
|
ret = am65_cpsw_nuss_ndev_add_tx_napi(common);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err;
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = devm_request_irq(dev, common->rx_chns.irq,
|
|
|
|
|
am65_cpsw_nuss_rx_irq,
|
|
|
|
|
@@ -1949,17 +2034,31 @@ static int am65_cpsw_nuss_ndev_reg_2g(struct am65_cpsw_common *common)
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "failure requesting rx irq %u, %d\n",
|
|
|
|
|
common->rx_chns.irq, ret);
|
|
|
|
|
goto err;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->port_num; i++) {
|
|
|
|
|
port = &common->ports[i];
|
|
|
|
|
|
|
|
|
|
if (!port->ndev)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ret = register_netdev(port->ndev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "error registering slave net device%i %d\n",
|
|
|
|
|
i, ret);
|
|
|
|
|
goto err_cleanup_ndev;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = register_netdev(port->ndev);
|
|
|
|
|
if (ret)
|
|
|
|
|
dev_err(dev, "error registering slave net device %d\n", ret);
|
|
|
|
|
|
|
|
|
|
/* can't auto unregister ndev using devm_add_action() due to
|
|
|
|
|
* devres release sequence in DD core for DMA
|
|
|
|
|
*/
|
|
|
|
|
err:
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
err_cleanup_ndev:
|
|
|
|
|
am65_cpsw_nuss_cleanup_ndev(common);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1972,19 +2071,7 @@ int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx)
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return am65_cpsw_nuss_ndev_add_napi_2g(common);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->port_num; i++) {
|
|
|
|
|
port = &common->ports[i];
|
|
|
|
|
if (port->ndev)
|
|
|
|
|
unregister_netdev(port->ndev);
|
|
|
|
|
}
|
|
|
|
|
return am65_cpsw_nuss_ndev_add_tx_napi(common);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct am65_cpsw_soc_pdata {
|
|
|
|
|
@@ -2005,10 +2092,14 @@ static const struct soc_device_attribute am65_cpsw_socinfo[] = {
|
|
|
|
|
|
|
|
|
|
static const struct am65_cpsw_pdata am65x_sr1_0 = {
|
|
|
|
|
.quirks = AM65_CPSW_QUIRK_I2027_NO_TX_CSUM,
|
|
|
|
|
.ale_dev_id = "am65x-cpsw2g",
|
|
|
|
|
.fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct am65_cpsw_pdata j721e_pdata = {
|
|
|
|
|
.quirks = 0,
|
|
|
|
|
.ale_dev_id = "am65x-cpsw2g",
|
|
|
|
|
.fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct of_device_id am65_cpsw_nuss_of_mtable[] = {
|
|
|
|
|
@@ -2068,9 +2159,6 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
of_node_put(node);
|
|
|
|
|
|
|
|
|
|
if (common->port_num != 1)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
common->rx_flow_id_base = -1;
|
|
|
|
|
init_completion(&common->tdown_complete);
|
|
|
|
|
common->tx_ch_num = 1;
|
|
|
|
|
@@ -2089,13 +2177,8 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
clk = devm_clk_get(dev, "fck");
|
|
|
|
|
if (IS_ERR(clk)) {
|
|
|
|
|
ret = PTR_ERR(clk);
|
|
|
|
|
|
|
|
|
|
if (ret != -EPROBE_DEFER)
|
|
|
|
|
dev_err(dev, "error getting fck clock %d\n", ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
if (IS_ERR(clk))
|
|
|
|
|
return dev_err_probe(dev, PTR_ERR(clk), "getting fck clock\n");
|
|
|
|
|
common->bus_freq = clk_get_rate(clk);
|
|
|
|
|
|
|
|
|
|
pm_runtime_enable(dev);
|
|
|
|
|
@@ -2145,7 +2228,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
ale_params.ale_ageout = AM65_CPSW_ALE_AGEOUT_DEFAULT;
|
|
|
|
|
ale_params.ale_ports = common->port_num + 1;
|
|
|
|
|
ale_params.ale_regs = common->cpsw_base + AM65_CPSW_NU_ALE_BASE;
|
|
|
|
|
ale_params.dev_id = "am65x-cpsw2g";
|
|
|
|
|
ale_params.dev_id = common->pdata.ale_dev_id;
|
|
|
|
|
ale_params.bus_freq = common->bus_freq;
|
|
|
|
|
|
|
|
|
|
common->ale = cpsw_ale_create(&ale_params);
|
|
|
|
|
@@ -2165,11 +2248,11 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
dev_set_drvdata(dev, common);
|
|
|
|
|
|
|
|
|
|
ret = am65_cpsw_nuss_init_ndev_2g(common);
|
|
|
|
|
ret = am65_cpsw_nuss_init_ndevs(common);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err_of_clear;
|
|
|
|
|
|
|
|
|
|
ret = am65_cpsw_nuss_ndev_reg_2g(common);
|
|
|
|
|
ret = am65_cpsw_nuss_register_ndevs(common);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err_of_clear;
|
|
|
|
|
|
|
|
|
|
|