mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2025-12-10 06:24:40 +01:00
Add a new microchipsw target aimed add supporting Microchip switch SoC-s. Start by supporting LAN969x SoC-s as the first subtarget. Signed-off-by: Robert Marko <robert.marko@sartura.hr>
359 lines
11 KiB
Diff
359 lines
11 KiB
Diff
From bb44231712c296fa992cf7e0f7206b0798a1b84c Mon Sep 17 00:00:00 2001
|
|
From: Daniel Machon <daniel.machon@microchip.com>
|
|
Date: Thu, 24 Oct 2024 00:01:30 +0200
|
|
Subject: [PATCH 54/82] net: lan969x: add function for calculating the DSM
|
|
calendar
|
|
|
|
Lan969x has support for RedBox / HSR / PRP (not implemented yet). In
|
|
order to accommodate for this in the future, we need to give lan969x it's
|
|
own function for calculating the DSM calendar.
|
|
|
|
The function calculates the calendar for each taxi bus. The calendar is
|
|
used for bandwidth allocation towards the ports attached to the taxi
|
|
bus. A calendar configuration consists of up-to 64 slots, which may be
|
|
allocated to ports or left unused. Each slot accounts for 1 clock cycle.
|
|
|
|
Also expose sparx5_cal_speed_to_value(), sparx5_get_port_cal_speed,
|
|
sparx5_cal_bw and SPX5_DSM_CAL_EMPTY for use by lan969x.
|
|
|
|
Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
|
|
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
|
|
Link: https://patch.msgid.link/20241024-sparx5-lan969x-switch-driver-2-v2-11-a0b5fae88a0f@microchip.com
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
---
|
|
.../net/ethernet/microchip/lan969x/Makefile | 2 +-
|
|
.../net/ethernet/microchip/lan969x/lan969x.c | 1 +
|
|
.../net/ethernet/microchip/lan969x/lan969x.h | 3 +
|
|
.../microchip/lan969x/lan969x_calendar.c | 191 ++++++++++++++++++
|
|
.../microchip/sparx5/sparx5_calendar.c | 20 +-
|
|
.../ethernet/microchip/sparx5/sparx5_main.h | 15 ++
|
|
6 files changed, 215 insertions(+), 17 deletions(-)
|
|
create mode 100644 drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c
|
|
|
|
--- a/drivers/net/ethernet/microchip/lan969x/Makefile
|
|
+++ b/drivers/net/ethernet/microchip/lan969x/Makefile
|
|
@@ -5,7 +5,7 @@
|
|
|
|
obj-$(CONFIG_LAN969X_SWITCH) += lan969x-switch.o
|
|
|
|
-lan969x-switch-y := lan969x_regs.o lan969x.o
|
|
+lan969x-switch-y := lan969x_regs.o lan969x.o lan969x_calendar.o
|
|
|
|
# Provide include files
|
|
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/fdma
|
|
--- a/drivers/net/ethernet/microchip/lan969x/lan969x.c
|
|
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x.c
|
|
@@ -332,6 +332,7 @@ static const struct sparx5_ops lan969x_o
|
|
.get_sdlb_group = &lan969x_get_sdlb_group,
|
|
.set_port_mux = &lan969x_port_mux_set,
|
|
.ptp_irq_handler = &lan969x_ptp_irq_handler,
|
|
+ .dsm_calendar_calc = &lan969x_dsm_calendar_calc,
|
|
};
|
|
|
|
const struct sparx5_match_data lan969x_desc = {
|
|
--- a/drivers/net/ethernet/microchip/lan969x/lan969x.h
|
|
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x.h
|
|
@@ -51,4 +51,7 @@ static inline bool lan969x_port_is_25g(i
|
|
return false;
|
|
}
|
|
|
|
+/* lan969x_calendar.c */
|
|
+int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
|
|
+ struct sparx5_calendar_data *data);
|
|
#endif
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/microchip/lan969x/lan969x_calendar.c
|
|
@@ -0,0 +1,191 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/* Microchip lan969x Switch driver
|
|
+ *
|
|
+ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
|
|
+ */
|
|
+
|
|
+#include "lan969x.h"
|
|
+
|
|
+#define LAN969X_DSM_CAL_DEVS_PER_TAXI 10
|
|
+#define LAN969X_DSM_CAL_TAXIS 5
|
|
+
|
|
+enum lan969x_dsm_cal_dev {
|
|
+ DSM_CAL_DEV_2G5,
|
|
+ DSM_CAL_DEV_5G,
|
|
+ DSM_CAL_DEV_10G,
|
|
+ DSM_CAL_DEV_OTHER, /* 1G or less */
|
|
+ DSM_CAL_DEV_MAX
|
|
+};
|
|
+
|
|
+/* Each entry in the following struct defines properties for a given speed
|
|
+ * (10G, 5G, 2.5G, or 1G or less).
|
|
+ */
|
|
+struct lan969x_dsm_cal_dev_speed {
|
|
+ /* Number of devices that requires this speed. */
|
|
+ u32 n_devs;
|
|
+
|
|
+ /* Array of devices that requires this speed. */
|
|
+ u32 devs[LAN969X_DSM_CAL_DEVS_PER_TAXI];
|
|
+
|
|
+ /* Number of slots required for one device running this speed. */
|
|
+ u32 n_slots;
|
|
+
|
|
+ /* Gap between two slots for one device running this speed. */
|
|
+ u32 gap;
|
|
+};
|
|
+
|
|
+static u32
|
|
+lan969x_taxi_ports[LAN969X_DSM_CAL_TAXIS][LAN969X_DSM_CAL_DEVS_PER_TAXI] = {
|
|
+ { 0, 4, 1, 2, 3, 5, 6, 7, 28, 29 },
|
|
+ { 8, 12, 9, 13, 10, 11, 14, 15, 99, 99 },
|
|
+ { 16, 20, 17, 21, 18, 19, 22, 23, 99, 99 },
|
|
+ { 24, 25, 99, 99, 99, 99, 99, 99, 99, 99 },
|
|
+ { 26, 27, 99, 99, 99, 99, 99, 99, 99, 99 }
|
|
+};
|
|
+
|
|
+static int lan969x_dsm_cal_idx_get(u32 *calendar, u32 cal_len, u32 *cal_idx)
|
|
+{
|
|
+ if (*cal_idx >= cal_len)
|
|
+ return -EINVAL;
|
|
+
|
|
+ do {
|
|
+ if (calendar[*cal_idx] == SPX5_DSM_CAL_EMPTY)
|
|
+ return 0;
|
|
+
|
|
+ (*cal_idx)++;
|
|
+ } while (*cal_idx < cal_len);
|
|
+
|
|
+ return -ENOENT;
|
|
+}
|
|
+
|
|
+static enum lan969x_dsm_cal_dev lan969x_dsm_cal_get_dev(int speed)
|
|
+{
|
|
+ return (speed == 10000 ? DSM_CAL_DEV_10G :
|
|
+ speed == 5000 ? DSM_CAL_DEV_5G :
|
|
+ speed == 2500 ? DSM_CAL_DEV_2G5 :
|
|
+ DSM_CAL_DEV_OTHER);
|
|
+}
|
|
+
|
|
+static int lan969x_dsm_cal_get_speed(enum lan969x_dsm_cal_dev dev)
|
|
+{
|
|
+ return (dev == DSM_CAL_DEV_10G ? 10000 :
|
|
+ dev == DSM_CAL_DEV_5G ? 5000 :
|
|
+ dev == DSM_CAL_DEV_2G5 ? 2500 :
|
|
+ 1000);
|
|
+}
|
|
+
|
|
+int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
|
|
+ struct sparx5_calendar_data *data)
|
|
+{
|
|
+ struct lan969x_dsm_cal_dev_speed dev_speeds[DSM_CAL_DEV_MAX] = {};
|
|
+ u32 cal_len, n_slots, taxi_bw, n_devs = 0, required_bw = 0;
|
|
+ struct lan969x_dsm_cal_dev_speed *speed;
|
|
+ int err;
|
|
+
|
|
+ /* Maximum bandwidth for this taxi */
|
|
+ taxi_bw = (128 * 1000000) / sparx5_clk_period(sparx5->coreclock);
|
|
+
|
|
+ memcpy(data->taxi_ports, &lan969x_taxi_ports[taxi],
|
|
+ LAN969X_DSM_CAL_DEVS_PER_TAXI * sizeof(u32));
|
|
+
|
|
+ for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) {
|
|
+ u32 portno = data->taxi_ports[i];
|
|
+ enum sparx5_cal_bw bw;
|
|
+
|
|
+ bw = sparx5_get_port_cal_speed(sparx5, portno);
|
|
+
|
|
+ if (portno < sparx5->data->consts->n_ports_all)
|
|
+ data->taxi_speeds[i] = sparx5_cal_speed_to_value(bw);
|
|
+ else
|
|
+ data->taxi_speeds[i] = 0;
|
|
+ }
|
|
+
|
|
+ /* Determine the different port types (10G, 5G, 2.5G, <= 1G) in the
|
|
+ * this taxi map.
|
|
+ */
|
|
+ for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) {
|
|
+ u32 taxi_speed = data->taxi_speeds[i];
|
|
+ enum lan969x_dsm_cal_dev dev;
|
|
+
|
|
+ if (taxi_speed == 0)
|
|
+ continue;
|
|
+
|
|
+ required_bw += taxi_speed;
|
|
+
|
|
+ dev = lan969x_dsm_cal_get_dev(taxi_speed);
|
|
+ speed = &dev_speeds[dev];
|
|
+ speed->devs[speed->n_devs++] = i;
|
|
+ n_devs++;
|
|
+ }
|
|
+
|
|
+ if (required_bw > taxi_bw) {
|
|
+ pr_err("Required bandwidth: %u is higher than total taxi bandwidth: %u",
|
|
+ required_bw, taxi_bw);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (n_devs == 0) {
|
|
+ data->schedule[0] = SPX5_DSM_CAL_EMPTY;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cal_len = n_devs;
|
|
+
|
|
+ /* Search for a calendar length that fits all active devices. */
|
|
+ while (cal_len < SPX5_DSM_CAL_LEN) {
|
|
+ u32 bw_per_slot = taxi_bw / cal_len;
|
|
+
|
|
+ n_slots = 0;
|
|
+
|
|
+ for (int i = 0; i < DSM_CAL_DEV_MAX; i++) {
|
|
+ speed = &dev_speeds[i];
|
|
+
|
|
+ if (speed->n_devs == 0)
|
|
+ continue;
|
|
+
|
|
+ required_bw = lan969x_dsm_cal_get_speed(i);
|
|
+ speed->n_slots = DIV_ROUND_UP(required_bw, bw_per_slot);
|
|
+
|
|
+ if (speed->n_slots)
|
|
+ speed->gap = DIV_ROUND_UP(cal_len,
|
|
+ speed->n_slots);
|
|
+ else
|
|
+ speed->gap = 0;
|
|
+
|
|
+ n_slots += speed->n_slots * speed->n_devs;
|
|
+ }
|
|
+
|
|
+ if (n_slots <= cal_len)
|
|
+ break; /* Found a suitable calendar length. */
|
|
+
|
|
+ /* Not good enough yet. */
|
|
+ cal_len = n_slots;
|
|
+ }
|
|
+
|
|
+ if (cal_len > SPX5_DSM_CAL_LEN) {
|
|
+ pr_err("Invalid length: %u for taxi: %u", cal_len, taxi);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ for (u32 i = 0; i < SPX5_DSM_CAL_LEN; i++)
|
|
+ data->schedule[i] = SPX5_DSM_CAL_EMPTY;
|
|
+
|
|
+ /* Place the remaining devices */
|
|
+ for (u32 i = 0; i < DSM_CAL_DEV_MAX; i++) {
|
|
+ speed = &dev_speeds[i];
|
|
+ for (u32 dev = 0; dev < speed->n_devs; dev++) {
|
|
+ u32 idx = 0;
|
|
+
|
|
+ for (n_slots = 0; n_slots < speed->n_slots; n_slots++) {
|
|
+ err = lan969x_dsm_cal_idx_get(data->schedule,
|
|
+ cal_len, &idx);
|
|
+ if (err)
|
|
+ return err;
|
|
+ data->schedule[idx] = speed->devs[dev];
|
|
+ idx += speed->gap;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
|
|
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c
|
|
@@ -15,7 +15,6 @@
|
|
#define SPX5_CALBITS_PER_PORT 3 /* Bit per port in calendar register */
|
|
|
|
/* DSM calendar information */
|
|
-#define SPX5_DSM_CAL_EMPTY 0xFFFF
|
|
#define SPX5_DSM_CAL_TAXIS 8
|
|
#define SPX5_DSM_CAL_BW_LOSS 553
|
|
|
|
@@ -74,18 +73,6 @@ static u32 sparx5_target_bandwidth(struc
|
|
}
|
|
}
|
|
|
|
-/* This is used in calendar configuration */
|
|
-enum sparx5_cal_bw {
|
|
- SPX5_CAL_SPEED_NONE = 0,
|
|
- SPX5_CAL_SPEED_1G = 1,
|
|
- SPX5_CAL_SPEED_2G5 = 2,
|
|
- SPX5_CAL_SPEED_5G = 3,
|
|
- SPX5_CAL_SPEED_10G = 4,
|
|
- SPX5_CAL_SPEED_25G = 5,
|
|
- SPX5_CAL_SPEED_0G5 = 6,
|
|
- SPX5_CAL_SPEED_12G5 = 7
|
|
-};
|
|
-
|
|
static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock)
|
|
{
|
|
switch (cclock) {
|
|
@@ -98,7 +85,7 @@ static u32 sparx5_clk_to_bandwidth(enum
|
|
return 0;
|
|
}
|
|
|
|
-static u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
|
|
+u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed)
|
|
{
|
|
switch (speed) {
|
|
case SPX5_CAL_SPEED_1G: return 1000;
|
|
@@ -111,6 +98,7 @@ static u32 sparx5_cal_speed_to_value(enu
|
|
default: return 0;
|
|
}
|
|
}
|
|
+EXPORT_SYMBOL_GPL(sparx5_cal_speed_to_value);
|
|
|
|
static u32 sparx5_bandwidth_to_calendar(u32 bw)
|
|
{
|
|
@@ -128,8 +116,7 @@ static u32 sparx5_bandwidth_to_calendar(
|
|
}
|
|
}
|
|
|
|
-static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5,
|
|
- u32 portno)
|
|
+enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno)
|
|
{
|
|
struct sparx5_port *port;
|
|
|
|
@@ -163,6 +150,7 @@ static enum sparx5_cal_bw sparx5_get_por
|
|
return SPX5_CAL_SPEED_NONE;
|
|
return sparx5_bandwidth_to_calendar(port->conf.bandwidth);
|
|
}
|
|
+EXPORT_SYMBOL_GPL(sparx5_get_port_cal_speed);
|
|
|
|
/* Auto configure the QSYS calendar based on port configuration */
|
|
int sparx5_config_auto_calendar(struct sparx5 *sparx5)
|
|
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
|
|
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
|
|
@@ -63,6 +63,18 @@ enum sparx5_vlan_port_type {
|
|
SPX5_VLAN_PORT_TYPE_S_CUSTOM /* S-port using custom type */
|
|
};
|
|
|
|
+/* This is used in calendar configuration */
|
|
+enum sparx5_cal_bw {
|
|
+ SPX5_CAL_SPEED_NONE = 0,
|
|
+ SPX5_CAL_SPEED_1G = 1,
|
|
+ SPX5_CAL_SPEED_2G5 = 2,
|
|
+ SPX5_CAL_SPEED_5G = 3,
|
|
+ SPX5_CAL_SPEED_10G = 4,
|
|
+ SPX5_CAL_SPEED_25G = 5,
|
|
+ SPX5_CAL_SPEED_0G5 = 6,
|
|
+ SPX5_CAL_SPEED_12G5 = 7
|
|
+};
|
|
+
|
|
#define SPX5_PORTS 65
|
|
#define SPX5_PORTS_ALL 70 /* Total number of ports */
|
|
|
|
@@ -113,6 +125,7 @@ enum sparx5_vlan_port_type {
|
|
|
|
#define SPX5_DSM_CAL_LEN 64
|
|
#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13
|
|
+#define SPX5_DSM_CAL_EMPTY 0xFFFF
|
|
|
|
#define SPARX5_MAX_PTP_ID 512
|
|
|
|
@@ -454,6 +467,8 @@ int sparx5_config_auto_calendar(struct s
|
|
int sparx5_config_dsm_calendar(struct sparx5 *sparx5);
|
|
int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
|
|
struct sparx5_calendar_data *data);
|
|
+u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed);
|
|
+enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno);
|
|
|
|
|
|
/* sparx5_ethtool.c */
|