struct intel_priv_data { int mdio_adhoc_addr; /* mdio address for serdes & etc */ unsignedlong crossts_adj; bool is_pse; constint *tsn_lane_regs; int max_tsn_lane_regs; struct pmc_serdes_reg_info pid_1g; struct pmc_serdes_reg_info pid_2p5g;
};
/* This struct is used to associate PCI Function of MAC controller on a board, * discovered via DMI, with the address of PHY connected to the MAC. The * negative value of the address means that MAC controller is not connected * with PHY.
*/ struct stmmac_pci_func_data { unsignedint func; int phy_addr;
};
/* Program PTP Clock Frequency for different variant of * Intel mGBE that has slightly different GPO mapping
*/ staticvoid intel_mgbe_ptp_clk_freq_config(struct stmmac_priv *priv)
{ struct intel_priv_data *intel_priv;
u32 gpio_value;
if (!boot_cpu_has(X86_FEATURE_ART)) return -EOPNOTSUPP;
intel_priv = priv->plat->bsp_priv;
/* Both internal crosstimestamping and external triggered event * timestamping cannot be run concurrently.
*/ if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN) return -EBUSY;
/* Trigger Internal snapshot signal * Create a rising edge by just toggle the GPO1 to low * and back to high.
*/
gpio_value = readl(ioaddr + GMAC_GPIO_STATUS);
gpio_value &= ~GMAC_GPO1;
writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
gpio_value |= GMAC_GPO1;
writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
/* Repeat until the timestamps are from the FIFO last segment */ for (i = 0; i < num_snapshot; i++) {
read_lock_irqsave(&priv->ptp_lock, flags);
stmmac_get_ptptime(priv, ptpaddr, &ptp_time);
*device = ns_to_ktime(ptp_time);
read_unlock_irqrestore(&priv->ptp_lock, flags);
get_arttime(priv->mii, intel_priv->mdio_adhoc_addr, &art_time);
system->cycles = art_time;
}
staticvoid intel_mgbe_pse_crossts_adj(struct intel_priv_data *intel_priv, int base)
{ if (boot_cpu_has(X86_FEATURE_ART)) { unsignedint art_freq;
/* On systems that support ART, ART frequency can be obtained * from ECX register of CPUID leaf (0x15).
*/
art_freq = cpuid_ecx(ART_CPUID_LEAF);
do_div(art_freq, base);
intel_priv->crossts_adj = art_freq;
}
}
ret = intel_tsn_lane_is_available(ndev, intel_priv); if (ret < 0) {
netdev_info(priv->dev, "No TSN lane available to set the registers.\n"); return ret;
}
staticstruct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv,
phy_interface_t interface)
{ /* plat->mdio_bus_data->has_xpcs has been set true, so there * should always be an XPCS. The original code would always * return this if present.
*/ return xpcs_to_phylink_pcs(priv->hw->xpcs);
}
staticint intel_mgbe_common_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat)
{ struct fwnode_handle *fwnode; char clk_name[20]; int ret; int i;
/* Multiplying factor to the clk_eee_i clock time * period to make it closer to 100 ns. This value * should be programmed such that the clk_eee_time_period * * (MULT_FACT_100NS + 1) should be within 80 ns to 120 ns * clk_eee frequency is 19.2Mhz * clk_eee_time_period is 52ns * 52ns * (1 + 1) = 104ns * MULT_FACT_100NS = 1
*/
plat->mult_fact_100ns = 1;
plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
for (i = 0; i < plat->rx_queues_to_use; i++) {
plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
plat->rx_queues_cfg[i].chan = i;
/* Disable Priority config by default */
plat->rx_queues_cfg[i].use_prio = false;
for (i = 0; i < plat->tx_queues_to_use; i++) {
plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
/* Disable Priority config by default */
plat->tx_queues_cfg[i].use_prio = false; /* Default TX Q0 to use TSO and rest TXQ for TBS */ if (i > 0)
plat->tx_queues_cfg[i].tbs_en = 1;
}
/* Set default value for multicast hash bins */
plat->multicast_filter_bins = HASH_TABLE_SIZE;
/* Set default value for unicast filter entries */
plat->unicast_filter_entries = 1;
/* Set the maxmtu to a default of JUMBO_LEN */
plat->maxmtu = JUMBO_LEN;
plat->flags |= STMMAC_FLAG_VLAN_FAIL_Q_EN;
/* Use the last Rx queue */
plat->vlan_fail_q = plat->rx_queues_to_use - 1;
/* For fixed-link setup, we allow phy-mode setting */
fwnode = dev_fwnode(&pdev->dev); if (fwnode) { int phy_mode;
/* "phy-mode" setting is optional. If it is set, * we allow either sgmii or 1000base-x for now.
*/
phy_mode = fwnode_get_phy_mode(fwnode); if (phy_mode >= 0) { if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
phy_mode == PHY_INTERFACE_MODE_1000BASEX)
plat->phy_interface = phy_mode; else
dev_warn(&pdev->dev, "Invalid phy-mode\n");
}
}
staticconststruct dmi_system_id quark_pci_dmi[] = {
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
},
.driver_data = (void *)&galileo_stmmac_dmi_data,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
},
.driver_data = (void *)&galileo_stmmac_dmi_data,
}, /* There are 2 types of SIMATIC IOT2000: IOT2020 and IOT2040. * The asset tag "6ES7647-0AA00-0YA2" is only for IOT2020 which * has only one pci network device while other asset tags are * for IOT2040 which has two.
*/
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, "6ES7647-0AA00-0YA2"),
},
.driver_data = (void *)&galileo_stmmac_dmi_data,
},
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
},
.driver_data = (void *)&iot2040_stmmac_dmi_data,
},
{}
};
staticint quark_default_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat)
{ int ret;
/* Set common default data first */
common_default_data(plat);
/* Refuse to load the driver and register net device if MAC controller * does not connect to any PHY interface.
*/
ret = stmmac_pci_find_phy_addr(pdev, quark_pci_dmi); if (ret < 0) { /* Return error to the caller on DMI enabled boards. */ if (dmi_get_system_info(DMI_BOARD_NAME)) return ret;
/* Galileo boards with old firmware don't support DMI. We always * use 1 here as PHY address, so at least the first found MAC * controller would be probed.
*/
ret = 1;
}
ret = pci_alloc_irq_vectors(pdev, 2, STMMAC_MSI_VEC_MAX,
PCI_IRQ_MSI | PCI_IRQ_MSIX); if (ret < 0) {
dev_info(&pdev->dev, "%s: multi MSI enablement failed\n",
__func__); return ret;
}
/* For RX MSI */ for (i = 0; i < plat->rx_queues_to_use; i++) {
res->rx_irq[i] = pci_irq_vector(pdev,
plat->msi_rx_base_vec + i * 2);
}
/* For TX MSI */ for (i = 0; i < plat->tx_queues_to_use; i++) {
res->tx_irq[i] = pci_irq_vector(pdev,
plat->msi_tx_base_vec + i * 2);
}
if (plat->msi_mac_vec < STMMAC_MSI_VEC_MAX)
res->irq = pci_irq_vector(pdev, plat->msi_mac_vec); if (plat->msi_wol_vec < STMMAC_MSI_VEC_MAX)
res->wol_irq = pci_irq_vector(pdev, plat->msi_wol_vec); if (plat->msi_lpi_vec < STMMAC_MSI_VEC_MAX)
res->lpi_irq = pci_irq_vector(pdev, plat->msi_lpi_vec); if (plat->msi_sfty_ce_vec < STMMAC_MSI_VEC_MAX)
res->sfty_ce_irq = pci_irq_vector(pdev, plat->msi_sfty_ce_vec); if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX)
res->sfty_ue_irq = pci_irq_vector(pdev, plat->msi_sfty_ue_vec);
plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
dev_info(&pdev->dev, "%s: multi MSI enablement successful\n", __func__);
return 0;
}
/** * intel_eth_pci_probe * * @pdev: pci device pointer * @id: pointer to table of device id/id's. * * Description: This probing function gets called for all PCI devices which * match the ID table and are not "owned" by other driver yet. This function * gets passed a "struct pci_dev *" for each device whose entry in the ID table * matches the device. The probe functions returns zero when the driver choose * to take "ownership" of the device or an error code(-ve no) otherwise.
*/ staticint intel_eth_pci_probe(struct pci_dev *pdev, conststruct pci_device_id *id)
{ struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data; struct intel_priv_data *intel_priv; struct plat_stmmacenet_data *plat; struct stmmac_resources res; int ret;
intel_priv = devm_kzalloc(&pdev->dev, sizeof(*intel_priv), GFP_KERNEL); if (!intel_priv) return -ENOMEM;
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;
plat->safety_feat_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->safety_feat_cfg),
GFP_KERNEL); if (!plat->safety_feat_cfg) return -ENOMEM;
/* Enable pci device */
ret = pcim_enable_device(pdev); if (ret) {
dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
__func__); return ret;
}
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret;
/* Initialize all MSI vectors to invalid so that it can be set * according to platform data settings below. * Note: MSI vector takes value from 0 upto 31 (STMMAC_MSI_VEC_MAX)
*/
plat->msi_mac_vec = STMMAC_MSI_VEC_MAX;
plat->msi_wol_vec = STMMAC_MSI_VEC_MAX;
plat->msi_lpi_vec = STMMAC_MSI_VEC_MAX;
plat->msi_sfty_ce_vec = STMMAC_MSI_VEC_MAX;
plat->msi_sfty_ue_vec = STMMAC_MSI_VEC_MAX;
plat->msi_rx_base_vec = STMMAC_MSI_VEC_MAX;
plat->msi_tx_base_vec = STMMAC_MSI_VEC_MAX;
ret = info->setup(pdev, plat); if (ret) return ret;
/** * intel_eth_pci_remove * * @pdev: pci device pointer * Description: this function calls the main to free the net resources * and releases the PCI resources.
*/ staticvoid intel_eth_pci_remove(struct pci_dev *pdev)
{ struct net_device *ndev = dev_get_drvdata(&pdev->dev); struct stmmac_priv *priv = netdev_priv(ndev);
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.