Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2022-12-29 18:54:22 +08:00
commit 3ef187c32f
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
54 changed files with 2701 additions and 2308 deletions

View File

@ -49,6 +49,7 @@ zbtlink,zbt-wg2626|\
zte,mf283plus)
ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x10000"
;;
asus,rt-ax53u|\
belkin,rt1800|\
h3c,tx1800-plus|\
h3c,tx1801-plus|\

View File

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=linux-firmware
PKG_VERSION:=20221109
PKG_RELEASE:=5
PKG_VERSION:=20221214
PKG_RELEASE:=2
PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_HASH:=c0ddffbbcf30f2e015bddd5c6d3ce1f13976b906aceabda4a57e3c41a3190701
PKG_HASH:=e793783e92acbde549965521462d1d1327827360664cf242dbda08f075654331
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>

View File

@ -19,5 +19,6 @@ define Package/ath11k-firmware-wcn6855/install
$(INSTALL_DIR) $(1)/lib/firmware/ath11k/WCN6855/hw2.0
$(INSTALL_DATA) \
$(PKG_BUILD_DIR)/ath11k/WCN6855/hw2.0/* $(1)/lib/firmware/ath11k/WCN6855/hw2.0/
$(LN) ./hw2.0 $(1)/lib/firmware/ath11k/WCN6855/hw2.1
endef
$(eval $(call BuildPackage,ath11k-firmware-wcn6855))

View File

@ -0,0 +1,298 @@
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -44,6 +44,7 @@ struct radius_das_attrs {
struct radius_das_conf {
int port;
const u8 *shared_secret;
+ const u8 *nas_identifier;
size_t shared_secret_len;
const struct hostapd_ip_addr *client_addr;
unsigned int time_window;
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1367,6 +1367,7 @@ static int hostapd_setup_bss(struct host
struct radius_das_conf das_conf;
os_memset(&das_conf, 0, sizeof(das_conf));
das_conf.port = conf->radius_das_port;
+ das_conf.nas_identifier = conf->nas_identifier;
das_conf.shared_secret = conf->radius_das_shared_secret;
das_conf.shared_secret_len =
conf->radius_das_shared_secret_len;
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -12,13 +12,26 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/ip_addr.h"
+#include "utils/list.h"
#include "radius.h"
#include "radius_das.h"
-struct radius_das_data {
+static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
+
+struct radius_das_port {
+ struct dl_list list;
+ struct dl_list das_data;
+
+ int port;
int sock;
+};
+
+struct radius_das_data {
+ struct dl_list list;
+ struct radius_das_port *port;
u8 *shared_secret;
+ u8 *nas_identifier;
size_t shared_secret_len;
struct hostapd_ip_addr client_addr;
unsigned int time_window;
@@ -378,56 +391,17 @@ fail:
}
-static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+static void
+radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
+ struct sockaddr *from, socklen_t fromlen,
+ char *abuf, int from_port)
{
- struct radius_das_data *das = eloop_ctx;
- u8 buf[1500];
- union {
- struct sockaddr_storage ss;
- struct sockaddr_in sin;
-#ifdef CONFIG_IPV6
- struct sockaddr_in6 sin6;
-#endif /* CONFIG_IPV6 */
- } from;
- char abuf[50];
- int from_port = 0;
- socklen_t fromlen;
- int len;
- struct radius_msg *msg, *reply = NULL;
+ struct radius_msg *reply = NULL;
struct radius_hdr *hdr;
struct wpabuf *rbuf;
+ struct os_time now;
u32 val;
int res;
- struct os_time now;
-
- fromlen = sizeof(from);
- len = recvfrom(sock, buf, sizeof(buf), 0,
- (struct sockaddr *) &from.ss, &fromlen);
- if (len < 0) {
- wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
- return;
- }
-
- os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
- from_port = ntohs(from.sin.sin_port);
-
- wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
- len, abuf, from_port);
- if (das->client_addr.u.v4.s_addr &&
- das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
- wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
- return;
- }
-
- msg = radius_msg_parse(buf, len);
- if (msg == NULL) {
- wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
- "from %s:%d failed", abuf, from_port);
- return;
- }
-
- if (wpa_debug_level <= MSG_MSGDUMP)
- radius_msg_dump(msg);
if (radius_msg_verify_das_req(msg, das->shared_secret,
das->shared_secret_len,
@@ -494,9 +468,8 @@ static void radius_das_receive(int sock,
radius_msg_dump(reply);
rbuf = radius_msg_get_buf(reply);
- res = sendto(das->sock, wpabuf_head(rbuf),
- wpabuf_len(rbuf), 0,
- (struct sockaddr *) &from.ss, fromlen);
+ res = sendto(das->port->sock, wpabuf_head(rbuf),
+ wpabuf_len(rbuf), 0, from, fromlen);
if (res < 0) {
wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
abuf, from_port, strerror(errno));
@@ -508,6 +481,72 @@ fail:
radius_msg_free(reply);
}
+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct radius_das_port *p = eloop_ctx;
+ struct radius_das_data *das;
+ u8 buf[1500];
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ struct radius_msg *msg;
+ size_t nasid_len = 0;
+ u8 *nasid_buf = NULL;
+ char abuf[50];
+ int from_port = 0;
+ socklen_t fromlen;
+ int found = 0;
+ int len;
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+ return;
+ }
+
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+ "from %s:%d failed", abuf, from_port);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(msg);
+
+ radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ &nasid_buf, &nasid_len, NULL);
+ dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
+ if (das->client_addr.u.v4.s_addr &&
+ das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
+ continue;
+
+ if (das->nas_identifier && nasid_buf &&
+ (nasid_len != os_strlen(das->nas_identifier) ||
+ os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
+ continue;
+
+ found = 1;
+ radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
+ fromlen, abuf, from_port);
+ }
+
+ if (!found)
+ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+}
+
static int radius_das_open_socket(int port)
{
@@ -533,6 +572,49 @@ static int radius_das_open_socket(int po
}
+static struct radius_das_port *
+radius_das_open_port(int port)
+{
+ struct radius_das_port *p;
+
+ dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
+ if (p->port == port)
+ return p;
+ }
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return NULL;
+
+ dl_list_init(&p->das_data);
+ p->port = port;
+ p->sock = radius_das_open_socket(port);
+ if (p->sock < 0)
+ goto free_port;
+
+ if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
+ goto close_port;
+
+ dl_list_add(&das_ports, &p->list);
+
+ return p;
+
+close_port:
+ close(p->sock);
+free_port:
+ os_free(p);
+
+ return NULL;
+}
+
+static void radius_das_close_port(struct radius_das_port *p)
+{
+ dl_list_del(&p->list);
+ eloop_unregister_read_sock(p->sock);
+ close(p->sock);
+ free(p);
+}
+
struct radius_das_data *
radius_das_init(struct radius_das_conf *conf)
{
@@ -553,6 +635,8 @@ radius_das_init(struct radius_das_conf *
das->ctx = conf->ctx;
das->disconnect = conf->disconnect;
das->coa = conf->coa;
+ if (conf->nas_identifier)
+ das->nas_identifier = os_strdup(conf->nas_identifier);
os_memcpy(&das->client_addr, conf->client_addr,
sizeof(das->client_addr));
@@ -565,19 +649,15 @@ radius_das_init(struct radius_das_conf *
}
das->shared_secret_len = conf->shared_secret_len;
- das->sock = radius_das_open_socket(conf->port);
- if (das->sock < 0) {
+ das->port = radius_das_open_port(conf->port);
+ if (!das->port) {
wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
"DAS");
radius_das_deinit(das);
return NULL;
}
- if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
- {
- radius_das_deinit(das);
- return NULL;
- }
+ dl_list_add(&das->port->das_data, &das->list);
return das;
}
@@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das
if (das == NULL)
return;
- if (das->sock >= 0) {
- eloop_unregister_read_sock(das->sock);
- close(das->sock);
+ if (das->port) {
+ dl_list_del(&das->list);
+
+ if (dl_list_empty(&das->port->das_data))
+ radius_das_close_port(das->port);
}
+ os_free(das->nas_identifier);
os_free(das->shared_secret);
os_free(das);
}

View File

@ -86,7 +86,8 @@ case "$FIRMWARE" in
avm,fritz300e)
caldata_extract_reverse "urloader" 0x1541 0x440
;;
buffalo,wzr-hp-g450h)
buffalo,wzr-hp-g450h|\
pcs,cap324)
caldata_extract "art" 0x1000 0x440
;;
dlink,dir-825-c1|\
@ -103,9 +104,8 @@ case "$FIRMWARE" in
;;
netgear,wnr2200-8m|\
netgear,wnr2200-16m|\
pcs,cap324|\
tplink,tl-wr842n-v1)
caldata_extract "art" 0x1000 0x1000
caldata_extract "art" 0x1000 0x3e0
;;
wd,mynet-n600|\
wd,mynet-n750)
@ -113,7 +113,7 @@ case "$FIRMWARE" in
ath9k_patch_mac $(mtd_get_mac_ascii devdata "wlan5mac")
;;
wd,mynet-wifi-rangeextender)
caldata_extract "art" 0x1000 0x1000
caldata_extract "art" 0x1000 0x440
ath9k_patch_mac $(nvram get wl0_hwaddr)
;;
*)

View File

@ -0,0 +1,31 @@
From 882882912cd25a637ba0cf09932ad248f584e680 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
Date: Wed, 28 Dec 2022 13:19:49 +0100
Subject: [PATCH 1/2] Revert "net: broadcom: Add PTP_1588_CLOCK_OPTIONAL
dependency for BCMGENET under ARCH_BCM2835"
[ Upstream commit 421f8663b3a775c32f724f793264097c60028f2e ]
This reverts commit eb96fd3983b2cca1c90db45eaff1de67b94f9950.
---
drivers/net/ethernet/broadcom/Kconfig | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -71,14 +71,13 @@ config BCM63XX_ENET
config BCMGENET
tristate "Broadcom GENET internal MAC support"
depends on HAS_IOMEM
- depends on PTP_1588_CLOCK_OPTIONAL || !ARCH_BCM2835
select MII
select PHYLIB
select FIXED_PHY
select BCM7XXX_PHY
select MDIO_BCM_UNIMAC
select DIMLIB
- select BROADCOM_PHY if ARCH_BCM2835
+ select BROADCOM_PHY if (ARCH_BCM2835 && PTP_1588_CLOCK_OPTIONAL)
help
This driver supports the built-in Ethernet MACs found in the
Broadcom BCM7xxx Set Top Box family chipset.

View File

@ -0,0 +1,23 @@
From f032f801658ce6b47498f3e140f7e4aef0645042 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
Date: Wed, 28 Dec 2022 13:20:24 +0100
Subject: [PATCH 2/2] Revert "net: broadcom: Fix BCMGENET Kconfig"
[ Upstream commit 8d820bc9d12b8beebca836cceaf2bbe68216c2f8 ]
This reverts commit 6a264203dbdb0d076891d83bf3bb274d6b3863f2.
---
drivers/net/ethernet/broadcom/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -77,7 +77,7 @@ config BCMGENET
select BCM7XXX_PHY
select MDIO_BCM_UNIMAC
select DIMLIB
- select BROADCOM_PHY if (ARCH_BCM2835 && PTP_1588_CLOCK_OPTIONAL)
+ select BROADCOM_PHY if ARCH_BCM2835
help
This driver supports the built-in Ethernet MACs found in the
Broadcom BCM7xxx Set Top Box family chipset.

View File

@ -1,12 +1,15 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 3 Nov 2022 12:38:49 +0100
Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with
sending small fragments
Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with sending
small fragments
When frames are sent with very small fragments, the DMA engine appears to
lock up and transmit attempts time out. Fix this by detecting the presence
of small fragments and use skb_gso_segment + skb_linearize to deal with
them
When lots of frames are sent with a number of very small fragments, an
internal FIFO can overflow, causing the DMA engine to lock up lock up and
transmit attempts time out.
Fix this on MT7986 by increasing the reserved FIFO space.
Fix this on older chips by detecting the presence of small fragments and use
skb_gso_segment + skb_linearize to deal with them.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
@ -42,11 +45,12 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
bool gso = false;
int tx_num;
@@ -1423,6 +1439,17 @@ static netdev_tx_t mtk_start_xmit(struct
@@ -1423,6 +1439,18 @@ static netdev_tx_t mtk_start_xmit(struct
return NETDEV_TX_BUSY;
}
+ if (skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) {
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
+ skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) {
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO);
+ if (IS_ERR(segs))
+ goto drop;
@ -60,19 +64,31 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* TSO: fill MSS info in tcp checksum field */
if (skb_is_gso(skb)) {
if (skb_cow_head(skb, 0)) {
@@ -1438,8 +1465,13 @@ static netdev_tx_t mtk_start_xmit(struct
@@ -1438,8 +1466,14 @@ static netdev_tx_t mtk_start_xmit(struct
}
}
- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
- goto drop;
+ skb_list_walk_safe(skb, skb, next) {
+ if ((mtk_skb_has_small_frag(skb) && skb_linearize(skb)) ||
+ if ((!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
+ mtk_skb_has_small_frag(skb) && skb_linearize(skb)) ||
+ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) {
+ stats->tx_dropped++;
+ dev_kfree_skb_any(skb);
+ stats->tx_dropped++;
+ dev_kfree_skb_any(skb);
+ }
+ }
if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
netif_tx_stop_all_queues(dev);
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -246,7 +246,7 @@
#define MTK_CHK_DDONE_EN BIT(28)
#define MTK_DMAD_WR_WDONE BIT(26)
#define MTK_WCOMP_EN BIT(24)
-#define MTK_RESV_BUF (0x40 << 16)
+#define MTK_RESV_BUF (0x80 << 16)
#define MTK_MUTLI_CNT (0x4 << 12)
#define MTK_LEAKY_BUCKET_EN BIT(11)

View File

@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3531,9 +3531,12 @@ static int mtk_hw_init(struct mtk_eth *e
@@ -3533,9 +3533,12 @@ static int mtk_hw_init(struct mtk_eth *e
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {

View File

@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1993,29 +1993,16 @@ static int mtk_poll_rx(struct napi_struc
@@ -1995,29 +1995,16 @@ static int mtk_poll_rx(struct napi_struc
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
mtk_ppe_check_skb(eth->ppe[0], skb, hash);
@ -50,7 +50,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
}
skb_record_rx_queue(skb, 0);
@@ -2832,29 +2819,11 @@ static netdev_features_t mtk_fix_feature
@@ -2834,29 +2821,11 @@ static netdev_features_t mtk_fix_feature
static int mtk_set_features(struct net_device *dev, netdev_features_t features)
{
@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return 0;
}
@@ -3153,30 +3122,6 @@ static int mtk_open(struct net_device *d
@@ -3155,30 +3124,6 @@ static int mtk_open(struct net_device *d
struct mtk_eth *eth = mac->hw;
int i, err;
@ -111,7 +111,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
if (err) {
netdev_err(dev, "%s: could not attach PHY: %d\n", __func__,
@@ -3217,6 +3162,35 @@ static int mtk_open(struct net_device *d
@@ -3219,6 +3164,35 @@ static int mtk_open(struct net_device *d
phylink_start(mac->phylink);
netif_tx_start_all_queues(dev);
@ -147,7 +147,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
return 0;
}
@@ -3510,10 +3484,9 @@ static int mtk_hw_init(struct mtk_eth *e
@@ -3512,10 +3486,9 @@ static int mtk_hw_init(struct mtk_eth *e
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
@ -160,7 +160,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/* set interrupt delays based on current Net DIM sample */
mtk_dim_rx(&eth->rx_dim.work);
@@ -4134,7 +4107,7 @@ static int mtk_add_mac(struct mtk_eth *e
@@ -4136,7 +4109,7 @@ static int mtk_add_mac(struct mtk_eth *e
eth->netdev[id]->hw_features |= NETIF_F_LRO;
eth->netdev[id]->vlan_features = eth->soc->hw_features &

View File

@ -0,0 +1,55 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 27 Dec 2022 15:02:51 +0100
Subject: [PATCH] net: ethernet: mtk_eth_soc: ppe: fix L2 offloading with DSA
untagging offload enabled
Check for skb metadata in order to detect the case where the DSA header is not
present.
Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1992,9 +1992,6 @@ static int mtk_poll_rx(struct napi_struc
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, netdev);
- if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
- mtk_ppe_check_skb(eth->ppe[0], skb, hash);
-
/* When using VLAN untagging in combination with DSA, the
* hardware treats the MTK special tag as a VLAN and untags it.
*/
@@ -2007,6 +2004,9 @@ static int mtk_poll_rx(struct napi_struc
skb_dst_set_noref(skb, &eth->dsa_meta[port]->dst);
}
+ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+ mtk_ppe_check_skb(eth->ppe[0], skb, hash);
+
skb_record_rx_queue(skb, 0);
napi_gro_receive(napi, skb);
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -8,6 +8,7 @@
#include <linux/platform_device.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
+#include <net/dst_metadata.h>
#include <net/dsa.h>
#include "mtk_eth_soc.h"
#include "mtk_ppe.h"
@@ -756,7 +757,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe
skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK)
goto out;
- tag += 4;
+ if (!skb_metadata_dst(skb))
+ tag += 4;
+
if (get_unaligned_be16(tag) != ETH_P_8021Q)
break;

View File

@ -60,12 +60,21 @@
partition@0 {
label = "u-boot";
reg = <0x0 0xe0000>;
reg = <0x0 0x80000>;
read-only;
};
partition@e0000 {
/*
* u-boot gets split here while keeping u-boot read-only,
* which allows safe usage of fw_setenv
*/
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x60000>;
};
partition@e0000 {
label = "nvram";
reg = <0xe0000 0x100000>;
read-only;
};

View File

@ -18,8 +18,17 @@ endef
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES += uboot-envtools ethtool kmod-gpio-button-hotplug \
firewall4 nftables kmod-nft-offload odhcp6c \
ip-full ip-bridge tc-bpf
DEFAULT_PACKAGES += \
ethtool \
firewall4 \
ip-bridge \
ip-full \
kmod-gpio-button-hotplug \
kmod-nft-offload \
nftables \
odhcp6c \
tc-bpf \
uboot-envtools \
$(eval $(call BuildTarget))

View File

@ -129,9 +129,9 @@
label = "jffs2";
reg = <0x160000 0x100000>;
};
partition@b260000 {
partition@260000 {
label = "firmware";
reg = <0x260000 0xda0000>;
reg = <0x260000 0x6d0000>;
compatible = "openwrt,uimage", "denx,uimage";
openwrt,ih-magic = <0x83800000>;
};

View File

@ -129,9 +129,9 @@
label = "jffs2";
reg = <0x160000 0x100000>;
};
partition@b260000 {
partition@260000 {
label = "firmware";
reg = <0x260000 0xda0000>;
reg = <0x260000 0x6d0000>;
compatible = "openwrt,uimage", "denx,uimage";
openwrt,ih-magic = <0x83800000>;
};

View File

@ -121,28 +121,45 @@ void rtl_table_release(struct table_reg *r)
// pr_info("Unlock done\n");
}
static int rtl_table_exec(struct table_reg *r, bool is_write, int idx)
{
int ret = 0;
u32 cmd, val;
/* Read/write bit has inverted meaning on RTL838x */
if (r->rmode)
cmd = is_write ? 0 : BIT(r->c_bit);
else
cmd = is_write ? BIT(r->c_bit) : 0;
cmd |= BIT(r->c_bit + 1); /* Execute bit */
cmd |= r->tbl << r->t_bit; /* Table type */
cmd |= idx & (BIT(r->t_bit) - 1); /* Index */
sw_w32(cmd, r->addr);
ret = readx_poll_timeout(sw_r32, r->addr, val,
!(val & BIT(r->c_bit + 1)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/*
* Reads table index idx into the data registers of the table
*/
void rtl_table_read(struct table_reg *r, int idx)
int rtl_table_read(struct table_reg *r, int idx)
{
u32 cmd = r->rmode ? BIT(r->c_bit) : 0;
cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1));
sw_w32(cmd, r->addr);
do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1));
return rtl_table_exec(r, false, idx);
}
/*
* Writes the content of the table data registers into the table at index idx
*/
void rtl_table_write(struct table_reg *r, int idx)
int rtl_table_write(struct table_reg *r, int idx)
{
u32 cmd = r->rmode ? 0 : BIT(r->c_bit);
cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1));
sw_w32(cmd, r->addr);
do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1));
return rtl_table_exec(r, true, idx);
}
/*
@ -323,7 +340,6 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
if (of_property_read_u32(dn, "reg", &pn))
continue;
pr_info("%s found port %d\n", __func__, pn);
phy_node = of_parse_phandle(dn, "phy-handle", 0);
if (!phy_node) {
if (pn != priv->cpu_port)
@ -331,14 +347,9 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
continue;
}
pr_info("%s port %d has phandle\n", __func__, pn);
if (of_property_read_u32(phy_node, "sds", &priv->ports[pn].sds_num))
priv->ports[pn].sds_num = -1;
else {
pr_info("%s sds port %d is %d\n", __func__, pn,
priv->ports[pn].sds_num);
}
pr_info("%s port %d has SDS\n", __func__, priv->ports[pn].sds_num);
pr_debug("%s port %d has SDS %d\n", __func__, pn, priv->ports[pn].sds_num);
if (of_get_phy_mode(dn, &interface))
interface = PHY_INTERFACE_MODE_NA;

View File

@ -343,6 +343,9 @@ static int l2_table_show(struct seq_file *m, void *v)
seq_printf(m, "Hash table bucket %d index %d ", bucket, index);
l2_table_print_entry(m, priv, &e);
if (!((i + 1) % 64))
cond_resched();
}
for (i = 0; i < 64; i++) {

View File

@ -1728,6 +1728,9 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
if (e.port == port || e.port == RTL930X_PORT_IGNORE)
cb(e.mac, e.vid, e.is_static, data);
if (!((i + 1) % 64))
cond_resched();
}
for (i = 0; i < 64; i++) {

View File

@ -67,8 +67,8 @@ typedef enum {
void rtl_table_init(void);
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t);
void rtl_table_release(struct table_reg *r);
void rtl_table_read(struct table_reg *r, int idx);
void rtl_table_write(struct table_reg *r, int idx);
int rtl_table_read(struct table_reg *r, int idx);
int rtl_table_write(struct table_reg *r, int idx);
inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);

View File

@ -96,7 +96,7 @@ struct notify_b {
static void rtl838x_create_tx_header(struct p_hdr *h, unsigned int dest_port, int prio)
{
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0401; // BIT 10: RTL8380_CPU_TAG, BIT0: L2LEARNING on
h->cpu_tag[1] = 0x0400; // BIT 10: RTL8380_CPU_TAG
h->cpu_tag[2] = 0x0200; // Set only AS_DPM, to enable DPM settings below
h->cpu_tag[3] = 0x0000;
h->cpu_tag[4] = BIT(dest_port) >> 16;
@ -111,7 +111,7 @@ static void rtl839x_create_tx_header(struct p_hdr *h, unsigned int dest_port, in
{
// cpu_tag[0] is reserved on the RTL83XX SoCs
h->cpu_tag[1] = 0x0100; // RTL8390_CPU_TAG marker
h->cpu_tag[2] = BIT(4) | BIT(7); /* AS_DPM (4) and L2LEARNING (7) flags */
h->cpu_tag[2] = BIT(4); /* AS_DPM flag */
h->cpu_tag[3] = h->cpu_tag[4] = h->cpu_tag[5] = 0;
// h->cpu_tag[1] |= BIT(1) | BIT(0); // Bypass filter 1/2
if (dest_port >= 32) {
@ -682,7 +682,7 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv)
else
reset_mask = 0xc;
sw_w32(reset_mask, priv->r->rst_glb_ctrl);
sw_w32_mask(0, reset_mask, priv->r->rst_glb_ctrl);
do { /* Wait for reset of NIC and Queues done */
udelay(20);

View File

@ -17,7 +17,7 @@ description: |
RTL83XX: 0x3100, 0x3110, 0x3120, 0x3130, 0x3140
RTL93XX: 0x3200, 0x3210, 0x3220, 0x3230, 0x3240
properties:
compatible:
items:

View File

@ -350,9 +350,7 @@
#define RTL931X_MAC_L2_GLOBAL_CTRL2 (0x1358)
#define RTL931X_MAC_L2_GLOBAL_CTRL1 (0x5548)
/*
* Switch interrupts
*/
/* Switch interrupts */
#define RTL838X_IMR_GLB (0x1100)
#define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104)
#define RTL838X_ISR_GLB_SRC (0x1148)
@ -368,7 +366,7 @@
#define RTL930X_ISR_GLB (0xC658)
#define RTL930X_ISR_PORT_LINK_STS_CHG (0xC660)
// IMR_GLB does not exit on RTL931X
/* IMR_GLB does not exit on RTL931X */
#define RTL931X_IMR_PORT_LINK_STS_CHG (0x126C)
#define RTL931X_ISR_GLB_SRC (0x12B4)
#define RTL931X_ISR_PORT_LINK_STS_CHG (0x12B8)

View File

@ -11,7 +11,7 @@
#include <mach-rtl83xx.h>
/*
/*
* Timer registers
* the RTL9300/9310 SoCs have 6 timers, each register block 0x10 apart
*/
@ -24,11 +24,11 @@
#define RTL9300_TC_INT_IP BIT(16)
#define RTL9300_TC_INT_IE BIT(20)
// Timer modes
/* Timer modes */
#define TIMER_MODE_REPEAT 1
#define TIMER_MODE_ONCE 0
// Minimum divider is 2
/* Minimum divider is 2 */
#define DIVISOR_RTL9300 2
#define N_BITS 28
@ -54,11 +54,12 @@ static irqreturn_t rtl9300_timer_interrupt(int irq, void *dev_id)
u32 v = readl(rtl_clk->base + RTL9300_TC_INT);
// Acknowledge the IRQ
/* Acknowledge the IRQ */
v |= RTL9300_TC_INT_IP;
writel(v, rtl_clk->base + RTL9300_TC_INT);
clk->event_handler(clk);
return IRQ_HANDLED;
}
@ -68,7 +69,7 @@ static void rtl9300_clock_stop(void __iomem *base)
writel(0, base + RTL9300_TC_CTRL);
// Acknowledge possibly pending IRQ
/* Acknowledge possibly pending IRQ */
v = readl(base + RTL9300_TC_INT);
writel(v | RTL9300_TC_INT_IP, base + RTL9300_TC_INT);
}
@ -101,6 +102,7 @@ static int rtl9300_state_periodic(struct clock_event_device *clk)
rtl9300_clock_stop(base);
writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
rtl9300_timer_start(base, TIMER_MODE_REPEAT);
return 0;
}
@ -112,6 +114,7 @@ static int rtl9300_state_oneshot(struct clock_event_device *clk)
rtl9300_clock_stop(base);
writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
rtl9300_timer_start(base, TIMER_MODE_ONCE);
return 0;
}
@ -121,6 +124,7 @@ static int rtl9300_shutdown(struct clock_event_device *clk)
pr_debug("------------- rtl9300_shutdown %08x\n", (u32)base);
rtl9300_clock_stop(base);
return 0;
}
@ -128,14 +132,14 @@ static void rtl9300_clock_setup(void __iomem *base)
{
u32 v;
// Disable timer
/* Disable timer */
writel(0, base + RTL9300_TC_CTRL);
// Acknowledge possibly pending IRQ
/* Acknowledge possibly pending IRQ */
v = readl(base + RTL9300_TC_INT);
writel(v | RTL9300_TC_INT_IP, base + RTL9300_TC_INT);
// Setup maximum period (for use as clock-source)
/* Setup maximum period (for use as clock-source) */
writel(0x0fffffff, base + RTL9300_TC_DATA);
}

View File

@ -147,4 +147,3 @@ wait_cpu:
.globl rtcl_838x_dram_size
rtcl_838x_dram_size:
.word .-rtcl_838x_dram_start

View File

@ -139,4 +139,3 @@ wait_pllclock:
.globl rtcl_839x_dram_size
rtcl_839x_dram_size:
.word .-rtcl_839x_dram_start

View File

@ -467,9 +467,9 @@ static long rtcl_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long
*/
#define RTCL_SRAM_FUNC(SOC, PBASE, FN) ({ \
rtcl_##SOC##_sram_##FN = ((void *)&rtcl_##SOC##_dram_##FN \
- (void *)&rtcl_##SOC##_dram_start) \
+ (void *)PBASE; })
rtcl_##SOC##_sram_##FN = ((void *)&rtcl_##SOC##_dram_##FN - \
(void *)&rtcl_##SOC##_dram_start) + \
(void *)PBASE; })
static const struct clk_ops rtcl_clk_ops = {
.set_rate = rtcl_set_rate,
@ -663,11 +663,10 @@ err_put_device:
void rtcl_ccu_log_early(void)
{
int clk_idx;
char meminfo[80], clkinfo[255], msg[255] = "rtl83xx-clk: initialized";
sprintf(meminfo, " (%d Bit DDR%d)", rtcl_ccu->dram.buswidth, rtcl_ccu->dram.type);
for (clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
for (int clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
sprintf(clkinfo, ", %s %lu MHz", rtcl_clk_info[clk_idx].display_name,
rtcl_ccu->clks[clk_idx].startup / 1000000);
if (clk_idx == CLK_MEM)
@ -679,12 +678,11 @@ void rtcl_ccu_log_early(void)
void rtcl_ccu_log_late(void)
{
int clk_idx;
struct rtcl_clk *rclk;
bool overclock = false;
char clkinfo[80], msg[255] = "rate setting enabled";
for (clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
for (int clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
rclk = &rtcl_ccu->clks[clk_idx];
overclock |= rclk->max > rclk->startup;
sprintf(clkinfo, ", %s %lu-%lu MHz", rtcl_clk_info[clk_idx].display_name,

View File

@ -45,7 +45,7 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg)
/* Set execution bit: cleared when operation completed */
t |= 1;
// Start execution
/* Start execution */
sw_w32(t, gpios->ext_gpio_indrt_access);
do {
udelay(1);
@ -55,7 +55,7 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg)
if (n >= USEC_TIMEOUT)
return 0x80000000;
pr_debug("%s: %x, %x, %x\n", __func__, gpios->smi_bus_id,
reg, (t & 0xffff0000) >> 16);
@ -76,7 +76,7 @@ static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data)
/* Set execution bit: cleared when operation completed */
t |= 1;
// Start execution
/* Start execution */
sw_w32(t, gpios->ext_gpio_indrt_access);
do {
udelay(1);
@ -127,6 +127,7 @@ static int rtl8231_pin_dir(struct rtl8231_gpios *gpios, u32 gpio, u32 dir)
rtl8231_write(gpios, pin_dir_addr, v);
gpios->reg_shadow[pin_dir_addr] = v;
gpios->reg_cached |= 1 << pin_dir_addr;
return 0;
}
@ -150,6 +151,7 @@ static int rtl8231_pin_dir_get(struct rtl8231_gpios *gpios, u32 gpio, u32 *dir)
*dir = 1;
else
*dir = 0;
return 0;
}
@ -166,6 +168,7 @@ static int rtl8231_pin_set(struct rtl8231_gpios *gpios, u32 gpio, u32 data)
rtl8231_write(gpios, RTL8231_GPIO_DATA(gpio), v);
gpios->reg_shadow[RTL8231_GPIO_DATA(gpio)] = v;
gpios->reg_cached |= 1 << RTL8231_GPIO_DATA(gpio);
return 0;
}
@ -179,6 +182,7 @@ static int rtl8231_pin_get(struct rtl8231_gpios *gpios, u32 gpio, u16 *state)
}
*state = v & 0xffff;
return 0;
}
@ -191,6 +195,7 @@ static int rtl8231_direction_input(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 1);
mutex_unlock(&miim_lock);
return err;
}
@ -203,8 +208,10 @@ static int rtl8231_direction_output(struct gpio_chip *gc, unsigned int offset, i
mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 0);
mutex_unlock(&miim_lock);
if (!err)
err = rtl8231_pin_set(gpios, offset, value);
return err;
}
@ -217,6 +224,7 @@ static int rtl8231_get_direction(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock);
rtl8231_pin_dir_get(gpios, offset, &v);
mutex_unlock(&miim_lock);
return v;
}
@ -228,8 +236,10 @@ static int rtl8231_gpio_get(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock);
rtl8231_pin_get(gpios, offset, &state);
mutex_unlock(&miim_lock);
if (state & (1 << (offset % 16)))
return 1;
return 0;
}
@ -249,10 +259,10 @@ int rtl8231_init(struct rtl8231_gpios *gpios)
gpios->reg_cached = 0;
if (soc_info.family == RTL8390_FAMILY_ID) {
// RTL8390: Enable external gpio in global led control register
/* RTL8390: Enable external gpio in global led control register */
sw_w32_mask(0x7 << 18, 0x4 << 18, RTL839X_LED_GLB_CTRL);
} else if (soc_info.family == RTL8380_FAMILY_ID) {
// RTL8380: Enable RTL8231 indirect access mode
/* RTL8380: Enable RTL8231 indirect access mode */
sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL);
sw_w32_mask(3, 1, RTL838X_DMY_REG5);
}
@ -337,8 +347,7 @@ static int rtl8231_gpio_probe(struct platform_device *pdev)
gpios->gc.get = rtl8231_gpio_get;
gpios->gc.get_direction = rtl8231_get_direction;
err = devm_gpiochip_add_data(dev, &gpios->gc, gpios);
return err;
return devm_gpiochip_add_data(dev, &gpios->gc, gpios);
}
static struct platform_driver rtl8231_gpio_driver = {

View File

@ -23,27 +23,27 @@ struct i2c_drv_data {
void (*config_io)(struct rtl9300_i2c *i2c, int scl_num, int sda_num);
u32 mst2_offset;
};
DEFINE_MUTEX(i2c_lock);
static void rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
// Set register address width
/* Set register address width */
REG_MASK(i2c, 0x3 << RTL9300_I2C_CTRL2_MADDR_WIDTH, len << RTL9300_I2C_CTRL2_MADDR_WIDTH,
RTL9300_I2C_CTRL2);
// Set register address
/* Set register address */
REG_MASK(i2c, 0xffffff << RTL9300_I2C_CTRL1_MEM_ADDR, reg << RTL9300_I2C_CTRL1_MEM_ADDR,
RTL9300_I2C_CTRL1);
}
static void rtl9310_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
// Set register address width
/* Set register address width */
REG_MASK(i2c, 0x3 << RTL9310_I2C_CTRL_MADDR_WIDTH, len << RTL9310_I2C_CTRL_MADDR_WIDTH,
RTL9310_I2C_CTRL);
// Set register address
/* Set register address */
writel(reg, REG(i2c, RTL9310_I2C_MEMADDR));
}
@ -51,14 +51,14 @@ static void rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, int scl_num, int sda_
{
u32 v;
// Set SCL pin
/* Set SCL pin */
REG_MASK(i2c, 0, BIT(RTL9300_I2C_CTRL1_GPIO8_SCL_SEL), RTL9300_I2C_CTRL1);
// Set SDA pin
/* Set SDA pin */
REG_MASK(i2c, 0x7 << RTL9300_I2C_CTRL1_SDA_OUT_SEL,
i2c->sda_num << RTL9300_I2C_CTRL1_SDA_OUT_SEL, RTL9300_I2C_CTRL1);
// Set SDA pin to I2C functionality
/* Set SDA pin to I2C functionality */
v = readl(i2c->base + RTL9300_I2C_MST_GLB_CTRL);
v |= BIT(i2c->sda_num);
writel(v, i2c->base + RTL9300_I2C_MST_GLB_CTRL);
@ -68,14 +68,14 @@ static void rtl9310_i2c_config_io(struct rtl9300_i2c *i2c, int scl_num, int sda_
{
u32 v;
// Set SCL pin
/* Set SCL pin */
REG_MASK(i2c, 0, BIT(RTL9310_I2C_MST_IF_SEL_GPIO_SCL_SEL + scl_num), RTL9310_I2C_MST_IF_SEL);
// Set SDA pin
/* Set SDA pin */
REG_MASK(i2c, 0x7 << RTL9310_I2C_CTRL_SDA_OUT_SEL,
i2c->sda_num << RTL9310_I2C_CTRL_SDA_OUT_SEL, RTL9310_I2C_CTRL);
// Set SDA pin to I2C functionality
/* Set SDA pin to I2C functionality */
v = readl(i2c->base + RTL9310_I2C_MST_IF_SEL);
v |= BIT(i2c->sda_num);
writel(v, i2c->base + RTL9310_I2C_MST_IF_SEL);
@ -83,19 +83,19 @@ static void rtl9310_i2c_config_io(struct rtl9300_i2c *i2c, int scl_num, int sda_
static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
{
// Set bus frequency
/* Set bus frequency */
REG_MASK(i2c, 0x3 << RTL9300_I2C_CTRL2_SCL_FREQ,
i2c->bus_freq << RTL9300_I2C_CTRL2_SCL_FREQ, RTL9300_I2C_CTRL2);
// Set slave device address
/* Set slave device address */
REG_MASK(i2c, 0x7f << RTL9300_I2C_CTRL2_DEV_ADDR,
addr << RTL9300_I2C_CTRL2_DEV_ADDR, RTL9300_I2C_CTRL2);
// Set data length
/* Set data length */
REG_MASK(i2c, 0xf << RTL9300_I2C_CTRL2_DATA_WIDTH,
((len - 1) & 0xf) << RTL9300_I2C_CTRL2_DATA_WIDTH, RTL9300_I2C_CTRL2);
// Set read mode to random
/* Set read mode to random */
REG_MASK(i2c, 0x1 << RTL9300_I2C_CTRL2_READ_MODE, 0, RTL9300_I2C_CTRL2);
return 0;
@ -103,19 +103,19 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
static int rtl9310_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
{
// Set bus frequency
/* Set bus frequency */
REG_MASK(i2c, 0x3 << RTL9310_I2C_CTRL_SCL_FREQ,
i2c->bus_freq << RTL9310_I2C_CTRL_SCL_FREQ, RTL9310_I2C_CTRL);
// Set slave device address
/* Set slave device address */
REG_MASK(i2c, 0x7f << RTL9310_I2C_CTRL_DEV_ADDR,
addr << RTL9310_I2C_CTRL_DEV_ADDR, RTL9310_I2C_CTRL);
// Set data length
/* Set data length */
REG_MASK(i2c, 0xf << RTL9310_I2C_CTRL_DATA_WIDTH,
((len - 1) & 0xf) << RTL9310_I2C_CTRL_DATA_WIDTH, RTL9310_I2C_CTRL);
// Set read mode to random
/* Set read mode to random */
REG_MASK(i2c, 0x1 << RTL9310_I2C_CTRL_READ_MODE, 0, RTL9310_I2C_CTRL);
return 0;
@ -123,13 +123,12 @@ static int rtl9310_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
static int i2c_read(void __iomem *r0, u8 *buf, int len)
{
int i;
u32 v;
if (len > 16)
return -EIO;
for (i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
u32 v;
if (i % 4 == 0)
v = readl(r0 + i);
buf[i] = v;
@ -141,13 +140,12 @@ static int i2c_read(void __iomem *r0, u8 *buf, int len)
static int i2c_write(void __iomem *r0, u8 *buf, int len)
{
u32 v;
int i;
if (len > 16)
return -EIO;
for (i = 0; i < len; i++) {
for (int i = 0; i < len; i++) {
u32 v;
if (! (i % 4))
v = 0;
v <<= 8;
@ -347,7 +345,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
int ret = 0;
pr_info("%s probing I2C adapter\n", __func__);
if (!node) {
dev_err(i2c->dev, "No DT found\n");
return -EINVAL;
@ -376,7 +374,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
case I2C_MAX_STANDARD_MODE_FREQ:
i2c->bus_freq = RTL9300_I2C_STD_FREQ;
break;
case I2C_MAX_FAST_MODE_FREQ:
i2c->bus_freq = RTL9300_I2C_FAST_FREQ;
break;
@ -451,7 +449,7 @@ struct i2c_drv_data rtl9300_i2c_drv_data = {
};
struct i2c_drv_data rtl9310_i2c_drv_data = {
.scl0_pin = 13,
.scl0_pin = 13,
.scl1_pin = 14,
.sda0_pin = 0,
.read = rtl9310_i2c_read,

View File

@ -55,8 +55,8 @@ struct rtl9300_i2c {
struct device *dev;
struct i2c_adapter adap;
u8 bus_freq;
u8 sda_num; // SDA channel number
u8 scl_num; // SCL channel, mapping to master 1 or 2
u8 sda_num; /* SDA channel number */
u8 scl_num; /* SCL channel, mapping to master 1 or 2 */
};
#endif

View File

@ -48,11 +48,11 @@ static int rtl9300_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
// Set SCL pin
/* Set SCL pin */
REG_MASK(channels[chan].scl_num, 0,
BIT(RTL9300_I2C_CTRL1_GPIO8_SCL_SEL), RTL9300_I2C_CTRL1);
// Set SDA pin
/* Set SDA pin */
REG_MASK(channels[chan].scl_num, 0x7 << RTL9300_I2C_CTRL1_SDA_OUT_SEL,
channels[chan].sda_num << RTL9300_I2C_CTRL1_SDA_OUT_SEL, RTL9300_I2C_CTRL1);
@ -66,11 +66,11 @@ static int rtl9310_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
// Set SCL pin
/* Set SCL pin */
REG_MASK(0, 0, BIT(RTL9310_I2C_MST_IF_SEL_GPIO_SCL_SEL + channels[chan].scl_num),
RTL9310_I2C_MST_IF_SEL);
// Set SDA pin
/* Set SDA pin */
REG_MASK(channels[chan].scl_num, 0xf << RTL9310_I2C_CTRL_SDA_OUT_SEL,
channels[chan].sda_num << RTL9310_I2C_CTRL_SDA_OUT_SEL, RTL9310_I2C_CTRL);
@ -90,7 +90,7 @@ static void rtl9300_sda_sel(struct i2c_mux_core *muxc, int pin)
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
u32 v;
// Set SDA pin to I2C functionality
/* Set SDA pin to I2C functionality */
v = readl(REG(0, RTL9300_I2C_MST_GLB_CTRL));
v |= BIT(pin);
writel(v, REG(0, RTL9300_I2C_MST_GLB_CTRL));
@ -101,7 +101,7 @@ static void rtl9310_sda_sel(struct i2c_mux_core *muxc, int pin)
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
u32 v;
// Set SDA pin to I2C functionality
/* Set SDA pin to I2C functionality */
v = readl(REG(0, RTL9310_I2C_MST_IF_SEL));
v |= BIT(pin);
writel(v, REG(0, RTL9310_I2C_MST_IF_SEL));
@ -123,8 +123,8 @@ static struct device_node *mux_parent_adapter(struct device *dev, struct rtl9300
if (!parent)
return ERR_PTR(-EPROBE_DEFER);
if (!(of_device_is_compatible(parent_np, "realtek,rtl9300-i2c")
|| of_device_is_compatible(parent_np, "realtek,rtl9310-i2c"))){
if (!(of_device_is_compatible(parent_np, "realtek,rtl9300-i2c") ||
of_device_is_compatible(parent_np, "realtek,rtl9310-i2c"))){
dev_err(dev, "I2C parent not an RTL9300 I2C controller\n");
return ERR_PTR(-ENODEV);
}
@ -147,7 +147,7 @@ struct i2c_mux_data rtl9300_i2c_mux_data = {
};
struct i2c_mux_data rtl9310_i2c_mux_data = {
.scl0_pin = 13,
.scl0_pin = 13,
.scl1_pin = 14,
.sda0_pin = 0,
.sda_pins = 16,
@ -177,7 +177,7 @@ static int rtl9300_i2c_mux_probe(struct platform_device *pdev)
int ret;
pr_info("%s probing I2C adapter\n", __func__);
if (!node) {
dev_err(dev, "No DT found\n");
return -EINVAL;

View File

@ -5,4 +5,3 @@ config NET_DSA_RTL83XX
select NET_DSA_TAG_TRAILER
help
This driver adds support for Realtek RTL83xx series switching.

View File

@ -9,8 +9,8 @@
#include <linux/inetdevice.h>
#include <linux/rhashtable.h>
#include <linux/of_net.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
extern struct rtl83xx_soc_info soc_info;
@ -58,40 +58,37 @@ int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port)
}
static struct table_reg rtl838x_tbl_regs[] = {
TBL_DESC(0x6900, 0x6908, 3, 15, 13, 1), // RTL8380_TBL_L2
TBL_DESC(0x6914, 0x6918, 18, 14, 12, 1), // RTL8380_TBL_0
TBL_DESC(0xA4C8, 0xA4CC, 6, 14, 12, 1), // RTL8380_TBL_1
TBL_DESC(0x6900, 0x6908, 3, 15, 13, 1), /* RTL8380_TBL_L2 */
TBL_DESC(0x6914, 0x6918, 18, 14, 12, 1), /* RTL8380_TBL_0 */
TBL_DESC(0xA4C8, 0xA4CC, 6, 14, 12, 1), /* RTL8380_TBL_1 */
TBL_DESC(0x1180, 0x1184, 3, 16, 14, 0), // RTL8390_TBL_L2
TBL_DESC(0x1190, 0x1194, 17, 15, 12, 0), // RTL8390_TBL_0
TBL_DESC(0x6B80, 0x6B84, 4, 14, 12, 0), // RTL8390_TBL_1
TBL_DESC(0x611C, 0x6120, 9, 8, 6, 0), // RTL8390_TBL_2
TBL_DESC(0x1180, 0x1184, 3, 16, 14, 0), /* RTL8390_TBL_L2 */
TBL_DESC(0x1190, 0x1194, 17, 15, 12, 0), /* RTL8390_TBL_0 */
TBL_DESC(0x6B80, 0x6B84, 4, 14, 12, 0), /* RTL8390_TBL_1 */
TBL_DESC(0x611C, 0x6120, 9, 8, 6, 0), /* RTL8390_TBL_2 */
TBL_DESC(0xB320, 0xB334, 3, 18, 16, 0), // RTL9300_TBL_L2
TBL_DESC(0xB340, 0xB344, 19, 16, 12, 0), // RTL9300_TBL_0
TBL_DESC(0xB3A0, 0xB3A4, 20, 16, 13, 0), // RTL9300_TBL_1
TBL_DESC(0xCE04, 0xCE08, 6, 14, 12, 0), // RTL9300_TBL_2
TBL_DESC(0xD600, 0xD604, 30, 7, 6, 0), // RTL9300_TBL_HSB
TBL_DESC(0x7880, 0x7884, 22, 9, 8, 0), // RTL9300_TBL_HSA
TBL_DESC(0xB320, 0xB334, 3, 18, 16, 0), /* RTL9300_TBL_L2 */
TBL_DESC(0xB340, 0xB344, 19, 16, 12, 0), /* RTL9300_TBL_0 */
TBL_DESC(0xB3A0, 0xB3A4, 20, 16, 13, 0), /* RTL9300_TBL_1 */
TBL_DESC(0xCE04, 0xCE08, 6, 14, 12, 0), /* RTL9300_TBL_2 */
TBL_DESC(0xD600, 0xD604, 30, 7, 6, 0), /* RTL9300_TBL_HSB */
TBL_DESC(0x7880, 0x7884, 22, 9, 8, 0), /* RTL9300_TBL_HSA */
TBL_DESC(0x8500, 0x8508, 8, 19, 15, 0), // RTL9310_TBL_0
TBL_DESC(0x40C0, 0x40C4, 22, 16, 14, 0), // RTL9310_TBL_1
TBL_DESC(0x8528, 0x852C, 6, 18, 14, 0), // RTL9310_TBL_2
TBL_DESC(0x0200, 0x0204, 9, 15, 12, 0), // RTL9310_TBL_3
TBL_DESC(0x20dc, 0x20e0, 29, 7, 6, 0), // RTL9310_TBL_4
TBL_DESC(0x7e1c, 0x7e20, 53, 8, 6, 0), // RTL9310_TBL_5
TBL_DESC(0x8500, 0x8508, 8, 19, 15, 0), /* RTL9310_TBL_0 */
TBL_DESC(0x40C0, 0x40C4, 22, 16, 14, 0), /* RTL9310_TBL_1 */
TBL_DESC(0x8528, 0x852C, 6, 18, 14, 0), /* RTL9310_TBL_2 */
TBL_DESC(0x0200, 0x0204, 9, 15, 12, 0), /* RTL9310_TBL_3 */
TBL_DESC(0x20dc, 0x20e0, 29, 7, 6, 0), /* RTL9310_TBL_4 */
TBL_DESC(0x7e1c, 0x7e20, 53, 8, 6, 0), /* RTL9310_TBL_5 */
};
void rtl_table_init(void)
{
int i;
for (i = 0; i < RTL_TBL_END; i++)
for (int i = 0; i < RTL_TBL_END; i++)
mutex_init(&rtl838x_tbl_regs[i].lock);
}
/*
* Request access to table t in table access register r
/* Request access to table t in table access register r
* Returns a handle to a lock for that table
*/
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
@ -108,45 +105,55 @@ struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
return &rtl838x_tbl_regs[r];
}
/*
* Release a table r, unlock the corresponding lock
*/
/* Release a table r, unlock the corresponding lock */
void rtl_table_release(struct table_reg *r)
{
if (!r)
return;
// pr_info("Unlocking %08x\n", (u32)r);
/* pr_info("Unlocking %08x\n", (u32)r); */
mutex_unlock(&r->lock);
// pr_info("Unlock done\n");
/* pr_info("Unlock done\n"); */
}
/*
* Reads table index idx into the data registers of the table
*/
void rtl_table_read(struct table_reg *r, int idx)
static int rtl_table_exec(struct table_reg *r, bool is_write, int idx)
{
u32 cmd = r->rmode ? BIT(r->c_bit) : 0;
int ret = 0;
u32 cmd, val;
/* Read/write bit has inverted meaning on RTL838x */
if (r->rmode)
cmd = is_write ? 0 : BIT(r->c_bit);
else
cmd = is_write ? BIT(r->c_bit) : 0;
cmd |= BIT(r->c_bit + 1); /* Execute bit */
cmd |= r->tbl << r->t_bit; /* Table type */
cmd |= idx & (BIT(r->t_bit) - 1); /* Index */
cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1));
sw_w32(cmd, r->addr);
do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1));
ret = readx_poll_timeout(sw_r32, r->addr, val,
!(val & BIT(r->c_bit + 1)), 20, 10000);
if (ret)
pr_err("%s: timeout\n", __func__);
return ret;
}
/*
* Writes the content of the table data registers into the table at index idx
*/
void rtl_table_write(struct table_reg *r, int idx)
/* Reads table index idx into the data registers of the table */
int rtl_table_read(struct table_reg *r, int idx)
{
u32 cmd = r->rmode ? 0 : BIT(r->c_bit);
cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1));
sw_w32(cmd, r->addr);
do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1));
return rtl_table_exec(r, false, idx);
}
/*
* Returns the address of the ith data register of table register r
/* Writes the content of the table data registers into the table at index idx */
int rtl_table_write(struct table_reg *r, int idx)
{
return rtl_table_exec(r, true, idx);
}
/* Returns the address of the ith data register of table register r
* the address is relative to the beginning of the Switch-IO block at 0xbb000000
*/
inline u16 rtl_table_data(struct table_reg *r, int i)
@ -179,7 +186,7 @@ void rtl838x_set_port_reg(u64 set, int reg)
u64 rtl838x_get_port_reg(int reg)
{
return ((u64) sw_r32(reg));
return ((u64)sw_r32(reg));
}
/* Port register accessor functions for the RTL839x and RTL931X SoCs */
@ -195,6 +202,7 @@ u64 rtl839x_get_port_reg_be(int reg)
v <<= 32;
v |= sw_r32(reg + 4);
return v;
}
@ -222,6 +230,7 @@ u64 rtl839x_get_port_reg_le(int reg)
v <<= 32;
v |= sw_r32(reg);
return v;
}
@ -237,6 +246,7 @@ int read_phy(u32 port, u32 page, u32 reg, u32 *val)
case RTL9310_FAMILY_ID:
return rtl931x_read_phy(port, page, reg, val);
}
return -1;
}
@ -252,6 +262,7 @@ int write_phy(u32 port, u32 page, u32 reg, u32 val)
case RTL9310_FAMILY_ID:
return rtl931x_write_phy(port, page, reg, val);
}
return -1;
}
@ -286,8 +297,7 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
bus->name = "rtl838x slave mii";
/*
* Since the NIC driver is loaded first, we can use the mdio rw functions
/* Since the NIC driver is loaded first, we can use the mdio rw functions
* assigned there.
*/
bus->read = priv->mii_bus->read;
@ -323,7 +333,6 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
if (of_property_read_u32(dn, "reg", &pn))
continue;
pr_info("%s found port %d\n", __func__, pn);
phy_node = of_parse_phandle(dn, "phy-handle", 0);
if (!phy_node) {
if (pn != priv->cpu_port)
@ -331,14 +340,9 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
continue;
}
pr_info("%s port %d has phandle\n", __func__, pn);
if (of_property_read_u32(phy_node, "sds", &priv->ports[pn].sds_num))
priv->ports[pn].sds_num = -1;
else {
pr_info("%s sds port %d is %d\n", __func__, pn,
priv->ports[pn].sds_num);
}
pr_info("%s port %d has SDS\n", __func__, priv->ports[pn].sds_num);
pr_debug("%s port %d has SDS %d\n", __func__, pn, priv->ports[pn].sds_num);
if (of_get_phy_mode(dn, &interface))
interface = PHY_INTERFACE_MODE_NA;
@ -353,7 +357,7 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
led_set = 0;
priv->ports[pn].led_set = led_set;
// Check for the integrated SerDes of the RTL8380M first
/* Check for the integrated SerDes of the RTL8380M first */
if (of_property_read_bool(phy_node, "phy-is-integrated")
&& priv->id == 0x8380 && pn >= 24) {
pr_debug("----> FÓUND A SERDES\n");
@ -368,21 +372,21 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
priv->ports[pn].phy = PHY_RTL930X_SDS;
}
} else {
if (of_property_read_bool(phy_node, "phy-is-integrated")
&& !of_property_read_bool(phy_node, "sfp")) {
if (of_property_read_bool(phy_node, "phy-is-integrated") &&
!of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8218B_INT;
continue;
}
}
if (!of_property_read_bool(phy_node, "phy-is-integrated")
&& of_property_read_bool(phy_node, "sfp")) {
if (!of_property_read_bool(phy_node, "phy-is-integrated") &&
of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8214FC;
continue;
}
if (!of_property_read_bool(phy_node, "phy-is-integrated")
&& !of_property_read_bool(phy_node, "sfp")) {
if (!of_property_read_bool(phy_node, "phy-is-integrated") &&
!of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8218B_EXT;
continue;
}
@ -408,6 +412,7 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
}
pr_debug("%s done\n", __func__);
return 0;
}
@ -424,6 +429,7 @@ static int __init rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv)
pr_debug("L2 AGING time: %d sec\n", t);
pr_debug("Dynamic aging for ports: %x\n", sw_r32(priv->r->l2_port_aging_out));
return t;
}
@ -458,6 +464,7 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
pr_err("%s: Port %d already member of LAG %d.\n", __func__, port, i);
return -ENOSPC;
}
switch(info->hash_type) {
case NETDEV_LAG_HASH_L2:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
@ -466,15 +473,15 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
case NETDEV_LAG_HASH_L23:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; //source ip
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; //dest ip
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 1;
break;
case NETDEV_LAG_HASH_L34:
algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; //sport
algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; //dport
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; //source ip
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; //dest ip
algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
algoidx = 2;
break;
default:
@ -486,6 +493,7 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
pr_info("%s: Added port %d to LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
return 0;
}
@ -509,18 +517,17 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
return -ENOSPC;
}
// 0x7f algo mask all
/* 0x7f algo mask all */
priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group));
priv->lags_port_members[group] &= ~BIT_ULL(port);
pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
return 0;
}
/*
* Allocate a 64 bit octet counter located in the LOG HW table
*/
/* Allocate a 64 bit octet counter located in the LOG HW table */
static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
{
int idx;
@ -539,8 +546,7 @@ static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
return idx;
}
/*
* Allocate a 32-bit packet counter
/* Allocate a 32-bit packet counter
* 2 32-bit packet counters share the location of a 64-bit octet counter
* Initially there are no free packet counters and 2 new ones need to be freed
* by allocating the corresponding octet counter
@ -574,8 +580,7 @@ int rtl83xx_packet_cntr_alloc(struct rtl838x_switch_priv *priv)
return idx;
}
/*
* Add an L2 nexthop entry for the L3 routing system / PIE forwarding in the SoC
/* Add an L2 nexthop entry for the L3 routing system / PIE forwarding in the SoC
* Use VID and MAC in rtl838x_l2_entry to identify either a free slot in the L2 hash table
* or mark an existing entry as a nexthop by setting it's nexthop bit
* Called from the L3 layer
@ -586,7 +591,7 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
struct rtl838x_l2_entry e;
u64 seed = priv->r->l2_hash_seed(nh->mac, nh->rvid);
u32 key = priv->r->l2_hash_key(priv, seed);
int i, idx = -1;
int idx = -1;
u64 entry;
pr_debug("%s searching for %08llx vid %d with key %d, seed: %016llx\n",
@ -596,8 +601,8 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
u64_to_ether_addr(nh->mac, &e.mac[0]);
e.port = nh->port;
// Loop over all entries in the hash-bucket and over the second block on 93xx SoCs
for (i = 0; i < priv->l2_bucket_size; i++) {
/* Loop over all entries in the hash-bucket and over the second block on 93xx SoCs */
for (int i = 0; i < priv->l2_bucket_size; i++) {
entry = priv->r->read_l2_entry_using_hash(key, i, &e);
if (!e.valid || ((entry & 0x0fffffffffffffffULL) == seed)) {
@ -612,14 +617,14 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
return -1;
}
// Found an existing (e->valid is true) or empty entry, make it a nexthop entry
/* Found an existing (e->valid is true) or empty entry, make it a nexthop entry */
nh->l2_id = idx;
if (e.valid) {
nh->port = e.port;
nh->vid = e.vid; // Save VID
nh->vid = e.vid; /* Save VID */
nh->rvid = e.rvid;
nh->dev_id = e.stack_dev;
// If the entry is already a valid next hop entry, don't change it
/* If the entry is already a valid next hop entry, don't change it */
if (e.next_hop)
return 0;
} else {
@ -631,12 +636,12 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
e.block_da = false;
e.block_sa = false;
e.suspended = false;
e.age = 0; // With port-ignore
e.age = 0; /* With port-ignore */
e.port = priv->port_ignore;
u64_to_ether_addr(nh->mac, &e.mac[0]);
}
e.next_hop = true;
e.nh_route_id = nh->id; // NH route ID takes place of VID
e.nh_route_id = nh->id; /* NH route ID takes place of VID */
e.nh_vlan_target = false;
priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e);
@ -644,8 +649,7 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
return 0;
}
/*
* Removes a Layer 2 next hop entry in the forwarding database
/* Removes a Layer 2 next hop entry in the forwarding database
* If it was static, the entire entry is removed, otherwise the nexthop bit is cleared
* and we wait until the entry ages out
*/
@ -665,7 +669,7 @@ int rtl83xx_l2_nexthop_rm(struct rtl838x_switch_priv *priv, struct rtl83xx_nexth
if (e.is_static)
e.valid = false;
e.next_hop = false;
e.vid = nh->vid; // Restore VID
e.vid = nh->vid; /* Restore VID */
e.rvid = nh->rvid;
priv->r->write_l2_entry_using_hash(key, i, &e);
@ -722,30 +726,30 @@ static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv,
out:
mutex_unlock(&priv->reg_mutex);
return 0;
}
/*
* Is the lower network device a DSA slave network device of our RTL930X-switch?
/* Is the lower network device a DSA slave network device of our RTL930X-switch?
* Unfortunately we cannot just follow dev->dsa_prt as this is only set for the
* DSA master device.
*/
int rtl83xx_port_is_under(const struct net_device * dev, struct rtl838x_switch_priv *priv)
{
int i;
/* TODO: On 5.12:
* if(!dsa_slave_dev_check(dev)) {
* netdev_info(dev, "%s: not a DSA device.\n", __func__);
* return -EINVAL;
* }
*/
// TODO: On 5.12:
// if(!dsa_slave_dev_check(dev)) {
// netdev_info(dev, "%s: not a DSA device.\n", __func__);
// return -EINVAL;
// }
for (i = 0; i < priv->cpu_port; i++) {
for (int i = 0; i < priv->cpu_port; i++) {
if (!priv->ports[i].dp)
continue;
if (priv->ports[i].dp->slave == dev)
return i;
}
return -EINVAL;
}
@ -780,9 +784,7 @@ const static struct rhashtable_params route_ht_params = {
.head_offset = offsetof(struct rtl83xx_route, linkage),
};
/*
* Updates an L3 next hop entry in the ROUTING table
*/
/* Updates an L3 next hop entry in the ROUTING table */
static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 ip_addr, u64 mac)
{
struct rtl83xx_route *r;
@ -799,7 +801,7 @@ static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 i
pr_info("%s: Setting up fwding: ip %pI4, GW mac %016llx\n",
__func__, &ip_addr, mac);
// Reads the ROUTING table entry associated with the route
/* Reads the ROUTING table entry associated with the route */
priv->r->route_read(r->id, r);
pr_info("Route with id %d to %pI4 / %d\n", r->id, &r->dst_ip, r->prefix_len);
@ -807,19 +809,19 @@ static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 i
r->nh.port = priv->port_ignore;
r->nh.id = r->id;
// Do we need to explicitly add a DMAC entry with the route's nh index?
/* Do we need to explicitly add a DMAC entry with the route's nh index? */
if (priv->r->set_l3_egress_mac)
priv->r->set_l3_egress_mac(r->id, mac);
// Update ROUTING table: map gateway-mac and switch-mac id to route id
/* Update ROUTING table: map gateway-mac and switch-mac id to route id */
rtl83xx_l2_nexthop_add(priv, &r->nh);
r->attr.valid = true;
r->attr.action = ROUTE_ACT_FORWARD;
r->attr.type = 0;
r->attr.hit = false; // Reset route-used indicator
r->attr.hit = false; /* Reset route-used indicator */
// Add PIE entry with dst_ip and prefix_len
/* Add PIE entry with dst_ip and prefix_len */
r->pr.dip = r->dst_ip;
r->pr.dip_m = inet_make_mask(r->prefix_len);
@ -854,6 +856,7 @@ static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 i
}
}
rcu_read_unlock();
return 0;
}
@ -884,6 +887,7 @@ static int rtl83xx_port_ipv4_resolve(struct rtl838x_switch_priv *priv,
}
neigh_release(n);
return err;
}
@ -941,7 +945,7 @@ static struct rtl83xx_route *rtl83xx_route_alloc(struct rtl838x_switch_priv *pri
r->id = idx;
r->gw_ip = ip;
r->pr.id = -1; // We still need to allocate a rule in HW
r->pr.id = -1; /* We still need to allocate a rule in HW */
r->is_host_route = false;
err = rhltable_insert(&priv->routes, &r->linkage, route_ht_params);
@ -959,6 +963,7 @@ static struct rtl83xx_route *rtl83xx_route_alloc(struct rtl838x_switch_priv *pri
out_free:
kfree(r);
return NULL;
}
@ -980,11 +985,12 @@ static struct rtl83xx_route *rtl83xx_host_route_alloc(struct rtl838x_switch_priv
}
/* We require a unique route ID irrespective of whether it is a prefix or host
* route (on RTL93xx) as we use this ID to associate a DMAC and next-hop entry */
* route (on RTL93xx) as we use this ID to associate a DMAC and next-hop entry
*/
r->id = idx + MAX_ROUTES;
r->gw_ip = ip;
r->pr.id = -1; // We still need to allocate a rule in HW
r->pr.id = -1; /* We still need to allocate a rule in HW */
r->is_host_route = true;
err = rhltable_insert(&priv->routes, &r->linkage, route_ht_params);
@ -1002,6 +1008,7 @@ static struct rtl83xx_route *rtl83xx_host_route_alloc(struct rtl838x_switch_priv
out_free:
kfree(r);
return NULL;
}
@ -1021,7 +1028,7 @@ static void rtl83xx_route_rm(struct rtl838x_switch_priv *priv, struct rtl83xx_ro
priv->r->host_route_write(id, r);
clear_bit(r->id - MAX_ROUTES, priv->host_route_use_bm);
} else {
// If there is a HW representation of the route, delete it
/* If there is a HW representation of the route, delete it */
if (priv->r->route_lookup_hw) {
id = priv->r->route_lookup_hw(r);
pr_info("%s: Got id for prefix route: %d\n", __func__, id);
@ -1071,17 +1078,16 @@ static int rtl83xx_fib4_del(struct rtl838x_switch_priv *priv,
return 0;
}
/*
* On the RTL93xx, an L3 termination endpoint MAC address on which the router waits
/* On the RTL93xx, an L3 termination endpoint MAC address on which the router waits
* for packets to be routed needs to be allocated.
*/
static int rtl83xx_alloc_router_mac(struct rtl838x_switch_priv *priv, u64 mac)
{
int i, free_mac = -1;
int free_mac = -1;
struct rtl93xx_rt_mac m;
mutex_lock(&priv->reg_mutex);
for (i = 0; i < MAX_ROUTER_MACS; i++) {
for (int i = 0; i < MAX_ROUTER_MACS; i++) {
priv->r->get_l3_router_mac(i, &m);
if (free_mac < 0 && !m.valid) {
free_mac = i;
@ -1101,13 +1107,13 @@ static int rtl83xx_alloc_router_mac(struct rtl838x_switch_priv *priv, u64 mac)
m.valid = true;
m.mac = mac;
m.p_type = 0; // An individual port, not a trunk port
m.p_id = 0x3f; // Listen on any port
m.p_type = 0; /* An individual port, not a trunk port */
m.p_id = 0x3f; /* Listen on any port */
m.p_id_mask = 0;
m.vid = 0; // Listen on any VLAN...
m.vid_mask = 0; // ... so mask needs to be 0
m.mac_mask = 0xffffffffffffULL; // We want an exact match of the interface MAC
m.action = L3_FORWARD; // Route the packet
m.vid = 0; /* Listen on any VLAN... */
m.vid_mask = 0; /* ... so mask needs to be 0 */
m.mac_mask = 0xffffffffffffULL; /* We want an exact match of the interface MAC */
m.action = L3_FORWARD; /* Route the packet */
priv->r->set_l3_router_mac(free_mac, &m);
mutex_unlock(&priv->reg_mutex);
@ -1117,12 +1123,12 @@ static int rtl83xx_alloc_router_mac(struct rtl838x_switch_priv *priv, u64 mac)
static int rtl83xx_alloc_egress_intf(struct rtl838x_switch_priv *priv, u64 mac, int vlan)
{
int i, free_mac = -1;
int free_mac = -1;
struct rtl838x_l3_intf intf;
u64 m;
mutex_lock(&priv->reg_mutex);
for (i = 0; i < MAX_SMACS; i++) {
for (int i = 0; i < MAX_SMACS; i++) {
m = priv->r->get_l3_egress_mac(L3_EGRESS_DMACS + i);
if (free_mac < 0 && !m) {
free_mac = i;
@ -1139,15 +1145,15 @@ static int rtl83xx_alloc_egress_intf(struct rtl838x_switch_priv *priv, u64 mac,
return -1;
}
// Set up default egress interface 1
/* Set up default egress interface 1 */
intf.vid = vlan;
intf.smac_idx = free_mac;
intf.ip4_mtu_id = 1;
intf.ip6_mtu_id = 1;
intf.ttl_scope = 1; // TTL
intf.hl_scope = 1; // Hop Limit
intf.ip4_icmp_redirect = intf.ip6_icmp_redirect = 2; // FORWARD
intf.ip4_pbr_icmp_redirect = intf.ip6_pbr_icmp_redirect = 2; // FORWARD;
intf.ttl_scope = 1; /* TTL */
intf.hl_scope = 1; /* Hop Limit */
intf.ip4_icmp_redirect = intf.ip6_icmp_redirect = 2; /* FORWARD */
intf.ip4_pbr_icmp_redirect = intf.ip6_pbr_icmp_redirect = 2; /* FORWARD; */
priv->r->set_l3_egress_intf(free_mac, &intf);
priv->r->set_l3_egress_mac(L3_EGRESS_DMACS + free_mac, mac);
@ -1181,22 +1187,22 @@ static int rtl83xx_fib4_add(struct rtl838x_switch_priv *priv,
if (port < 0)
return -1;
// For now we only work with routes that have a gateway and are not ourself
// if ((!nh->fib_nh_gw4) && (info->dst_len != 32))
// return 0;
/* For now we only work with routes that have a gateway and are not ourself */
/* if ((!nh->fib_nh_gw4) && (info->dst_len != 32)) */
/* return 0; */
if ((info->dst & 0xff) == 0xff)
return 0;
// Do not offload routes to 192.168.100.x
/* Do not offload routes to 192.168.100.x */
if ((info->dst & 0xffffff00) == 0xc0a86400)
return 0;
// Do not offload routes to 127.x.x.x
/* Do not offload routes to 127.x.x.x */
if ((info->dst & 0xff000000) == 0x7f000000)
return 0;
// Allocate route or host-route (entry if hardware supports this)
/* Allocate route or host-route (entry if hardware supports this) */
if (info->dst_len == 32 && priv->r->host_route_write)
r = rtl83xx_host_route_alloc(priv, nh->fib_nh_gw4);
else
@ -1220,7 +1226,7 @@ static int rtl83xx_fib4_add(struct rtl838x_switch_priv *priv,
if (rtl83xx_alloc_router_mac(priv, mac))
goto out_free_rt;
// vid = 0: Do not care about VID
/* vid = 0: Do not care about VID */
r->nh.if_id = rtl83xx_alloc_egress_intf(priv, mac, vlan);
if (r->nh.if_id < 0)
goto out_free_rmac;
@ -1240,7 +1246,7 @@ static int rtl83xx_fib4_add(struct rtl838x_switch_priv *priv,
}
}
// We need to resolve the mac address of the GW
/* We need to resolve the mac address of the GW */
if (!to_localhost)
rtl83xx_port_ipv4_resolve(priv, dev, nh->fib_nh_gw4);
@ -1257,7 +1263,8 @@ static int rtl83xx_fib6_add(struct rtl838x_switch_priv *priv,
struct fib6_entry_notifier_info *info)
{
pr_debug("In %s\n", __func__);
// nh->fib_nh_flags |= RTNH_F_OFFLOAD;
/* nh->fib_nh_flags |= RTNH_F_OFFLOAD; */
return 0;
}
@ -1441,7 +1448,7 @@ static int rtl83xx_fib_event(struct notifier_block *this, unsigned long event, v
static int __init rtl83xx_sw_probe(struct platform_device *pdev)
{
int err = 0, i;
int err = 0;
struct rtl838x_switch_priv *priv;
struct device *dev = &pdev->dev;
u64 bpdu_mask;
@ -1452,7 +1459,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
return -EINVAL;
}
// Initialize access to RTL switch tables
/* Initialize access to RTL switch tables */
rtl_table_init();
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -1546,18 +1553,18 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
*/
return err;
}
err = dsa_register_switch(priv->ds);
if (err) {
dev_err(dev, "Error registering switch: %d\n", err);
return err;
}
/*
* dsa_to_port returns dsa_port from the port list in
/* dsa_to_port returns dsa_port from the port list in
* dsa_switch_tree, the tree is built when the switch
* is registered by dsa_register_switch
*/
for (i = 0; i <= priv->cpu_port; i++)
for (int i = 0; i <= priv->cpu_port; i++)
priv->ports[i].dp = dsa_to_port(priv->ds, i);
/* Enable link and media change interrupts. Are the SERDES masks needed? */
@ -1571,19 +1578,19 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
switch (priv->family_id) {
case RTL8380_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl838x_switch_irq,
IRQF_SHARED, "rtl838x-link-state", priv->ds);
IRQF_SHARED, "rtl838x-link-state", priv->ds);
break;
case RTL8390_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl839x_switch_irq,
IRQF_SHARED, "rtl839x-link-state", priv->ds);
IRQF_SHARED, "rtl839x-link-state", priv->ds);
break;
case RTL9300_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl930x_switch_irq,
IRQF_SHARED, "rtl930x-link-state", priv->ds);
IRQF_SHARED, "rtl930x-link-state", priv->ds);
break;
case RTL9310_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl931x_switch_irq,
IRQF_SHARED, "rtl931x-link-state", priv->ds);
IRQF_SHARED, "rtl931x-link-state", priv->ds);
break;
}
if (err) {
@ -1602,12 +1609,10 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
priv->r->l3_setup(priv);
/* Clear all destination ports for mirror groups */
for (i = 0; i < 4; i++)
for (int i = 0; i < 4; i++)
priv->mirror_group_ports[i] = -1;
/*
* Register netdevice event callback to catch changes in link aggregation groups
*/
/* Register netdevice event callback to catch changes in link aggregation groups */
priv->nb.notifier_call = rtl83xx_netdevice_event;
if (register_netdevice_notifier(&priv->nb)) {
priv->nb.notifier_call = NULL;
@ -1615,11 +1620,10 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
goto err_register_nb;
}
// Initialize hash table for L3 routing
/* Initialize hash table for L3 routing */
rhltable_init(&priv->routes, &route_ht_params);
/*
* Register netevent notifier callback to catch notifications about neighboring
/* Register netevent notifier callback to catch notifications about neighboring
* changes to update nexthop entries for L3 routing.
*/
priv->ne_nb.notifier_call = rtl83xx_netevent_event;
@ -1631,8 +1635,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
priv->fib_nb.notifier_call = rtl83xx_fib_event;
/*
* Register Forwarding Information Base notifier to offload routes where
/* Register Forwarding Information Base notifier to offload routes where
* where possible
* Only FIBs pointing to our own netdevs are programmed into
* the device, so no need to pass a callback.
@ -1641,13 +1644,13 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
if (err)
goto err_register_fib_nb;
// TODO: put this into l2_setup()
// Flood BPDUs to all ports including cpu-port
/* TODO: put this into l2_setup() */
/* Flood BPDUs to all ports including cpu-port */
if (soc_info.family != RTL9300_FAMILY_ID) {
bpdu_mask = soc_info.family == RTL8380_FAMILY_ID ? 0x1FFFFFFF : 0x1FFFFFFFFFFFFF;
priv->r->set_port_reg_be(bpdu_mask, priv->r->rma_bpdu_fld_pmask);
// TRAP 802.1X frames (EAPOL) to the CPU-Port, bypass STP and VLANs
/* TRAP 802.1X frames (EAPOL) to the CPU-Port, bypass STP and VLANs */
sw_w32(7, priv->r->spcl_trap_eapol_ctrl);
rtl838x_dbgfs_init(priv);
@ -1667,8 +1670,9 @@ err_register_nb:
static int rtl83xx_sw_remove(struct platform_device *pdev)
{
// TODO:
/* TODO: */
pr_debug("Removing platform driver for rtl83xx-sw\n");
return 0;
}

View File

@ -2,8 +2,8 @@
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
#define RTL838X_DRIVER_NAME "rtl838x"
@ -109,21 +109,21 @@ const char *rtl930x_drop_cntr[] = {
const char *rtl931x_drop_cntr[] = {
"ALE_RX_GOOD_PKTS", "RX_MAX_FRAME_SIZE", "MAC_RX_DROP", "OPENFLOW_IP_MPLS_TTL", "OPENFLOW_TBL_MISS",
"IGR_BW", "SPECIAL_CONGEST", "EGR_QUEUE", "RESERVED", "EGR_LINK_STATUS", "STACK_UCAST_NONUCAST_TTL", // 10
"IGR_BW", "SPECIAL_CONGEST", "EGR_QUEUE", "RESERVED", "EGR_LINK_STATUS", "STACK_UCAST_NONUCAST_TTL", /* 10 */
"STACK_NONUC_BLOCKING_PMSK", "L2_CRC", "SRC_PORT_FILTER", "PARSER_PACKET_TOO_LONG", "PARSER_MALFORM_PACKET",
"MPLS_OVER_2_LBL", "EACL_METER", "IACL_METER", "PROTO_STORM", "INVALID_CAPWAP_HEADER", // 20
"MPLS_OVER_2_LBL", "EACL_METER", "IACL_METER", "PROTO_STORM", "INVALID_CAPWAP_HEADER", /* 20 */
"MAC_IP_SUBNET_BASED_VLAN", "OAM_PARSER", "UC_MC_RPF", "IP_MAC_BINDING_MATCH_MISMATCH", "SA_BLOCK",
"TUNNEL_IP_ADDRESS_CHECK", "EACL_DROP", "IACL_DROP", "ATTACK_PREVENT", "SYSTEM_PORT_LIMIT_LEARN", // 30,
"TUNNEL_IP_ADDRESS_CHECK", "EACL_DROP", "IACL_DROP", "ATTACK_PREVENT", "SYSTEM_PORT_LIMIT_LEARN", /* 30 */
"OAMPDU", "CCM_RX", "CFM_UNKNOWN_TYPE", "LBM_LBR_LTM_LTR", "Y_1731", "VLAN_LIMIT_LEARN",
"VLAN_ACCEPT_FRAME_TYPE", "CFI_1", "STATIC_DYNAMIC_PORT_MOVING", "PORT_MOVE_FORBID", // 40
"VLAN_ACCEPT_FRAME_TYPE", "CFI_1", "STATIC_DYNAMIC_PORT_MOVING", "PORT_MOVE_FORBID", /* 40 */
"L3_CRC", "BPDU_PTP_LLDP_EAPOL_RMA", "MSTP_SRC_DROP_DISABLED_BLOCKING", "INVALID_SA", "NEW_SA",
"VLAN_IGR_FILTER", "IGR_VLAN_CONVERT", "GRATUITOUS_ARP", "MSTP_SRC_DROP", "L2_HASH_FULL", // 50
"VLAN_IGR_FILTER", "IGR_VLAN_CONVERT", "GRATUITOUS_ARP", "MSTP_SRC_DROP", "L2_HASH_FULL", /* 50 */
"MPLS_UNKNOWN_LBL", "L3_IPUC_NON_IP", "TTL", "MTU", "ICMP_REDIRECT", "STORM_CONTROL", "L3_DIP_DMAC_MISMATCH",
"IP4_IP_OPTION", "IP6_HBH_EXT_HEADER", "IP4_IP6_HEADER_ERROR", // 60
"IP4_IP_OPTION", "IP6_HBH_EXT_HEADER", "IP4_IP6_HEADER_ERROR", /* 60 */
"ROUTING_IP_ADDR_CHECK", "ROUTING_EXCEPTION", "DA_BLOCK", "OAM_MUX", "PORT_ISOLATION", "VLAN_EGR_FILTER",
"MIRROR_ISOLATE", "MSTP_DESTINATION_DROP", "L2_MC_BRIDGE", "IP_UC_MC_ROUTING_LOOK_UP_MISS", // 70
"MIRROR_ISOLATE", "MSTP_DESTINATION_DROP", "L2_MC_BRIDGE", "IP_UC_MC_ROUTING_LOOK_UP_MISS", /* 70 */
"L2_UC", "L2_MC", "IP4_MC", "IP6_MC", "L3_UC_MC_ROUTE", "UNKNOWN_L2_UC_FLPM", "BC_FLPM",
"VLAN_PRO_UNKNOWN_L2_MC_FLPM", "VLAN_PRO_UNKNOWN_IP4_MC_FLPM", "VLAN_PROFILE_UNKNOWN_IP6_MC_FLPM" // 80,
"VLAN_PRO_UNKNOWN_L2_MC_FLPM", "VLAN_PRO_UNKNOWN_IP4_MC_FLPM", "VLAN_PROFILE_UNKNOWN_IP6_MC_FLPM", /* 80 */
};
static ssize_t rtl838x_common_read(char __user *buffer, size_t count,
@ -214,7 +214,6 @@ static ssize_t drop_counter_read(struct file *filp, char __user *buffer, size_t
loff_t *ppos)
{
struct rtl838x_switch_priv *priv = filp->private_data;
int i;
const char **d;
u32 v;
char *buf;
@ -248,7 +247,7 @@ static ssize_t drop_counter_read(struct file *filp, char __user *buffer, size_t
if (!buf)
return -ENOMEM;
for (i = 0; i < num; i++) {
for (int i = 0; i < num; i++) {
v = sw_r32(offset + (i << 2)) & 0xffff;
n += sprintf(buf + n, "%s: %d\n", d[i], v);
}
@ -274,7 +273,6 @@ static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv
struct rtl838x_l2_entry *e)
{
u64 portmask;
int i;
if (e->type == L2_UNICAST) {
seq_puts(m, "L2_UNICAST\n");
@ -315,7 +313,7 @@ static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv
portmask = priv->r->read_mcast_pmask(e->mc_portmask_index);
seq_printf(m, " index %u ports", e->mc_portmask_index);
for (i = 0; i < 64; i++) {
for (int i = 0; i < 64; i++) {
if (portmask & BIT_ULL(i))
seq_printf(m, " %d", i);
}
@ -329,11 +327,11 @@ static int l2_table_show(struct seq_file *m, void *v)
{
struct rtl838x_switch_priv *priv = m->private;
struct rtl838x_l2_entry e;
int i, bucket, index;
int bucket, index;
mutex_lock(&priv->reg_mutex);
for (i = 0; i < priv->fib_entries; i++) {
for (int i = 0; i < priv->fib_entries; i++) {
bucket = i >> 2;
index = i & 0x3;
priv->r->read_l2_entry_using_hash(bucket, index, &e);
@ -343,9 +341,12 @@ static int l2_table_show(struct seq_file *m, void *v)
seq_printf(m, "Hash table bucket %d index %d ", bucket, index);
l2_table_print_entry(m, priv, &e);
if (!((i + 1) % 64))
cond_resched();
}
for (i = 0; i < 64; i++) {
for (int i = 0; i < 64; i++) {
priv->r->read_cam(i, &e);
if (!e.valid)
@ -462,7 +463,7 @@ void rtl838x_dbgfs_cleanup(struct rtl838x_switch_priv *priv)
{
debugfs_remove_recursive(priv->dbgfs_dir);
// kfree(priv->dbgfs_entries);
/* kfree(priv->dbgfs_entries); */
}
static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_priv *priv,
@ -514,9 +515,6 @@ static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_
static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv *priv)
{
struct dentry *led_dir;
int p;
char led_sw_p_ctrl_name[20];
char port_led_name[20];
led_dir = debugfs_create_dir("led", parent);
@ -537,20 +535,24 @@ static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv
(u32 *)(RTL838X_SW_BASE + RTL8380_LED1_SW_P_EN_CTRL));
debugfs_create_x32("led2_sw_p_en_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8380_LED2_SW_P_EN_CTRL));
for (p = 0; p < 28; p++) {
for (int p = 0; p < 28; p++) {
char led_sw_p_ctrl_name[20];
snprintf(led_sw_p_ctrl_name, sizeof(led_sw_p_ctrl_name),
"led_sw_p_ctrl.%02d", p);
debugfs_create_x32(led_sw_p_ctrl_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8380_LED_SW_P_CTRL(p)));
}
} else if (priv->family_id == RTL8390_FAMILY_ID) {
char port_led_name[20];
debugfs_create_x32("led_glb_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_GLB_CTRL));
debugfs_create_x32("led_set_2_3", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_2_3_CTRL));
debugfs_create_x32("led_set_0_1", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_0_1_CTRL));
for (p = 0; p < 4; p++) {
for (int p = 0; p < 4; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_copr_set_sel.%1d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_SET_SEL_CTRL(p << 4)));
@ -572,12 +574,12 @@ static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(32)));
debugfs_create_x32("led_sw_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_CTRL));
for (p = 0; p < 5; p++) {
for (int p = 0; p < 5; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_en_ctrl.%1d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_EN_CTRL(p * 10)));
}
for (p = 0; p < 28; p++) {
for (int p = 0; p < 28; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_ctrl.%02d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_CTRL(p)));
@ -592,7 +594,7 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
struct dentry *port_dir;
struct dentry *mirror_dir;
struct debugfs_regset32 *port_ctrl_regset;
int ret, i;
int ret;
char lag_name[10];
char mirror_name[10];
@ -607,7 +609,7 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
(u32 *)(RTL838X_SW_BASE + RTL838X_MODEL_NAME_INFO));
/* Create one directory per port */
for (i = 0; i < priv->cpu_port; i++) {
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
ret = rtl838x_dbgfs_port_init(rtl838x_dir, priv, i);
if (ret)
@ -630,7 +632,7 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
debugfs_create_u8("id", 0444, port_dir, &priv->cpu_port);
/* Create entries for LAGs */
for (i = 0; i < priv->n_lags; i++) {
for (int i = 0; i < priv->n_lags; i++) {
snprintf(lag_name, sizeof(lag_name), "lag.%02d", i);
if (priv->family_id == RTL8380_FAMILY_ID)
debugfs_create_x32(lag_name, 0644, rtl838x_dir,
@ -641,7 +643,7 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
}
/* Create directories for mirror groups */
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
snprintf(mirror_name, sizeof(mirror_name), "mirror.%1d", i);
mirror_dir = debugfs_create_dir(mirror_name, rtl838x_dir);
if (priv->family_id == RTL8380_FAMILY_ID) {

View File

@ -2,14 +2,12 @@
#include <net/dsa.h>
#include <linux/if_bridge.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
extern struct rtl83xx_soc_info soc_info;
static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
{
mutex_lock(&priv->reg_mutex);
@ -28,12 +26,11 @@ static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
static void rtl83xx_enable_phy_polling(struct rtl838x_switch_priv *priv)
{
int i;
u64 v = 0;
msleep(1000);
/* Enable all ports with a PHY, including the SFP-ports */
for (i = 0; i < priv->cpu_port; i++) {
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy)
v |= BIT_ULL(i);
}
@ -111,13 +108,10 @@ static enum dsa_tag_protocol rtl83xx_get_tag_protocol(struct dsa_switch *ds,
return DSA_TAG_PROTO_TRAILER;
}
/*
* Initialize all VLANS
*/
/* Initialize all VLANS */
static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
{
struct rtl838x_vlan_info info;
int i;
pr_info("In %s\n", __func__);
@ -126,39 +120,37 @@ static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
pr_info("UNKNOWN_MC_PMASK: %016llx\n", priv->r->read_mcast_pmask(UNKNOWN_MC_PMASK));
priv->r->vlan_profile_dump(0);
info.fid = 0; // Default Forwarding ID / MSTI
info.hash_uc_fid = false; // Do not build the L2 lookup hash with FID, but VID
info.hash_mc_fid = false; // Do the same for Multicast packets
info.profile_id = 0; // Use default Vlan Profile 0
info.tagged_ports = 0; // Initially no port members
info.fid = 0; /* Default Forwarding ID / MSTI */
info.hash_uc_fid = false; /* Do not build the L2 lookup hash with FID, but VID */
info.hash_mc_fid = false; /* Do the same for Multicast packets */
info.profile_id = 0; /* Use default Vlan Profile 0 */
info.tagged_ports = 0; /* Initially no port members */
if (priv->family_id == RTL9310_FAMILY_ID) {
info.if_id = 0;
info.multicast_grp_mask = 0;
info.l2_tunnel_list_id = -1;
}
// Initialize all vlans 0-4095
for (i = 0; i < MAX_VLANS; i ++)
/* Initialize all vlans 0-4095 */
for (int i = 0; i < MAX_VLANS; i ++)
priv->r->vlan_set_tagged(i, &info);
// reset PVIDs; defaults to 1 on reset
for (i = 0; i <= priv->ds->num_ports; i++) {
/* reset PVIDs; defaults to 1 on reset */
for (int i = 0; i <= priv->ds->num_ports; i++) {
priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_INNER, 0);
priv->r->vlan_port_pvid_set(i, PBVLAN_TYPE_OUTER, 0);
priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_INNER, PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(i, PBVLAN_TYPE_OUTER, PBVLAN_MODE_UNTAG_AND_PRITAG);
}
// Set forwarding action based on inner VLAN tag
for (i = 0; i < priv->cpu_port; i++)
/* Set forwarding action based on inner VLAN tag */
for (int i = 0; i < priv->cpu_port; i++)
priv->r->vlan_fwd_on_inner(i, true);
}
static void rtl83xx_setup_bpdu_traps(struct rtl838x_switch_priv *priv)
{
int i;
for (i = 0; i < priv->cpu_port; i++)
for (int i = 0; i < priv->cpu_port; i++)
priv->r->set_receive_management_action(i, BPDU, COPY2CPU);
}
@ -174,7 +166,6 @@ static void rtl83xx_port_set_salrn(struct rtl838x_switch_priv *priv,
static int rtl83xx_setup(struct dsa_switch *ds)
{
int i;
struct rtl838x_switch_priv *priv = ds->priv;
u64 port_bitmap = BIT_ULL(priv->cpu_port);
@ -183,7 +174,7 @@ static int rtl83xx_setup(struct dsa_switch *ds)
/* Disable MAC polling the PHY so that we can start configuration */
priv->r->set_port_reg_le(0ULL, priv->r->smi_poll_ctrl);
for (i = 0; i < ds->num_ports; i++)
for (int i = 0; i < ds->num_ports; i++)
priv->ports[i].enable = false;
priv->ports[priv->cpu_port].enable = true;
@ -191,7 +182,7 @@ static int rtl83xx_setup(struct dsa_switch *ds)
/* Setting bit j in register RTL838X_PORT_ISO_CTRL(i) allows
* traffic from source port i to destination port j
*/
for (i = 0; i < priv->cpu_port; i++) {
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
priv->r->set_port_reg_be(BIT_ULL(priv->cpu_port) | BIT_ULL(i),
priv->r->port_iso_ctrl(i));
@ -218,8 +209,7 @@ static int rtl83xx_setup(struct dsa_switch *ds)
rtl83xx_port_set_salrn(priv, priv->cpu_port, false);
ds->assisted_learning_on_cpu_port = true;
/*
* Make sure all frames sent to the switch's MAC are trapped to the CPU-port
/* Make sure all frames sent to the switch's MAC are trapped to the CPU-port
* 0: FWD, 1: DROP, 2: TRAP2CPU
*/
if (priv->family_id == RTL8380_FAMILY_ID)
@ -238,7 +228,6 @@ static int rtl83xx_setup(struct dsa_switch *ds)
static int rtl93xx_setup(struct dsa_switch *ds)
{
int i;
struct rtl838x_switch_priv *priv = ds->priv;
u32 port_bitmap = BIT(priv->cpu_port);
@ -253,12 +242,12 @@ static int rtl93xx_setup(struct dsa_switch *ds)
sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL + 4);
}
// Disable all ports except CPU port
for (i = 0; i < ds->num_ports; i++)
/* Disable all ports except CPU port */
for (int i = 0; i < ds->num_ports; i++)
priv->ports[i].enable = false;
priv->ports[priv->cpu_port].enable = true;
for (i = 0; i < priv->cpu_port; i++) {
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
priv->r->traffic_set(i, BIT_ULL(priv->cpu_port) | BIT_ULL(i));
port_bitmap |= BIT_ULL(i);
@ -268,7 +257,7 @@ static int rtl93xx_setup(struct dsa_switch *ds)
rtl930x_print_matrix();
// TODO: Initialize statistics
/* TODO: Initialize statistics */
rtl83xx_vlan_setup(priv);
@ -413,9 +402,9 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port,
phylink_set(mask, 1000baseT_Half);
}
// Internal phys of the RTL93xx family provide 10G
if (priv->ports[port].phy_is_integrated
&& state->interface == PHY_INTERFACE_MODE_1000BASEX) {
/* Internal phys of the RTL93xx family provide 10G */
if (priv->ports[port].phy_is_integrated &&
state->interface == PHY_INTERFACE_MODE_1000BASEX) {
phylink_set(mask, 1000baseX_Full);
} else if (priv->ports[port].phy_is_integrated) {
phylink_set(mask, 1000baseX_Full);
@ -492,6 +481,7 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
state->pause |= MLO_PAUSE_RX;
if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
state->pause |= MLO_PAUSE_TX;
return 1;
}
@ -506,8 +496,7 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
if (port < 0 || port > priv->cpu_port)
return -EINVAL;
/*
* On the RTL9300 for at least the RTL8226B PHY, the MAC-side link
/* On the RTL9300 for at least the RTL8226B PHY, the MAC-side link
* state needs to be read twice in order to read a correct result.
* This would not be necessary for ports connected e.g. to RTL8218D
* PHYs.
@ -574,6 +563,7 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
state->pause |= MLO_PAUSE_RX;
if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
state->pause |= MLO_PAUSE_TX;
return 1;
}
@ -683,7 +673,7 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port,
reg |= 1 << speed_bit;
break;
default:
break; // Ignore, including 10MBit which has a speed value of 0
break; /* Ignore, including 10MBit which has a speed value of 0 */
}
if (priv->family_id == RTL8380_FAMILY_ID) {
@ -700,7 +690,7 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port,
reg |= RTL839X_DUPLEX_MODE;
}
// LAG members must use DUPLEX and we need to enable the link
/* LAG members must use DUPLEX and we need to enable the link */
if (priv->lagmembers & BIT_ULL(port)) {
switch(priv->family_id) {
case RTL8380_FAMILY_ID:
@ -712,7 +702,7 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port,
}
}
// Disable AN
/* Disable AN */
if (priv->family_id == RTL8380_FAMILY_ID)
reg &= ~RTL838X_NWAY_EN;
sw_w32(reg, priv->r->mac_force_mode_ctrl(port));
@ -750,7 +740,7 @@ static void rtl931x_phylink_mac_config(struct dsa_switch *ds, int port,
rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_10GBASER);
break;
case PHY_INTERFACE_MODE_USXGMII:
// Translates to MII_USXGMII_10GSXGMII
/* Translates to MII_USXGMII_10GSXGMII */
band = rtl931x_sds_cmu_band_get(sds_num, PHY_INTERFACE_MODE_USXGMII);
rtl931x_sds_init(sds_num, PHY_INTERFACE_MODE_USXGMII);
break;
@ -776,7 +766,7 @@ static void rtl931x_phylink_mac_config(struct dsa_switch *ds, int port,
reg &= ~(RTL931X_DUPLEX_MODE | RTL931X_FORCE_EN | RTL931X_FORCE_LINK_EN);
reg &= ~(0xf << 12);
reg |= 0x2 << 12; // Set SMI speed to 0x2
reg |= 0x2 << 12; /* Set SMI speed to 0x2 */
reg |= RTL931X_TX_PAUSE_EN | RTL931X_RX_PAUSE_EN;
@ -801,7 +791,7 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port,
pr_info("%s port %d, mode %x, phy-mode: %s, speed %d, link %d\n", __func__,
port, mode, phy_modes(state->interface), state->speed, state->link);
// Nothing to be done for the CPU-port
/* Nothing to be done for the CPU-port */
if (port == priv->cpu_port)
return;
@ -823,7 +813,7 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port,
break;
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_10GKR:
sds_mode = 0x1b; // 10G 1000X Auto
sds_mode = 0x1b; /* 10G 1000X Auto */
break;
case PHY_INTERFACE_MODE_USXGMII:
sds_mode = 0x0d;
@ -868,7 +858,7 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port,
reg |= RTL930X_DUPLEX_MODE;
if (priv->ports[port].phy_is_integrated)
reg &= ~RTL930X_FORCE_EN; // Clear MAC_FORCE_EN to allow SDS-MAC link
reg &= ~RTL930X_FORCE_EN; /* Clear MAC_FORCE_EN to allow SDS-MAC link */
else
reg |= RTL930X_FORCE_EN;
@ -884,7 +874,7 @@ static void rtl83xx_phylink_mac_link_down(struct dsa_switch *ds, int port,
/* Stop TX/RX to port */
sw_w32_mask(0x3, 0, priv->r->mac_port_ctrl(port));
// No longer force link
/* No longer force link */
sw_w32_mask(0x3, 0, priv->r->mac_force_mode_ctrl(port));
}
@ -898,7 +888,7 @@ static void rtl93xx_phylink_mac_link_down(struct dsa_switch *ds, int port,
/* Stop TX/RX to port */
sw_w32_mask(0x3, 0, priv->r->mac_port_ctrl(port));
// No longer force link
/* No longer force link */
if (priv->family_id == RTL9300_FAMILY_ID)
v = RTL930X_FORCE_EN | RTL930X_FORCE_LINK_EN;
else if (priv->family_id == RTL9310_FAMILY_ID)
@ -916,7 +906,7 @@ static void rtl83xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
struct rtl838x_switch_priv *priv = ds->priv;
/* Restart TX/RX to port */
sw_w32_mask(0, 0x3, priv->r->mac_port_ctrl(port));
// TODO: Set speed/duplex/pauses
/* TODO: Set speed/duplex/pauses */
}
static void rtl93xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
@ -930,18 +920,16 @@ static void rtl93xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
/* Restart TX/RX to port */
sw_w32_mask(0, 0x3, priv->r->mac_port_ctrl(port));
// TODO: Set speed/duplex/pauses
/* TODO: Set speed/duplex/pauses */
}
static void rtl83xx_get_strings(struct dsa_switch *ds,
int port, u32 stringset, u8 *data)
{
int i;
if (stringset != ETH_SS_STATS)
return;
for (i = 0; i < ARRAY_SIZE(rtl83xx_mib); i++)
for (int i = 0; i < ARRAY_SIZE(rtl83xx_mib); i++)
strncpy(data + i * ETH_GSTRING_LEN, rtl83xx_mib[i].name,
ETH_GSTRING_LEN);
}
@ -951,10 +939,9 @@ static void rtl83xx_get_ethtool_stats(struct dsa_switch *ds, int port,
{
struct rtl838x_switch_priv *priv = ds->priv;
const struct rtl83xx_mib_desc *mib;
int i;
u64 h;
for (i = 0; i < ARRAY_SIZE(rtl83xx_mib); i++) {
for (int i = 0; i < ARRAY_SIZE(rtl83xx_mib); i++) {
mib = &rtl83xx_mib[i];
data[i] = sw_r32(priv->r->stat_port_std_mib + (port << 8) + 252 - mib->offset);
@ -987,8 +974,8 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port)
}
set_bit(mc_group, priv->mc_group_bm);
mc_group++; // We cannot use group 0, as this is used for lookup miss flooding
portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port);
mc_group++; /* We cannot use group 0, as this is used for lookup miss flooding */
portmask = BIT_ULL(port) | BIT_ULL(priv->cpu_port);
priv->r->write_mcast_pmask(mc_group, portmask);
return mc_group;
@ -1030,9 +1017,7 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr
static void store_mcgroups(struct rtl838x_switch_priv *priv, int port)
{
int mc_group;
for (mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) {
for (int mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) {
u64 portmask = priv->r->read_mcast_pmask(mc_group);
if (portmask & BIT_ULL(port)) {
priv->mc_group_saves[mc_group] = port;
@ -1043,9 +1028,7 @@ static void store_mcgroups(struct rtl838x_switch_priv *priv, int port)
static void load_mcgroups(struct rtl838x_switch_priv *priv, int port)
{
int mc_group;
for (mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) {
for (int mc_group = 0; mc_group < MAX_MC_GROUPS; mc_group++) {
if (priv->mc_group_saves[mc_group] == port) {
rtl83xx_mc_group_add_port(priv, mc_group, port);
priv->mc_group_saves[mc_group] = -1;
@ -1083,7 +1066,7 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port,
v |= priv->ports[port].pm;
priv->r->traffic_set(port, v);
// TODO: Figure out if this is necessary
/* TODO: Figure out if this is necessary */
if (priv->family_id == RTL9300_FAMILY_ID) {
sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_SABLK_CTRL);
sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_DABLK_CTRL);
@ -1105,7 +1088,7 @@ static void rtl83xx_port_disable(struct dsa_switch *ds, int port)
if (!dsa_is_user_port(ds, port))
return;
// BUG: This does not work on RTL931X
/* BUG: This does not work on RTL931X */
/* remove port from switch mask of CPU_PORT */
priv->r->traffic_disable(priv->cpu_port, port);
store_mcgroups(priv, port);
@ -1134,6 +1117,7 @@ static int rtl83xx_set_mac_eee(struct dsa_switch *ds, int port,
pr_info("Enabled EEE for port %d\n", port);
else
pr_info("Disabled EEE for port %d\n", port);
return 0;
}
@ -1158,8 +1142,9 @@ static int rtl93xx_get_mac_eee(struct dsa_switch *ds, int port,
{
struct rtl838x_switch_priv *priv = ds->priv;
e->supported = SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full
| SUPPORTED_2500baseX_Full;
e->supported = SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full;
priv->r->eee_port_ability(priv, e, port);
@ -1175,6 +1160,7 @@ static int rtl83xx_set_ageing_time(struct dsa_switch *ds, unsigned int msec)
struct rtl838x_switch_priv *priv = ds->priv;
priv->r->set_ageing_time(msec);
return 0;
}
@ -1183,7 +1169,6 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port,
{
struct rtl838x_switch_priv *priv = ds->priv;
u64 port_bitmap = BIT_ULL(priv->cpu_port), v;
int i;
pr_debug("%s %x: %d %llx", __func__, (u32)priv, port, port_bitmap);
@ -1193,7 +1178,7 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port,
}
mutex_lock(&priv->reg_mutex);
for (i = 0; i < ds->num_ports; i++) {
for (int i = 0; i < ds->num_ports; i++) {
/* Add this port to the port matrix of the other ports in the
* same bridge. If the port is disabled, port matrix is kept
* and not being setup until the port becomes enabled.
@ -1228,11 +1213,10 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port,
{
struct rtl838x_switch_priv *priv = ds->priv;
u64 port_bitmap = BIT_ULL(priv->cpu_port), v;
int i;
pr_debug("%s %x: %d", __func__, (u32)priv, port);
mutex_lock(&priv->reg_mutex);
for (i = 0; i < ds->num_ports; i++) {
for (int i = 0; i < ds->num_ports; i++) {
/* Remove this port from the port matrix of the other ports
* in the same bridge. If the port is disabled, port matrix
* is kept and not being setup until the port becomes enabled.
@ -1306,7 +1290,7 @@ void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
case BR_STATE_LEARNING: /* 2 */
port_state[index] |= (2 << bit);
break;
case BR_STATE_FORWARDING: /* 3*/
case BR_STATE_FORWARDING: /* 3 */
port_state[index] |= (3 << bit);
default:
break;
@ -1463,9 +1447,9 @@ static int rtl83xx_vlan_add(struct dsa_switch *ds, int port,
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, vlan->vid);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, vlan->vid);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->ports[port].pvid = vlan->vid;
}
@ -1523,9 +1507,9 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port,
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_INNER, 0);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, 0);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
PBVLAN_MODE_UNTAG_AND_PRITAG);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_OUTER,
PBVLAN_MODE_UNTAG_AND_PRITAG);
PBVLAN_MODE_UNTAG_AND_PRITAG);
}
/* Get port memberships of this vlan */
priv->r->vlan_tables_read(vlan->vid, &info);
@ -1576,8 +1560,7 @@ static void rtl83xx_setup_l2_mc_entry(struct rtl838x_l2_entry *e, int vid, u64 m
u64_to_ether_addr(mac, e->mac);
}
/*
* Uses the seed to identify a hash bucket in the L2 using the derived hash key and then loops
/* Uses the seed to identify a hash bucket in the L2 using the derived hash key and then loops
* over the entries in the bucket until either a matching entry is found or an empty slot
* Returns the filled in rtl838x_l2_entry and the index in the bucket when an entry was found
* when an empty slot was found and must exist is false, the index of the slot is returned
@ -1586,13 +1569,13 @@ static void rtl83xx_setup_l2_mc_entry(struct rtl838x_l2_entry *e, int vid, u64 m
static int rtl83xx_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed,
bool must_exist, struct rtl838x_l2_entry *e)
{
int i, idx = -1;
int idx = -1;
u32 key = priv->r->l2_hash_key(priv, seed);
u64 entry;
pr_debug("%s: using key %x, for seed %016llx\n", __func__, key, seed);
// Loop over all entries in the hash-bucket and over the second block on 93xx SoCs
for (i = 0; i < priv->l2_bucket_size; i++) {
/* Loop over all entries in the hash-bucket and over the second block on 93xx SoCs */
for (int i = 0; i < priv->l2_bucket_size; i++) {
entry = priv->r->read_l2_entry_using_hash(key, i, e);
pr_debug("valid %d, mac %016llx\n", e->valid, ether_addr_to_u64(&e->mac[0]));
if (must_exist && !e->valid)
@ -1606,8 +1589,7 @@ static int rtl83xx_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed
return idx;
}
/*
* Uses the seed to identify an entry in the CAM by looping over all its entries
/* Uses the seed to identify an entry in the CAM by looping over all its entries
* Returns the filled in rtl838x_l2_entry and the index in the CAM when an entry was found
* when an empty slot was found the index of the slot is returned
* when no slots are available returns -1
@ -1615,10 +1597,10 @@ static int rtl83xx_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed
static int rtl83xx_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed,
bool must_exist, struct rtl838x_l2_entry *e)
{
int i, idx = -1;
int idx = -1;
u64 entry;
for (i = 0; i < 64; i++) {
for (int i = 0; i < 64; i++) {
entry = priv->r->read_cam(i, e);
if (!must_exist && !e->valid) {
if (idx < 0) /* First empty entry? */
@ -1630,6 +1612,7 @@ static int rtl83xx_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed,
break;
}
}
return idx;
}
@ -1651,14 +1634,14 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port,
idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e);
// Found an existing or empty entry
/* Found an existing or empty entry */
if (idx >= 0) {
rtl83xx_setup_l2_uc_entry(&e, port, vid, mac);
priv->r->write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e);
goto out;
}
// Hash buckets full, try CAM
/* Hash buckets full, try CAM */
rtl83xx_find_l2_cam_entry(priv, seed, false, &e);
if (idx >= 0) {
@ -1668,8 +1651,10 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port,
}
err = -ENOTSUPP;
out:
mutex_unlock(&priv->reg_mutex);
return err;
}
@ -1703,8 +1688,10 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port,
goto out;
}
err = -ENOENT;
out:
mutex_unlock(&priv->reg_mutex);
return err;
}
@ -1713,11 +1700,10 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
{
struct rtl838x_l2_entry e;
struct rtl838x_switch_priv *priv = ds->priv;
int i;
mutex_lock(&priv->reg_mutex);
for (i = 0; i < priv->fib_entries; i++) {
for (int i = 0; i < priv->fib_entries; i++) {
priv->r->read_l2_entry_using_hash(i >> 2, i & 0x3, &e);
if (!e.valid)
@ -1725,9 +1711,12 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
if (e.port == port || e.port == RTL930X_PORT_IGNORE)
cb(e.mac, e.vid, e.is_static, data);
if (!((i + 1) % 64))
cond_resched();
}
for (i = 0; i < 64; i++) {
for (int i = 0; i < 64; i++) {
priv->r->read_cam(i, &e);
if (!e.valid)
@ -1738,6 +1727,7 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
}
mutex_unlock(&priv->reg_mutex);
return 0;
}
@ -1766,7 +1756,7 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e);
// Found an existing or empty entry
/* Found an existing or empty entry */
if (idx >= 0) {
if (e.valid) {
pr_debug("Found an existing entry %016llx, mc_group %d\n",
@ -1785,7 +1775,7 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
goto out;
}
// Hash buckets full, try CAM
/* Hash buckets full, try CAM */
rtl83xx_find_l2_cam_entry(priv, seed, false, &e);
if (idx >= 0) {
@ -1807,6 +1797,7 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
}
err = -ENOTSUPP;
out:
mutex_unlock(&priv->reg_mutex);
if (err)
@ -1858,9 +1849,11 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port,
}
goto out;
}
// TODO: Re-enable with a newer kernel: err = -ENOENT;
/* TODO: Re-enable with a newer kernel: err = -ENOENT; */
out:
mutex_unlock(&priv->reg_mutex);
return err;
}
@ -1871,7 +1864,7 @@ static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port,
/* We support 4 mirror groups, one destination port per group */
int group;
struct rtl838x_switch_priv *priv = ds->priv;
int ctrl_reg, dpm_reg, spm_reg;
int ctrl_reg, dpm_reg, spm_reg;
pr_debug("In %s\n", __func__);
@ -1920,6 +1913,7 @@ static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port,
priv->mirror_group_ports[group] = mirror->to_local_port;
mutex_unlock(&priv->reg_mutex);
return 0;
}
@ -2022,7 +2016,7 @@ static int rtl83xx_port_lag_change(struct dsa_switch *ds, int port)
struct rtl838x_switch_priv *priv = ds->priv;
pr_debug("%s: %d\n", __func__, port);
// Nothing to be done...
/* Nothing to be done... */
return 0;
}
@ -2051,8 +2045,8 @@ static int rtl83xx_port_lag_join(struct dsa_switch *ds, int port,
if (!priv->lag_devs[i])
priv->lag_devs[i] = lag;
if (priv->lag_primary[i]==-1) {
priv->lag_primary[i]=port;
if (priv->lag_primary[i] == -1) {
priv->lag_primary[i] = port;
} else
priv->is_lagmember[port] = 1;
@ -2067,8 +2061,8 @@ static int rtl83xx_port_lag_join(struct dsa_switch *ds, int port,
out:
mutex_unlock(&priv->reg_mutex);
return err;
return err;
}
static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port,
@ -2078,7 +2072,7 @@ static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port,
struct rtl838x_switch_priv *priv = ds->priv;
mutex_lock(&priv->reg_mutex);
for (i=0;i<priv->n_lags;i++) {
for (i = 0; i < priv->n_lags; i++) {
if (priv->lags_port_members[i] & BIT_ULL(port)) {
group = i;
break;
@ -2119,8 +2113,9 @@ int dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg)
u32 offset = 0;
struct rtl838x_switch_priv *priv = ds->priv;
if (phy_addr >= 24 && phy_addr <= 27
&& priv->ports[24].phy == PHY_RTL838X_SDS) {
if ((phy_addr >= 24) &&
(phy_addr <= 27) &&
(priv->ports[24].phy == PHY_RTL838X_SDS)) {
if (phy_addr == 26)
offset = 0x100;
val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff;
@ -2136,8 +2131,9 @@ int dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val)
u32 offset = 0;
struct rtl838x_switch_priv *priv = ds->priv;
if (phy_addr >= 24 && phy_addr <= 27
&& priv->ports[24].phy == PHY_RTL838X_SDS) {
if ((phy_addr >= 24) &&
(phy_addr <= 27) &&
(priv->ports[24].phy == PHY_RTL838X_SDS)) {
if (phy_addr == 26)
offset = 0x100;
sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2));

View File

@ -2,8 +2,8 @@
#include <net/dsa.h>
#include <linux/delay.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
static struct rtl838x_switch_priv *switch_priv;
@ -20,34 +20,34 @@ int dot1p_priority_remapping[] = {0, 1, 2, 3, 4, 5, 6, 7};
static void rtl839x_read_scheduling_table(int port)
{
u32 cmd = 1 << 9 /* Execute cmd */
| 0 << 8 /* Read */
| 0 << 6 /* Table type 0b00 */
| (port & 0x3f);
u32 cmd = 1 << 9 | /* Execute cmd */
0 << 8 | /* Read */
0 << 6 | /* Table type 0b00 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl839x_write_scheduling_table(int port)
{
u32 cmd = 1 << 9 /* Execute cmd */
| 1 << 8 /* Write */
| 0 << 6 /* Table type 0b00 */
| (port & 0x3f);
u32 cmd = 1 << 9 | /* Execute cmd */
1 << 8 | /* Write */
0 << 6 | /* Table type 0b00 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl839x_read_out_q_table(int port)
{
u32 cmd = 1 << 9 /* Execute cmd */
| 0 << 8 /* Read */
| 2 << 6 /* Table type 0b10 */
| (port & 0x3f);
u32 cmd = 1 << 9 | /* Execute cmd */
0 << 8 | /* Read */
2 << 6 | /* Table type 0b10 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl838x_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable)
{
// Enable Storm control for that port for UC, MC, and BC
/* Enable Storm control for that port for UC, MC, and BC */
if (enable)
sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port));
else
@ -56,12 +56,10 @@ static void rtl838x_storm_enable(struct rtl838x_switch_priv *priv, int port, boo
u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
{
u32 rate;
if (port > priv->cpu_port)
return 0;
rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)) & 0x3fff;
return rate;
return sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)) & 0x3fff;
}
/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
@ -86,40 +84,41 @@ void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
{
if (port > priv->cpu_port)
return;
if (queue > 7)
return;
sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue));
}
static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv)
{
int i;
pr_info("Enabling Storm control\n");
// TICK_PERIOD_PPS
/* TICK_PERIOD_PPS */
if (priv->id == 0x8380)
sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0);
// Set burst rate
sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); // UC
sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); // MC and BC
/* Set burst rate */
sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); /* UC */
sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); /* MC and BC */
// Set burst Packets per Second to 32
sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); // UC
sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); // MC and BC
/* Set burst Packets per Second to 32 */
sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); /* UC */
sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); /* MC and BC */
// Include IFG in storm control, rate based on bytes/s (0 = packets)
/* Include IFG in storm control, rate based on bytes/s (0 = packets) */
sw_w32_mask(0, 1 << 6 | 1 << 5, RTL838X_STORM_CTRL);
// Bandwidth control includes preamble and IFG (10 Bytes)
/* Bandwidth control includes preamble and IFG (10 Bytes) */
sw_w32_mask(0, 1, RTL838X_SCHED_CTRL);
// On SoCs except RTL8382M, set burst size of port egress
/* On SoCs except RTL8382M, set burst size of port egress */
if (priv->id != 0x8382)
sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR);
/* Enable storm control on all ports with a PHY and limit rates,
* for UC and MC for both known and unknown addresses */
for (i = 0; i < priv->cpu_port; i++) {
* for UC and MC for both known and unknown addresses
*/
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i));
sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i));
@ -128,14 +127,14 @@ static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv)
}
}
// Attack prevention, enable all attack prevention measures
//sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL);
/* Attack prevention, enable all attack prevention measures */
/* sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL); */
/* Attack prevention, drop (bit = 0) problematic packets on all ports.
* Setting bit = 1 means: trap to CPU
*/
//sw_w32(0, RTL838X_ATK_PRVNT_ACT);
// Enable attack prevention on all ports
//sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN);
/* sw_w32(0, RTL838X_ATK_PRVNT_ACT); */
/* Enable attack prevention on all ports */
/* sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN); */
}
/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
@ -180,7 +179,7 @@ int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate
sw_w32_mask(0xfff << 20, rate << 20, RTL839X_TBL_ACCESS_DATA_2(8));
rtl839x_write_scheduling_table(port);
mutex_unlock(&priv->reg_mutex);
return old_rate;
@ -221,27 +220,25 @@ void rtl839x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
{
int p, q;
pr_info("%s: enabling rate control\n", __func__);
/* Tick length and token size settings for SoC with 250MHz,
* RTL8350 family would use 50MHz
*/
// Set the special tick period
/* Set the special tick period */
sw_w32(976563, RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL);
// Ingress tick period and token length 10G
/* Ingress tick period and token length 10G */
sw_w32(18 << 11 | 151, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0);
// Ingress tick period and token length 1G
/* Ingress tick period and token length 1G */
sw_w32(245 << 11 | 129, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1);
// Egress tick period 10G, bytes/token 10G and tick period 1G, bytes/token 1G
/* Egress tick period 10G, bytes/token 10G and tick period 1G, bytes/token 1G */
sw_w32(18 << 24 | 151 << 16 | 185 << 8 | 97, RTL839X_SCHED_LB_TICK_TKN_CTRL);
// Set the tick period of the CPU and the Token Len
/* Set the tick period of the CPU and the Token Len */
sw_w32(3815 << 8 | 1, RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL);
// Set the Weighted Fair Queueing burst size
/* Set the Weighted Fair Queueing burst size */
sw_w32_mask(0xffff, 4500, RTL839X_SCHED_LB_THR);
// Storm-rate calculation is based on bytes/sec (bit 5), include IFG (bit 6)
/* Storm-rate calculation is based on bytes/sec (bit 5), include IFG (bit 6) */
sw_w32_mask(0, 1 << 5 | 1 << 6, RTL839X_STORM_CTRL);
/* Based on the rate control mode being bytes/s
@ -255,7 +252,7 @@ static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
* for UC, MC and BC
* For 1G port, the minimum burst rate is 1700, maximum 65535,
* For 10G ports it is 2650 and 1048575 respectively */
for (p = 0; p < priv->cpu_port; p++) {
for (int p = 0; p < priv->cpu_port; p++) {
if (priv->ports[p].phy && !priv->ports[p].is10G) {
sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_UC_1(p));
sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_MC_1(p));
@ -264,29 +261,29 @@ static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
}
/* Setup ingress/egress per-port rate control */
for (p = 0; p < priv->cpu_port; p++) {
for (int p = 0; p < priv->cpu_port; p++) {
if (!priv->ports[p].phy)
continue;
if (priv->ports[p].is10G)
rtl839x_set_egress_rate(priv, p, 625000); // 10GB/s
rtl839x_set_egress_rate(priv, p, 625000); /* 10GB/s */
else
rtl839x_set_egress_rate(priv, p, 62500); // 1GB/s
rtl839x_set_egress_rate(priv, p, 62500); /* 1GB/s */
// Setup queues: all RTL83XX SoCs have 8 queues, maximum rate
for (q = 0; q < 8; q++)
/* Setup queues: all RTL83XX SoCs have 8 queues, maximum rate */
for (int q = 0; q < 8; q++)
rtl839x_egress_rate_queue_limit(priv, p, q, 0xfffff);
if (priv->ports[p].is10G) {
// Set high threshold to maximum
/* Set high threshold to maximum */
sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p));
} else {
// Set high threshold to maximum
/* Set high threshold to maximum */
sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_1(p));
}
}
// Set global ingress low watermark rate
/* Set global ingress low watermark rate */
sw_w32(65532, RTL839X_IGR_BWCTRL_CTRL_LB_THR);
}
@ -294,22 +291,19 @@ static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
void rtl838x_setup_prio2queue_matrix(int *min_queues)
{
int i;
u32 v;
pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL838X_QM_INTPRI2QID_CTRL));
for (i = 0; i < MAX_PRIOS; i++)
for (int i = 0; i < MAX_PRIOS; i++)
v |= i << (min_queues[i] * 3);
sw_w32(v, RTL838X_QM_INTPRI2QID_CTRL);
}
void rtl839x_setup_prio2queue_matrix(int *min_queues)
{
int i, q;
pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL839X_QM_INTPRI2QID_CTRL(0)));
for (i = 0; i < MAX_PRIOS; i++) {
q = min_queues[i];
for (int i = 0; i < MAX_PRIOS; i++) {
int q = min_queues[i];
sw_w32(i << (q * 3), RTL839X_QM_INTPRI2QID_CTRL(q));
}
}
@ -317,13 +311,12 @@ void rtl839x_setup_prio2queue_matrix(int *min_queues)
/* Sets the CPU queue depending on the internal priority of a packet */
void rtl83xx_setup_prio2queue_cpu_matrix(int *max_queues)
{
int reg = soc_info.family == RTL8380_FAMILY_ID ? RTL838X_QM_PKT2CPU_INTPRI_MAP
int reg = soc_info.family == RTL8380_FAMILY_ID ? RTL838X_QM_PKT2CPU_INTPRI_MAP
: RTL839X_QM_PKT2CPU_INTPRI_MAP;
int i;
u32 v;
pr_info("QM_PKT2CPU_INTPRI_MAP: %08x\n", sw_r32(reg));
for (i = 0; i < MAX_PRIOS; i++)
for (int i = 0; i < MAX_PRIOS; i++)
v |= max_queues[i] << (i * 3);
sw_w32(v, reg);
}
@ -351,7 +344,6 @@ void rtl83xx_set_ingress_priority(int port, int priority)
sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port));
else
sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port));
}
int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
@ -367,6 +359,7 @@ int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
if (v & BIT(19))
return WEIGHTED_ROUND_ROBIN;
return WEIGHTED_FAIR_QUEUE;
}
@ -381,24 +374,24 @@ void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port
mutex_lock(&priv->reg_mutex);
/* Check whether we need to empty the egress queue of that port due to Errata E0014503 */
if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
// Read Operations, Adminstatrion and Management control register
/* Read Operations, Adminstatrion and Management control register */
oam_state = sw_r32(RTL839X_OAM_CTRL);
// Get current OAM state
/* Get current OAM state */
oam_port_state = sw_r32(RTL839X_OAM_PORT_ACT_CTRL(port));
// Disable OAM to block traffice
/* Disable OAM to block traffice */
v = sw_r32(RTL839X_OAM_CTRL);
sw_w32_mask(0, 1, RTL839X_OAM_CTRL);
v = sw_r32(RTL839X_OAM_CTRL);
// Set to trap action OAM forward (bits 1, 2) and OAM Mux Action Drop (bit 0)
/* Set to trap action OAM forward (bits 1, 2) and OAM Mux Action Drop (bit 0) */
sw_w32(0x2, RTL839X_OAM_PORT_ACT_CTRL(port));
// Set port egress rate to unlimited
/* Set port egress rate to unlimited */
egress_rate = rtl839x_set_egress_rate(priv, port, 0xFFFFF);
// Wait until the egress used page count of that port is 0
/* Wait until the egress used page count of that port is 0 */
i = 0;
do {
usleep_range(100, 200);
@ -409,19 +402,19 @@ void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port
} while (i < 3500 && count > 0);
}
// Actually set the scheduling algorithm
/* Actually set the scheduling algorithm */
rtl839x_read_scheduling_table(port);
sw_w32_mask(BIT(19), sched ? BIT(19) : 0, RTL839X_TBL_ACCESS_DATA_2(8));
rtl839x_write_scheduling_table(port);
if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
// Restore OAM state to control register
/* Restore OAM state to control register */
sw_w32(oam_state, RTL839X_OAM_CTRL);
// Restore trap action state
/* Restore trap action state */
sw_w32(oam_port_state, RTL839X_OAM_PORT_ACT_CTRL(port));
// Restore port egress rate
/* Restore port egress rate */
rtl839x_set_egress_rate(priv, port, egress_rate);
}
@ -431,17 +424,16 @@ void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port
void rtl839x_set_scheduling_queue_weights(struct rtl838x_switch_priv *priv, int port,
int *queue_weights)
{
int i, lsb, low_byte, start_bit, high_mask;
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
for (i = 0; i < 8; i++) {
lsb = 48 + i * 8;
low_byte = 8 - (lsb >> 5);
start_bit = lsb - (low_byte << 5);
high_mask = 0x3ff >> (32 - start_bit);
for (int i = 0; i < 8; i++) {
int lsb = 48 + i * 8;
int low_byte = 8 - (lsb >> 5);
int start_bit = lsb - (low_byte << 5);
int high_mask = 0x3ff >> (32 - start_bit);
sw_w32_mask(0x3ff << start_bit, (queue_weights[i] & 0x3ff) << start_bit,
RTL839X_TBL_ACCESS_DATA_2(low_byte));
if (high_mask)
@ -455,14 +447,13 @@ void rtl839x_set_scheduling_queue_weights(struct rtl838x_switch_priv *priv, int
void rtl838x_config_qos(void)
{
int i, p;
u32 v;
pr_info("Setting up RTL838X QoS\n");
pr_info("RTL838X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL838X_PRI_SEL_TBL_CTRL(0)));
rtl83xx_setup_default_prio2queue();
// Enable inner (bit 12) and outer (bit 13) priority remapping from DSCP
/* Enable inner (bit 12) and outer (bit 13) priority remapping from DSCP */
sw_w32_mask(0, BIT(12) | BIT(13), RTL838X_PRI_DSCP_INVLD_CTRL0);
/* Set default weight for calculating internal priority, in prio selection group 0
@ -471,37 +462,36 @@ void rtl838x_config_qos(void)
v = 3 | (4 << 3) | (5 << 6) | (6 << 9) | (7 << 12);
sw_w32(v, RTL838X_PRI_SEL_TBL_CTRL(0));
// Set the inner and outer priority one-to-one to re-marked outer dot1p priority
/* Set the inner and outer priority one-to-one to re-marked outer dot1p priority */
v = 0;
for (p = 0; p < 8; p++)
for (int p = 0; p < 8; p++)
v |= p << (3 * p);
sw_w32(v, RTL838X_RMK_OPRI_CTRL);
sw_w32(v, RTL838X_RMK_IPRI_CTRL);
v = 0;
for (p = 0; p < 8; p++)
for (int p = 0; p < 8; p++)
v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
sw_w32(v, RTL838X_PRI_SEL_IPRI_REMAP);
// On all ports set scheduler type to WFQ
for (i = 0; i <= soc_info.cpu_port; i++)
/* On all ports set scheduler type to WFQ */
for (int i = 0; i <= soc_info.cpu_port; i++)
sw_w32(0, RTL838X_SCHED_P_TYPE_CTRL(i));
// Enable egress scheduler for CPU-Port
/* Enable egress scheduler for CPU-Port */
sw_w32_mask(0, BIT(8), RTL838X_SCHED_LB_CTRL(soc_info.cpu_port));
// Enable egress drop allways on
/* Enable egress drop allways on */
sw_w32_mask(0, BIT(11), RTL838X_FC_P_EGR_DROP_CTRL(soc_info.cpu_port));
// Give special trap frames priority 7 (BPDUs) and routing exceptions:
/* Give special trap frames priority 7 (BPDUs) and routing exceptions: */
sw_w32_mask(0, 7 << 3 | 7, RTL838X_QM_PKT2CPU_INTPRI_2);
// Give RMA frames priority 7:
/* Give RMA frames priority 7: */
sw_w32_mask(0, 7, RTL838X_QM_PKT2CPU_INTPRI_1);
}
void rtl839x_config_qos(void)
{
int port, p, q;
u32 v;
struct rtl838x_switch_priv *priv = switch_priv;
@ -509,26 +499,26 @@ void rtl839x_config_qos(void)
pr_info("RTL839X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL839X_PRI_SEL_TBL_CTRL(0)));
rtl83xx_setup_default_prio2queue();
for (port = 0; port < soc_info.cpu_port; port++)
for (int port = 0; port < soc_info.cpu_port; port++)
sw_w32(7, RTL839X_QM_PORT_QNUM(port));
// CPU-port gets queue number 7
/* CPU-port gets queue number 7 */
sw_w32(7, RTL839X_QM_PORT_QNUM(soc_info.cpu_port));
for (port = 0; port <= soc_info.cpu_port; port++) {
for (int port = 0; port <= soc_info.cpu_port; port++) {
rtl83xx_set_ingress_priority(port, 0);
rtl839x_set_scheduling_algorithm(priv, port, WEIGHTED_FAIR_QUEUE);
rtl839x_set_scheduling_queue_weights(priv, port, default_queue_weights);
// Do re-marking based on outer tag
/* Do re-marking based on outer tag */
sw_w32_mask(0, BIT(port % 32), RTL839X_RMK_PORT_DEI_TAG_CTRL(port));
}
// Remap dot1p priorities to internal priority, for this the outer tag needs be re-marked
/* Remap dot1p priorities to internal priority, for this the outer tag needs be re-marked */
v = 0;
for (p = 0; p < 8; p++)
for (int p = 0; p < 8; p++)
v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
sw_w32(v, RTL839X_PRI_SEL_IPRI_REMAP);
/* Configure Drop Precedence for Drop Eligible Indicator (DEI)
* Index 0: 0
* Index 1: 2
@ -536,7 +526,7 @@ void rtl839x_config_qos(void)
*/
sw_w32(2 << 2, RTL839X_PRI_SEL_DEI2DP_REMAP);
// Re-mark DEI: 4 bit-fields of 2 bits each, field 0 is bits 0-1, ...
/* Re-mark DEI: 4 bit-fields of 2 bits each, field 0 is bits 0-1, ... */
sw_w32((0x1 << 2) | (0x1 << 4), RTL839X_RMK_DEI_CTRL);
/* Set Congestion avoidance drop probability to 0 for drop precedences 0-2 (bits 24-31)
@ -550,7 +540,7 @@ void rtl839x_config_qos(void)
/* Set queue-based congestion avoidance properties, register fields are as
* for forward RTL839X_WRED_PORT_THR_CTRL
*/
for (q = 0; q < 8; q++) {
for (int q = 0; q < 8; q++) {
sw_w32(255 << 24 | 78 << 12 | 68, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
sw_w32(255 << 24 | 74 << 12 | 64, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
sw_w32(255 << 24 | 70 << 12 | 60, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
@ -572,5 +562,4 @@ void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv)
rtl838x_rate_control_init(priv);
else if (priv->family_id == RTL8390_FAMILY_ID)
rtl839x_rate_control_init(priv);
}

View File

@ -5,9 +5,7 @@
#include <net/dsa.h>
/*
* Register definition
*/
/* Register definition */
#define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7)))
#define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7)))
#define RTL930X_MAC_PORT_CTRL(port) (0x3260 + (((port) << 6)))
@ -398,17 +396,16 @@
#define RTL839X_SPCL_TRAP_SWITCH_IPV4_ADDR_CTRL (0x106C)
#define RTL839X_SPCL_TRAP_CRC_CTRL (0x1070)
/* special port action controls */
/*
values:
0 = FORWARD (default)
1 = DROP
2 = TRAP2CPU
3 = FLOOD IN ALL PORT
Register encoding.
offset = CTRL + (port >> 4) << 2
value/mask = 3 << ((port&0xF) << 1)
*/
/* values:
* 0 = FORWARD (default)
* 1 = DROP
* 2 = TRAP2CPU
* 3 = FLOOD IN ALL PORT
*
* Register encoding.
* offset = CTRL + (port >> 4) << 2
* value/mask = 3 << ((port & 0xF) << 1)
*/
typedef enum {
BPDU = 0,
@ -429,17 +426,17 @@ typedef enum {
COPY2CPU,
} action_type_t;
#define RTL838X_RMA_BPDU_CTRL (0x4330)
#define RTL838X_RMA_BPDU_CTRL (0x4330)
#define RTL839X_RMA_BPDU_CTRL (0x122C)
#define RTL930X_RMA_BPDU_CTRL (0x9E7C)
#define RTL931X_RMA_BPDU_CTRL (0x881C)
#define RTL838X_RMA_PTP_CTRL (0x4338)
#define RTL838X_RMA_PTP_CTRL (0x4338)
#define RTL839X_RMA_PTP_CTRL (0x123C)
#define RTL930X_RMA_PTP_CTRL (0x9E88)
#define RTL931X_RMA_PTP_CTRL (0x8834)
#define RTL838X_RMA_LLTP_CTRL (0x4340)
#define RTL838X_RMA_LLTP_CTRL (0x4340)
#define RTL839X_RMA_LLTP_CTRL (0x124C)
#define RTL930X_RMA_LLTP_CTRL (0x9EFC)
#define RTL931X_RMA_LLTP_CTRL (0x8918)
@ -521,13 +518,13 @@ typedef enum {
#define RTL930X_PIE_BLK_PHASE_CTRL (0xA5A4)
#define RTL931X_PIE_BLK_PHASE_CTRL (0x4184)
// PIE actions
/* PIE actions */
#define PIE_ACT_COPY_TO_PORT 2
#define PIE_ACT_REDIRECT_TO_PORT 4
#define PIE_ACT_ROUTE_UC 6
#define PIE_ACT_VID_ASSIGN 0
// L3 actions
/* L3 actions */
#define L3_FORWARD 0
#define L3_DROP 1
#define L3_TRAP2CPU 2
@ -536,7 +533,7 @@ typedef enum {
#define L3_COPY2MASTERCPU 5
#define L3_HARDDROP 6
// Route actions
/* Route actions */
#define ROUTE_ACT_FORWARD 0
#define ROUTE_ACT_TRAP2CPU 1
#define ROUTE_ACT_COPY2CPU 2
@ -634,10 +631,10 @@ struct rtl838x_vlan_info {
u8 profile_id;
bool hash_mc_fid;
bool hash_uc_fid;
u8 fid; // AKA MSTI
u8 fid; /* AKA MSTI */
// The following fields are used only by the RTL931X
int if_id; // Interface (index in L3_EGR_INTF_IDX)
/* The following fields are used only by the RTL931X */
int if_id; /* Interface (index in L3_EGR_INTF_IDX) */
u16 multicast_grp_mask;
int l2_tunnel_list_id;
};
@ -673,9 +670,9 @@ struct rtl838x_l2_entry {
u32 mc_sip;
u16 mc_mac_index;
u16 nh_route_id;
bool nh_vlan_target; // Only RTL83xx: VLAN used for next hop
bool nh_vlan_target; /* Only RTL83xx: VLAN used for next hop */
// The following is only valid on RTL931x
/* The following is only valid on RTL931x */
bool is_open_flow;
bool is_pe_forward;
bool is_local_forward;
@ -712,35 +709,35 @@ enum egr_filter {
* to SoC family (e.g. because of different port ranges) */
struct pie_rule {
int id;
enum pie_phase phase; // Phase in which this template is applied
int packet_cntr; // ID of a packet counter assigned to this rule
int octet_cntr; // ID of a byte counter assigned to this rule
enum pie_phase phase; /* Phase in which this template is applied */
int packet_cntr; /* ID of a packet counter assigned to this rule */
int octet_cntr; /* ID of a byte counter assigned to this rule */
u32 last_packet_cnt;
u64 last_octet_cnt;
// The following are requirements for the pie template
/* The following are requirements for the pie template */
bool is_egress;
bool is_ipv6; // This is a rule with IPv6 fields
bool is_ipv6; /* This is a rule with IPv6 fields */
// Fixed fields that are always matched against on RTL8380
/* Fixed fields that are always matched against on RTL8380 */
u8 spmmask_fix;
u8 spn; // Source port number
bool stacking_port; // Source port is stacking port
bool mgnt_vlan; // Packet arrived on management VLAN
bool dmac_hit_sw; // The packet's destination MAC matches one of the device's
bool content_too_deep; // The content of the packet cannot be parsed: too many layers
bool not_first_frag; // Not the first IP fragment
u8 frame_type_l4; // 0: UDP, 1: TCP, 2: ICMP/ICMPv6, 3: IGMP
u8 frame_type; // 0: ARP, 1: L2 only, 2: IPv4, 3: IPv6
bool otag_fmt; // 0: outer tag packet, 1: outer priority tag or untagged
bool itag_fmt; // 0: inner tag packet, 1: inner priority tag or untagged
bool otag_exist; // packet with outer tag
bool itag_exist; // packet with inner tag
bool frame_type_l2; // 0: Ethernet, 1: LLC_SNAP, 2: LLC_Other, 3: Reserved
bool igr_normal_port; // Ingress port is not cpu or stacking port
u8 tid; // The template ID defining the what the templated fields mean
u8 spn; /* Source port number */
bool stacking_port; /* Source port is stacking port */
bool mgnt_vlan; /* Packet arrived on management VLAN */
bool dmac_hit_sw; /* The packet's destination MAC matches one of the device's */
bool content_too_deep; /* The content of the packet cannot be parsed: too many layers */
bool not_first_frag; /* Not the first IP fragment */
u8 frame_type_l4; /* 0: UDP, 1: TCP, 2: ICMP/ICMPv6, 3: IGMP */
u8 frame_type; /* 0: ARP, 1: L2 only, 2: IPv4, 3: IPv6 */
bool otag_fmt; /* 0: outer tag packet, 1: outer priority tag or untagged */
bool itag_fmt; /* 0: inner tag packet, 1: inner priority tag or untagged */
bool otag_exist; /* packet with outer tag */
bool itag_exist; /* packet with inner tag */
bool frame_type_l2; /* 0: Ethernet, 1: LLC_SNAP, 2: LLC_Other, 3: Reserved */
bool igr_normal_port; /* Ingress port is not cpu or stacking port */
u8 tid; /* The template ID defining the what the templated fields mean */
// Masks for the fields that are always matched against on RTL8380
/* Masks for the fields that are always matched against on RTL8380 */
u8 spmmask_fix_m;
u8 spn_m;
bool stacking_port_m;
@ -758,52 +755,52 @@ struct pie_rule {
bool igr_normal_port_m;
u8 tid_m;
// Logical operations between rules, special rules for rule numbers apply
/* Logical operations between rules, special rules for rule numbers apply */
bool valid;
bool cond_not; // Matches when conditions not match
bool cond_and1; // And this rule 2n with the next rule 2n+1 in same block
bool cond_and2; // And this rule m in block 2n with rule m in block 2n+1
bool cond_not; /* Matches when conditions not match */
bool cond_and1; /* And this rule 2n with the next rule 2n+1 in same block */
bool cond_and2; /* And this rule m in block 2n with rule m in block 2n+1 */
bool ivalid;
// Actions to be performed
bool drop; // Drop the packet
bool fwd_sel; // Forward packet: to port, portmask, dest route, next rule, drop
bool ovid_sel; // So something to outer vlan-id: shift, re-assign
bool ivid_sel; // Do something to inner vlan-id: shift, re-assign
bool flt_sel; // Filter the packet when sending to certain ports
bool log_sel; // Log the packet in one of the LOG-table counters
bool rmk_sel; // Re-mark the packet, i.e. change the priority-tag
bool meter_sel; // Meter the packet, i.e. limit rate of this type of packet
bool tagst_sel; // Change the ergress tag
bool mir_sel; // Mirror the packet to a Link Aggregation Group
bool nopri_sel; // Change the normal priority
bool cpupri_sel; // Change the CPU priority
bool otpid_sel; // Change Outer Tag Protocol Identifier (802.1q)
bool itpid_sel; // Change Inner Tag Protocol Identifier (802.1q)
bool shaper_sel; // Apply traffic shaper
bool mpls_sel; // MPLS actions
bool bypass_sel; // Bypass actions
bool fwd_sa_lrn; // Learn the source address when forwarding
bool fwd_mod_to_cpu; // Forward the modified VLAN tag format to CPU-port
/* Actions to be performed */
bool drop; /* Drop the packet */
bool fwd_sel; /* Forward packet: to port, portmask, dest route, next rule, drop */
bool ovid_sel; /* So something to outer vlan-id: shift, re-assign */
bool ivid_sel; /* Do something to inner vlan-id: shift, re-assign */
bool flt_sel; /* Filter the packet when sending to certain ports */
bool log_sel; /* Log the packet in one of the LOG-table counters */
bool rmk_sel; /* Re-mark the packet, i.e. change the priority-tag */
bool meter_sel; /* Meter the packet, i.e. limit rate of this type of packet */
bool tagst_sel; /* Change the ergress tag */
bool mir_sel; /* Mirror the packet to a Link Aggregation Group */
bool nopri_sel; /* Change the normal priority */
bool cpupri_sel; /* Change the CPU priority */
bool otpid_sel; /* Change Outer Tag Protocol Identifier (802.1q) */
bool itpid_sel; /* Change Inner Tag Protocol Identifier (802.1q) */
bool shaper_sel; /* Apply traffic shaper */
bool mpls_sel; /* MPLS actions */
bool bypass_sel; /* Bypass actions */
bool fwd_sa_lrn; /* Learn the source address when forwarding */
bool fwd_mod_to_cpu; /* Forward the modified VLAN tag format to CPU-port */
// Fields used in predefined templates 0-2 on RTL8380 / 90 / 9300
u64 spm; // Source Port Matrix
u16 otag; // Outer VLAN-ID
u8 smac[ETH_ALEN]; // Source MAC address
u8 dmac[ETH_ALEN]; // Destination MAC address
u16 ethertype; // Ethernet frame type field in ethernet header
u16 itag; // Inner VLAN-ID
/* Fields used in predefined templates 0-2 on RTL8380 / 90 / 9300 */
u64 spm; /* Source Port Matrix */
u16 otag; /* Outer VLAN-ID */
u8 smac[ETH_ALEN]; /* Source MAC address */
u8 dmac[ETH_ALEN]; /* Destination MAC address */
u16 ethertype; /* Ethernet frame type field in ethernet header */
u16 itag; /* Inner VLAN-ID */
u16 field_range_check;
u32 sip; // Source IP
struct in6_addr sip6; // IPv6 Source IP
u32 dip; // Destination IP
struct in6_addr dip6; // IPv6 Destination IP
u16 tos_proto; // IPv4: TOS + Protocol fields, IPv6: Traffic class + next header
u16 sport; // TCP/UDP source port
u16 dport; // TCP/UDP destination port
u32 sip; /* Source IP */
struct in6_addr sip6; /* IPv6 Source IP */
u32 dip; /* Destination IP */
struct in6_addr dip6; /* IPv6 Destination IP */
u16 tos_proto; /* IPv4: TOS + Protocol fields, IPv6: Traffic class + next header */
u16 sport; /* TCP/UDP source port */
u16 dport; /* TCP/UDP destination port */
u16 icmp_igmp;
u16 tcp_info;
u16 dsap_ssap; // Destination / Source Service Access Point bytes (802.3)
u16 dsap_ssap; /* Destination / Source Service Access Point bytes (802.3) */
u64 spm_m;
u16 otag_m;
@ -813,9 +810,9 @@ struct pie_rule {
u16 itag_m;
u16 field_range_check_m;
u32 sip_m;
struct in6_addr sip6_m; // IPv6 Source IP mask
struct in6_addr sip6_m; /* IPv6 Source IP mask */
u32 dip_m;
struct in6_addr dip6_m; // IPv6 Destination IP mask
struct in6_addr dip6_m; /* IPv6 Destination IP mask */
u16 tos_proto_m;
u16 sport_m;
u16 dport_m;
@ -823,25 +820,25 @@ struct pie_rule {
u16 tcp_info_m;
u16 dsap_ssap_m;
// Data associated with actions
u8 fwd_act; // Type of forwarding action
// 0: permit, 1: drop, 2: copy to port id, 4: copy to portmask
// 4: redirect to portid, 5: redirect to portmask
// 6: route, 7: vlan leaky (only 8380)
u16 fwd_data; // Additional data for forwarding action, e.g. destination port
/* Data associated with actions */
u8 fwd_act; /* Type of forwarding action */
/* 0: permit, 1: drop, 2: copy to port id, 4: copy to portmask */
/* 4: redirect to portid, 5: redirect to portmask */
/* 6: route, 7: vlan leaky (only 8380) */
u16 fwd_data; /* Additional data for forwarding action, e.g. destination port */
u8 ovid_act;
u16 ovid_data; // Outer VLAN ID
u16 ovid_data; /* Outer VLAN ID */
u8 ivid_act;
u16 ivid_data; // Inner VLAN ID
u16 flt_data; // Filtering data
u16 log_data; // ID of packet or octet counter in LOG table, on RTL93xx
// unnecessary since PIE-Rule-ID == LOG-counter-ID
u16 ivid_data; /* Inner VLAN ID */
u16 flt_data; /* Filtering data */
u16 log_data; /* ID of packet or octet counter in LOG table, on RTL93xx */
/* unnecessary since PIE-Rule-ID == LOG-counter-ID */
bool log_octets;
u8 mpls_act; // MPLS action type
u16 mpls_lib_idx; // MPLS action data
u8 mpls_act; /* MPLS action type */
u16 mpls_lib_idx; /* MPLS action data */
u16 rmk_data; // Data for remarking
u16 meter_data; // ID of meter for bandwidth control
u16 rmk_data; /* Data for remarking */
u16 meter_data; /* ID of meter for bandwidth control */
u16 tagst_data;
u16 mir_data;
u16 nopri_data;
@ -850,10 +847,10 @@ struct pie_rule {
u16 itpid_data;
u16 shaper_data;
// Bypass actions, ignored on RTL8380
bool bypass_all; // Not clear
bool bypass_igr_stp; // Bypass Ingress STP state
bool bypass_ibc_sc; // Bypass Ingress Bandwidth Control and Storm Control
/* Bypass actions, ignored on RTL8380 */
bool bypass_all; /* Not clear */
bool bypass_igr_stp; /* Bypass Ingress STP state */
bool bypass_ibc_sc; /* Bypass Ingress Bandwidth Control and Storm Control */
};
struct rtl838x_l3_intf {
@ -871,37 +868,36 @@ struct rtl838x_l3_intf {
u8 ip6_pbr_icmp_redirect;
};
/*
* An entry in the RTL93XX SoC's ROUTER_MAC tables setting up a termination point
/* An entry in the RTL93XX SoC's ROUTER_MAC tables setting up a termination point
* for the L3 routing system. Packets arriving and matching an entry in this table
* will be considered for routing.
* Mask fields state whether the corresponding data fields matter for matching
*/
struct rtl93xx_rt_mac {
bool valid; // Valid or not
bool p_type; // Individual (0) or trunk (1) port
bool p_mask; // Whether the port type is used
bool valid; /* Valid or not */
bool p_type; /* Individual (0) or trunk (1) port */
bool p_mask; /* Whether the port type is used */
u8 p_id;
u8 p_id_mask; // Mask for the port
u8 action; // Routing action performed: 0: FORWARD, 1: DROP, 2: TRAP2CPU
// 3: COPY2CPU, 4: TRAP2MASTERCPU, 5: COPY2MASTERCPU, 6: HARDDROP
u8 p_id_mask; /* Mask for the port */
u8 action; /* Routing action performed: 0: FORWARD, 1: DROP, 2: TRAP2CPU */
/* 3: COPY2CPU, 4: TRAP2MASTERCPU, 5: COPY2MASTERCPU, 6: HARDDROP */
u16 vid;
u16 vid_mask;
u64 mac; // MAC address used as source MAC in the routed packet
u64 mac; /* MAC address used as source MAC in the routed packet */
u64 mac_mask;
};
struct rtl83xx_nexthop {
u16 id; // ID: L3_NEXT_HOP table-index or route-index set in L2_NEXT_HOP
u16 id; /* ID: L3_NEXT_HOP table-index or route-index set in L2_NEXT_HOP */
u32 dev_id;
u16 port;
u16 vid; // VLAN-ID for L2 table entry (saved from L2-UC entry)
u16 rvid; // Relay VID/FID for the L2 table entry
u64 mac; // The MAC address of the entry in the L2_NEXT_HOP table
u16 vid; /* VLAN-ID for L2 table entry (saved from L2-UC entry) */
u16 rvid; /* Relay VID/FID for the L2 table entry */
u64 mac; /* The MAC address of the entry in the L2_NEXT_HOP table */
u16 mac_id;
u16 l2_id; // Index of this next hop forwarding entry in L2 FIB table
u64 gw; // The gateway MAC address packets are forwarded to
int if_id; // Interface (into L3_EGR_INTF_IDX)
u16 l2_id; /* Index of this next hop forwarding entry in L2 FIB table */
u64 gw; /* The gateway MAC address packets are forwarded to */
int if_id; /* Interface (into L3_EGR_INTF_IDX) */
};
struct rtl838x_switch_priv;
@ -928,14 +924,14 @@ struct rtl93xx_route_attr {
};
struct rtl83xx_route {
u32 gw_ip; // IP of the route's gateway
u32 dst_ip; // IP of the destination net
u32 gw_ip; /* IP of the route's gateway */
u32 dst_ip; /* IP of the destination net */
struct in6_addr dst_ip6;
int prefix_len; // Network prefix len of the destination net
int prefix_len; /* Network prefix len of the destination net */
bool is_host_route;
int id; // ID number of this route
int id; /* ID number of this route */
struct rhlist_head linkage;
u16 switch_mac_id; // Index into switch's own MACs, RTL839X only
u16 switch_mac_id; /* Index into switch's own MACs, RTL839X only */
struct rtl83xx_nexthop nh;
struct pie_rule pr;
struct rtl93xx_route_attr attr;
@ -1047,8 +1043,8 @@ struct rtl838x_switch_priv {
u16 family_id;
char version;
struct rtl838x_port ports[57];
struct mutex reg_mutex; // Mutex for individual register manipulations
struct mutex pie_mutex; // Mutex for Packet Inspection Engine
struct mutex reg_mutex; /* Mutex for individual register manipulations */
struct mutex pie_mutex; /* Mutex for Packet Inspection Engine */
int link_state_irq;
int mirror_group_ports[4];
struct mii_bus *mii_bus;
@ -1067,7 +1063,7 @@ struct rtl838x_switch_priv {
u32 lag_primary[MAX_LAGS];
u32 is_lagmember[57];
u64 lagmembers;
struct notifier_block nb; // TODO: change to different name
struct notifier_block nb; /* TODO: change to different name */
struct notifier_block ne_nb;
struct notifier_block fib_nb;
bool eee_enabled;

View File

@ -67,8 +67,8 @@ typedef enum {
void rtl_table_init(void);
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t);
void rtl_table_release(struct table_reg *r);
void rtl_table_read(struct table_reg *r, int idx);
void rtl_table_write(struct table_reg *r, int idx);
int rtl_table_read(struct table_reg *r, int idx);
int rtl_table_write(struct table_reg *r, int idx);
inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
@ -134,4 +134,3 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port);
#endif /* _NET_DSA_RTL83XX_H */

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
#define RTL931X_VLAN_PORT_TAG_STS_INTERNAL 0x0
@ -79,9 +80,9 @@ enum template_field_id {
*/
#define TEMPLATE_FIELD_VLAN TEMPLATE_FIELD_ITAG
// Number of fixed templates predefined in the RTL9300 SoC
/* Number of fixed templates predefined in the RTL9300 SoC */
#define N_FIXED_TEMPLATES 5
// RTL931x specific predefined templates
/* RTL931x specific predefined templates */
static enum template_field_id fixed_templates[N_FIXED_TEMPLATES][N_FIXED_FIELDS_RTL931X] =
{
{
@ -142,12 +143,12 @@ void rtl931x_vlan_profile_dump(int index)
return;
profile[0] = sw_r32(RTL931X_VLAN_PROFILE_SET(index));
profile[1] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 4) & 0x1FFFFFFFULL) << 32
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 8) & 0xFFFFFFFF);
profile[2] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFFULL) << 32
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 12) & 0xFFFFFFFF);
profile[3] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 20) & 0x1FFFFFFFULL) << 32
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 24) & 0xFFFFFFFF);
profile[1] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 4) & 0x1FFFFFFFULL) << 32 |
(sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 8) & 0xFFFFFFFF);
profile[2] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFFULL) << 32 |
(sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 12) & 0xFFFFFFFF);
profile[3] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 20) & 0x1FFFFFFFULL) << 32 |
(sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 24) & 0xFFFFFFFF);
pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %llx, \
IPv4 Unknown MultiCast Field %llx, IPv6 Unknown MultiCast Field: %llx",
@ -156,25 +157,23 @@ void rtl931x_vlan_profile_dump(int index)
static void rtl931x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{
int i;
u32 cmd = 1 << 20 /* Execute cmd */
| 0 << 19 /* Read */
| 5 << 15 /* Table type 0b101 */
| (msti & 0x3fff);
u32 cmd = 1 << 20 | /* Execute cmd */
0 << 19 | /* Read */
5 << 15 | /* Table type 0b101 */
(msti & 0x3fff);
priv->r->exec_tbl0_cmd(cmd);
for (i = 0; i < 4; i++)
for (int i = 0; i < 4; i++)
port_state[i] = sw_r32(priv->r->tbl_access_data_0(i));
}
static void rtl931x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{
int i;
u32 cmd = 1 << 20 /* Execute cmd */
| 1 << 19 /* Write */
| 5 << 15 /* Table type 0b101 */
| (msti & 0x3fff);
for (i = 0; i < 4; i++)
u32 cmd = 1 << 20 | /* Execute cmd */
1 << 19 | /* Write */
5 << 15 | /* Table type 0b101 */
(msti & 0x3fff);
for (int i = 0; i < 4; i++)
sw_w32(port_state[i], priv->r->tbl_access_data_0(i));
priv->r->exec_tbl0_cmd(cmd);
}
@ -187,7 +186,7 @@ inline static int rtl931x_trk_mbr_ctr(int group)
static void rtl931x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
{
u32 v, w, x, y;
// Read VLAN table (3) via register 0
/* Read VLAN table (3) via register 0 */
struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 3);
rtl_table_read(r, vlan);
@ -200,7 +199,7 @@ static void rtl931x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
pr_debug("VLAN_READ %d: %08x %08x %08x %08x\n", vlan, v, w, x, y);
info->tagged_ports = ((u64) v) << 25 | (w >> 7);
info->profile_id = (x >> 16) & 0xf;
info->fid = w & 0x7f; // AKA MSTI depending on context
info->fid = w & 0x7f; /* AKA MSTI depending on context */
info->hash_uc_fid = !!(x & BIT(31));
info->hash_mc_fid = !!(x & BIT(30));
info->if_id = (x >> 20) & 0x3ff;
@ -214,7 +213,7 @@ static void rtl931x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
info->tagged_ports, info->profile_id, info->hash_uc_fid, info->hash_mc_fid,
info->if_id);
// Read UNTAG table via table register 3
/* Read UNTAG table via table register 3 */
r = rtl_table_get(RTL9310_TBL_3, 0);
rtl_table_read(r, vlan);
v = ((u64)sw_r32(rtl_table_data(r, 0))) << 25;
@ -227,7 +226,7 @@ static void rtl931x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
static void rtl931x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info)
{
u32 v, w, x, y;
// Access VLAN table (1) via register 0
/* Access VLAN table (1) via register 0 */
struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 3);
v = info->tagged_ports >> 25;
@ -294,18 +293,17 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
u32 status = sw_r32(RTL931X_ISR_GLB_SRC);
u64 ports = rtl839x_get_port_reg_le(RTL931X_ISR_PORT_LINK_STS_CHG);
u64 link;
int i;
/* Clear status */
rtl839x_set_port_reg_le(ports, RTL931X_ISR_PORT_LINK_STS_CHG);
pr_debug("RTL931X Link change: status: %x, ports %016llx\n", status, ports);
link = rtl839x_get_port_reg_le(RTL931X_MAC_LINK_STS);
// Must re-read this to get correct status
/* Must re-read this to get correct status */
link = rtl839x_get_port_reg_le(RTL931X_MAC_LINK_STS);
pr_debug("RTL931X Link change: status: %x, link status %016llx\n", status, link);
for (i = 0; i < 56; i++) {
for (int i = 0; i < 56; i++) {
if (ports & BIT_ULL(i)) {
if (link & BIT_ULL(i)) {
pr_info("%s port %d up\n", __func__, i);
@ -316,6 +314,7 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
}
}
}
return IRQ_HANDLED;
}
@ -352,6 +351,7 @@ int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
err = -EIO;
mutex_unlock(&smi_lock);
return err;
}
@ -380,12 +380,11 @@ int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
__func__, port, page, reg, *val, v);
mutex_unlock(&smi_lock);
return 0;
}
/*
* Read an mmd register of the PHY
*/
/* Read an mmd register of the PHY */
int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{
int err = 0;
@ -400,20 +399,20 @@ int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
mutex_lock(&smi_lock);
// Set PHY to access via port-number
/* Set PHY to access via port-number */
sw_w32(port << 5, RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL);
// Set MMD device number and register to write to
/* Set MMD device number and register to write to */
sw_w32(devnum << 16 | mdiobus_c45_regad(regnum), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);
v = type << 2 | BIT(0); // MMD-access-type | EXEC
v = type << 2 | BIT(0); /* MMD-access-type | EXEC */
sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
do {
v = sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0);
} while (v & BIT(0));
// Check for error condition
/* Check for error condition */
if (v & BIT(1))
err = -EIO;
@ -427,9 +426,7 @@ int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
return err;
}
/*
* Write to an mmd register of the PHY
*/
/* Write to an mmd register of the PHY */
int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{
int err = 0;
@ -439,18 +436,18 @@ int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
mutex_lock(&smi_lock);
// Set PHY to access via port-mask
/* Set PHY to access via port-mask */
pm = (u64)1 << port;
sw_w32((u32)pm, RTL931X_SMI_INDRT_ACCESS_CTRL_2);
sw_w32((u32)(pm >> 32), RTL931X_SMI_INDRT_ACCESS_CTRL_2 + 4);
// Set data to write
/* Set data to write */
sw_w32_mask(0xffff, val, RTL931X_SMI_INDRT_ACCESS_CTRL_3);
// Set MMD device number and register to write to
/* Set MMD device number and register to write to */
sw_w32(devnum << 16 | mdiobus_c45_regad(regnum), RTL931X_SMI_INDRT_ACCESS_MMD_CTRL);
v = BIT(4) | type << 2 | BIT(0); // WRITE | MMD-access-type | EXEC
v = BIT(4) | type << 2 | BIT(0); /* WRITE | MMD-access-type | EXEC */
sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0);
do {
@ -460,15 +457,15 @@ int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
port, devnum, mdiobus_c45_regad(regnum), val, err);
mutex_unlock(&smi_lock);
return err;
}
void rtl931x_print_matrix(void)
{
volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0);
int i;
for (i = 0; i < 52; i += 4)
for (int i = 0; i < 52; i += 4)
pr_info("> %16llx %16llx %16llx %16llx\n",
ptr[i + 0], ptr[i + 1], ptr[i + 2], ptr[i + 3]);
pr_info("CPU_PORT> %16llx\n", ptr[52]);
@ -507,9 +504,9 @@ void rtl931x_set_receive_management_action(int port, rma_ctrl_t type, action_typ
sw_w32_mask(7 << ((port % 10) * 3), value << ((port % 10) * 3), RTL931X_RMA_BPDU_CTRL + ((port / 10) << 2));
break;
case PTP:
//udp
/* udp */
sw_w32_mask(3 << 2, value << 2, RTL931X_RMA_PTP_CTRL + (port << 2));
//eth2
/* eth2 */
sw_w32_mask(3, value, RTL931X_RMA_PTP_CTRL + (port << 2));
break;
case PTP_UDP:
@ -538,12 +535,12 @@ u64 rtl931x_traffic_get(int source)
rtl_table_read(r, source);
v = sw_r32(rtl_table_data(r, 0));
rtl_table_release(r);
return v >> 3;
v = v >> 3;
return v;
}
/*
* Enable traffic between a source port and a destination port matrix
*/
/* Enable traffic between a source port and a destination port matrix */
void rtl931x_traffic_set(int source, u64 dest_matrix)
{
struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 6);
@ -581,8 +578,7 @@ static u64 rtl931x_l2_hash_seed(u64 mac, u32 vid)
return v;
}
/*
* Calculate both the block 0 and the block 1 hash by applyingthe same hash
/* Calculate both the block 0 and the block 1 hash by applyingthe same hash
* algorithm as the one used currently by the ASIC to the seed, and return
* both hashes in the lower and higher word of the return value since only 12 bit of
* the hash are significant.
@ -609,7 +605,7 @@ static u32 rtl931x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
h4 = (seed >> 48) & 0xfff;
k1 = h0 ^ h1 ^ h2 ^ h3 ^ h4;
// Algorithm choice for block 0
/* Algorithm choice for block 0 */
if (sw_r32(RTL931X_L2_CTRL) & BIT(0))
h = k1;
else
@ -629,9 +625,7 @@ static u32 rtl931x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
return h;
}
/*
* Fills an L2 entry structure from the SoC registers
*/
/* Fills an L2 entry structure from the SoC registers */
static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
{
pr_debug("In %s valid?\n", __func__);
@ -661,7 +655,7 @@ static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
e->is_l2_tunnel = !!(r[2] & BIT(31));
e->is_static = !!(r[2] & BIT(13));
e->port = (r[2] >> 19) & 0x3ff;
// Check for trunk port
/* Check for trunk port */
if (r[2] & BIT(29)) {
e->is_trunk = true;
e->stack_dev = (e->port >> 9) & 1;
@ -677,7 +671,7 @@ static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
e->suspended = !!(r[2] & BIT(12));
e->age = (r[2] >> 16) & 3;
// the UC_VID field in hardware is used for the VID or for the route id
/* the UC_VID field in hardware is used for the VID or for the route id */
if (e->next_hop) {
e->nh_route_id = r[2] & 0x7ff;
e->vid = 0;
@ -687,7 +681,7 @@ static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
}
if (e->is_l2_tunnel)
e->l2_tunnel_id = ((r[2] & 0xff) << 4) | (r[3] >> 28);
// TODO: Implement VLAN conversion
/* TODO: Implement VLAN conversion */
} else {
e->type = L2_MULTICAST;
e->is_local_forward = !!(r[2] & BIT(31));
@ -697,9 +691,7 @@ static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
}
}
/*
* Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry
*/
/* Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry */
static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
{
u32 port;
@ -709,11 +701,14 @@ static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
return;
}
r[2] = BIT(31); // Set valid bit
r[2] = BIT(31); /* Set valid bit */
r[0] = ((u32)e->mac[0]) << 24 | ((u32)e->mac[1]) << 16
| ((u32)e->mac[2]) << 8 | ((u32)e->mac[3]);
r[1] = ((u32)e->mac[4]) << 24 | ((u32)e->mac[5]) << 16;
r[0] = ((u32)e->mac[0]) << 24 |
((u32)e->mac[1]) << 16 |
((u32)e->mac[2]) << 8 |
((u32)e->mac[3]);
r[1] = ((u32)e->mac[4]) << 24 |
((u32)e->mac[5]) << 16;
r[2] |= e->next_hop ? BIT(12) : 0;
@ -733,19 +728,18 @@ static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
r[2] |= e->block_sa ? BIT(17) : 0;
r[2] |= e->suspended ? BIT(13) : 0;
r[2] |= (e->age & 0x3) << 17;
// the UC_VID field in hardware is used for the VID or for the route id
/* the UC_VID field in hardware is used for the VID or for the route id */
if (e->next_hop)
r[2] |= e->nh_route_id & 0x7ff;
else
r[2] |= e->vid & 0xfff;
} else { // L2_MULTICAST
} else { /* L2_MULTICAST */
r[2] |= (e->mc_portmask_index & 0x3ff) << 16;
r[2] |= e->mc_mac_index & 0x7ff;
}
}
/*
* Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table
/* Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table
* hash is the id of the bucket and pos is the position of the entry in that bucket
* The data read from the SoC is filled into rtl838x_l2_entry
*/
@ -754,7 +748,6 @@ static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
u32 r[4];
struct table_reg *q = rtl_table_get(RTL9310_TBL_0, 0);
u32 idx;
int i;
u64 mac;
u64 seed;
@ -762,7 +755,8 @@ static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
/* On the RTL93xx, 2 different hash algorithms are used making it a total of
* 8 buckets that need to be searched, 4 for each hash-half
* Use second hash space when bucket is between 4 and 8 */
* Use second hash space when bucket is between 4 and 8
*/
if (pos >= 4) {
pos -= 4;
hash >>= 16;
@ -770,11 +764,11 @@ static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
hash &= 0xffff;
}
idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket
idx = (0 << 14) | (hash << 2) | pos; /* Search SRAM, with hash and at pos in bucket */
pr_debug("%s: NOW hash %08x, pos: %d\n", __func__, hash, pos);
rtl_table_read(q, idx);
for (i = 0; i < 4; i++)
for (int i = 0; i < 4; i++)
r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q);
@ -785,18 +779,23 @@ static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
if (!e->valid)
return 0;
mac = ((u64)e->mac[0]) << 40 | ((u64)e->mac[1]) << 32 | ((u64)e->mac[2]) << 24
| ((u64)e->mac[3]) << 16 | ((u64)e->mac[4]) << 8 | ((u64)e->mac[5]);
mac = ((u64)e->mac[0]) << 40 |
((u64)e->mac[1]) << 32 |
((u64)e->mac[2]) << 24 |
((u64)e->mac[3]) << 16 |
((u64)e->mac[4]) << 8 |
((u64)e->mac[5]);
seed = rtl931x_l2_hash_seed(mac, e->rvid);
pr_debug("%s: mac %016llx, seed %016llx\n", __func__, mac, seed);
// return vid with concatenated mac as unique id
/* return vid with concatenated mac as unique id */
return seed;
}
static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e)
{
return 0;
return 0;
}
static void rtl931x_write_cam(int idx, struct rtl838x_l2_entry *e)
@ -807,8 +806,7 @@ static void rtl931x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
{
u32 r[4];
struct table_reg *q = rtl_table_get(RTL9310_TBL_0, 0);
u32 idx = (0 << 14) | (hash << 2) | pos; // Access SRAM, with hash and at pos in bucket
int i;
u32 idx = (0 << 14) | (hash << 2) | pos; /* Access SRAM, with hash and at pos in bucket */
pr_info("%s: hash %d, pos %d\n", __func__, hash, pos);
pr_info("%s: index %d -> mac %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, idx,
@ -817,17 +815,16 @@ static void rtl931x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
rtl931x_fill_l2_row(r, e);
pr_info("%s: %d: %08x %08x %08x\n", __func__, idx, r[0], r[1], r[2]);
for (i= 0; i < 4; i++)
for (int i = 0; i < 4; i++)
sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx);
rtl_table_release(q);
}
static void rtl931x_vlan_fwd_on_inner(int port, bool is_set)
{
// Always set all tag modes to fwd based on either inner or outer tag
/* Always set all tag modes to fwd based on either inner or outer tag */
if (is_set)
sw_w32_mask(0, 0xf, RTL931X_VLAN_PORT_FWD + (port << 2));
else
@ -837,7 +834,6 @@ static void rtl931x_vlan_fwd_on_inner(int port, bool is_set)
static void rtl931x_vlan_profile_setup(int profile)
{
u32 p[7];
int i;
pr_info("In %s\n", __func__);
@ -846,38 +842,38 @@ static void rtl931x_vlan_profile_setup(int profile)
p[0] = sw_r32(RTL931X_VLAN_PROFILE_SET(profile));
// Enable routing of Ipv4/6 Unicast and IPv4/6 Multicast traffic
//p[0] |= BIT(17) | BIT(16) | BIT(13) | BIT(12);
p[0] |= 0x3 << 11; // COPY2CPU
/* Enable routing of Ipv4/6 Unicast and IPv4/6 Multicast traffic */
/* p[0] |= BIT(17) | BIT(16) | BIT(13) | BIT(12); */
p[0] |= 0x3 << 11; /* COPY2CPU */
p[1] = 0x1FFFFFF; // L2 unknwon MC flooding portmask all ports, including the CPU-port
p[1] = 0x1FFFFFF; /* L2 unknwon MC flooding portmask all ports, including the CPU-port */
p[2] = 0xFFFFFFFF;
p[3] = 0x1FFFFFF; // IPv4 unknwon MC flooding portmask
p[3] = 0x1FFFFFF; /* IPv4 unknwon MC flooding portmask */
p[4] = 0xFFFFFFFF;
p[5] = 0x1FFFFFF; // IPv6 unknwon MC flooding portmask
p[5] = 0x1FFFFFF; /* IPv6 unknwon MC flooding portmask */
p[6] = 0xFFFFFFFF;
for (i = 0; i < 7; i++)
for (int i = 0; i < 7; i++)
sw_w32(p[i], RTL931X_VLAN_PROFILE_SET(profile) + i * 4);
pr_info("Leaving %s\n", __func__);
}
static void rtl931x_l2_learning_setup(void)
{
// Portmask for flooding broadcast traffic
/* Portmask for flooding broadcast traffic */
rtl839x_set_port_reg_be(0x1FFFFFFFFFFFFFF, RTL931X_L2_BC_FLD_PMSK);
// Portmask for flooding unicast traffic with unknown destination
/* Portmask for flooding unicast traffic with unknown destination */
rtl839x_set_port_reg_be(0x1FFFFFFFFFFFFFF, RTL931X_L2_UNKN_UC_FLD_PMSK);
// Limit learning to maximum: 64k entries, after that just flood (bits 0-2)
/* Limit learning to maximum: 64k entries, after that just flood (bits 0-2) */
sw_w32((0xffff << 3) | FORWARD, RTL931X_L2_LRN_CONSTRT_CTRL);
}
static u64 rtl931x_read_mcast_pmask(int idx)
{
u64 portmask;
// Read MC_PMSK (2) via register RTL9310_TBL_0
/* Read MC_PMSK (2) via register RTL9310_TBL_0 */
struct table_reg *q = rtl_table_get(RTL9310_TBL_0, 2);
rtl_table_read(q, idx);
@ -888,6 +884,7 @@ static u64 rtl931x_read_mcast_pmask(int idx)
rtl_table_release(q);
pr_debug("%s: Index idx %d has portmask %016llx\n", __func__, idx, portmask);
return portmask;
}
@ -895,7 +892,7 @@ static void rtl931x_write_mcast_pmask(int idx, u64 portmask)
{
u64 pm = portmask;
// Access MC_PMSK (2) via register RTL9310_TBL_0
/* Access MC_PMSK (2) via register RTL9310_TBL_0 */
struct table_reg *q = rtl_table_get(RTL9310_TBL_0, 2);
pr_debug("%s: Index idx %d has portmask %016llx\n", __func__, idx, pm);
@ -919,11 +916,12 @@ static int rtl931x_set_ageing_time(unsigned long msec)
t = t > 0x1FFFFF ? 0x1FFFFF : t;
sw_w32_mask(0x1FFFFF, t, RTL931X_L2_AGE_CTRL);
pr_debug("Dynamic aging for ports: %x\n", sw_r32(RTL931X_L2_PORT_AGE_CTRL));
return 0;
}
void rtl931x_sw_init(struct rtl838x_switch_priv *priv)
{
// rtl931x_sds_init(priv);
/* rtl931x_sds_init(priv); */
}
static void rtl931x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int index)
@ -933,8 +931,7 @@ static void rtl931x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int inde
sw_w32_mask(0, BIT(block), RTL931X_PIE_BLK_LOOKUP_CTRL);
}
/*
* Fills the data in the intermediate representation in the pie_rule structure
/* Fills the data in the intermediate representation in the pie_rule structure
* into a data field for a given template field field_type
* TODO: This function looks very similar to the function of the rtl9300, but
* since it uses the physical template_field_id, which are different for each
@ -1031,7 +1028,6 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
*data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
*data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
break;
case TEMPLATE_FIELD_DIP0:
if (pr->is_ipv6) {
*data = pr->dip6.s6_addr16[7];
@ -1050,7 +1046,6 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
*data_m = pr->dip_m >> 16;
}
break;
case TEMPLATE_FIELD_DIP2:
case TEMPLATE_FIELD_DIP3:
case TEMPLATE_FIELD_DIP4:
@ -1060,7 +1055,6 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
*data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
*data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
break;
case TEMPLATE_FIELD_IP_TOS_PROTO:
*data = pr->tos_proto;
*data_m = pr->tos_proto_m;
@ -1092,8 +1086,7 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
return 0;
}
/*
* Reads the intermediate representation of the templated match-fields of the
/* Reads the intermediate representation of the templated match-fields of the
* PIE rule in the pie_rule structure and fills in the raw data fields in the
* raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1103,13 +1096,12 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
*/
static void rtl931x_write_pie_templated(u32 r[], struct pie_rule *pr, enum template_field_id t[])
{
int i;
u16 data, data_m;
for (int i = 0; i < N_FIXED_FIELDS; i++) {
u16 data, data_m;
for (i = 0; i < N_FIXED_FIELDS; i++) {
rtl931x_pie_data_fill(t[i], pr, &data, &data_m);
// On the RTL9300, the mask fields are not word aligned!
/* On the RTL9300, the mask fields are not word aligned! */
if (!(i % 2)) {
r[5 - i / 2] = data;
r[12 - i / 2] |= ((u32)data_m << 8);
@ -1126,7 +1118,7 @@ static void rtl931x_read_pie_fixed_fields(u32 r[], struct pie_rule *pr)
pr->mgnt_vlan = r[7] & BIT(31);
if (pr->phase == PHASE_IACL)
pr->dmac_hit_sw = r[7] & BIT(30);
else // TODO: EACL/VACL phase handling
else /* TODO: EACL/VACL phase handling */
pr->content_too_deep = r[7] & BIT(30);
pr->not_first_frag = r[7] & BIT(29);
pr->frame_type_l4 = (r[7] >> 26) & 7;
@ -1203,15 +1195,15 @@ static void rtl931x_write_pie_fixed_fields(u32 r[], struct pie_rule *pr)
static void rtl931x_write_pie_action(u32 r[], struct pie_rule *pr)
{
// Either drop or forward
/* Either drop or forward */
if (pr->drop) {
r[15] |= BIT(11) | BIT(12) | BIT(13); // Do Green, Yellow and Red drops
// Actually DROP, not PERMIT in Green / Yellow / Red
r[15] |= BIT(11) | BIT(12) | BIT(13); /* Do Green, Yellow and Red drops */
/* Actually DROP, not PERMIT in Green / Yellow / Red */
r[16] |= BIT(27) | BIT(28) | BIT(29);
} else {
r[15] |= pr->fwd_sel ? BIT(14) : 0;
r[16] |= pr->fwd_act << 24;
r[16] |= BIT(21); // We overwrite any drop
r[16] |= BIT(21); /* We overwrite any drop */
}
if (pr->phase == PHASE_VACL)
r[16] |= pr->fwd_sa_lrn ? BIT(22) : 0;
@ -1225,7 +1217,7 @@ static void rtl931x_write_pie_action(u32 r[], struct pie_rule *pr)
r[15] |= pr->log_sel ? BIT(26) : 0;
r[16] |= ((u32)(pr->fwd_data & 0xfff)) << 9;
// r[15] |= pr->log_octets ? BIT(31) : 0;
/* r[15] |= pr->log_octets ? BIT(31) : 0; */
r[15] |= (u32)(pr->meter_data) >> 2;
r[16] |= (((u32)(pr->meter_data) >> 7) & 0x3) << 29;
@ -1261,16 +1253,15 @@ void rtl931x_pie_rule_dump_raw(u32 r[])
static int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, struct pie_rule *pr)
{
// Access IACL table (0) via register 1, the table size is 4096
/* Access IACL table (0) via register 1, the table size is 4096 */
struct table_reg *q = rtl_table_get(RTL9310_TBL_1, 0);
u32 r[22];
int i;
int block = idx / PIE_BLOCK_SIZE;
u32 t_select = sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block));
pr_info("%s: %d, t_select: %08x\n", __func__, idx, t_select);
for (i = 0; i < 22; i++)
for (int i = 0; i < 22; i++)
r[i] = 0;
if (!pr->valid) {
@ -1287,7 +1278,7 @@ static int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, str
rtl931x_pie_rule_dump_raw(r);
for (i = 0; i < 22; i++)
for (int i = 0; i < 22; i++)
sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx);
@ -1298,11 +1289,8 @@ static int rtl931x_pie_rule_write(struct rtl838x_switch_priv *priv, int idx, str
static bool rtl931x_pie_templ_has(int t, enum template_field_id field_type)
{
int i;
enum template_field_id ft;
for (i = 0; i < N_FIXED_FIELDS_RTL931X; i++) {
ft = fixed_templates[t][i];
for (int i = 0; i < N_FIXED_FIELDS_RTL931X; i++) {
enum template_field_id ft = fixed_templates[t][i];
if (field_type == ft)
return true;
}
@ -1310,8 +1298,7 @@ static bool rtl931x_pie_templ_has(int t, enum template_field_id field_type)
return false;
}
/*
* Verify that the rule pr is compatible with a given template t in block block
/* Verify that the rule pr is compatible with a given template t in block block
* Note that this function is SoC specific since the values of e.g. TEMPLATE_FIELD_SIP0
* depend on the SoC
*/
@ -1327,13 +1314,17 @@ static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv,
return -1;
if (pr->is_ipv6) {
if ((pr->sip6_m.s6_addr32[0] || pr->sip6_m.s6_addr32[1]
|| pr->sip6_m.s6_addr32[2] || pr->sip6_m.s6_addr32[3])
&& !rtl931x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
if ((pr->sip6_m.s6_addr32[0] ||
pr->sip6_m.s6_addr32[1] ||
pr->sip6_m.s6_addr32[2] ||
pr->sip6_m.s6_addr32[3]) &&
!rtl931x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
return -1;
if ((pr->dip6_m.s6_addr32[0] || pr->dip6_m.s6_addr32[1]
|| pr->dip6_m.s6_addr32[2] || pr->dip6_m.s6_addr32[3])
&& !rtl931x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
if ((pr->dip6_m.s6_addr32[0] ||
pr->dip6_m.s6_addr32[1] ||
pr->dip6_m.s6_addr32[2] ||
pr->dip6_m.s6_addr32[3]) &&
!rtl931x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
return -1;
}
@ -1343,7 +1334,7 @@ static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv,
if (ether_addr_to_u64(pr->dmac) && !rtl931x_pie_templ_has(t, TEMPLATE_FIELD_DMAC0))
return -1;
// TODO: Check more
/* TODO: Check more */
i = find_first_zero_bit(&priv->pie_use_bm[block * 4], PIE_BLOCK_SIZE);
@ -1355,7 +1346,7 @@ static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv,
static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rule *pr)
{
int idx, block, j, t;
int idx, block, j;
int min_block = 0;
int max_block = priv->n_pie_blocks / 2;
@ -1369,7 +1360,7 @@ static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
for (block = min_block; block < max_block; block++) {
for (j = 0; j < 2; j++) {
t = (sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf;
int t = (sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)) >> (j * 4)) & 0xf;
pr_info("Testing block %d, template %d, template id %d\n", block, j, t);
pr_info("%s: %08x\n",
__func__, sw_r32(RTL931X_PIE_BLK_TMPLTE_CTRL(block)));
@ -1390,7 +1381,7 @@ static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
set_bit(idx, priv->pie_use_bm);
pr->valid = true;
pr->tid = j; // Mapped to template number
pr->tid = j; /* Mapped to template number */
pr->tid_m = 0x1;
pr->id = idx;
@ -1398,12 +1389,11 @@ static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
rtl931x_pie_rule_write(priv, idx, pr);
mutex_unlock(&priv->pie_mutex);
return 0;
}
/*
* Delete a range of Packet Inspection Engine rules
*/
/* Delete a range of Packet Inspection Engine rules */
static int rtl931x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to)
{
u32 v = (index_from << 1)| (index_to << 13 ) | BIT(0);
@ -1411,14 +1401,15 @@ static int rtl931x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from
pr_info("%s: from %d to %d\n", __func__, index_from, index_to);
mutex_lock(&priv->reg_mutex);
// Write from-to and execute bit into control register
/* Write from-to and execute bit into control register */
sw_w32(v, RTL931X_PIE_CLR_CTRL);
// Wait until command has completed
/* Wait until command has completed */
do {
} while (sw_r32(RTL931X_PIE_CLR_CTRL) & BIT(0));
mutex_unlock(&priv->reg_mutex);
return 0;
}
@ -1432,28 +1423,27 @@ static void rtl931x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rul
static void rtl931x_pie_init(struct rtl838x_switch_priv *priv)
{
int i;
u32 template_selectors;
mutex_init(&priv->pie_mutex);
pr_info("%s\n", __func__);
// Enable ACL lookup on all ports, including CPU_PORT
for (i = 0; i <= priv->cpu_port; i++)
/* Enable ACL lookup on all ports, including CPU_PORT */
for (int i = 0; i <= priv->cpu_port; i++)
sw_w32(1, RTL931X_ACL_PORT_LOOKUP_CTRL(i));
// Include IPG in metering
/* Include IPG in metering */
sw_w32_mask(0, 1, RTL931X_METER_GLB_CTRL);
// Delete all present rules, block size is 128 on all SoC families
/* Delete all present rules, block size is 128 on all SoC families */
rtl931x_pie_rule_del(priv, 0, priv->n_pie_blocks * 128 - 1);
// Assign first half blocks 0-7 to VACL phase, second half to IACL
// 3 bits are used for each block, values for PIE blocks are
// 6: Disabled, 0: VACL, 1: IACL, 2: EACL
// And for OpenFlow Flow blocks: 3: Ingress Flow table 0,
// 4: Ingress Flow Table 3, 5: Egress flow table 0
for (i = 0; i < priv->n_pie_blocks; i++) {
/* Assign first half blocks 0-7 to VACL phase, second half to IACL */
/* 3 bits are used for each block, values for PIE blocks are */
/* 6: Disabled, 0: VACL, 1: IACL, 2: EACL */
/* And for OpenFlow Flow blocks: 3: Ingress Flow table 0, */
/* 4: Ingress Flow Table 3, 5: Egress flow table 0 */
for (int i = 0; i < priv->n_pie_blocks; i++) {
int pos = (i % 10) * 3;
u32 r = RTL931X_PIE_BLK_PHASE_CTRL + 4 * (i / 10);
@ -1463,24 +1453,24 @@ static void rtl931x_pie_init(struct rtl838x_switch_priv *priv)
sw_w32_mask(0x7 << pos, 1 << pos, r);
}
// Enable predefined templates 0, 1 for first quarter of all blocks
/* Enable predefined templates 0, 1 for first quarter of all blocks */
template_selectors = 0 | (1 << 4);
for (i = 0; i < priv->n_pie_blocks / 4; i++)
for (int i = 0; i < priv->n_pie_blocks / 4; i++)
sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i));
// Enable predefined templates 2, 3 for second quarter of all blocks
/* Enable predefined templates 2, 3 for second quarter of all blocks */
template_selectors = 2 | (3 << 4);
for (i = priv->n_pie_blocks / 4; i < priv->n_pie_blocks / 2; i++)
for (int i = priv->n_pie_blocks / 4; i < priv->n_pie_blocks / 2; i++)
sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i));
// Enable predefined templates 0, 1 for third quater of all blocks
/* Enable predefined templates 0, 1 for third quater of all blocks */
template_selectors = 0 | (1 << 4);
for (i = priv->n_pie_blocks / 2; i < priv->n_pie_blocks * 3 / 4; i++)
for (int i = priv->n_pie_blocks / 2; i < priv->n_pie_blocks * 3 / 4; i++)
sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i));
// Enable predefined templates 2, 3 for fourth quater of all blocks
/* Enable predefined templates 2, 3 for fourth quater of all blocks */
template_selectors = 2 | (3 << 4);
for (i = priv->n_pie_blocks * 3 / 4; i < priv->n_pie_blocks; i++)
for (int i = priv->n_pie_blocks * 3 / 4; i < priv->n_pie_blocks; i++)
sw_w32(template_selectors, RTL931X_PIE_BLK_TMPLTE_CTRL(i));
}
@ -1533,7 +1523,7 @@ void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
u32 newmask = 0;
/* TODO: for now we set algoidx to 0 */
algoidx=0;
algoidx = 0;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) {
l3shift = 4;
@ -1569,12 +1559,7 @@ void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
{
int i, pos;
u32 v, set;
u64 pm_copper = 0, pm_fiber = 0;
u32 setlen;
const __be32 *led_set;
char set_name[9];
struct device_node *node;
pr_info("%s called\n", __func__);
@ -1584,15 +1569,18 @@ static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
return;
}
for (i= 0; i < priv->cpu_port; i++) {
pos = (i << 1) % 32;
for (int i = 0; i < priv->cpu_port; i++) {
int pos = (i << 1) % 32;
u32 set;
u32 v;
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
if (!priv->ports[i].phy)
continue;
v = 0x1; // Found on the EdgeCore, but we do not have any HW description
v = 0x1; /* Found on the EdgeCore, but we do not have any HW description */
sw_w32_mask(0x3 << pos, v << pos, RTL931X_LED_PORT_NUM_CTRL(i));
if (priv->ports[i].phy_is_integrated)
@ -1605,7 +1593,12 @@ static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
sw_w32_mask(0, set << pos, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
}
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
const __be32 *led_set;
char set_name[9];
u32 setlen;
u32 v;
sprintf(set_name, "led_set%d", i);
pr_info(">%s<\n", set_name);
led_set = of_get_property(node, set_name, &setlen);
@ -1617,16 +1610,15 @@ static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
sw_w32(v, RTL931X_LED_SET0_0_CTRL - i * 8);
}
// Set LED mode to serial (0x1)
/* Set LED mode to serial (0x1) */
sw_w32_mask(0x3, 0x1, RTL931X_LED_GLB_CTRL);
rtl839x_set_port_reg_le(pm_copper, RTL931X_LED_PORT_COPR_MASK_CTRL);
rtl839x_set_port_reg_le(pm_fiber, RTL931X_LED_PORT_FIB_MASK_CTRL);
rtl839x_set_port_reg_le(pm_copper | pm_fiber, RTL931X_LED_PORT_COMBO_MASK_CTRL);
for (i = 0; i < 32; i++)
for (int i = 0; i < 32; i++)
pr_info("%s %08x: %08x\n",__func__, 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4));
}
const struct rtl838x_reg rtl931x_reg = {
@ -1638,7 +1630,7 @@ const struct rtl838x_reg rtl931x_reg = {
.get_port_reg_le = rtl839x_get_port_reg_le,
.stat_port_rst = RTL931X_STAT_PORT_RST,
.stat_rst = RTL931X_STAT_RST,
.stat_port_std_mib = 0, // Not defined
.stat_port_std_mib = 0, /* Not defined */
.traffic_enable = rtl931x_traffic_enable,
.traffic_disable = rtl931x_traffic_disable,
.traffic_get = rtl931x_traffic_get,
@ -1647,7 +1639,7 @@ const struct rtl838x_reg rtl931x_reg = {
.l2_ctrl_1 = RTL931X_L2_AGE_CTRL,
.l2_port_aging_out = RTL931X_L2_PORT_AGE_CTRL,
.set_ageing_time = rtl931x_set_ageing_time,
// .smi_poll_ctrl does not exist
/* .smi_poll_ctrl does not exist */
.l2_tbl_flush_ctrl = RTL931X_L2_TBL_FLUSH_CTRL,
.exec_tbl0_cmd = rtl931x_exec_tbl0_cmd,
.exec_tbl1_cmd = rtl931x_exec_tbl1_cmd,
@ -1655,7 +1647,7 @@ const struct rtl838x_reg rtl931x_reg = {
.isr_glb_src = RTL931X_ISR_GLB_SRC,
.isr_port_link_sts_chg = RTL931X_ISR_PORT_LINK_STS_CHG,
.imr_port_link_sts_chg = RTL931X_IMR_PORT_LINK_STS_CHG,
// imr_glb does not exist on RTL931X
/* imr_glb does not exist on RTL931X */
.vlan_tables_read = rtl931x_vlan_tables_read,
.vlan_set_tagged = rtl931x_vlan_set_tagged,
.vlan_set_untagged = rtl931x_vlan_set_untagged,
@ -1698,4 +1690,3 @@ const struct rtl838x_reg rtl931x_reg = {
.l3_setup = rtl931x_l3_setup,
.led_init = rtl931x_led_init,
};

View File

@ -5,14 +5,12 @@
#include <linux/netdevice.h>
#include <net/flow_offload.h>
#include <linux/rhashtable.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
#include "rtl838x.h"
/*
* Parse the flow rule for the matching conditions
*/
/* Parse the flow rule for the matching conditions */
static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
struct flow_rule *rule, struct rtl83xx_flow *flow)
{
@ -44,8 +42,7 @@ static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
flow->rule.frame_type_l4 = 0;
if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 1;
if (match.key->ip_proto == IPPROTO_ICMP
|| match.key->ip_proto ==IPPROTO_ICMPV6)
if (match.key->ip_proto == IPPROTO_ICMP || match.key->ip_proto == IPPROTO_ICMPV6)
flow->rule.frame_type_l4 = 2;
if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 3;
@ -72,7 +69,7 @@ static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
flow_rule_match_vlan(rule, &match);
flow->rule.itag = match.key->vlan_id;
flow->rule.itag_m = match.mask->vlan_id;
// TODO: What about match.key->vlan_priority ?
/* TODO: What about match.key->vlan_priority? */
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
@ -108,7 +105,7 @@ static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
flow->rule.sport_m = match.mask->src;
}
// TODO: ICMP
/* TODO: ICMP */
return 0;
}
@ -150,7 +147,7 @@ static int rtl83xx_add_flow(struct rtl838x_switch_priv *priv, struct flow_cls_of
pr_debug("%s\n", __func__);
rtl83xx_parse_flow_rule(priv, rule, flow);
flow_action_for_each(i, act, &rule->action) {
switch (act->id) {
case FLOW_ACTION_DROP:
@ -176,7 +173,7 @@ static int rtl83xx_add_flow(struct rtl838x_switch_priv *priv, struct flow_cls_of
case FLOW_ACTION_VLAN_PUSH:
pr_debug("%s: VLAN_PUSH\n", __func__);
// TODO: act->vlan.proto
/* TODO: act->vlan.proto */
flow->rule.ivid_act = PIE_ACT_VID_ASSIGN;
flow->rule.ivid_sel = true;
flow->rule.ivid_data = htons(act->vlan.vid);
@ -271,9 +268,9 @@ rcu_unlock:
goto out_free;
}
rtl83xx_add_flow(priv, f, flow); // TODO: check error
rtl83xx_add_flow(priv, f, flow); /* TODO: check error */
// Add log action to flow
/* Add log action to flow */
flow->rule.packet_cntr = rtl83xx_packet_cntr_alloc(priv);
if (flow->rule.packet_cntr >= 0) {
pr_debug("Using packet counter %d\n", flow->rule.packet_cntr);
@ -288,6 +285,7 @@ out_free:
kfree(flow);
out:
pr_err("%s: error %d\n", __func__, err);
return err;
}
@ -311,6 +309,7 @@ static int rtl83xx_delete_flower(struct rtl838x_switch_priv *priv,
kfree_rcu(flow, rcu_head);
rcu_read_unlock();
return 0;
}
@ -333,9 +332,10 @@ static int rtl83xx_stats_flower(struct rtl838x_switch_priv *priv,
flow->rule.last_packet_cnt = total_packets;
}
// TODO: We need a second PIE rule to count the bytes
/* TODO: We need a second PIE rule to count the bytes */
flow_stats_update(&cls_flower->stats, 100 * new_packets, new_packets, 0, lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0;
}

View File

@ -3,9 +3,7 @@
#ifndef _RTL838X_ETH_H
#define _RTL838X_ETH_H
/*
* Register definition
*/
/* Register definition */
/* Per port MAC control */
#define RTL838X_MAC_PORT_CTRL (0xd560)
@ -118,7 +116,7 @@
#define RTL930X_MAC_LINK_DUP_STS (0xCB28)
#define RTL931X_MAC_LINK_DUP_STS (0x0ef0)
// TODO: RTL8390_MAC_LINK_MEDIA_STS_ADDR ???
/* TODO: RTL8390_MAC_LINK_MEDIA_STS_ADDR??? */
#define RTL838X_MAC_TX_PAUSE_STS (0xa1a0)
#define RTL839X_MAC_TX_PAUSE_STS (0x03b8)

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ struct __attribute__ ((__packed__)) fw_header {
struct part parts[10];
};
// TODO: fixed path?
/* TODO: fixed path? */
#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw"
#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw"
#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw"
@ -35,7 +35,7 @@ struct __attribute__ ((__packed__)) fw_header {
#define PHY_ID_RTL8393_I 0x001c8393
#define PHY_ID_RTL9300_I 0x70d03106
// PHY MMD devices
/* PHY MMD devices */
#define MMD_AN 7
#define MMD_VEND2 31
@ -60,7 +60,7 @@ struct __attribute__ ((__packed__)) fw_header {
#define RTL930X_SDS_INDACS_DATA (0x03B4)
#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C)
/*Registers of the internal SerDes of the 9310 */
/* Registers of the internal SerDes of the 9310 */
#define RTL931X_SERDES_INDRT_ACCESS_CTRL (0x5638)
#define RTL931X_SERDES_INDRT_DATA_CTRL (0x563C)
#define RTL931X_SERDES_MODE_CTRL (0x13cc)

View File

@ -6,9 +6,15 @@ include $(INCLUDE_DIR)/image.mk
KERNEL_LOADADDR = 0x80000000
KERNEL_ENTRY = 0x80000400
DEVICE_VARS += ZYXEL_VERS DLINK_KERNEL_PART_SIZE
DEVICE_VARS += CAMEO_KERNEL_PART CAMEO_ROOTFS_PART CAMEO_CUSTOMER_SIGNATURE CAMEO_BOARD_VERSION
DEVICE_VARS += H3C_PRODUCT_ID H3C_DEVICE_ID
DEVICE_VARS += \
CAMEO_BOARD_VERSION \
CAMEO_CUSTOMER_SIGNATURE \
CAMEO_KERNEL_PART \
CAMEO_ROOTFS_PART \
DLINK_KERNEL_PART_SIZE \
H3C_DEVICE_ID \
H3C_PRODUCT_ID \
ZYXEL_VERS
define Build/zyxel-vers
( echo VERS;\
@ -81,13 +87,26 @@ endef
define Device/Default
PROFILES = Default
KERNEL := kernel-bin | append-dtb | gzip | uImage gzip
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | uImage gzip
KERNEL := \
kernel-bin | \
append-dtb | \
gzip | \
uImage gzip
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
gzip | \
uImage gzip
DEVICE_DTS_DIR := ../dts-$(KERNEL_PATCHVER)
DEVICE_DTS = $$(SOC)_$(1)
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | pad-to 64k | append-rootfs | pad-rootfs | \
check-size | append-metadata
IMAGE/sysupgrade.bin := \
append-kernel | \
pad-to 64k | \
append-rootfs | \
pad-rootfs | \
check-size | \
append-metadata
endef
include $(SUBTARGET).mk

View File

@ -4,15 +4,26 @@ define Device/d-link_dgs-1210
IMAGE_SIZE := 13824k
DEVICE_VENDOR := D-Link
DLINK_KERNEL_PART_SIZE := 1572864
KERNEL := kernel-bin | append-dtb | gzip | uImage gzip | dlink-cameo
KERNEL := \
kernel-bin | \
append-dtb | \
gzip | \
uImage gzip | \
dlink-cameo
CAMEO_KERNEL_PART := 2
CAMEO_ROOTFS_PART := 3
CAMEO_CUSTOMER_SIGNATURE := 2
CAMEO_BOARD_VERSION := 32
IMAGES += factory_image1.bin
IMAGE/factory_image1.bin := append-kernel | pad-to 64k | \
append-rootfs | pad-rootfs | pad-to 16 | check-size | \
dlink-version | dlink-headers
IMAGE/factory_image1.bin := \
append-kernel | \
pad-to 64k | \
append-rootfs | \
pad-rootfs | \
pad-to 16 | \
check-size | \
dlink-version | \
dlink-headers
endef
define Device/hpe_1920
@ -20,8 +31,36 @@ define Device/hpe_1920
IMAGE_SIZE := 29632k
BLOCKSIZE := 64k
H3C_PRODUCT_ID := 0x3c010501
KERNEL := kernel-bin | append-dtb | relocate-kernel | 7z | h3c-image | h3c-vfs
KERNEL_INITRAMFS := kernel-bin | append-dtb | relocate-kernel | 7z | h3c-image
IMAGE/sysupgrade.bin := append-kernel | pad-to $$$$(BLOCKSIZE) | append-rootfs | \
pad-rootfs | check-size | append-metadata
KERNEL := \
kernel-bin | \
append-dtb | \
relocate-kernel | \
7z | \
h3c-image | \
h3c-vfs
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
relocate-kernel | \
7z | \
h3c-image
IMAGE/sysupgrade.bin := \
append-kernel | \
pad-to $$$$(BLOCKSIZE) | \
append-rootfs | \
pad-rootfs | \
check-size | \
append-metadata
endef
define Device/zyxel_gs1900
DEVICE_VENDOR := ZyXEL
IMAGE_SIZE := 6976k
UIMAGE_MAGIC := 0x83800000
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
gzip | \
zyxel-vers | \
uImage gzip
endef

View File

@ -67,7 +67,10 @@ define Device/engenius_ews2910p
DEVICE_VENDOR := EnGenius
DEVICE_MODEL := EWP2910P
UIMAGE_MAGIC := 0x03802910
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | \
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
gzip | \
uImage gzip -n 'IMG-0.00.00-c0.0.00'
endef
TARGET_DEVICES += engenius_ews2910p
@ -116,8 +119,16 @@ TARGET_DEVICES += iodata_bsh-g24mb
# "NGE" refers to the uImage magic
define Device/netgear_nge
KERNEL := kernel-bin | append-dtb | lzma | uImage lzma
KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | uImage lzma
KERNEL := \
kernel-bin | \
append-dtb | \
lzma | \
uImage lzma
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
lzma | \
uImage lzma
SOC := rtl8380
IMAGE_SIZE := 14848k
UIMAGE_MAGIC := 0x4e474520
@ -207,17 +218,9 @@ define Device/tplink_sg2210p-v3
endef
TARGET_DEVICES += tplink_sg2210p-v3
define Device/zyxel_gs1900
SOC := rtl8380
IMAGE_SIZE := 6976k
DEVICE_VENDOR := ZyXEL
UIMAGE_MAGIC := 0x83800000
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers | \
uImage gzip
endef
define Device/zyxel_gs1900-10hp
$(Device/zyxel_gs1900)
SOC := rtl8380
DEVICE_MODEL := GS1900-10HP
ZYXEL_VERS := AAZI
endef
@ -233,6 +236,7 @@ TARGET_DEVICES += zyxel_gs1900-16
define Device/zyxel_gs1900-8
$(Device/zyxel_gs1900)
SOC := rtl8380
DEVICE_MODEL := GS1900-8
ZYXEL_VERS := AAHH
endef
@ -240,6 +244,7 @@ TARGET_DEVICES += zyxel_gs1900-8
define Device/zyxel_gs1900-8hp-v1
$(Device/zyxel_gs1900)
SOC := rtl8380
DEVICE_MODEL := GS1900-8HP
DEVICE_VARIANT := v1
ZYXEL_VERS := AAHI
@ -249,6 +254,7 @@ TARGET_DEVICES += zyxel_gs1900-8hp-v1
define Device/zyxel_gs1900-8hp-v2
$(Device/zyxel_gs1900)
SOC := rtl8380
DEVICE_MODEL := GS1900-8HP
DEVICE_VARIANT := v2
ZYXEL_VERS := AAHI

View File

@ -15,7 +15,10 @@ define Device/panasonic_m48eg-pn28480k
DEVICE_VENDOR := Panasonic
DEVICE_MODEL := Switch-M48eG
DEVICE_VARIANT := PN28480K
DEVICE_PACKAGES := kmod-hwmon-gpiofan kmod-hwmon-lm75 kmod-i2c-mux-pca954x \
DEVICE_PACKAGES := \
kmod-hwmon-gpiofan \
kmod-hwmon-lm75 \
kmod-i2c-mux-pca954x \
kmod-thermal
endef
TARGET_DEVICES += panasonic_m48eg-pn28480k
@ -27,18 +30,16 @@ define Device/tplink_sg2452p-v4
DEVICE_VENDOR := TP-Link
DEVICE_MODEL := SG2452P
DEVICE_VARIANT := v4
DEVICE_PACKAGES := kmod-hwmon-gpiofan kmod-hwmon-tps23861
DEVICE_PACKAGES := \
kmod-hwmon-gpiofan \
kmod-hwmon-tps23861
endef
TARGET_DEVICES += tplink_sg2452p-v4
define Device/zyxel_gs1900-48
$(Device/zyxel_gs1900)
SOC := rtl8393
IMAGE_SIZE := 13952k
DEVICE_VENDOR := ZyXEL
UIMAGE_MAGIC := 0x83800000
ZYXEL_VERS := AAHO
DEVICE_MODEL := GS1900-48
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers $$$$(ZYXEL_VERS) | \
uImage gzip
ZYXEL_VERS := AAHN
endef
TARGET_DEVICES += zyxel_gs1900-48

View File

@ -6,9 +6,12 @@ define Device/zyxel_xgs1250-12
ZYXEL_VERS := ABWE
DEVICE_VENDOR := Zyxel
DEVICE_MODEL := XGS1250-12
IMAGE_SIZE := 13312k
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers $$$$(ZYXEL_VERS) | \
IMAGE_SIZE := 13312k
KERNEL_INITRAMFS := \
kernel-bin | \
append-dtb | \
gzip | \
zyxel-vers $$$$(ZYXEL_VERS) | \
uImage gzip
endef
TARGET_DEVICES += zyxel_xgs1250-12

View File

@ -12,4 +12,3 @@ define Target/Description
endef
FEATURES := $(filter-out mips16,$(FEATURES))

View File

@ -10,4 +10,3 @@ KERNEL_PATCHVER:=5.10
define Target/Description
Build firmware images for Realtek RTL839x based boards.
endef

View File

@ -10,4 +10,3 @@ KERNEL_PATCHVER:=5.10
define Target/Description
Build firmware images for Realtek RTL930x based boards.
endef