The driver ring handling consists of two parts:
- rx_data: DMA coherent data shared with the SoC
- rx_qs: driver internal handling data
It is unclear what "qs" stands for. Rename that part to "rx_info".
While we are here:
- relocate slot from rx_data to rx_info as it is only needed by
the driver and not the SoC.
- rename page_pool to pool because there is only this single pool
inside the driver.
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The Realtek SoC hardware can split incoming packets over multiple buffers.
This allows to receive packets that are larger than the current 2K page
pool limit without changing the design to higher order pages. Add a logic
to handle these fragments.
As a first proof of concept simulate fragmentation by reducing the buffer
size down to 400 bytes. With the current support for standard MTU (1500)
the packets might consist of up to 4 fragments.
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Reorder the code around napi_gro_receive() so that it fits nicely
for the upcoming fragment handling. For this relocate the FCS
stripping and eth_type_trans() calls short before the handover
when the packet is fully built.
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Until now the driver packs each received packet into one ring buffer.
In the future jumbo packets will be split into multiple fragments.
Prepare the ring counters for this:
- Add the more flag to SoC packet header. This denotes if a packet
has more data after the current fragment.
- Ring counters must be handled per packet and not per fragment.
Increase work_done after each packet and not after each fragment.
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Testing shows that the existing performance boost by aligning the data
to 2 bytes (NET_IP_ALIGN) breaks fragment handling on RTL838x devices. The
SoC silently drops 2 bytes between each fragment. Use this tricky alignment
only when it is supported. This will bring down performance on RTL838x SoCs
by 30%. All other SoCs are unaffected. This is a legitimate tradeoff for
allowing multiple fragments. While we are here make clearer what the
definies are about and rename them to a SKB_ prefix.
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Add a helper to simplify SKB freeing and rx counter handling. If SKB
is given, it is freed and the pointer is set to zero. The return value
is the number of freed SKBs (0/1). With this the existing cleanup and
error handling can be simplified like
dev->stats.tx_errors += rteth_free_skb(&packet->skb);
Link: https://github.com/openwrt/openwrt/pull/24245
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The RTL839x has the following hard-coded bus topology:
- Bus 0: Port 0-23
- Bus 1: Port 24-51
So the bus number and the PHY address in the dts are mostly
ignored. Nevertheless fix the assignment for the Zyxel GS1920.
This does not change the functionality it just describes the
hardware correctly. While we are here add the PHY package
description too.
Link: https://github.com/openwrt/openwrt/pull/24281
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The layer 3 code shares the register access lock with the DSA driver.
It is currently unclear to which extent this is really needed. To
avoid permanent access to the DSA private structure reorganize the
locking as follows:
- create a lock pointer in the layer 3 control structure
- link it to the DSA lock during probing
- use the ctrl->lock pointer whenever needed.
Link: https://github.com/openwrt/openwrt/pull/23979
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
With all the code relocation it is time to clean the headers.
- otto_l3_route_ht_params is internal and can be moved to l3.c
- otto_l3_route is no longer needed in rtl-otto.h
- additionally reorder structures to avoid forward declarations
Link: https://github.com/openwrt/openwrt/pull/23979
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
All the layer 3 device specific functions and attributes currently
live in the DSA driver. Add a configuration structure to the layer
3 code. For now provide and fill a dummy value. It will be replaced
with meaningful data with the next patches.
Link: https://github.com/openwrt/openwrt/pull/23963
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The DSA private structure provides an overwhelming mix of
information. L3 data is part of this. Provide a new separated
structure that is linked bidirectionally to the old data.
For the start it only contains a reference pointer and no L3
specific data.
Link: https://github.com/openwrt/openwrt/pull/23937
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The L3 code is manually initialized and finalized in the DSA
probe/remove functions. Relocate the code into seperate helpers
that encapsule all required steps. Make no longer exposed L3
functions static.
Link: https://github.com/openwrt/openwrt/pull/23937
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
DSA is layer 2 and not layer 3. Nevertheless all routing management
needs a home. Separate it into its own source file. This first
step is far from perfect but at least it guides the DSA driver into
the right direction.
No functional changes. Just relocating, renaming and proper including.
Link: https://github.com/openwrt/openwrt/pull/23937
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Improve the DSA receive tagging. For this convert the receive path
to METADATA_HW_PORT_MUX. This way no skb data mangling is needed.
See e.g. airoha_eth.c or mtk_eth_soc.c.
Link: https://github.com/openwrt/openwrt/pull/23948
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This is just some reordering/simplifcation of the transmit path.
Relocate the port extraction into a separate helper for a smaller
xmit function. While we are here add some documentation and
reorder the tag and its contents. As these are only arbitrary
values that help the ethernet driver to identifiy the tag this
is just cosmetic.
Link: https://github.com/openwrt/openwrt/pull/23948
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
A network interface card (NIC) hardware ring of the Realtek Otto switch
SoCs is nothing more than a list of pointers to the ring headers. I.E.
address | content | comment
--------+-----------+------------------------
x + 0 | pointer 0 | points to ring header 0
x + 4 | pointer 1 | points to ring header 1
...
x + 4*n | pointer n | points to ring header n
Headers must be 4 byte aligend. So the lower two bits of the pointers
are unused. Hardware designers desided to give them special meanings.
- Bit 0: Owner of this ring entry, 1 = hardware, 0 = software
- Bit 1: Wrap, 1 = last ring pointer, 0 = normal ring pointer
The driver uses constant defines with slightly confusing naming. Replace
OWN_CPU with OWN_HW to make clear what it is about. Align prefix and
make the defines bitmasks for better readability.
Link: https://github.com/openwrt/openwrt/pull/23676
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
There is currently a difference how upstream and downstream define
the switch in the dts. Downstream holds the switch as a member
node below a root switchcore parent. Upstream uses the switch as
the parent.
Upstream:
ethernet-switch@1b000000 {
mdio-controller@ca00 { };
ethernet { };
ethernet-ports { };
}
Downstream:
switchcore@1b000000 {
ethernet-switch {
ethernet-ports { };
};
mdio-controller@ca00 { };
ethernet { };
}
Align downstream to upstream and merge the ethernet-switch into
the parent node. For this to work adapt the port lookup in the MDIO
and PCS driver.
Remark! With this commit the boot process will give the spurious
error message "rtl838x_eth 1b000000.ethernet-switch:ethernet eth0:
Failed to create a device link to DSA switch 1b000000.ethernet-switch"
This comes from the fact that the switch is the parent of the ethernet
device. Thus a link back from ethernet device to the switch is no
longer possible. Testing shows that the error is just cosmetic.
Link: https://github.com/openwrt/openwrt/pull/23599
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Drop the legacy receive handling and convert the driver to make
use of a zero-copy receive path. To save memory use the page
pool fragment feature. This way two SKBs will fit into one 4KB
page. With the parametrization of this patch the driver will
allocate about 600KB of receive buffers (2 rings with 300KB
each. This already includes space for the SKB header.
iperf3 benchmark gives:
RTL930x
- 1x stream send / from switch 170 Mbit -> 170 MBit
- 4x stream send / from switch 150 MBit -> 150 MBit
- 1x stream receive / to switch 320 MBit -> 400 MBit
- 4x stream receive / to switch 260 MBit -> 300 MBit
Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Although never observed, a transmit timeout might happen.
In that case there is a resource leak inside rteth_tx_timeout().
This happens when rteth_setup_ring_buffer() reinitializes the
transmit buffers and overwrites all transmit slots. Any linked
SKB is lost and leaked at this point.
Be defensive and add a cleanup rteth_free_tx_buffers() function.
Call this alongside rteth_free_rx_buffers() where needed.
Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
There are two helpers to cleanup SKBs that call iternally
dev_kfree_skb_any_reason() but with different error codes.
- dev_kfree_skb_any() reason SKB_DROP_REASON_NOT_SPECIFIED
- dev_consume_skb_any() reason SKB_CONSUMED
The driver does not distinct between the two. Change this and
clean up a SKB that was handed over to the hardware with
dev_consume_skb_any(). This way kernel knows that everything
went well.
Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The cleanup order of the driver is quite confusing. At least
two issues exist.
- phylink_destroy() is missing
- The implicit unregister_netdev() at the end of rteth_remove() is called
too late. The manually managed resources are removed before. This can
lead to stale data access.
Convert to register_netdev() and bring rteth_remove() into a meaningful
order to avoid such issues when converting to page_pool.
Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The error handling flow during probing has some shortcomings.
1. In case an error occurs after netif_napi_add() this must be
cleaned up with a call to netif_napi_del().
2. If devm_register_netdev() fails not only NAPI must be cleaned
up but also the phylink.
Add a cleanup section for the probe. Implement it generically
(checking for 0/NULL values) so it can be called any time when
encountering probe failures.
Link: https://github.com/openwrt/openwrt/pull/23483
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The kernel has two helper defines that guide about hardware
characteristics.
MIPS_L1_CACHE_SHIFT defines the cache line sizes (1<<x) of the
target. It defaults to 5 - so it is assumed that the device has
a cache line size of 32 bytes. This is not true for MIPS 4KEc
cores that are driving the RTL838x SOCs. These cores have 16
byte cache line sizes. Adapt the CONFIG properties for this
target to match the hardware.
ARCH_DMA_MINALIGN definies the alignment for memory allocations.
Other than its name suggests on MIPS devices that have non
coherent DMA kmalloc() respects this configuration. This ensures
that no normal memory is corrupted by DMA blocks that share the
same cache line.
The default for this is 128 bytes. And kernel states itself
"Total overkill for most systems but need as a safe default. Set
this one if any device in the system might do non-coherent DMA".
Realtek devices use non coherent DMA so they are affected by the
setting of ARCH_DMA_MINALIGN. Set this to cache line size for
all devices to reduce memory waste.
Link: https://github.com/openwrt/openwrt/pull/23492
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
In the network context there might be confusion between "struct netdev"
and "struct device". The driver should avoid variables of type device
and name "dev" where possible. Remove all variables that point to the
device and use pdev->dev instead. This is like other network drivers
do it.
While we are here modernize logging during probing. Remove messages
from helpers and log errors during probing with dev_err_probe().
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23420
Signed-off-by: Robert Marko <robimarko@gmail.com>
The function init_mac() can produce errors for the RTL931x devices.
When this happens it throws a message but continues. That can
leave the hardware in a wrong state.
Cleanup the error handling. Remove all messages from the function
and simply return an error value. In the probe() consumer evaluate
this error and abort probing if needed. As there were no reported
issues in the past it is ok to drop the detailed messages and
aggregate them in a single one.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23420
Signed-off-by: Robert Marko <robimarko@gmail.com>
Upstream netdev does not like big guards. Especially
around debugging functions. Convert to scoped_guard()
and only lock the really needed code parts. This way
all debugging can run outside of the lock.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23411
Signed-off-by: Robert Marko <robimarko@gmail.com>
Majority of kernel uses a_to_b(a) instead of b_from_a(a).
Convert to that to be consistent with all helpers in the
driver. Additionally drop inline function definitions.
Let the compiler decide what is best.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23411
Signed-off-by: Robert Marko <robimarko@gmail.com>
The driver uses lazy initialization - during first temperature
get. Checking enabled status over and over again does not make
sense. Provide separate setup functions for this. With this split
the error handling will be improved. If initialization fails, the
sensor will not be registered at all.
While we are here fix some minor typos.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23405
Signed-off-by: Robert Marko <robimarko@gmail.com>
In rtpcs_probe_serdes_bus(), the code manages the device
tree node reference incorrectly:
- It acquires a node pointer np via of_find_compatible_node(),
which increments the reference count.
- It calls of_mdio_find_bus(np) to locate the bus.
- It calls of_node_put(np), which decrements the reference
count. If this was the last reference, the node is freed.
- It then attempts to check if (!of_device_is_available(np)).
The pointer np is used after its reference has been released.
This can lead to a kernel oops or unpredictable behavior if
the memory has been reclaimed.
Fixes: fe27cce1e ("realtek: add SerDes PCS driver")
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23391
Signed-off-by: Robert Marko <robimarko@gmail.com>
As soon as devm_register_netdev returns, the network
interface is "live" and the kernel can call rteth_open().
If the interface is brought up immediately (e.g., by a
userspace script), rteth_open will attempt to call
phylink_start(ctrl->phylink), which will crash the
system because ctrl->phylink has not been assigned yet.
Reorder probing sequence.
While we are here sort the variables by length.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23375
Signed-off-by: Robert Marko <robimarko@gmail.com>
packet->dma is overwritten with a new mapping before
the previous buffer is unmapped. This causes the kernel
to unmap the wrong memory address, leading to memory
leaks and potential corruption.
Additionally set skb pointer to NULL to avoid a free
when the buffer is recycled next time.
Reorder unmapping/mapping sequence.
Fixes: 41300fd88 ("refactor transmit function")
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23375
Signed-off-by: Robert Marko <robimarko@gmail.com>
The mdio driver currently leaves the phy polling disabled after
setup. The dsa driver takes over and mangles the polling registers
so that they fit its needs. While polling is something in between
mdio (PHY) and dsa (MAC) it should be controlled by the mdio
driver.
Add a final "polling enable" function to the mdio driver so that
the MAC registers are filled automatically. For this
- split valid_ports into phy_ports (attached to PHY) and sds_ports
(attached to SerDes)
- Improve the probing so it can differentiate between a phy and a
sds port. This is resolved by the "phy-handle" attribute.
- Split the for_each_port macro into a phy and sds version.
- After probing enable polling for all phy and sds ports.
With this in place the dsa driver can remove the polling setup
completely.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23299
Signed-off-by: Robert Marko <robimarko@gmail.com>
Until now there is a O(n) loop that looks up a port for a
given bus/phy combination. This is slow for high port count
devices (RTL839x and RTL931x). Implement a efficient reverse
lookup table for that.
While we are here adapt tiny bits of the documentation to
better reflect the driver logic after the recent refactoring.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23230
Signed-off-by: Robert Marko <robimarko@gmail.com>
Until now the driver works as follows:
- low level functions do a bulk write
- high level functions have device specific structures
Turn this upside down and hide the register logic in the low
level functions. To achieve this:
- add a register map to each device
- change the low level write to use this map
- use only one common unique command structure
- use the command structure in the high level functions
While we are here fix the RTL838x access patterns. The read
functions do not need to set the bitmask.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23230
Signed-off-by: Robert Marko <robimarko@gmail.com>
Be consistent with the rest of the code and make clear when the
driver accesses ports. For this rename num_phys to num_ports.
Additionally make the device specific port numbers a define and
use them in the configuration structure.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23230
Signed-off-by: Robert Marko <robimarko@gmail.com>
In the define section there are still some masks that are not sorted
into the corresponding register. Move them around.
- This makes clear that C22 and command data share a register
- Add a prefix to the PHY_PATCH_DONE mask to align with rest of code
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23230
Signed-off-by: Robert Marko <robimarko@gmail.com>
Each device specific implementation disables the hardware polling
differently. Harmonize this by providing a central helper. With
this
- disable polling at the very beginning
- remove unneeded sleeping (SDK does not need it too)
- add checks for regmap returncodes
Especially for RTL839x avoid to disable hardware polling at all.
It is enough that the port specific polling is disabled during
configuration.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23230
Signed-off-by: Robert Marko <robimarko@gmail.com>
The mdio driver has found a simple way to handle phy addresses
for all devices with upstream kernel defaults. Remove all unneeded
hacks from the corresponding patch and reword it.
While we are here increase DSA_MAX_PORTS to 56 to match RTL931x.
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23186
Signed-off-by: Robert Marko <robimarko@gmail.com>
The RTL839x actually has two mdio busses.
- mdio bus 0 serves ports 0..23
- mdio bus 1 serves ports 24..51
This is baked into hardware and cannot be changed during mdio driver
setup with any register write. With the recent changes the driver
handles ports, phys and busses in a more logical way. So a port X
is assigned to a bus Y and a phy Z (on that bus). This gives a
mapping like
- port 16 <=> bus 0, address 16
- port 32 <=> bus 1, address 8
This unique assignment is used in the mdio driver as follows:
- Request to read bus 1, address 8
- Lookup corresponding port = 32
- Read from port 32
Looking at RTL839x it becomes clear that bus/phy => port lookup can
be achieved in multiple different ways. The simple reason is, that
for this device the driver cannot setup the smi topology. It is
baked into the hardware. So adding a "virtual" second bus does not
change the hardware access but allows to keep phy addresses below 32.
Making an example
mdio_bus0 {
PHY_C22(40, 40)
}
resolves to port 40. But the same can be achieved with
mdio_bus1 {
PHY_C22(40, 16)
}
In the first case the kernel sees bus/phy = 0/40 and in the second
case it sees bus/phy = 1/16. Both result in the access to the same
phy device on hardware port 40.
Use this analogy for RTL839x devices to match the real hardware
topology. For this change the existing dts and
- activate mdio bus 1 in rtl839x.dtsi
- rearrange devices with ports 24..51 to make use of bus 1
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23186
Signed-off-by: Robert Marko <robimarko@gmail.com>
Add the basic bits to allow 100base-FX SFP mode on the RTL8214FC.
While this looks good fom ethtool perspective, it does not really
change the phy registers to enforce the mode. The SFP is still
driven in 1000base-X.
While it might seem useless at the moment this at least opens
up a new phy control method. This comes handy with one known bug.
In rare cases a SFP that is plugged in during boot does not get
a link. One option to revive the dead port seems to be
root@OpenWrt:~# ethtool -s lan28 speed 100 duplex full autoneg off
rtl83xx-switch 1b000000.switchcore:ethernet-switch lan28: Link is Up - 100Mbps/Full - flow control off
switch: port 28(lan28) entered blocking state
switch: port 28(lan28) entered forwarding state
rtl83xx_fib_event: FIB_RULE ADD/DEL for IPv6 not supported
rtl83xx_fib_event: FIB_RULE ADD/DEL for IPv6 not supported
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/23087
Signed-off-by: Robert Marko <robimarko@gmail.com>