|
@@ -387,6 +387,9 @@ struct cpsw_priv {
|
|
|
struct cpsw_ale *ale;
|
|
|
bool rx_pause;
|
|
|
bool tx_pause;
|
|
|
+ bool quirk_irq;
|
|
|
+ bool rx_irq_disabled;
|
|
|
+ bool tx_irq_disabled;
|
|
|
/* snapshot of IRQ numbers */
|
|
|
u32 irqs_table[4];
|
|
|
u32 num_irqs;
|
|
@@ -755,6 +758,11 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
|
|
|
writel(0, &priv->wr_regs->tx_en);
|
|
|
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);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
@@ -766,6 +774,11 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
|
|
|
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
|
|
|
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);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
@@ -779,6 +792,10 @@ static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget)
|
|
|
if (num_tx < budget) {
|
|
|
napi_complete(napi_tx);
|
|
|
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)
|
|
@@ -796,6 +813,10 @@ static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget)
|
|
|
if (num_rx < budget) {
|
|
|
napi_complete(napi_rx);
|
|
|
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)
|
|
@@ -1267,6 +1288,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
|
|
|
napi_enable(&priv_sl0->napi_rx);
|
|
|
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))
|
|
|
priv->data.rx_descs = 128;
|
|
|
|
|
@@ -2128,6 +2159,44 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
|
|
|
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)
|
|
|
{
|
|
|
struct cpsw_platform_data *data;
|
|
@@ -2137,6 +2206,7 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
|
struct cpsw_ale_params ale_params;
|
|
|
void __iomem *ss_regs;
|
|
|
struct resource *res, *ss_res;
|
|
|
+ const struct of_device_id *of_id;
|
|
|
u32 slave_offset, sliver_offset, slave_size;
|
|
|
int ret = 0, i;
|
|
|
int irq;
|
|
@@ -2327,6 +2397,13 @@ static int cpsw_probe(struct platform_device *pdev)
|
|
|
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
|
|
|
* MISC IRQs which are always kept disabled with this driver so
|
|
|
* we will not request them.
|
|
@@ -2491,12 +2568,6 @@ static int cpsw_resume(struct device *dev)
|
|
|
|
|
|
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 = {
|
|
|
.driver = {
|
|
|
.name = "cpsw",
|