[U-Boot] [PATCH 1/2 v2] drivers: net: add NXP ENETC ethernet driver
Alexandru Marginean
alexandru.marginean at nxp.com
Tue Jun 11 14:27:44 UTC 2019
Hi Bin,
On 6/11/2019 11:18 AM, Alexandru Marginean wrote:
> Hi Bin,
>
> On 6/10/2019 6:42 AM, Bin Meng wrote:
>> Hi Alex,
>>
>> On Sat, Jun 8, 2019 at 12:12 AM Alex Marginean <alexm.osslist at gmail.com> wrote:
>>>
>>> Adds a driver for NXP ENETC ethernet controller currently integrated in
>>> LS1028a. ENETC is a fairly straight-forward BD ring device and interfaces
>>> are presented as PCI EPs on the SoC ECAM.
>>>
>>> Signed-off-by: Catalin Horghidan <catalin.horghidan at nxp.com>
>>> Signed-off-by: Alex Marginean <alexm.osslist at gmail.com>
>>> ---
>>>
>>> Changes in v2:
>>> - Added SXGMII MAC configuration
>>> - simplified naming code in _bind
>>> - renamed ENETC_DBG to enetc_dbg and make it use debug()
>>> - replaced a couple of magic numbers with macros
>>> - droped _V1 from PCI ID macro
>>> - several styling and cosmetic updates to the header file
>>>
>>> configs/ls1028aqds_tfa_defconfig | 1 +
>>> configs/ls1028ardb_tfa_defconfig | 1 +
>>> drivers/net/Kconfig | 7 +
>>> drivers/net/Makefile | 1 +
>>> drivers/net/fsl_enetc.c | 344 +++++++++++++++++++++++++++++++
>>> drivers/net/fsl_enetc.h | 172 ++++++++++++++++
>>> include/pci_ids.h | 1 +
>>> 7 files changed, 527 insertions(+)
>>> create mode 100644 drivers/net/fsl_enetc.c
>>> create mode 100644 drivers/net/fsl_enetc.h
>>>
[snip]
>>> diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
>>> new file mode 100644
>>> index 0000000000..325e032746
>>> --- /dev/null
>>> +++ b/drivers/net/fsl_enetc.c
>>> @@ -0,0 +1,344 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * ENETC ethernet controller driver
>>> + * Copyright 2017-2019 NXP
>>> + */
>>> +
>>> +#include "fsl_enetc.h"
>>
>> nits: this local include should come after all other includes.
>>
>>> +
>>> +#include <dm.h>
>>> +#include <errno.h>
>>> +#include <memalign.h>
>>> +#include <asm/io.h>
>>> +#include <asm/processor.h>
>>> +#include <pci.h>
>>> +
>>> +static int enetc_bind(struct udevice *dev)
>>> +{
>>> + char name[16];
>>> +
>>> + sprintf(name, "enetc#%u", PCI_FUNC(dm_pci_get_bdf(dev)));
>>> + device_set_name(dev, name);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/*
>>> + * Probe ENETC driver:
>>> + * - initialize port and station interface BARs
>>> + */
>>> +static int enetc_probe(struct udevice *dev)
>>> +{
>>> + struct enetc_devfn *hw = dev_get_priv(dev);
>>> + int err = 0;
>>> +
>>> + if (ofnode_valid(dev->node) && !ofnode_is_available(dev->node)) {
>>> + enetc_dbg(dev, "interface disabled\n");
>>> + return -ENODEV;
>>> + }
>>> +
>>> + /* initialize register */
>>> + hw->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
>>> + if (!hw->regs_base) {
>>> + enetc_dbg(dev, "failed to map BAR0\n");
>>> + return -EINVAL;
>>> + }
>>> + hw->port_regs = hw->regs_base + ENETC_PORT_REGS_OFF;
>>> +
>>> + dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
>>> +
>>> + return err;
>>> +}
>>> +
>>> +/* ENETC Port MAC address registers accept big-endian format */
>>> +static void enetc_set_primary_mac_addr(struct enetc_devfn *hw, const u8 *addr)
>>> +{
>>> + u16 lower = *(const u16 *)(addr + 4);
>>> + u32 upper = *(const u32 *)addr;
>>> +
>>> + enetc_write_port(hw, ENETC_PSIPMAR0, upper);
>>> + enetc_write_port(hw, ENETC_PSIPMAR1, lower);
>>> +}
>>> +
>>> +int enetc_enable_si_port(struct enetc_devfn *hw)
>>
>> nits: this should be static. Can we put a single line comment to
>> describe what this function does, like others?
>>
>>> +{
>>> + u32 val;
>>> +
>>> + /* set Rx/Tx BDR count */
>>> + val = ENETC_PSICFGR_SET_TXBDR(ENETC_TX_BDR_CNT);
>>> + val |= ENETC_PSICFGR_SET_RXBDR(ENETC_RX_BDR_CNT);
>>> + enetc_write_port(hw, ENETC_PSICFGR(0), val);
>>> + /* set Rx max frame size */
>>> + enetc_write_port(hw, ENETC_PM_MAXFRM, ENETC_RX_MAXFRM_SIZE);
>>> + /* enable MAC port */
>>> + enetc_write_port(hw, ENETC_PM_CC, ENETC_PM_CC_RX_TX_EN);
>>> + /* enable port */
>>> + enetc_write_port(hw, ENETC_PMR, ENETC_PMR_SI0_EN);
>>> + /* set SI cache policy */
>>> + enetc_write(hw, ENETC_SICAR0, ENETC_SICAR_RD_CFG | ENETC_SICAR_WR_CFG);
>>> + /* enable SI */
>>> + enetc_write(hw, ENETC_SIMR, ENETC_SIMR_EN);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/* Use a single set of BDs and buffers. It's functionally OK as u-boot doesn't
>>> + * use multiple interfaces at once.
>>
>> Yep this is true for U-Boot, however it's not a good practice. Could
>> you please move these to the "struct enetc_devfn"?
>>
>>> + */
>>> +DEFINE_ALIGN_BUFFER(struct enetc_tx_bd, enetc_txbd, ENETC_BD_CNT, ENETC_ALIGN);
>>> +DEFINE_ALIGN_BUFFER(union enetc_rx_bd, enetc_rxbd, ENETC_BD_CNT, ENETC_ALIGN);
>>> +DEFINE_ALIGN_BUFFER(u8, enetc_rx_buff, ENETC_RX_MBUFF_SIZE, ENETC_ALIGN);
>>
>> For the rx buffer, isn't the one provided by U-Boot does not fit the
>> hardware requirement, so we have to create our own rx buffer?
>
> I think the reason why we have this here is mostly related to the early
> debug days rather than HW buffer restrictions. I'll look into removing
> the rx buffer and I'll move the descriptors to private structure.
On the buffer provided by u-boot that you mentioned, do you mean
eth_rcv_bufs? It looks like that's only available for legacy eth.
It looks like the expectation for DM is that drivers allocate for
themselves.
Certainly each driver statically allocating for itself bloats u-boot
and dynamic allocation in probe probably leads to fragmentation in
memory pools. It looks to me like the eth_rcv_bufs approach is pretty
good. Is it available, or is there an alternative for DM that I missed?
If a global static like eth_rcv_bufs isn't available I'll allocate the
buffers dynamically.
Thank you!
Alex
More information about the U-Boot
mailing list