Commit 646244b2 authored by David S. Miller's avatar David S. Miller

Merge branch 'cpsw-errata-workaround'

Mugunthan V N says:

====================
Add AM335x PG1.0 CPSW errata workaround

With commit 870915fe ("drivers: net: cpsw: remove
disable_irq/enable_irq as irq can be masked from cpsw itself"),
CPSW on AM335x beagle bone white is broken as there is a errata
for AM335x PG1.0. This patch series implements the workaround by
disabling the interrupts from ARM IRQ controller for AM335x SoC
in addition to the masking of interrupts in CPSW.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 182ad468 21696f71
...@@ -700,7 +700,7 @@ ehrpwm2: ehrpwm@48304200 { ...@@ -700,7 +700,7 @@ ehrpwm2: ehrpwm@48304200 {
}; };
mac: ethernet@4a100000 { mac: ethernet@4a100000 {
compatible = "ti,cpsw"; compatible = "ti,am335x-cpsw","ti,cpsw";
ti,hwmods = "cpgmac0"; ti,hwmods = "cpgmac0";
clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>; clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
clock-names = "fck", "cpts"; clock-names = "fck", "cpts";
......
...@@ -1399,7 +1399,7 @@ crossbar_mpu: crossbar@4a002a48 { ...@@ -1399,7 +1399,7 @@ crossbar_mpu: crossbar@4a002a48 {
}; };
mac: ethernet@4a100000 { mac: ethernet@4a100000 {
compatible = "ti,cpsw"; compatible = "ti,dra7-cpsw","ti,cpsw";
ti,hwmods = "gmac"; ti,hwmods = "gmac";
clocks = <&dpll_gmac_ck>, <&gmac_gmii_ref_clk_div>; clocks = <&dpll_gmac_ck>, <&gmac_gmii_ref_clk_div>;
clock-names = "fck", "cpts"; clock-names = "fck", "cpts";
......
...@@ -387,6 +387,9 @@ struct cpsw_priv { ...@@ -387,6 +387,9 @@ struct cpsw_priv {
struct cpsw_ale *ale; struct cpsw_ale *ale;
bool rx_pause; bool rx_pause;
bool tx_pause; bool tx_pause;
bool quirk_irq;
bool rx_irq_disabled;
bool tx_irq_disabled;
/* snapshot of IRQ numbers */ /* snapshot of IRQ numbers */
u32 irqs_table[4]; u32 irqs_table[4];
u32 num_irqs; u32 num_irqs;
...@@ -755,6 +758,11 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) ...@@ -755,6 +758,11 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
writel(0, &priv->wr_regs->tx_en); writel(0, &priv->wr_regs->tx_en);
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
if (priv->quirk_irq) {
disable_irq_nosync(priv->irqs_table[1]);
priv->tx_irq_disabled = true;
}
napi_schedule(&priv->napi_tx); napi_schedule(&priv->napi_tx);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -766,6 +774,11 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) ...@@ -766,6 +774,11 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
writel(0, &priv->wr_regs->rx_en); writel(0, &priv->wr_regs->rx_en);
if (priv->quirk_irq) {
disable_irq_nosync(priv->irqs_table[0]);
priv->rx_irq_disabled = true;
}
napi_schedule(&priv->napi_rx); napi_schedule(&priv->napi_rx);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -779,6 +792,10 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) ...@@ -779,6 +792,10 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget)
if (num_tx < budget) { if (num_tx < budget) {
napi_complete(napi_tx); napi_complete(napi_tx);
writel(0xff, &priv->wr_regs->tx_en); writel(0xff, &priv->wr_regs->tx_en);
if (priv->quirk_irq && priv->tx_irq_disabled) {
priv->tx_irq_disabled = false;
enable_irq(priv->irqs_table[1]);
}
} }
if (num_tx) if (num_tx)
...@@ -796,6 +813,10 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) ...@@ -796,6 +813,10 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget)
if (num_rx < budget) { if (num_rx < budget) {
napi_complete(napi_rx); napi_complete(napi_rx);
writel(0xff, &priv->wr_regs->rx_en); writel(0xff, &priv->wr_regs->rx_en);
if (priv->quirk_irq && priv->rx_irq_disabled) {
priv->rx_irq_disabled = false;
enable_irq(priv->irqs_table[0]);
}
} }
if (num_rx) if (num_rx)
...@@ -1267,6 +1288,16 @@ static int cpsw_ndo_open(struct net_device *ndev) ...@@ -1267,6 +1288,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
napi_enable(&priv_sl0->napi_rx); napi_enable(&priv_sl0->napi_rx);
napi_enable(&priv_sl0->napi_tx); napi_enable(&priv_sl0->napi_tx);
if (priv_sl0->tx_irq_disabled) {
priv_sl0->tx_irq_disabled = false;
enable_irq(priv->irqs_table[1]);
}
if (priv_sl0->rx_irq_disabled) {
priv_sl0->rx_irq_disabled = false;
enable_irq(priv->irqs_table[0]);
}
if (WARN_ON(!priv->data.rx_descs)) if (WARN_ON(!priv->data.rx_descs))
priv->data.rx_descs = 128; priv->data.rx_descs = 128;
...@@ -2128,6 +2159,44 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev, ...@@ -2128,6 +2159,44 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
return ret; return ret;
} }
#define CPSW_QUIRK_IRQ BIT(0)
static struct platform_device_id cpsw_devtype[] = {
{
/* keep it for existing comaptibles */
.name = "cpsw",
.driver_data = CPSW_QUIRK_IRQ,
}, {
.name = "am335x-cpsw",
.driver_data = CPSW_QUIRK_IRQ,
}, {
.name = "am4372-cpsw",
.driver_data = 0,
}, {
.name = "dra7-cpsw",
.driver_data = 0,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, cpsw_devtype);
enum ti_cpsw_type {
CPSW = 0,
AM335X_CPSW,
AM4372_CPSW,
DRA7_CPSW,
};
static const struct of_device_id cpsw_of_mtable[] = {
{ .compatible = "ti,cpsw", .data = &cpsw_devtype[CPSW], },
{ .compatible = "ti,am335x-cpsw", .data = &cpsw_devtype[AM335X_CPSW], },
{ .compatible = "ti,am4372-cpsw", .data = &cpsw_devtype[AM4372_CPSW], },
{ .compatible = "ti,dra7-cpsw", .data = &cpsw_devtype[DRA7_CPSW], },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static int cpsw_probe(struct platform_device *pdev) static int cpsw_probe(struct platform_device *pdev)
{ {
struct cpsw_platform_data *data; struct cpsw_platform_data *data;
...@@ -2137,6 +2206,7 @@ static int cpsw_probe(struct platform_device *pdev) ...@@ -2137,6 +2206,7 @@ static int cpsw_probe(struct platform_device *pdev)
struct cpsw_ale_params ale_params; struct cpsw_ale_params ale_params;
void __iomem *ss_regs; void __iomem *ss_regs;
struct resource *res, *ss_res; struct resource *res, *ss_res;
const struct of_device_id *of_id;
u32 slave_offset, sliver_offset, slave_size; u32 slave_offset, sliver_offset, slave_size;
int ret = 0, i; int ret = 0, i;
int irq; int irq;
...@@ -2327,6 +2397,13 @@ static int cpsw_probe(struct platform_device *pdev) ...@@ -2327,6 +2397,13 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_ale_ret; goto clean_ale_ret;
} }
of_id = of_match_device(cpsw_of_mtable, &pdev->dev);
if (of_id) {
pdev->id_entry = of_id->data;
if (pdev->id_entry->driver_data)
priv->quirk_irq = true;
}
/* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and
* MISC IRQs which are always kept disabled with this driver so * MISC IRQs which are always kept disabled with this driver so
* we will not request them. * we will not request them.
...@@ -2491,12 +2568,6 @@ static int cpsw_resume(struct device *dev) ...@@ -2491,12 +2568,6 @@ static int cpsw_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume); static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume);
static const struct of_device_id cpsw_of_mtable[] = {
{ .compatible = "ti,cpsw", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static struct platform_driver cpsw_driver = { static struct platform_driver cpsw_driver = {
.driver = { .driver = {
.name = "cpsw", .name = "cpsw",
......
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