/* Only channel 0 supports checksum, * so turn off checksum to enable multiple channels.
*/ for (int i = 1; i < 8; i++)
plat->tx_queues_cfg[i].coe_unsupported = 1;
/* The integrated PHY has a weird problem with switching from the low * speeds to 1000Mbps mode. The speedup procedure requires the PHY-link * re-negotiation.
*/ if (speed == SPEED_1000) { if (readl(ptr->ioaddr + MAC_CTRL_REG) &
GMAC_CONTROL_PS) /* Word around hardware bug, restart autoneg */
phy_restart_aneg(ndev->phydev);
}
}
value |= DMA_BUS_MODE_USP;
value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK);
value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT);
value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT);
/* Set the Fixed burst mode */ if (dma_cfg->fixed_burst)
value |= DMA_BUS_MODE_FB;
/* Mixed Burst has no effect when fb is set */ if (dma_cfg->mixed_burst)
value |= DMA_BUS_MODE_MB;
if (dma_cfg->atds)
value |= DMA_BUS_MODE_ATDS;
if (dma_cfg->aal)
value |= DMA_BUS_MODE_AAL;
writel(value, ioaddr + DMA_CHAN_BUS_MODE(chan));
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK_LOONGSON, ioaddr +
DMA_CHAN_INTR_ENA(chan));
}
/* ABNORMAL interrupts */ if (unlikely(abnor_intr_status)) { if (unlikely(intr_status & DMA_STATUS_UNF)) {
ret = tx_hard_error_bump_tc;
x->tx_undeflow_irq++;
} if (unlikely(intr_status & DMA_STATUS_TJT))
x->tx_jabber_irq++; if (unlikely(intr_status & DMA_STATUS_OVF))
x->rx_overflow_irq++; if (unlikely(intr_status & DMA_STATUS_RU))
x->rx_buf_unav_irq++; if (unlikely(intr_status & DMA_STATUS_RPS))
x->rx_process_stopped_irq++; if (unlikely(intr_status & DMA_STATUS_RWT))
x->rx_watchdog_irq++; if (unlikely(intr_status & DMA_STATUS_ETI))
x->tx_early_irq++; if (unlikely(intr_status & DMA_STATUS_TPS)) {
x->tx_process_stopped_irq++;
ret = tx_hard_error;
} if (unlikely(fb_intr_status)) {
x->fatal_bus_error_irq++;
ret = tx_hard_error;
}
} /* TX/RX NORMAL interrupts */ if (likely(nor_intr_status)) { if (likely(intr_status & DMA_STATUS_RI)) {
u32 value = readl(ioaddr + DMA_INTR_ENA); /* to schedule NAPI on real RIE event. */ if (likely(value & DMA_INTR_ENA_RIE)) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->rx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
} if (likely(intr_status & DMA_STATUS_TI)) {
u64_stats_update_begin(&stats->syncp);
u64_stats_inc(&stats->tx_normal_irq_n[chan]);
u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
} if (unlikely(intr_status & DMA_STATUS_ERI))
x->rx_early_irq++;
} /* Optional hardware blocks, interrupts should be disabled */ if (unlikely(intr_status &
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
pr_warn("%s: unexpected status %08x\n", __func__, intr_status);
/* Clear the interrupt by writing a logic 1 to the CSR5[19-0] */
writel((intr_status & 0x7ffff), ioaddr + DMA_CHAN_STATUS(chan));
mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); if (!mac) return NULL;
dma = devm_kzalloc(priv->device, sizeof(*dma), GFP_KERNEL); if (!dma) return NULL;
/* The Loongson GMAC and GNET devices are based on the DW GMAC * v3.50a and v3.73a IP-cores. But the HW designers have changed * the GMAC_VERSION.SNPSVER field to the custom 0x10/0x12 value * on the network controllers with the multi-channels feature * available to emphasize the differences: multiple DMA-channels, * AV feature and GMAC_INT_STATUS CSR flags layout. Get back the * original value so the correct HW-interface would be selected.
*/ if (ld->multichan) {
priv->synopsys_id = DWMAC_CORE_3_70;
*dma = dwmac1000_dma_ops;
dma->init_chan = loongson_dwmac_dma_init_channel;
dma->dma_interrupt = loongson_dwmac_dma_interrupt;
mac->dma = dma;
}
priv->dev->priv_flags |= IFF_UNICAST_FLT;
/* Pre-initialize the respective "mac" fields as it's done in * dwmac1000_setup()
*/
mac->pcsr = priv->ioaddr;
mac->multicast_filter_bins = priv->plat->multicast_filter_bins;
mac->unicast_filter_entries = priv->plat->unicast_filter_entries;
mac->mcast_bits_log2 = 0;
if (mac->multicast_filter_bins)
mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
/* Loongson GMAC doesn't support the flow control. Loongson GNET * without multi-channel doesn't support the half-duplex link mode.
*/ if (pdev->device != PCI_DEVICE_ID_LOONGSON_GNET) {
mac->link.caps = MAC_10 | MAC_100 | MAC_1000;
} else { if (ld->multichan)
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100 | MAC_1000; else
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10FD | MAC_100FD | MAC_1000FD;
}
plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) return -ENOMEM;
plat->mdio_bus_data = devm_kzalloc(&pdev->dev, sizeof(*plat->mdio_bus_data),
GFP_KERNEL); if (!plat->mdio_bus_data) return -ENOMEM;
plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL); if (!plat->dma_cfg) return -ENOMEM;
ld = devm_kzalloc(&pdev->dev, sizeof(*ld), GFP_KERNEL); if (!ld) return -ENOMEM;
/* Enable pci device */
ret = pci_enable_device(pdev); if (ret) {
dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); return ret;
}
pci_set_master(pdev);
/* Get the base address of device */
res.addr = pcim_iomap_region(pdev, 0, DRIVER_NAME);
ret = PTR_ERR_OR_ZERO(res.addr); if (ret) goto err_disable_device;
if (dev_of_node(&pdev->dev))
ret = loongson_dwmac_dt_config(pdev, plat, &res); else
ret = loongson_dwmac_acpi_config(pdev, plat, &res); if (ret) goto err_disable_device;
/* Use the common MAC IRQ if per-channel MSIs allocation failed */ if (ld->multichan)
loongson_dwmac_msi_config(pdev, plat, &res);
ret = stmmac_dvr_probe(&pdev->dev, plat, &res); if (ret) goto err_plat_clear;
return 0;
err_plat_clear: if (dev_of_node(&pdev->dev))
loongson_dwmac_dt_clear(pdev, plat); if (ld->multichan)
loongson_dwmac_msi_clear(pdev);
err_disable_device:
pci_disable_device(pdev); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.