Commit ebbb293f authored by Giuseppe CAVALLARO's avatar Giuseppe CAVALLARO Committed by David S. Miller

stmmac: consolidate and tidy-up the COE support

The first version of the driver had hard-coded the logic
for handling the checksum offloading.
This was designed according to the chips included in
the STM platforms where:
o MAC10/100 supports no COE at all.
o GMAC fully supports RX/TX COE.

This is not good for other chip configurations where,
for example, the mac10/100 supports the tx csum in HW
or when the GMAC has no IPC.

Thanks to Johannes Stezenbach; he provided me a first
draft of this patch that only reviewed the IPC for the
GMAC devices.

This patch also helps on SPEAr platforms where the
MAC10/100 can perform the TX csum in HW.
Thanks to Deepak SIKRI for his support on this.

In the end, GMAC devices for STM platforms have
a bugged Jumbo frame support that needs to have
the Tx COE disabled for oversized frames (due to
limited buffer sizes). This information is also
passed through the driver's platform structure.
Signed-off-by: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarJohannes Stezenbach <js@sig21.net>
Signed-off-by: default avatarDeepak SIKRI <deepak.sikri@st.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dfb8fb96
...@@ -102,8 +102,6 @@ struct stmmac_extra_stats { ...@@ -102,8 +102,6 @@ struct stmmac_extra_stats {
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ #define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
#define HW_CSUM 1
#define NO_HW_CSUM 0
enum rx_frame_status { /* IPC status */ enum rx_frame_status { /* IPC status */
good_frame = 0, good_frame = 0,
discard_frame = 1, discard_frame = 1,
...@@ -205,6 +203,8 @@ struct stmmac_dma_ops { ...@@ -205,6 +203,8 @@ struct stmmac_dma_ops {
struct stmmac_ops { struct stmmac_ops {
/* MAC core initialization */ /* MAC core initialization */
void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned; void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
/* Support checksum offload engine */
int (*rx_coe) (void __iomem *ioaddr);
/* Dump MAC registers */ /* Dump MAC registers */
void (*dump_regs) (void __iomem *ioaddr); void (*dump_regs) (void __iomem *ioaddr);
/* Handle extra events on specific interrupts hw dependent */ /* Handle extra events on specific interrupts hw dependent */
......
...@@ -99,7 +99,7 @@ enum inter_frame_gap { ...@@ -99,7 +99,7 @@ enum inter_frame_gap {
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */ #define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \ #define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
GMAC_CONTROL_IPC | GMAC_CONTROL_JE | GMAC_CONTROL_BE) GMAC_CONTROL_JE | GMAC_CONTROL_BE)
/* GMAC Frame Filter defines */ /* GMAC Frame Filter defines */
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */ #define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
......
...@@ -50,6 +50,18 @@ static void dwmac1000_core_init(void __iomem *ioaddr) ...@@ -50,6 +50,18 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
#endif #endif
} }
static int dwmac1000_rx_coe_supported(void __iomem *ioaddr)
{
u32 value = readl(ioaddr + GMAC_CONTROL);
value |= GMAC_CONTROL_IPC;
writel(value, ioaddr + GMAC_CONTROL);
value = readl(ioaddr + GMAC_CONTROL);
return !!(value & GMAC_CONTROL_IPC);
}
static void dwmac1000_dump_regs(void __iomem *ioaddr) static void dwmac1000_dump_regs(void __iomem *ioaddr)
{ {
int i; int i;
...@@ -202,6 +214,7 @@ static void dwmac1000_irq_status(void __iomem *ioaddr) ...@@ -202,6 +214,7 @@ static void dwmac1000_irq_status(void __iomem *ioaddr)
struct stmmac_ops dwmac1000_ops = { struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init, .core_init = dwmac1000_core_init,
.rx_coe = dwmac1000_rx_coe_supported,
.dump_regs = dwmac1000_dump_regs, .dump_regs = dwmac1000_dump_regs,
.host_irq_status = dwmac1000_irq_status, .host_irq_status = dwmac1000_irq_status,
.set_filter = dwmac1000_set_filter, .set_filter = dwmac1000_set_filter,
......
...@@ -42,6 +42,11 @@ static void dwmac100_core_init(void __iomem *ioaddr) ...@@ -42,6 +42,11 @@ static void dwmac100_core_init(void __iomem *ioaddr)
#endif #endif
} }
static int dwmac100_rx_coe_supported(void __iomem *ioaddr)
{
return 0;
}
static void dwmac100_dump_mac_regs(void __iomem *ioaddr) static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
{ {
pr_info("\t----------------------------------------------\n" pr_info("\t----------------------------------------------\n"
...@@ -165,6 +170,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode) ...@@ -165,6 +170,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
struct stmmac_ops dwmac100_ops = { struct stmmac_ops dwmac100_ops = {
.core_init = dwmac100_core_init, .core_init = dwmac100_core_init,
.rx_coe = dwmac100_rx_coe_supported,
.dump_regs = dwmac100_dump_mac_regs, .dump_regs = dwmac100_dump_mac_regs,
.host_irq_status = dwmac100_irq_status, .host_irq_status = dwmac100_irq_status,
.set_filter = dwmac100_set_filter, .set_filter = dwmac100_set_filter,
......
...@@ -51,7 +51,6 @@ struct stmmac_priv { ...@@ -51,7 +51,6 @@ struct stmmac_priv {
int is_gmac; int is_gmac;
dma_addr_t dma_rx_phy; dma_addr_t dma_rx_phy;
unsigned int dma_rx_size; unsigned int dma_rx_size;
int rx_csum;
unsigned int dma_buf_sz; unsigned int dma_buf_sz;
struct device *device; struct device *device;
struct mac_device_info *hw; struct mac_device_info *hw;
...@@ -92,6 +91,9 @@ struct stmmac_priv { ...@@ -92,6 +91,9 @@ struct stmmac_priv {
struct vlan_group *vlgrp; struct vlan_group *vlgrp;
#endif #endif
int enh_desc; int enh_desc;
int rx_coe;
int bugged_jumbo;
int no_csum_insertion;
}; };
#ifdef CONFIG_STM_DRIVERS #ifdef CONFIG_STM_DRIVERS
......
...@@ -209,7 +209,7 @@ u32 stmmac_ethtool_get_rx_csum(struct net_device *dev) ...@@ -209,7 +209,7 @@ u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
{ {
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
return priv->rx_csum; return priv->rx_coe;
} }
static void static void
......
...@@ -134,13 +134,6 @@ static int buf_sz = DMA_BUFFER_SIZE; ...@@ -134,13 +134,6 @@ static int buf_sz = DMA_BUFFER_SIZE;
module_param(buf_sz, int, S_IRUGO | S_IWUSR); module_param(buf_sz, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(buf_sz, "DMA buffer size"); MODULE_PARM_DESC(buf_sz, "DMA buffer size");
/* In case of Giga ETH, we can enable/disable the COE for the
* transmit HW checksum computation.
* Note that, if tx csum is off in HW, SG will be still supported. */
static int tx_coe = HW_CSUM;
module_param(tx_coe, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tx_coe, "GMAC COE type 2 [on/off]");
static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_IFUP | NETIF_MSG_LINK | NETIF_MSG_IFUP |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
...@@ -569,29 +562,22 @@ static void free_dma_desc_resources(struct stmmac_priv *priv) ...@@ -569,29 +562,22 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
* stmmac_dma_operation_mode - HW DMA operation mode * stmmac_dma_operation_mode - HW DMA operation mode
* @priv : pointer to the private device structure. * @priv : pointer to the private device structure.
* Description: it sets the DMA operation mode: tx/rx DMA thresholds * Description: it sets the DMA operation mode: tx/rx DMA thresholds
* or Store-And-Forward capability. It also verifies the COE for the * or Store-And-Forward capability.
* transmission in case of Giga ETH.
*/ */
static void stmmac_dma_operation_mode(struct stmmac_priv *priv) static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{ {
if (!priv->is_gmac) { if (likely((priv->tx_coe) && (!priv->no_csum_insertion))) {
/* MAC 10/100 */ /* In case of GMAC, SF mode has to be enabled
priv->hw->dma->dma_mode(priv->ioaddr, tc, 0); * to perform the TX COE. This depends on:
priv->tx_coe = NO_HW_CSUM; * 1) TX COE if actually supported
} else { * 2) There is no bugged Jumbo frame support
if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) { * that needs to not insert csum in the TDES.
priv->hw->dma->dma_mode(priv->ioaddr, */
SF_DMA_MODE, SF_DMA_MODE); priv->hw->dma->dma_mode(priv->ioaddr,
tc = SF_DMA_MODE; SF_DMA_MODE, SF_DMA_MODE);
priv->tx_coe = HW_CSUM; tc = SF_DMA_MODE;
} else { } else
/* Checksum computation is performed in software. */ priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
priv->hw->dma->dma_mode(priv->ioaddr, tc,
SF_DMA_MODE);
priv->tx_coe = NO_HW_CSUM;
}
}
tx_coe = priv->tx_coe;
} }
/** /**
...@@ -858,6 +844,12 @@ static int stmmac_open(struct net_device *dev) ...@@ -858,6 +844,12 @@ static int stmmac_open(struct net_device *dev)
/* Initialize the MAC Core */ /* Initialize the MAC Core */
priv->hw->mac->core_init(priv->ioaddr); priv->hw->mac->core_init(priv->ioaddr);
priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr);
if (priv->rx_coe)
pr_info("stmmac: Rx Checksum Offload Engine supported\n");
if (priv->tx_coe)
pr_info("\tTX Checksum insertion supported\n");
priv->shutdown = 0; priv->shutdown = 0;
/* Initialise the MMC (if present) to disable all interrupts. */ /* Initialise the MMC (if present) to disable all interrupts. */
...@@ -1066,7 +1058,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1066,7 +1058,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return stmmac_sw_tso(priv, skb); return stmmac_sw_tso(priv, skb);
if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) { if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
if (likely(priv->tx_coe == NO_HW_CSUM)) if (unlikely((!priv->tx_coe) || (priv->no_csum_insertion)))
skb_checksum_help(skb); skb_checksum_help(skb);
else else
csum_insertion = 1; csum_insertion = 1;
...@@ -1390,6 +1382,15 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1390,6 +1382,15 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL; return -EINVAL;
} }
/* Some GMAC devices have a bugged Jumbo frame support that
* needs to have the Tx COE disabled for oversized frames
* (due to limited buffer sizes). In this case we disable
* the TX csum insertionin the TDES and not use SF. */
if ((priv->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN))
priv->no_csum_insertion = 1;
else
priv->no_csum_insertion = 0;
dev->mtu = new_mtu; dev->mtu = new_mtu;
return 0; return 0;
...@@ -1510,9 +1511,6 @@ static int stmmac_probe(struct net_device *dev) ...@@ -1510,9 +1511,6 @@ static int stmmac_probe(struct net_device *dev)
#endif #endif
priv->msg_enable = netif_msg_init(debug, default_msg_level); priv->msg_enable = netif_msg_init(debug, default_msg_level);
if (priv->is_gmac)
priv->rx_csum = 1;
if (flow_ctrl) if (flow_ctrl)
priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
...@@ -1662,7 +1660,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev) ...@@ -1662,7 +1660,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
pr_info("done!\n"); pr_info("\tdone!\n");
if (!request_mem_region(res->start, resource_size(res), if (!request_mem_region(res->start, resource_size(res),
pdev->name)) { pdev->name)) {
...@@ -1705,6 +1703,8 @@ static int stmmac_dvr_probe(struct platform_device *pdev) ...@@ -1705,6 +1703,8 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
priv->bus_id = plat_dat->bus_id; priv->bus_id = plat_dat->bus_id;
priv->pbl = plat_dat->pbl; /* TLI */ priv->pbl = plat_dat->pbl; /* TLI */
priv->mii_clk_csr = plat_dat->clk_csr; priv->mii_clk_csr = plat_dat->clk_csr;
priv->tx_coe = plat_dat->tx_coe;
priv->bugged_jumbo = plat_dat->bugged_jumbo;
priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */ priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */
priv->enh_desc = plat_dat->enh_desc; priv->enh_desc = plat_dat->enh_desc;
priv->ioaddr = addr; priv->ioaddr = addr;
...@@ -1966,8 +1966,6 @@ static int __init stmmac_cmdline_opt(char *str) ...@@ -1966,8 +1966,6 @@ static int __init stmmac_cmdline_opt(char *str)
strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz); strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz);
else if (!strncmp(opt, "tc:", 3)) else if (!strncmp(opt, "tc:", 3))
strict_strtoul(opt + 3, 0, (unsigned long *)&tc); strict_strtoul(opt + 3, 0, (unsigned long *)&tc);
else if (!strncmp(opt, "tx_coe:", 7))
strict_strtoul(opt + 7, 0, (unsigned long *)&tx_coe);
else if (!strncmp(opt, "watchdog:", 9)) else if (!strncmp(opt, "watchdog:", 9))
strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog); strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog);
else if (!strncmp(opt, "flow_ctrl:", 10)) else if (!strncmp(opt, "flow_ctrl:", 10))
......
...@@ -35,6 +35,8 @@ struct plat_stmmacenet_data { ...@@ -35,6 +35,8 @@ struct plat_stmmacenet_data {
int clk_csr; int clk_csr;
int has_gmac; int has_gmac;
int enh_desc; int enh_desc;
int tx_coe;
int bugged_jumbo;
void (*fix_mac_speed)(void *priv, unsigned int speed); void (*fix_mac_speed)(void *priv, unsigned int speed);
void (*bus_setup)(void __iomem *ioaddr); void (*bus_setup)(void __iomem *ioaddr);
#ifdef CONFIG_STM_DRIVERS #ifdef CONFIG_STM_DRIVERS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment