162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci/* Copyright 2021 NXP 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * The Integrated Endpoint Register Block (IERB) is configured by pre-boot 562306a36Sopenharmony_ci * software and is supposed to be to ENETC what a NVRAM is to a 'real' PCIe 662306a36Sopenharmony_ci * card. Upon FLR, values from the IERB are transferred to the ENETC PFs, and 762306a36Sopenharmony_ci * are read-only in the PF memory space. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This driver fixes up the power-on reset values for the ENETC shared FIFO, 1062306a36Sopenharmony_ci * such that the TX and RX allocations are sufficient for jumbo frames, and 1162306a36Sopenharmony_ci * that intelligent FIFO dropping is enabled before the internal data 1262306a36Sopenharmony_ci * structures are corrupted. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Even though not all ports might be used on a given board, we are not 1562306a36Sopenharmony_ci * concerned with partitioning the FIFO, because the default values configure 1662306a36Sopenharmony_ci * no strict reservations, so the entire FIFO can be used by the RX of a single 1762306a36Sopenharmony_ci * port, or the TX of a single port. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/pci.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include "enetc.h" 2662306a36Sopenharmony_ci#include "enetc_ierb.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* IERB registers */ 2962306a36Sopenharmony_ci#define ENETC_IERB_TXMBAR(port) (((port) * 0x100) + 0x8080) 3062306a36Sopenharmony_ci#define ENETC_IERB_RXMBER(port) (((port) * 0x100) + 0x8090) 3162306a36Sopenharmony_ci#define ENETC_IERB_RXMBLR(port) (((port) * 0x100) + 0x8094) 3262306a36Sopenharmony_ci#define ENETC_IERB_RXBCR(port) (((port) * 0x100) + 0x80a0) 3362306a36Sopenharmony_ci#define ENETC_IERB_TXBCR(port) (((port) * 0x100) + 0x80a8) 3462306a36Sopenharmony_ci#define ENETC_IERB_FMBDTR 0xa000 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ENETC_RESERVED_FOR_ICM 1024 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct enetc_ierb { 3962306a36Sopenharmony_ci void __iomem *regs; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void enetc_ierb_write(struct enetc_ierb *ierb, u32 offset, u32 val) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci iowrite32(val, ierb->regs + offset); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint enetc_ierb_register_pf(struct platform_device *pdev, 4862306a36Sopenharmony_ci struct pci_dev *pf_pdev) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct enetc_ierb *ierb = platform_get_drvdata(pdev); 5162306a36Sopenharmony_ci int port = enetc_pf_to_port(pf_pdev); 5262306a36Sopenharmony_ci u16 tx_credit, rx_credit, tx_alloc; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (port < 0) 5562306a36Sopenharmony_ci return -ENODEV; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!ierb) 5862306a36Sopenharmony_ci return -EPROBE_DEFER; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* By default, it is recommended to set the Host Transfer Agent 6162306a36Sopenharmony_ci * per port transmit byte credit to "1000 + max_frame_size/2". 6262306a36Sopenharmony_ci * The power-on reset value (1800 bytes) is rounded up to the nearest 6362306a36Sopenharmony_ci * 100 assuming a maximum frame size of 1536 bytes. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci tx_credit = roundup(1000 + ENETC_MAC_MAXFRM_SIZE / 2, 100); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* Internal memory allocated for transmit buffering is guaranteed but 6862306a36Sopenharmony_ci * not reserved; i.e. if the total transmit allocation is not used, 6962306a36Sopenharmony_ci * then the unused portion is not left idle, it can be used for receive 7062306a36Sopenharmony_ci * buffering but it will be reclaimed, if required, from receive by 7162306a36Sopenharmony_ci * intelligently dropping already stored receive frames in the internal 7262306a36Sopenharmony_ci * memory to ensure that the transmit allocation is respected. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * PaTXMBAR must be set to a value larger than 7562306a36Sopenharmony_ci * PaTXBCR + 2 * max_frame_size + 32 7662306a36Sopenharmony_ci * if frame preemption is not enabled, or to 7762306a36Sopenharmony_ci * 2 * PaTXBCR + 2 * p_max_frame_size (pMAC maximum frame size) + 7862306a36Sopenharmony_ci * 2 * np_max_frame_size (eMAC maximum frame size) + 64 7962306a36Sopenharmony_ci * if frame preemption is enabled. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci tx_alloc = roundup(2 * tx_credit + 4 * ENETC_MAC_MAXFRM_SIZE + 64, 16); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Initial credits, in units of 8 bytes, to the Ingress Congestion 8462306a36Sopenharmony_ci * Manager for the maximum amount of bytes the port is allocated for 8562306a36Sopenharmony_ci * pending traffic. 8662306a36Sopenharmony_ci * It is recommended to set the initial credits to 2 times the maximum 8762306a36Sopenharmony_ci * frame size (2 frames of maximum size). 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci rx_credit = DIV_ROUND_UP(ENETC_MAC_MAXFRM_SIZE * 2, 8); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci enetc_ierb_write(ierb, ENETC_IERB_TXBCR(port), tx_credit); 9262306a36Sopenharmony_ci enetc_ierb_write(ierb, ENETC_IERB_TXMBAR(port), tx_alloc); 9362306a36Sopenharmony_ci enetc_ierb_write(ierb, ENETC_IERB_RXBCR(port), rx_credit); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL(enetc_ierb_register_pf); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int enetc_ierb_probe(struct platform_device *pdev) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct enetc_ierb *ierb; 10262306a36Sopenharmony_ci void __iomem *regs; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ierb = devm_kzalloc(&pdev->dev, sizeof(*ierb), GFP_KERNEL); 10562306a36Sopenharmony_ci if (!ierb) 10662306a36Sopenharmony_ci return -ENOMEM; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); 10962306a36Sopenharmony_ci if (IS_ERR(regs)) 11062306a36Sopenharmony_ci return PTR_ERR(regs); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci ierb->regs = regs; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Free buffer depletion threshold in bytes. 11562306a36Sopenharmony_ci * This sets the minimum amount of free buffer memory that should be 11662306a36Sopenharmony_ci * maintained in the datapath sub system, and when the amount of free 11762306a36Sopenharmony_ci * buffer memory falls below this threshold, a depletion indication is 11862306a36Sopenharmony_ci * asserted, which may trigger "intelligent drop" frame releases from 11962306a36Sopenharmony_ci * the ingress queues in the ICM. 12062306a36Sopenharmony_ci * It is recommended to set the free buffer depletion threshold to 1024 12162306a36Sopenharmony_ci * bytes, since the ICM needs some FIFO memory for its own use. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci enetc_ierb_write(ierb, ENETC_IERB_FMBDTR, ENETC_RESERVED_FOR_ICM); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci platform_set_drvdata(pdev, ierb); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const struct of_device_id enetc_ierb_match[] = { 13162306a36Sopenharmony_ci { .compatible = "fsl,ls1028a-enetc-ierb", }, 13262306a36Sopenharmony_ci {}, 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, enetc_ierb_match); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic struct platform_driver enetc_ierb_driver = { 13762306a36Sopenharmony_ci .driver = { 13862306a36Sopenharmony_ci .name = "fsl-enetc-ierb", 13962306a36Sopenharmony_ci .of_match_table = enetc_ierb_match, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci .probe = enetc_ierb_probe, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cimodule_platform_driver(enetc_ierb_driver); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP ENETC IERB"); 14762306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 148