diff options
Diffstat (limited to 'drivers/net/ethernet/ti')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 201 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 180 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.h | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/davinci_cpdma.c | 164 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/davinci_cpdma.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/davinci_emac.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/netcp.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/netcp_core.c | 104 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/netcp_ethss.c | 25 |
9 files changed, 520 insertions, 199 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b203143647e6..9f3d9c67e3fe 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -145,6 +145,7 @@ do { \ cpsw->data.active_slave) #define IRQ_NUM 2 #define CPSW_MAX_QUEUES 8 +#define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256 static int debug_level; module_param(debug_level, int, 0); @@ -158,6 +159,10 @@ static int rx_packet_max = CPSW_MAX_PACKET_SIZE; module_param(rx_packet_max, int, 0); MODULE_PARM_DESC(rx_packet_max, "maximum receive packet size (bytes)"); +static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT; +module_param(descs_pool_size, int, 0444); +MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool"); + struct cpsw_wr_regs { u32 id_ver; u32 soft_reset; @@ -352,7 +357,6 @@ struct cpsw_slave { struct phy_device *phy; struct net_device *ndev; u32 port_vlan; - u32 open_stat; }; static inline u32 slave_read(struct cpsw_slave *slave, u32 offset) @@ -395,6 +399,7 @@ struct cpsw_common { struct cpts *cpts; int rx_ch_num, tx_ch_num; int speed; + int usage_count; }; struct cpsw_priv { @@ -699,18 +704,9 @@ static void cpsw_rx_handler(void *token, int len, int status) cpsw_dual_emac_src_port_detect(cpsw, status, ndev, skb); if (unlikely(status < 0) || unlikely(!netif_running(ndev))) { - bool ndev_status = false; - struct cpsw_slave *slave = cpsw->slaves; - int n; - - if (cpsw->data.dual_emac) { - /* In dual emac mode check for all interfaces */ - for (n = cpsw->data.slaves; n; n--, slave++) - if (netif_running(slave->ndev)) - ndev_status = true; - } - - if (ndev_status && (status >= 0)) { + /* In dual emac mode check for all interfaces */ + if (cpsw->data.dual_emac && cpsw->usage_count && + (status >= 0)) { /* The packet received is for the interface which * is already down and the other interface is up * and running, instead of freeing which results @@ -934,7 +930,7 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) } if (num_rx < budget) { - napi_complete(napi_rx); + napi_complete_done(napi_rx, num_rx); writel(0xff, &cpsw->wr_regs->rx_en); if (cpsw->quirk_irq && cpsw->rx_irq_disabled) { cpsw->rx_irq_disabled = false; @@ -1230,21 +1226,6 @@ static void cpsw_get_ethtool_stats(struct net_device *ndev, } } -static int cpsw_common_res_usage_state(struct cpsw_common *cpsw) -{ - u32 i; - u32 usage_count = 0; - - if (!cpsw->data.dual_emac) - return 0; - - for (i = 0; i < cpsw->data.slaves; i++) - if (cpsw->slaves[i].open_stat) - usage_count++; - - return usage_count; -} - static inline int cpsw_tx_packet_submit(struct cpsw_priv *priv, struct sk_buff *skb, struct cpdma_chan *txch) @@ -1478,8 +1459,6 @@ static int cpsw_ndo_open(struct net_device *ndev) return ret; } - if (!cpsw_common_res_usage_state(cpsw)) - cpsw_intr_disable(cpsw); netif_carrier_off(ndev); /* Notify the stack of the actual queue counts. */ @@ -1501,8 +1480,8 @@ static int cpsw_ndo_open(struct net_device *ndev) CPSW_MAJOR_VERSION(reg), CPSW_MINOR_VERSION(reg), CPSW_RTL_VERSION(reg)); - /* initialize host and slave ports */ - if (!cpsw_common_res_usage_state(cpsw)) + /* Initialize host and slave ports */ + if (!cpsw->usage_count) cpsw_init_host_port(priv); for_each_slave(priv, cpsw_slave_open, priv); @@ -1513,7 +1492,8 @@ static int cpsw_ndo_open(struct net_device *ndev) cpsw_ale_add_vlan(cpsw->ale, cpsw->data.default_vlan, ALE_ALL_PORTS, ALE_ALL_PORTS, 0, 0); - if (!cpsw_common_res_usage_state(cpsw)) { + /* initialize shared resources for every ndev */ + if (!cpsw->usage_count) { /* disable priority elevation */ __raw_writel(0, &cpsw->regs->ptype); @@ -1555,9 +1535,7 @@ static int cpsw_ndo_open(struct net_device *ndev) cpdma_ctlr_start(cpsw->dma); cpsw_intr_enable(cpsw); - - if (cpsw->data.dual_emac) - cpsw->slaves[priv->emac_port].open_stat = true; + cpsw->usage_count++; return 0; @@ -1578,7 +1556,7 @@ static int cpsw_ndo_stop(struct net_device *ndev) netif_tx_stop_all_queues(priv->ndev); netif_carrier_off(priv->ndev); - if (cpsw_common_res_usage_state(cpsw) <= 1) { + if (cpsw->usage_count <= 1) { napi_disable(&cpsw->napi_rx); napi_disable(&cpsw->napi_tx); cpts_unregister(cpsw->cpts); @@ -1591,9 +1569,8 @@ static int cpsw_ndo_stop(struct net_device *ndev) if (cpsw_need_resplit(cpsw)) cpsw_split_res(ndev); + cpsw->usage_count--; pm_runtime_put_sync(cpsw->dev); - if (cpsw->data.dual_emac) - cpsw->slaves[priv->emac_port].open_stat = false; return 0; } @@ -1606,12 +1583,10 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, struct cpdma_chan *txch; int ret, q_idx; - netif_trans_update(ndev); - if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) { cpsw_err(priv, tx_err, "packet pad failed\n"); ndev->stats.tx_dropped++; - return NETDEV_TX_OK; + return NET_XMIT_DROP; } if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && @@ -2363,17 +2338,11 @@ static int cpsw_update_channels(struct cpsw_priv *priv, return 0; } -static int cpsw_set_channels(struct net_device *ndev, - struct ethtool_channels *chs) +static void cpsw_suspend_data_pass(struct net_device *ndev) { - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); struct cpsw_slave *slave; - int i, ret; - - ret = cpsw_check_ch_settings(cpsw, chs); - if (ret < 0) - return ret; + int i; /* Disable NAPI scheduling */ cpsw_intr_disable(cpsw); @@ -2391,6 +2360,51 @@ static int cpsw_set_channels(struct net_device *ndev, /* Handle rest of tx packets and stop cpdma channels */ cpdma_ctlr_stop(cpsw->dma); +} + +static int cpsw_resume_data_pass(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + int i, ret; + + /* Allow rx packets handling */ + for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++) + if (slave->ndev && netif_running(slave->ndev)) + netif_dormant_off(slave->ndev); + + /* After this receive is started */ + if (cpsw->usage_count) { + ret = cpsw_fill_rx_channels(priv); + if (ret) + return ret; + + cpdma_ctlr_start(cpsw->dma); + cpsw_intr_enable(cpsw); + } + + /* Resume transmit for every affected interface */ + for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++) + if (slave->ndev && netif_running(slave->ndev)) + netif_tx_start_all_queues(slave->ndev); + + return 0; +} + +static int cpsw_set_channels(struct net_device *ndev, + struct ethtool_channels *chs) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + int i, ret; + + ret = cpsw_check_ch_settings(cpsw, chs); + if (ret < 0) + return ret; + + cpsw_suspend_data_pass(ndev); ret = cpsw_update_channels(priv, chs); if (ret) goto err; @@ -2413,30 +2427,14 @@ static int cpsw_set_channels(struct net_device *ndev, dev_err(priv->dev, "cannot set real number of rx queues\n"); goto err; } - - /* Enable rx packets handling */ - netif_dormant_off(slave->ndev); } - if (cpsw_common_res_usage_state(cpsw)) { - ret = cpsw_fill_rx_channels(priv); - if (ret) - goto err; - + if (cpsw->usage_count) cpsw_split_res(ndev); - /* After this receive is started */ - cpdma_ctlr_start(cpsw->dma); - cpsw_intr_enable(cpsw); - } - - /* Resume transmit for every affected interface */ - for (i = cpsw->data.slaves, slave = cpsw->slaves; i; i--, slave++) { - if (!(slave->ndev && netif_running(slave->ndev))) - continue; - netif_tx_start_all_queues(slave->ndev); - } - return 0; + ret = cpsw_resume_data_pass(ndev); + if (!ret) + return 0; err: dev_err(priv->dev, "cannot update channels number, closing device\n"); dev_close(ndev); @@ -2479,6 +2477,52 @@ static int cpsw_nway_reset(struct net_device *ndev) return -EOPNOTSUPP; } +static void cpsw_get_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + /* not supported */ + ering->tx_max_pending = 0; + ering->tx_pending = cpdma_get_num_tx_descs(cpsw->dma); + ering->rx_max_pending = descs_pool_size - CPSW_MAX_QUEUES; + ering->rx_pending = cpdma_get_num_rx_descs(cpsw->dma); +} + +static int cpsw_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ering) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ret; + + /* ignore ering->tx_pending - only rx_pending adjustment is supported */ + + if (ering->rx_mini_pending || ering->rx_jumbo_pending || + ering->rx_pending < CPSW_MAX_QUEUES || + ering->rx_pending > (descs_pool_size - CPSW_MAX_QUEUES)) + return -EINVAL; + + if (ering->rx_pending == cpdma_get_num_rx_descs(cpsw->dma)) + return 0; + + cpsw_suspend_data_pass(ndev); + + cpdma_set_num_rx_descs(cpsw->dma, ering->rx_pending); + + if (cpsw->usage_count) + cpdma_chan_split_pool(cpsw->dma); + + ret = cpsw_resume_data_pass(ndev); + if (!ret) + return 0; + + dev_err(&ndev->dev, "cannot set ring params, closing device\n"); + dev_close(ndev); + return ret; +} + static const struct ethtool_ops cpsw_ethtool_ops = { .get_drvinfo = cpsw_get_drvinfo, .get_msglevel = cpsw_get_msglevel, @@ -2505,6 +2549,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = { .get_eee = cpsw_get_eee, .set_eee = cpsw_set_eee, .nway_reset = cpsw_nway_reset, + .get_ringparam = cpsw_get_ringparam, + .set_ringparam = cpsw_set_ringparam, }; static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_common *cpsw, @@ -2969,6 +3015,7 @@ static int cpsw_probe(struct platform_device *pdev) dma_params.has_ext_regs = true; dma_params.desc_hw_addr = dma_params.desc_mem_phys; dma_params.bus_freq_mhz = cpsw->bus_freq_mhz; + dma_params.descs_pool_size = descs_pool_size; cpsw->dma = cpdma_ctlr_create(&dma_params); if (!cpsw->dma) { @@ -2985,7 +3032,7 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_dma_ret; } - ale_params.dev = &ndev->dev; + ale_params.dev = &pdev->dev; ale_params.ale_ageout = ale_ageout; ale_params.ale_entries = data->ale_entries; ale_params.ale_ports = data->slaves; @@ -3072,9 +3119,9 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_ale_ret; } - cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n", - &ss_res->start, ndev->irq); - + cpsw_notice(priv, probe, + "initialized device (regs %pa, irq %d, pool size %d)\n", + &ss_res->start, ndev->irq, dma_params.descs_pool_size); if (cpsw->data.dual_emac) { ret = cpsw_probe_dual_emac(priv); if (ret) { @@ -3160,7 +3207,7 @@ static int cpsw_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = platform_get_drvdata(pdev); - struct cpsw_common *cpsw = netdev_priv(ndev); + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); /* Select default pin state */ pinctrl_pm_select_default_state(dev); diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 43b061bd8e07..ddd43e09111e 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -1,5 +1,5 @@ /* - * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine + * Texas Instruments N-Port Ethernet Switch Address Lookup Engine * * Copyright (C) 2012 Texas Instruments * @@ -27,11 +27,14 @@ #define BITMASK(bits) (BIT(bits) - 1) -#define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff) +#define ALE_VERSION_MAJOR(rev, mask) (((rev) >> 8) & (mask)) #define ALE_VERSION_MINOR(rev) (rev & 0xff) +#define ALE_VERSION_1R3 0x0103 +#define ALE_VERSION_1R4 0x0104 /* ALE Registers */ #define ALE_IDVER 0x00 +#define ALE_STATUS 0x04 #define ALE_CONTROL 0x08 #define ALE_PRESCALE 0x10 #define ALE_UNKNOWNVLAN 0x18 @@ -39,6 +42,13 @@ #define ALE_TABLE 0x34 #define ALE_PORTCTL 0x40 +/* ALE NetCP NU switch specific Registers */ +#define ALE_UNKNOWNVLAN_MEMBER 0x90 +#define ALE_UNKNOWNVLAN_UNREG_MCAST_FLOOD 0x94 +#define ALE_UNKNOWNVLAN_REG_MCAST_FLOOD 0x98 +#define ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS 0x9C +#define ALE_VLAN_MASK_MUX(reg) (0xc0 + (0x4 * (reg))) + #define ALE_TABLE_WRITE BIT(31) #define ALE_TYPE_FREE 0 @@ -51,6 +61,10 @@ #define ALE_UCAST_OUI 2 #define ALE_UCAST_TOUCHED 3 +#define ALE_TABLE_SIZE_MULTIPLIER 1024 +#define ALE_STATUS_SIZE_MASK 0x1f +#define ALE_TABLE_SIZE_DEFAULT 64 + static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) { int idx; @@ -84,20 +98,34 @@ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } +#define DEFINE_ALE_FIELD1(name, start) \ +static inline int cpsw_ale_get_##name(u32 *ale_entry, u32 bits) \ +{ \ + return cpsw_ale_get_field(ale_entry, start, bits); \ +} \ +static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value, \ + u32 bits) \ +{ \ + cpsw_ale_set_field(ale_entry, start, bits, value); \ +} + DEFINE_ALE_FIELD(entry_type, 60, 2) DEFINE_ALE_FIELD(vlan_id, 48, 12) DEFINE_ALE_FIELD(mcast_state, 62, 2) -DEFINE_ALE_FIELD(port_mask, 66, 3) +DEFINE_ALE_FIELD1(port_mask, 66) DEFINE_ALE_FIELD(super, 65, 1) DEFINE_ALE_FIELD(ucast_type, 62, 2) -DEFINE_ALE_FIELD(port_num, 66, 2) +DEFINE_ALE_FIELD1(port_num, 66) DEFINE_ALE_FIELD(blocked, 65, 1) DEFINE_ALE_FIELD(secure, 64, 1) -DEFINE_ALE_FIELD(vlan_untag_force, 24, 3) -DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3) -DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3) -DEFINE_ALE_FIELD(vlan_member_list, 0, 3) +DEFINE_ALE_FIELD1(vlan_untag_force, 24) +DEFINE_ALE_FIELD1(vlan_reg_mcast, 16) +DEFINE_ALE_FIELD1(vlan_unreg_mcast, 8) +DEFINE_ALE_FIELD1(vlan_member_list, 0) DEFINE_ALE_FIELD(mcast, 40, 1) +/* ALE NetCP nu switch specific */ +DEFINE_ALE_FIELD(vlan_unreg_mcast_idx, 20, 3) +DEFINE_ALE_FIELD(vlan_reg_mcast_idx, 44, 3) /* The MAC address field in the ALE entry cannot be macroized as above */ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) @@ -223,14 +251,16 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, { int mask; - mask = cpsw_ale_get_port_mask(ale_entry); + mask = cpsw_ale_get_port_mask(ale_entry, + ale->port_mask_bits); if ((mask & port_mask) == 0) return; /* ports dont intersect, not interested */ mask &= ~port_mask; /* free if only remaining port is host port */ if (mask) - cpsw_ale_set_port_mask(ale_entry, mask); + cpsw_ale_set_port_mask(ale_entry, mask, + ale->port_mask_bits); else cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); } @@ -291,7 +321,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); - cpsw_ale_set_port_num(ale_entry, port); + cpsw_ale_set_port_num(ale_entry, port, ale->port_num_bits); idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); if (idx < 0) @@ -338,9 +368,11 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); cpsw_ale_set_mcast_state(ale_entry, mcast_state); - mask = cpsw_ale_get_port_mask(ale_entry); + mask = cpsw_ale_get_port_mask(ale_entry, + ale->port_mask_bits); port_mask |= mask; - cpsw_ale_set_port_mask(ale_entry, port_mask); + cpsw_ale_set_port_mask(ale_entry, port_mask, + ale->port_mask_bits); if (idx < 0) idx = cpsw_ale_match_free(ale); @@ -367,7 +399,8 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, cpsw_ale_read(ale, idx, ale_entry); if (port_mask) - cpsw_ale_set_port_mask(ale_entry, port_mask); + cpsw_ale_set_port_mask(ale_entry, port_mask, + ale->port_mask_bits); else cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); @@ -376,6 +409,21 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, } EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); +/* ALE NetCP NU switch specific vlan functions */ +static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, + int reg_mcast, int unreg_mcast) +{ + int idx; + + /* Set VLAN registered multicast flood mask */ + idx = cpsw_ale_get_vlan_reg_mcast_idx(ale_entry); + writel(reg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); + + /* Set VLAN unregistered multicast flood mask */ + idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry); + writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); +} + int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) { @@ -389,10 +437,16 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); cpsw_ale_set_vlan_id(ale_entry, vid); - cpsw_ale_set_vlan_untag_force(ale_entry, untag); - cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast); - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); - cpsw_ale_set_vlan_member_list(ale_entry, port); + cpsw_ale_set_vlan_untag_force(ale_entry, untag, ale->vlan_field_bits); + if (!ale->params.nu_switch_ale) { + cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, + ale->vlan_field_bits); + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, + ale->vlan_field_bits); + } else { + cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast); + } + cpsw_ale_set_vlan_member_list(ale_entry, port, ale->vlan_field_bits); if (idx < 0) idx = cpsw_ale_match_free(ale); @@ -418,7 +472,8 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) cpsw_ale_read(ale, idx, ale_entry); if (port_mask) - cpsw_ale_set_vlan_member_list(ale_entry, port_mask); + cpsw_ale_set_vlan_member_list(ale_entry, port_mask, + ale->vlan_field_bits); else cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); @@ -446,12 +501,15 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) if (type != ALE_TYPE_VLAN) continue; - unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry); + unreg_mcast = + cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); if (allmulti) unreg_mcast |= 1; else unreg_mcast &= ~1; - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, + ale->vlan_field_bits); cpsw_ale_write(ale, idx, ale_entry); } } @@ -464,7 +522,7 @@ struct ale_control_info { int bits; }; -static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { +static struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = { [ALE_ENABLE] = { .name = "enable", .offset = ALE_CONTROL, @@ -721,11 +779,83 @@ static void cpsw_ale_timer(unsigned long arg) void cpsw_ale_start(struct cpsw_ale *ale) { - u32 rev; + u32 rev, ale_entries; rev = __raw_readl(ale->params.ale_regs + ALE_IDVER); - dev_dbg(ale->params.dev, "initialized cpsw ale revision %d.%d\n", - ALE_VERSION_MAJOR(rev), ALE_VERSION_MINOR(rev)); + if (!ale->params.major_ver_mask) + ale->params.major_ver_mask = 0xff; + ale->version = + (ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) | + ALE_VERSION_MINOR(rev); + dev_info(ale->params.dev, "initialized cpsw ale version %d.%d\n", + ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask), + ALE_VERSION_MINOR(rev)); + + if (!ale->params.ale_entries) { + ale_entries = + __raw_readl(ale->params.ale_regs + ALE_STATUS) & + ALE_STATUS_SIZE_MASK; + /* ALE available on newer NetCP switches has introduced + * a register, ALE_STATUS, to indicate the size of ALE + * table which shows the size as a multiple of 1024 entries. + * For these, params.ale_entries will be set to zero. So + * read the register and update the value of ale_entries. + * ALE table on NetCP lite, is much smaller and is indicated + * by a value of zero in ALE_STATUS. So use a default value + * of ALE_TABLE_SIZE_DEFAULT for this. Caller is expected + * to set the value of ale_entries for all other versions + * of ALE. + */ + if (!ale_entries) + ale_entries = ALE_TABLE_SIZE_DEFAULT; + else + ale_entries *= ALE_TABLE_SIZE_MULTIPLIER; + ale->params.ale_entries = ale_entries; + } + dev_info(ale->params.dev, + "ALE Table size %ld\n", ale->params.ale_entries); + + /* set default bits for existing h/w */ + ale->port_mask_bits = 3; + ale->port_num_bits = 2; + ale->vlan_field_bits = 3; + + /* Set defaults override for ALE on NetCP NU switch and for version + * 1R3 + */ + if (ale->params.nu_switch_ale) { + /* Separate registers for unknown vlan configuration. + * Also there are N bits, where N is number of ale + * ports and shift value should be 0 + */ + ale_controls[ALE_PORT_UNKNOWN_VLAN_MEMBER].bits = + ale->params.ale_ports; + ale_controls[ALE_PORT_UNKNOWN_VLAN_MEMBER].offset = + ALE_UNKNOWNVLAN_MEMBER; + ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].bits = + ale->params.ale_ports; + ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].shift = 0; + ale_controls[ALE_PORT_UNKNOWN_MCAST_FLOOD].offset = + ALE_UNKNOWNVLAN_UNREG_MCAST_FLOOD; + ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].bits = + ale->params.ale_ports; + ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].shift = 0; + ale_controls[ALE_PORT_UNKNOWN_REG_MCAST_FLOOD].offset = + ALE_UNKNOWNVLAN_REG_MCAST_FLOOD; + ale_controls[ALE_PORT_UNTAGGED_EGRESS].bits = + ale->params.ale_ports; + ale_controls[ALE_PORT_UNTAGGED_EGRESS].shift = 0; + ale_controls[ALE_PORT_UNTAGGED_EGRESS].offset = + ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS; + ale->port_mask_bits = ale->params.ale_ports; + ale->port_num_bits = ale->params.ale_ports - 1; + ale->vlan_field_bits = ale->params.ale_ports; + } else if (ale->version == ALE_VERSION_1R3) { + ale->port_mask_bits = ale->params.ale_ports; + ale->port_num_bits = 3; + ale->vlan_field_bits = ale->params.ale_ports; + } + cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index a7001894f3da..25d24e8d0904 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -1,5 +1,5 @@ /* - * Texas Instruments 3-Port Ethernet Switch Address Lookup Engine APIs + * Texas Instruments N-Port Ethernet Switch Address Lookup Engine APIs * * Copyright (C) 2012 Texas Instruments * @@ -21,6 +21,16 @@ struct cpsw_ale_params { unsigned long ale_ageout; /* in secs */ unsigned long ale_entries; unsigned long ale_ports; + /* NU Switch has specific handling as number of bits in ALE entries + * are different than other versions of ALE. Also there are specific + * registers for unknown vlan specific fields. So use nu_switch_ale + * to identify this hardware. + */ + bool nu_switch_ale; + /* mask bit used in NU Switch ALE is 3 bits instead of 8 bits. So + * pass it from caller. + */ + u32 major_ver_mask; }; struct cpsw_ale { @@ -28,6 +38,11 @@ struct cpsw_ale { struct timer_list timer; unsigned long ageout; int allmulti; + u32 version; + /* These bits are different on NetCP NU Switch ALE */ + u32 port_mask_bits; + u32 port_num_bits; + u32 vlan_field_bits; }; enum cpsw_ale_control { diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index 36518fc5c7cc..7ecc6b70e7e8 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -108,6 +108,8 @@ struct cpdma_ctlr { spinlock_t lock; struct cpdma_chan *channels[2 * CPDMA_MAX_CHANNELS]; int chan_num; + int num_rx_desc; /* RX descriptors number */ + int num_tx_desc; /* TX descriptors number */ }; struct cpdma_chan { @@ -166,12 +168,12 @@ static struct cpdma_control_info controls[] = { #define num_chan params.num_chan /* various accessors */ -#define dma_reg_read(ctlr, ofs) __raw_readl((ctlr)->dmaregs + (ofs)) -#define chan_read(chan, fld) __raw_readl((chan)->fld) -#define desc_read(desc, fld) __raw_readl(&(desc)->fld) -#define dma_reg_write(ctlr, ofs, v) __raw_writel(v, (ctlr)->dmaregs + (ofs)) -#define chan_write(chan, fld, v) __raw_writel(v, (chan)->fld) -#define desc_write(desc, fld, v) __raw_writel((u32)(v), &(desc)->fld) +#define dma_reg_read(ctlr, ofs) readl((ctlr)->dmaregs + (ofs)) +#define chan_read(chan, fld) readl((chan)->fld) +#define desc_read(desc, fld) readl(&(desc)->fld) +#define dma_reg_write(ctlr, ofs, v) writel(v, (ctlr)->dmaregs + (ofs)) +#define chan_write(chan, fld, v) writel(v, (chan)->fld) +#define desc_write(desc, fld, v) writel((u32)(v), &(desc)->fld) #define cpdma_desc_to_port(chan, mode, directed) \ do { \ @@ -181,8 +183,10 @@ static struct cpdma_control_info controls[] = { (directed << CPDMA_TO_PORT_SHIFT)); \ } while (0) -static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool) +static void cpdma_desc_pool_destroy(struct cpdma_ctlr *ctlr) { + struct cpdma_desc_pool *pool = ctlr->pool; + if (!pool) return; @@ -191,10 +195,8 @@ static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool) gen_pool_size(pool->gen_pool), gen_pool_avail(pool->gen_pool)); if (pool->cpumap) - dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap, + dma_free_coherent(ctlr->dev, pool->mem_size, pool->cpumap, pool->phys); - else - iounmap(pool->iomap); } /* @@ -203,37 +205,50 @@ static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool) * devices (e.g. cpsw switches) use plain old memory. Descriptor pools * abstract out these details */ -static struct cpdma_desc_pool * -cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr, - int size, int align) +int cpdma_desc_pool_create(struct cpdma_ctlr *ctlr) { + struct cpdma_params *cpdma_params = &ctlr->params; struct cpdma_desc_pool *pool; - int ret; + int ret = -ENOMEM; - pool = devm_kzalloc(dev, sizeof(*pool), GFP_KERNEL); + pool = devm_kzalloc(ctlr->dev, sizeof(*pool), GFP_KERNEL); if (!pool) goto gen_pool_create_fail; + ctlr->pool = pool; + + pool->mem_size = cpdma_params->desc_mem_size; + pool->desc_size = ALIGN(sizeof(struct cpdma_desc), + cpdma_params->desc_align); + pool->num_desc = pool->mem_size / pool->desc_size; + + if (cpdma_params->descs_pool_size) { + /* recalculate memory size required cpdma descriptor pool + * basing on number of descriptors specified by user and + * if memory size > CPPI internal RAM size (desc_mem_size) + * then switch to use DDR + */ + pool->num_desc = cpdma_params->descs_pool_size; + pool->mem_size = pool->desc_size * pool->num_desc; + if (pool->mem_size > cpdma_params->desc_mem_size) + cpdma_params->desc_mem_phys = 0; + } - pool->dev = dev; - pool->mem_size = size; - pool->desc_size = ALIGN(sizeof(struct cpdma_desc), align); - pool->num_desc = size / pool->desc_size; - - pool->gen_pool = devm_gen_pool_create(dev, ilog2(pool->desc_size), -1, - "cpdma"); + pool->gen_pool = devm_gen_pool_create(ctlr->dev, ilog2(pool->desc_size), + -1, "cpdma"); if (IS_ERR(pool->gen_pool)) { - dev_err(dev, "pool create failed %ld\n", - PTR_ERR(pool->gen_pool)); + ret = PTR_ERR(pool->gen_pool); + dev_err(ctlr->dev, "pool create failed %d\n", ret); goto gen_pool_create_fail; } - if (phys) { - pool->phys = phys; - pool->iomap = ioremap(phys, size); /* should be memremap? */ - pool->hw_addr = hw_addr; + if (cpdma_params->desc_mem_phys) { + pool->phys = cpdma_params->desc_mem_phys; + pool->iomap = devm_ioremap(ctlr->dev, pool->phys, + pool->mem_size); + pool->hw_addr = cpdma_params->desc_hw_addr; } else { - pool->cpumap = dma_alloc_coherent(dev, size, &pool->hw_addr, - GFP_KERNEL); + pool->cpumap = dma_alloc_coherent(ctlr->dev, pool->mem_size, + &pool->hw_addr, GFP_KERNEL); pool->iomap = (void __iomem __force *)pool->cpumap; pool->phys = pool->hw_addr; /* assumes no IOMMU, don't use this value */ } @@ -244,16 +259,17 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, dma_addr_t hw_addr, ret = gen_pool_add_virt(pool->gen_pool, (unsigned long)pool->iomap, pool->phys, pool->mem_size, -1); if (ret < 0) { - dev_err(dev, "pool add failed %d\n", ret); + dev_err(ctlr->dev, "pool add failed %d\n", ret); goto gen_pool_add_virt_fail; } - return pool; + return 0; gen_pool_add_virt_fail: - cpdma_desc_pool_destroy(pool); + cpdma_desc_pool_destroy(ctlr); gen_pool_create_fail: - return NULL; + ctlr->pool = NULL; + return ret; } static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, @@ -502,13 +518,11 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) ctlr->chan_num = 0; spin_lock_init(&ctlr->lock); - ctlr->pool = cpdma_desc_pool_create(ctlr->dev, - ctlr->params.desc_mem_phys, - ctlr->params.desc_hw_addr, - ctlr->params.desc_mem_size, - ctlr->params.desc_align); - if (!ctlr->pool) + if (cpdma_desc_pool_create(ctlr)) return NULL; + /* split pool equally between RX/TX by default */ + ctlr->num_tx_desc = ctlr->pool->num_desc / 2; + ctlr->num_rx_desc = ctlr->pool->num_desc - ctlr->num_tx_desc; if (WARN_ON(ctlr->num_chan > CPDMA_MAX_CHANNELS)) ctlr->num_chan = CPDMA_MAX_CHANNELS; @@ -542,10 +556,10 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) } for (i = 0; i < ctlr->num_chan; i++) { - __raw_writel(0, ctlr->params.txhdp + 4 * i); - __raw_writel(0, ctlr->params.rxhdp + 4 * i); - __raw_writel(0, ctlr->params.txcp + 4 * i); - __raw_writel(0, ctlr->params.rxcp + 4 * i); + writel(0, ctlr->params.txhdp + 4 * i); + writel(0, ctlr->params.rxhdp + 4 * i); + writel(0, ctlr->params.txcp + 4 * i); + writel(0, ctlr->params.rxcp + 4 * i); } dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff); @@ -623,7 +637,7 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) cpdma_chan_destroy(ctlr->channels[i]); - cpdma_desc_pool_destroy(ctlr->pool); + cpdma_desc_pool_destroy(ctlr); return ret; } EXPORT_SYMBOL_GPL(cpdma_ctlr_destroy); @@ -708,22 +722,22 @@ static void cpdma_chan_set_descs(struct cpdma_ctlr *ctlr, } } /* use remains */ - most_chan->desc_num += desc_cnt; + if (most_chan) + most_chan->desc_num += desc_cnt; } /** * cpdma_chan_split_pool - Splits ctrl pool between all channels. * Has to be called under ctlr lock */ -static int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) +int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) { int tx_per_ch_desc = 0, rx_per_ch_desc = 0; - struct cpdma_desc_pool *pool = ctlr->pool; int free_rx_num = 0, free_tx_num = 0; int rx_weight = 0, tx_weight = 0; int tx_desc_num, rx_desc_num; struct cpdma_chan *chan; - int i, tx_num = 0; + int i; if (!ctlr->chan_num) return 0; @@ -741,15 +755,14 @@ static int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) if (!chan->weight) free_tx_num++; tx_weight += chan->weight; - tx_num++; } } if (rx_weight > 100 || tx_weight > 100) return -EINVAL; - tx_desc_num = (tx_num * pool->num_desc) / ctlr->chan_num; - rx_desc_num = pool->num_desc - tx_desc_num; + tx_desc_num = ctlr->num_tx_desc; + rx_desc_num = ctlr->num_rx_desc; if (free_tx_num) { tx_per_ch_desc = tx_desc_num - (tx_weight * tx_desc_num) / 100; @@ -765,6 +778,8 @@ static int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr) return 0; } +EXPORT_SYMBOL_GPL(cpdma_chan_split_pool); + /* cpdma_chan_set_weight - set weight of a channel in percentage. * Tx and Rx channels have separate weights. That is 100% for RX @@ -820,8 +835,8 @@ EXPORT_SYMBOL_GPL(cpdma_chan_get_min_rate); */ int cpdma_chan_set_rate(struct cpdma_chan *ch, u32 rate) { - struct cpdma_ctlr *ctlr = ch->ctlr; unsigned long flags, ch_flags; + struct cpdma_ctlr *ctlr; int ret, prio_mode; u32 rmask; @@ -831,6 +846,7 @@ int cpdma_chan_set_rate(struct cpdma_chan *ch, u32 rate) if (ch->rate == rate) return rate; + ctlr = ch->ctlr; spin_lock_irqsave(&ctlr->lock, flags); spin_lock_irqsave(&ch->lock, ch_flags); @@ -898,7 +914,6 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, chan->chan_num = chan_num; chan->handler = handler; chan->rate = 0; - chan->desc_num = ctlr->pool->num_desc / 2; chan->weight = 0; if (is_rx_chan(chan)) { @@ -1061,13 +1076,17 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; cpdma_desc_to_port(chan, mode, directed); - desc_write(desc, hw_next, 0); - desc_write(desc, hw_buffer, buffer); - desc_write(desc, hw_len, len); - desc_write(desc, hw_mode, mode | len); - desc_write(desc, sw_token, token); - desc_write(desc, sw_buffer, buffer); - desc_write(desc, sw_len, len); + /* Relaxed IO accessors can be used here as there is read barrier + * at the end of write sequence. + */ + writel_relaxed(0, &desc->hw_next); + writel_relaxed(buffer, &desc->hw_buffer); + writel_relaxed(len, &desc->hw_len); + writel_relaxed(mode | len, &desc->hw_mode); + writel_relaxed(token, &desc->sw_token); + writel_relaxed(buffer, &desc->sw_buffer); + writel_relaxed(len, &desc->sw_len); + desc_read(desc, sw_len); __cpdma_chan_submit(chan, desc); @@ -1136,7 +1155,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan) } desc_dma = desc_phys(pool, desc); - status = __raw_readl(&desc->hw_mode); + status = desc_read(desc, hw_mode); outlen = status & 0x7ff; if (status & CPDMA_DESC_OWNER) { chan->stats.busy_dequeue++; @@ -1155,7 +1174,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan) chan->count--; chan->stats.good_dequeue++; - if (status & CPDMA_DESC_EOQ) { + if ((status & CPDMA_DESC_EOQ) && chan->head) { chan->stats.requeue++; chan_write(chan, hdp, desc_phys(pool, chan->head)); } @@ -1316,4 +1335,23 @@ int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value) } EXPORT_SYMBOL_GPL(cpdma_control_set); +int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr) +{ + return ctlr->num_rx_desc; +} +EXPORT_SYMBOL_GPL(cpdma_get_num_rx_descs); + +int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr) +{ + return ctlr->num_tx_desc; +} +EXPORT_SYMBOL_GPL(cpdma_get_num_tx_descs); + +void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc) +{ + ctlr->num_rx_desc = num_rx_desc; + ctlr->num_tx_desc = ctlr->pool->num_desc - ctlr->num_rx_desc; +} +EXPORT_SYMBOL_GPL(cpdma_set_num_rx_descs); + MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h index 4a167db2abab..fd65ce2b83de 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.h +++ b/drivers/net/ethernet/ti/davinci_cpdma.h @@ -37,6 +37,7 @@ struct cpdma_params { int desc_mem_size; int desc_align; u32 bus_freq_mhz; + u32 descs_pool_size; /* * Some instances of embedded cpdma controllers have extra control and @@ -113,5 +114,9 @@ enum cpdma_control { int cpdma_control_get(struct cpdma_ctlr *ctlr, int control); int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value); +int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr); +void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc); +int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr); +int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr); #endif diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 481c7bf0395b..64d5527feb2a 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1295,7 +1295,7 @@ static int emac_poll(struct napi_struct *napi, int budget) &emac_rxhost_errcodes[cause][0], ch); } } else if (num_rx_pkts < budget) { - napi_complete(napi); + napi_complete_done(napi, num_rx_pkts); emac_int_enable(priv); } diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h index 0f58c584ae09..8900a6fad318 100644 --- a/drivers/net/ethernet/ti/netcp.h +++ b/drivers/net/ethernet/ti/netcp.h @@ -23,6 +23,7 @@ #include <linux/netdevice.h> #include <linux/soc/ti/knav_dma.h> +#include <linux/u64_stats_sync.h> /* Maximum Ethernet frame size supported by Keystone switch */ #define NETCP_MAX_FRAME_SIZE 9504 @@ -68,6 +69,20 @@ struct netcp_addr { struct list_head node; }; +struct netcp_stats { + struct u64_stats_sync syncp_rx ____cacheline_aligned_in_smp; + u64 rx_packets; + u64 rx_bytes; + u32 rx_errors; + u32 rx_dropped; + + struct u64_stats_sync syncp_tx ____cacheline_aligned_in_smp; + u64 tx_packets; + u64 tx_bytes; + u32 tx_errors; + u32 tx_dropped; +}; + struct netcp_intf { struct device *dev; struct device *ndev_dev; @@ -87,6 +102,11 @@ struct netcp_intf { void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN]; struct napi_struct rx_napi; struct napi_struct tx_napi; +#define ETH_SW_CAN_REMOVE_ETH_FCS BIT(0) + u32 hw_cap; + + /* 64-bit netcp stats */ + struct netcp_stats stats; void *rx_channel; const char *dma_chan_name; @@ -115,6 +135,7 @@ struct netcp_packet { struct sk_buff *skb; __le32 *epib; u32 *psdata; + u32 eflags; unsigned int psdata_len; struct netcp_intf *netcp; struct netcp_tx_pipe *tx_pipe; diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index c243335ed649..7c7ae0890e90 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -122,6 +122,13 @@ static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc, *ndesc = le32_to_cpu(desc->next_desc); } +static void get_desc_info(u32 *desc_info, u32 *pkt_info, + struct knav_dma_desc *desc) +{ + *desc_info = le32_to_cpu(desc->desc_info); + *pkt_info = le32_to_cpu(desc->packet_info); +} + static u32 get_sw_data(int index, struct knav_dma_desc *desc) { /* No Endian conversion needed as this data is untouched by hw */ @@ -622,6 +629,7 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp, static void netcp_empty_rx_queue(struct netcp_intf *netcp) { + struct netcp_stats *rx_stats = &netcp->stats; struct knav_dma_desc *desc; unsigned int dma_sz; dma_addr_t dma; @@ -635,16 +643,17 @@ static void netcp_empty_rx_queue(struct netcp_intf *netcp) if (unlikely(!desc)) { dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n", __func__); - netcp->ndev->stats.rx_errors++; + rx_stats->rx_errors++; continue; } netcp_free_rx_desc_chain(netcp, desc); - netcp->ndev->stats.rx_dropped++; + rx_stats->rx_dropped++; } } static int netcp_process_one_rx_packet(struct netcp_intf *netcp) { + struct netcp_stats *rx_stats = &netcp->stats; unsigned int dma_sz, buf_len, org_buf_len; struct knav_dma_desc *desc, *ndesc; unsigned int pkt_sz = 0, accum_sz; @@ -653,6 +662,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp) struct netcp_packet p_info; struct sk_buff *skb; void *org_buf_ptr; + u32 tmp; dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz); if (!dma_desc) @@ -724,21 +734,27 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp) knav_pool_desc_put(netcp->rx_pool, ndesc); } - /* Free the primary descriptor */ - knav_pool_desc_put(netcp->rx_pool, desc); - /* check for packet len and warn */ if (unlikely(pkt_sz != accum_sz)) dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n", pkt_sz, accum_sz); - /* Remove ethernet FCS from the packet */ - __pskb_trim(skb, skb->len - ETH_FCS_LEN); + /* Newer version of the Ethernet switch can trim the Ethernet FCS + * from the packet and is indicated in hw_cap. So trim it only for + * older h/w + */ + if (!(netcp->hw_cap & ETH_SW_CAN_REMOVE_ETH_FCS)) + __pskb_trim(skb, skb->len - ETH_FCS_LEN); /* Call each of the RX hooks */ p_info.skb = skb; skb->dev = netcp->ndev; p_info.rxtstamp_complete = false; + get_desc_info(&tmp, &p_info.eflags, desc); + p_info.epib = desc->epib; + p_info.psdata = (u32 __force *)desc->psdata; + p_info.eflags = ((p_info.eflags >> KNAV_DMA_DESC_EFLAGS_SHIFT) & + KNAV_DMA_DESC_EFLAGS_MASK); list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) { int ret; @@ -747,14 +763,20 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp) if (unlikely(ret)) { dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n", rx_hook->order, ret); - netcp->ndev->stats.rx_errors++; + /* Free the primary descriptor */ + rx_stats->rx_dropped++; + knav_pool_desc_put(netcp->rx_pool, desc); dev_kfree_skb(skb); return 0; } } + /* Free the primary descriptor */ + knav_pool_desc_put(netcp->rx_pool, desc); - netcp->ndev->stats.rx_packets++; - netcp->ndev->stats.rx_bytes += skb->len; + u64_stats_update_begin(&rx_stats->syncp_rx); + rx_stats->rx_packets++; + rx_stats->rx_bytes += skb->len; + u64_stats_update_end(&rx_stats->syncp_rx); /* push skb up the stack */ skb->protocol = eth_type_trans(skb, netcp->ndev); @@ -763,7 +785,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp) free_desc: netcp_free_rx_desc_chain(netcp, desc); - netcp->ndev->stats.rx_errors++; + rx_stats->rx_errors++; return 0; } @@ -947,7 +969,7 @@ static int netcp_rx_poll(struct napi_struct *napi, int budget) netcp_rxpool_refill(netcp); if (packets < budget) { - napi_complete(&netcp->rx_napi); + napi_complete_done(&netcp->rx_napi, packets); knav_queue_enable_notify(netcp->rx_queue); } @@ -994,6 +1016,7 @@ static void netcp_free_tx_desc_chain(struct netcp_intf *netcp, static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, unsigned int budget) { + struct netcp_stats *tx_stats = &netcp->stats; struct knav_dma_desc *desc; struct netcp_tx_cb *tx_cb; struct sk_buff *skb; @@ -1008,7 +1031,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz); if (unlikely(!desc)) { dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n"); - netcp->ndev->stats.tx_errors++; + tx_stats->tx_errors++; continue; } @@ -1019,7 +1042,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, netcp_free_tx_desc_chain(netcp, desc, dma_sz); if (!skb) { dev_err(netcp->ndev_dev, "No skb in Tx desc\n"); - netcp->ndev->stats.tx_errors++; + tx_stats->tx_errors++; continue; } @@ -1036,8 +1059,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, netif_wake_subqueue(netcp->ndev, subqueue); } - netcp->ndev->stats.tx_packets++; - netcp->ndev->stats.tx_bytes += skb->len; + u64_stats_update_begin(&tx_stats->syncp_tx); + tx_stats->tx_packets++; + tx_stats->tx_bytes += skb->len; + u64_stats_update_end(&tx_stats->syncp_tx); dev_kfree_skb(skb); pkts++; } @@ -1212,9 +1237,9 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp, /* psdata points to both native-endian and device-endian data */ __le32 *psdata = (void __force *)p_info.psdata; - memmove(p_info.psdata, p_info.psdata + p_info.psdata_len, - p_info.psdata_len); - set_words(p_info.psdata, p_info.psdata_len, psdata); + set_words((u32 *)psdata + + (KNAV_DMA_NUM_PS_WORDS - p_info.psdata_len), + p_info.psdata_len, psdata); tmp |= (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) << KNAV_DMA_DESC_PSLEN_SHIFT; } @@ -1258,6 +1283,7 @@ out: static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_stats *tx_stats = &netcp->stats; int subqueue = skb_get_queue_mapping(skb); struct knav_dma_desc *desc; int desc_count, ret = 0; @@ -1273,7 +1299,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* If we get here, the skb has already been dropped */ dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n", ret); - ndev->stats.tx_dropped++; + tx_stats->tx_dropped++; return ret; } skb->len = NETCP_MIN_PACKET_SIZE; @@ -1290,8 +1316,6 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (ret) goto drop; - netif_trans_update(ndev); - /* Check Tx pool count & stop subqueue if needed */ desc_count = knav_pool_count(netcp->tx_pool); if (desc_count < netcp->tx_pause_threshold) { @@ -1301,7 +1325,7 @@ static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; drop: - ndev->stats.tx_dropped++; + tx_stats->tx_dropped++; if (desc) netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc)); dev_kfree_skb(skb); @@ -1883,12 +1907,44 @@ static int netcp_setup_tc(struct net_device *dev, u32 handle, __be16 proto, return 0; } +static void +netcp_get_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats) +{ + struct netcp_intf *netcp = netdev_priv(ndev); + struct netcp_stats *p = &netcp->stats; + u64 rxpackets, rxbytes, txpackets, txbytes; + unsigned int start; + + do { + start = u64_stats_fetch_begin_irq(&p->syncp_rx); + rxpackets = p->rx_packets; + rxbytes = p->rx_bytes; + } while (u64_stats_fetch_retry_irq(&p->syncp_rx, start)); + + do { + start = u64_stats_fetch_begin_irq(&p->syncp_tx); + txpackets = p->tx_packets; + txbytes = p->tx_bytes; + } while (u64_stats_fetch_retry_irq(&p->syncp_tx, start)); + + stats->rx_packets = rxpackets; + stats->rx_bytes = rxbytes; + stats->tx_packets = txpackets; + stats->tx_bytes = txbytes; + + /* The following are stored as 32 bit */ + stats->rx_errors = p->rx_errors; + stats->rx_dropped = p->rx_dropped; + stats->tx_dropped = p->tx_dropped; +} + static const struct net_device_ops netcp_netdev_ops = { .ndo_open = netcp_ndo_open, .ndo_stop = netcp_ndo_stop, .ndo_start_xmit = netcp_ndo_start_xmit, .ndo_set_rx_mode = netcp_set_rx_mode, .ndo_do_ioctl = netcp_ndo_ioctl, + .ndo_get_stats64 = netcp_get_stats, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_vlan_rx_add_vid = netcp_rx_add_vid, @@ -1935,6 +1991,8 @@ static int netcp_create_interface(struct netcp_device *netcp_device, INIT_LIST_HEAD(&netcp->txhook_list_head); INIT_LIST_HEAD(&netcp->rxhook_list_head); INIT_LIST_HEAD(&netcp->addr_list); + u64_stats_init(&netcp->stats.syncp_rx); + u64_stats_init(&netcp->stats.syncp_tx); netcp->netcp_device = netcp_device; netcp->dev = netcp_device->device; netcp->ndev = ndev; diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 7d9e36f66735..eece3e2eec14 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -81,7 +81,6 @@ #define GBENU_CPTS_OFFSET 0x1d000 #define GBENU_ALE_OFFSET 0x1e000 #define GBENU_HOST_PORT_NUM 0 -#define GBENU_NUM_ALE_ENTRIES 1024 #define GBENU_SGMII_MODULE_SIZE 0x100 /* 10G Ethernet SS defines */ @@ -103,7 +102,7 @@ #define XGBE10_ALE_OFFSET 0x700 #define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HOST_PORT_NUM 0 -#define XGBE10_NUM_ALE_ENTRIES 1024 +#define XGBE10_NUM_ALE_ENTRIES 2048 #define GBE_TIMER_INTERVAL (HZ / 2) @@ -122,6 +121,7 @@ #define MACSL_FULLDUPLEX BIT(0) #define GBE_CTL_P0_ENABLE BIT(2) +#define ETH_SW_CTL_P0_TX_CRC_REMOVE BIT(13) #define GBE13_REG_VAL_STAT_ENABLE_ALL 0xff #define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf #define GBE_STATS_CD_SEL BIT(28) @@ -2313,7 +2313,6 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) dev_dbg(priv->dev, "phy found: id is: 0x%s\n", phydev_name(slave->phy)); phy_start(slave->phy); - phy_read_status(slave->phy); } return 0; } @@ -2821,7 +2820,7 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) struct netcp_intf *netcp = netdev_priv(ndev); struct gbe_slave *slave = gbe_intf->slave; int port_num = slave->port_num; - u32 reg; + u32 reg, val; int ret; reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver)); @@ -2851,7 +2850,12 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype)); /* Control register */ - writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control)); + val = GBE_CTL_P0_ENABLE; + if (IS_SS_ID_MU(gbe_dev)) { + val |= ETH_SW_CTL_P0_TX_CRC_REMOVE; + netcp->hw_cap = ETH_SW_CAN_REMOVE_ETH_FCS; + } + writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, control)); /* All statistics enabled and STAT AB visible by default */ writel(gbe_dev->stats_en_mask, GBE_REG_ADDR(gbe_dev, switch_regs, @@ -2930,7 +2934,9 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, } slave->open = false; - slave->phy_node = of_parse_phandle(node, "phy-handle", 0); + if ((slave->link_interface == SGMII_LINK_MAC_PHY) || + (slave->link_interface == XGMII_LINK_MAC_PHY)) + slave->phy_node = of_parse_phandle(node, "phy-handle", 0); slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num); if (slave->link_interface >= XGMII_LINK_MAC_PHY) @@ -3112,7 +3118,6 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, dev_dbg(dev, "phy found: id is: 0x%s\n", phydev_name(slave->phy)); phy_start(slave->phy); - phy_read_status(slave->phy); } } } @@ -3433,7 +3438,6 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET; gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBENU_HOST_PORT_NUM; - gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; /* Subsystem registers */ @@ -3601,7 +3605,10 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ale_params.ale_ageout = GBE_DEFAULT_ALE_AGEOUT; ale_params.ale_entries = gbe_dev->ale_entries; ale_params.ale_ports = gbe_dev->ale_ports; - + if (IS_SS_ID_MU(gbe_dev)) { + ale_params.major_ver_mask = 0x7; + ale_params.nu_switch_ale = true; + } gbe_dev->ale = cpsw_ale_create(&ale_params); if (!gbe_dev->ale) { dev_err(gbe_dev->dev, "error initializing ale engine\n"); |