1e7d48e5fSVladimir Oltean // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
23c9cfb52SVladimir Oltean /* Copyright 2021 NXP
3e7d48e5fSVladimir Oltean *
4e7d48e5fSVladimir Oltean * The Integrated Endpoint Register Block (IERB) is configured by pre-boot
5e7d48e5fSVladimir Oltean * software and is supposed to be to ENETC what a NVRAM is to a 'real' PCIe
6e7d48e5fSVladimir Oltean * card. Upon FLR, values from the IERB are transferred to the ENETC PFs, and
7e7d48e5fSVladimir Oltean * are read-only in the PF memory space.
8e7d48e5fSVladimir Oltean *
9e7d48e5fSVladimir Oltean * This driver fixes up the power-on reset values for the ENETC shared FIFO,
10e7d48e5fSVladimir Oltean * such that the TX and RX allocations are sufficient for jumbo frames, and
11e7d48e5fSVladimir Oltean * that intelligent FIFO dropping is enabled before the internal data
12e7d48e5fSVladimir Oltean * structures are corrupted.
13e7d48e5fSVladimir Oltean *
14e7d48e5fSVladimir Oltean * Even though not all ports might be used on a given board, we are not
15e7d48e5fSVladimir Oltean * concerned with partitioning the FIFO, because the default values configure
16e7d48e5fSVladimir Oltean * no strict reservations, so the entire FIFO can be used by the RX of a single
17e7d48e5fSVladimir Oltean * port, or the TX of a single port.
18e7d48e5fSVladimir Oltean */
19e7d48e5fSVladimir Oltean
20e7d48e5fSVladimir Oltean #include <linux/io.h>
21*3d40aed8SRob Herring #include <linux/mod_devicetable.h>
22e7d48e5fSVladimir Oltean #include <linux/module.h>
23e7d48e5fSVladimir Oltean #include <linux/pci.h>
24e7d48e5fSVladimir Oltean #include <linux/platform_device.h>
25e7d48e5fSVladimir Oltean #include "enetc.h"
26e7d48e5fSVladimir Oltean #include "enetc_ierb.h"
27e7d48e5fSVladimir Oltean
28e7d48e5fSVladimir Oltean /* IERB registers */
29e7d48e5fSVladimir Oltean #define ENETC_IERB_TXMBAR(port) (((port) * 0x100) + 0x8080)
30e7d48e5fSVladimir Oltean #define ENETC_IERB_RXMBER(port) (((port) * 0x100) + 0x8090)
31e7d48e5fSVladimir Oltean #define ENETC_IERB_RXMBLR(port) (((port) * 0x100) + 0x8094)
32e7d48e5fSVladimir Oltean #define ENETC_IERB_RXBCR(port) (((port) * 0x100) + 0x80a0)
33e7d48e5fSVladimir Oltean #define ENETC_IERB_TXBCR(port) (((port) * 0x100) + 0x80a8)
34e7d48e5fSVladimir Oltean #define ENETC_IERB_FMBDTR 0xa000
35e7d48e5fSVladimir Oltean
36e7d48e5fSVladimir Oltean #define ENETC_RESERVED_FOR_ICM 1024
37e7d48e5fSVladimir Oltean
38e7d48e5fSVladimir Oltean struct enetc_ierb {
39e7d48e5fSVladimir Oltean void __iomem *regs;
40e7d48e5fSVladimir Oltean };
41e7d48e5fSVladimir Oltean
enetc_ierb_write(struct enetc_ierb * ierb,u32 offset,u32 val)42e7d48e5fSVladimir Oltean static void enetc_ierb_write(struct enetc_ierb *ierb, u32 offset, u32 val)
43e7d48e5fSVladimir Oltean {
44e7d48e5fSVladimir Oltean iowrite32(val, ierb->regs + offset);
45e7d48e5fSVladimir Oltean }
46e7d48e5fSVladimir Oltean
enetc_ierb_register_pf(struct platform_device * pdev,struct pci_dev * pf_pdev)47e7d48e5fSVladimir Oltean int enetc_ierb_register_pf(struct platform_device *pdev,
48e7d48e5fSVladimir Oltean struct pci_dev *pf_pdev)
49e7d48e5fSVladimir Oltean {
50e7d48e5fSVladimir Oltean struct enetc_ierb *ierb = platform_get_drvdata(pdev);
51e7d48e5fSVladimir Oltean int port = enetc_pf_to_port(pf_pdev);
52e7d48e5fSVladimir Oltean u16 tx_credit, rx_credit, tx_alloc;
53e7d48e5fSVladimir Oltean
54e7d48e5fSVladimir Oltean if (port < 0)
55e7d48e5fSVladimir Oltean return -ENODEV;
56e7d48e5fSVladimir Oltean
57e7d48e5fSVladimir Oltean if (!ierb)
58e7d48e5fSVladimir Oltean return -EPROBE_DEFER;
59e7d48e5fSVladimir Oltean
60e7d48e5fSVladimir Oltean /* By default, it is recommended to set the Host Transfer Agent
61e7d48e5fSVladimir Oltean * per port transmit byte credit to "1000 + max_frame_size/2".
62e7d48e5fSVladimir Oltean * The power-on reset value (1800 bytes) is rounded up to the nearest
63e7d48e5fSVladimir Oltean * 100 assuming a maximum frame size of 1536 bytes.
64e7d48e5fSVladimir Oltean */
65e7d48e5fSVladimir Oltean tx_credit = roundup(1000 + ENETC_MAC_MAXFRM_SIZE / 2, 100);
66e7d48e5fSVladimir Oltean
67e7d48e5fSVladimir Oltean /* Internal memory allocated for transmit buffering is guaranteed but
68e7d48e5fSVladimir Oltean * not reserved; i.e. if the total transmit allocation is not used,
69e7d48e5fSVladimir Oltean * then the unused portion is not left idle, it can be used for receive
70e7d48e5fSVladimir Oltean * buffering but it will be reclaimed, if required, from receive by
71e7d48e5fSVladimir Oltean * intelligently dropping already stored receive frames in the internal
72e7d48e5fSVladimir Oltean * memory to ensure that the transmit allocation is respected.
73e7d48e5fSVladimir Oltean *
74e7d48e5fSVladimir Oltean * PaTXMBAR must be set to a value larger than
75e7d48e5fSVladimir Oltean * PaTXBCR + 2 * max_frame_size + 32
76e7d48e5fSVladimir Oltean * if frame preemption is not enabled, or to
77e7d48e5fSVladimir Oltean * 2 * PaTXBCR + 2 * p_max_frame_size (pMAC maximum frame size) +
78e7d48e5fSVladimir Oltean * 2 * np_max_frame_size (eMAC maximum frame size) + 64
79e7d48e5fSVladimir Oltean * if frame preemption is enabled.
80e7d48e5fSVladimir Oltean */
81e7d48e5fSVladimir Oltean tx_alloc = roundup(2 * tx_credit + 4 * ENETC_MAC_MAXFRM_SIZE + 64, 16);
82e7d48e5fSVladimir Oltean
83e7d48e5fSVladimir Oltean /* Initial credits, in units of 8 bytes, to the Ingress Congestion
84e7d48e5fSVladimir Oltean * Manager for the maximum amount of bytes the port is allocated for
85e7d48e5fSVladimir Oltean * pending traffic.
86e7d48e5fSVladimir Oltean * It is recommended to set the initial credits to 2 times the maximum
87e7d48e5fSVladimir Oltean * frame size (2 frames of maximum size).
88e7d48e5fSVladimir Oltean */
89e7d48e5fSVladimir Oltean rx_credit = DIV_ROUND_UP(ENETC_MAC_MAXFRM_SIZE * 2, 8);
90e7d48e5fSVladimir Oltean
91e7d48e5fSVladimir Oltean enetc_ierb_write(ierb, ENETC_IERB_TXBCR(port), tx_credit);
92e7d48e5fSVladimir Oltean enetc_ierb_write(ierb, ENETC_IERB_TXMBAR(port), tx_alloc);
93e7d48e5fSVladimir Oltean enetc_ierb_write(ierb, ENETC_IERB_RXBCR(port), rx_credit);
94e7d48e5fSVladimir Oltean
95e7d48e5fSVladimir Oltean return 0;
96e7d48e5fSVladimir Oltean }
97e7d48e5fSVladimir Oltean EXPORT_SYMBOL(enetc_ierb_register_pf);
98e7d48e5fSVladimir Oltean
enetc_ierb_probe(struct platform_device * pdev)99e7d48e5fSVladimir Oltean static int enetc_ierb_probe(struct platform_device *pdev)
100e7d48e5fSVladimir Oltean {
101e7d48e5fSVladimir Oltean struct enetc_ierb *ierb;
102e7d48e5fSVladimir Oltean void __iomem *regs;
103e7d48e5fSVladimir Oltean
104e7d48e5fSVladimir Oltean ierb = devm_kzalloc(&pdev->dev, sizeof(*ierb), GFP_KERNEL);
105e7d48e5fSVladimir Oltean if (!ierb)
106e7d48e5fSVladimir Oltean return -ENOMEM;
107e7d48e5fSVladimir Oltean
108b5d64b43SYang Yingliang regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
109e7d48e5fSVladimir Oltean if (IS_ERR(regs))
110e7d48e5fSVladimir Oltean return PTR_ERR(regs);
111e7d48e5fSVladimir Oltean
112e7d48e5fSVladimir Oltean ierb->regs = regs;
113e7d48e5fSVladimir Oltean
114e7d48e5fSVladimir Oltean /* Free buffer depletion threshold in bytes.
115e7d48e5fSVladimir Oltean * This sets the minimum amount of free buffer memory that should be
116e7d48e5fSVladimir Oltean * maintained in the datapath sub system, and when the amount of free
117e7d48e5fSVladimir Oltean * buffer memory falls below this threshold, a depletion indication is
118e7d48e5fSVladimir Oltean * asserted, which may trigger "intelligent drop" frame releases from
119e7d48e5fSVladimir Oltean * the ingress queues in the ICM.
120e7d48e5fSVladimir Oltean * It is recommended to set the free buffer depletion threshold to 1024
121e7d48e5fSVladimir Oltean * bytes, since the ICM needs some FIFO memory for its own use.
122e7d48e5fSVladimir Oltean */
123e7d48e5fSVladimir Oltean enetc_ierb_write(ierb, ENETC_IERB_FMBDTR, ENETC_RESERVED_FOR_ICM);
124e7d48e5fSVladimir Oltean
125e7d48e5fSVladimir Oltean platform_set_drvdata(pdev, ierb);
126e7d48e5fSVladimir Oltean
127e7d48e5fSVladimir Oltean return 0;
128e7d48e5fSVladimir Oltean }
129e7d48e5fSVladimir Oltean
130e7d48e5fSVladimir Oltean static const struct of_device_id enetc_ierb_match[] = {
131e7d48e5fSVladimir Oltean { .compatible = "fsl,ls1028a-enetc-ierb", },
132e7d48e5fSVladimir Oltean {},
133e7d48e5fSVladimir Oltean };
134e7d48e5fSVladimir Oltean MODULE_DEVICE_TABLE(of, enetc_ierb_match);
135e7d48e5fSVladimir Oltean
136e7d48e5fSVladimir Oltean static struct platform_driver enetc_ierb_driver = {
137e7d48e5fSVladimir Oltean .driver = {
138e7d48e5fSVladimir Oltean .name = "fsl-enetc-ierb",
139e7d48e5fSVladimir Oltean .of_match_table = enetc_ierb_match,
140e7d48e5fSVladimir Oltean },
141e7d48e5fSVladimir Oltean .probe = enetc_ierb_probe,
142e7d48e5fSVladimir Oltean };
143e7d48e5fSVladimir Oltean
144e7d48e5fSVladimir Oltean module_platform_driver(enetc_ierb_driver);
145e7d48e5fSVladimir Oltean
146e7d48e5fSVladimir Oltean MODULE_DESCRIPTION("NXP ENETC IERB");
147e7d48e5fSVladimir Oltean MODULE_LICENSE("Dual BSD/GPL");
148