realtek: Whitespace and codestyle cleanup

Fix some ugly whitepsaces and codestyle issues around the realtek sources.

While this is by no means perfect, it catches what it caught.

Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
This commit is contained in:
Olliver Schinagl 2022-08-30 21:25:25 +02:00 committed by Sander Vanheule
parent 2c40359c5c
commit 758c88b969
25 changed files with 767 additions and 810 deletions

View file

@ -350,9 +350,7 @@
#define RTL931X_MAC_L2_GLOBAL_CTRL2 (0x1358) #define RTL931X_MAC_L2_GLOBAL_CTRL2 (0x1358)
#define RTL931X_MAC_L2_GLOBAL_CTRL1 (0x5548) #define RTL931X_MAC_L2_GLOBAL_CTRL1 (0x5548)
/* /* Switch interrupts */
* Switch interrupts
*/
#define RTL838X_IMR_GLB (0x1100) #define RTL838X_IMR_GLB (0x1100)
#define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104) #define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104)
#define RTL838X_ISR_GLB_SRC (0x1148) #define RTL838X_ISR_GLB_SRC (0x1148)

View file

@ -59,6 +59,7 @@ static irqreturn_t rtl9300_timer_interrupt(int irq, void *dev_id)
writel(v, rtl_clk->base + RTL9300_TC_INT); writel(v, rtl_clk->base + RTL9300_TC_INT);
clk->event_handler(clk); clk->event_handler(clk);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -101,6 +102,7 @@ static int rtl9300_state_periodic(struct clock_event_device *clk)
rtl9300_clock_stop(base); rtl9300_clock_stop(base);
writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA); writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
rtl9300_timer_start(base, TIMER_MODE_REPEAT); rtl9300_timer_start(base, TIMER_MODE_REPEAT);
return 0; return 0;
} }
@ -112,6 +114,7 @@ static int rtl9300_state_oneshot(struct clock_event_device *clk)
rtl9300_clock_stop(base); rtl9300_clock_stop(base);
writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA); writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
rtl9300_timer_start(base, TIMER_MODE_ONCE); rtl9300_timer_start(base, TIMER_MODE_ONCE);
return 0; return 0;
} }
@ -121,6 +124,7 @@ static int rtl9300_shutdown(struct clock_event_device *clk)
pr_debug("------------- rtl9300_shutdown %08x\n", (u32)base); pr_debug("------------- rtl9300_shutdown %08x\n", (u32)base);
rtl9300_clock_stop(base); rtl9300_clock_stop(base);
return 0; return 0;
} }

View file

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

View file

@ -139,4 +139,3 @@ wait_pllclock:
.globl rtcl_839x_dram_size .globl rtcl_839x_dram_size
rtcl_839x_dram_size: rtcl_839x_dram_size:
.word .-rtcl_839x_dram_start .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) ({ \ #define RTCL_SRAM_FUNC(SOC, PBASE, FN) ({ \
rtcl_##SOC##_sram_##FN = ((void *)&rtcl_##SOC##_dram_##FN \ rtcl_##SOC##_sram_##FN = ((void *)&rtcl_##SOC##_dram_##FN - \
- (void *)&rtcl_##SOC##_dram_start) \ (void *)&rtcl_##SOC##_dram_start) + \
+ (void *)PBASE; }) (void *)PBASE; })
static const struct clk_ops rtcl_clk_ops = { static const struct clk_ops rtcl_clk_ops = {
.set_rate = rtcl_set_rate, .set_rate = rtcl_set_rate,

View file

@ -127,6 +127,7 @@ static int rtl8231_pin_dir(struct rtl8231_gpios *gpios, u32 gpio, u32 dir)
rtl8231_write(gpios, pin_dir_addr, v); rtl8231_write(gpios, pin_dir_addr, v);
gpios->reg_shadow[pin_dir_addr] = v; gpios->reg_shadow[pin_dir_addr] = v;
gpios->reg_cached |= 1 << pin_dir_addr; gpios->reg_cached |= 1 << pin_dir_addr;
return 0; return 0;
} }
@ -150,6 +151,7 @@ static int rtl8231_pin_dir_get(struct rtl8231_gpios *gpios, u32 gpio, u32 *dir)
*dir = 1; *dir = 1;
else else
*dir = 0; *dir = 0;
return 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); rtl8231_write(gpios, RTL8231_GPIO_DATA(gpio), v);
gpios->reg_shadow[RTL8231_GPIO_DATA(gpio)] = v; gpios->reg_shadow[RTL8231_GPIO_DATA(gpio)] = v;
gpios->reg_cached |= 1 << RTL8231_GPIO_DATA(gpio); gpios->reg_cached |= 1 << RTL8231_GPIO_DATA(gpio);
return 0; return 0;
} }
@ -179,6 +182,7 @@ static int rtl8231_pin_get(struct rtl8231_gpios *gpios, u32 gpio, u16 *state)
} }
*state = v & 0xffff; *state = v & 0xffff;
return 0; return 0;
} }
@ -191,6 +195,7 @@ static int rtl8231_direction_input(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock); mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 1); err = rtl8231_pin_dir(gpios, offset, 1);
mutex_unlock(&miim_lock); mutex_unlock(&miim_lock);
return err; return err;
} }
@ -203,8 +208,10 @@ static int rtl8231_direction_output(struct gpio_chip *gc, unsigned int offset, i
mutex_lock(&miim_lock); mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 0); err = rtl8231_pin_dir(gpios, offset, 0);
mutex_unlock(&miim_lock); mutex_unlock(&miim_lock);
if (!err) if (!err)
err = rtl8231_pin_set(gpios, offset, value); err = rtl8231_pin_set(gpios, offset, value);
return err; return err;
} }
@ -217,6 +224,7 @@ static int rtl8231_get_direction(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock); mutex_lock(&miim_lock);
rtl8231_pin_dir_get(gpios, offset, &v); rtl8231_pin_dir_get(gpios, offset, &v);
mutex_unlock(&miim_lock); mutex_unlock(&miim_lock);
return v; return v;
} }
@ -228,8 +236,10 @@ static int rtl8231_gpio_get(struct gpio_chip *gc, unsigned int offset)
mutex_lock(&miim_lock); mutex_lock(&miim_lock);
rtl8231_pin_get(gpios, offset, &state); rtl8231_pin_get(gpios, offset, &state);
mutex_unlock(&miim_lock); mutex_unlock(&miim_lock);
if (state & (1 << (offset % 16))) if (state & (1 << (offset % 16)))
return 1; return 1;
return 0; return 0;
} }
@ -337,8 +347,7 @@ static int rtl8231_gpio_probe(struct platform_device *pdev)
gpios->gc.get = rtl8231_gpio_get; gpios->gc.get = rtl8231_gpio_get;
gpios->gc.get_direction = rtl8231_get_direction; gpios->gc.get_direction = rtl8231_get_direction;
err = devm_gpiochip_add_data(dev, &gpios->gc, gpios); return devm_gpiochip_add_data(dev, &gpios->gc, gpios);
return err;
} }
static struct platform_driver rtl8231_gpio_driver = { static struct platform_driver rtl8231_gpio_driver = {

View file

@ -123,8 +123,8 @@ static struct device_node *mux_parent_adapter(struct device *dev, struct rtl9300
if (!parent) if (!parent)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
if (!(of_device_is_compatible(parent_np, "realtek,rtl9300-i2c") if (!(of_device_is_compatible(parent_np, "realtek,rtl9300-i2c") ||
|| of_device_is_compatible(parent_np, "realtek,rtl9310-i2c"))){ of_device_is_compatible(parent_np, "realtek,rtl9310-i2c"))){
dev_err(dev, "I2C parent not an RTL9300 I2C controller\n"); dev_err(dev, "I2C parent not an RTL9300 I2C controller\n");
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }

View file

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

View file

@ -9,8 +9,8 @@
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/rhashtable.h> #include <linux/rhashtable.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
extern struct rtl83xx_soc_info soc_info; extern struct rtl83xx_soc_info soc_info;
@ -90,8 +90,7 @@ void rtl_table_init(void)
mutex_init(&rtl838x_tbl_regs[i].lock); 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 * Returns a handle to a lock for that table
*/ */
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t) struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
@ -108,9 +107,7 @@ struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t)
return &rtl838x_tbl_regs[r]; 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) void rtl_table_release(struct table_reg *r)
{ {
if (!r) if (!r)
@ -146,24 +143,19 @@ static int rtl_table_exec(struct table_reg *r, bool is_write, int idx)
return ret; return ret;
} }
/* /* Reads table index idx into the data registers of the table */
* Reads table index idx into the data registers of the table
*/
int rtl_table_read(struct table_reg *r, int idx) int rtl_table_read(struct table_reg *r, int idx)
{ {
return rtl_table_exec(r, false, idx); return rtl_table_exec(r, false, idx);
} }
/* /* Writes the content of the table data registers into the table at index idx */
* Writes the content of the table data registers into the table at index idx
*/
int rtl_table_write(struct table_reg *r, int idx) int rtl_table_write(struct table_reg *r, int idx)
{ {
return rtl_table_exec(r, true, idx); return rtl_table_exec(r, true, idx);
} }
/* /* Returns the address of the ith data register of table register r
* 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 * 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) inline u16 rtl_table_data(struct table_reg *r, int i)
@ -196,7 +188,7 @@ void rtl838x_set_port_reg(u64 set, int reg)
u64 rtl838x_get_port_reg(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 */ /* Port register accessor functions for the RTL839x and RTL931X SoCs */
@ -212,6 +204,7 @@ u64 rtl839x_get_port_reg_be(int reg)
v <<= 32; v <<= 32;
v |= sw_r32(reg + 4); v |= sw_r32(reg + 4);
return v; return v;
} }
@ -239,6 +232,7 @@ u64 rtl839x_get_port_reg_le(int reg)
v <<= 32; v <<= 32;
v |= sw_r32(reg); v |= sw_r32(reg);
return v; return v;
} }
@ -254,6 +248,7 @@ int read_phy(u32 port, u32 page, u32 reg, u32 *val)
case RTL9310_FAMILY_ID: case RTL9310_FAMILY_ID:
return rtl931x_read_phy(port, page, reg, val); return rtl931x_read_phy(port, page, reg, val);
} }
return -1; return -1;
} }
@ -269,6 +264,7 @@ int write_phy(u32 port, u32 page, u32 reg, u32 val)
case RTL9310_FAMILY_ID: case RTL9310_FAMILY_ID:
return rtl931x_write_phy(port, page, reg, val); return rtl931x_write_phy(port, page, reg, val);
} }
return -1; return -1;
} }
@ -303,8 +299,7 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
bus->name = "rtl838x slave mii"; 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. * assigned there.
*/ */
bus->read = priv->mii_bus->read; bus->read = priv->mii_bus->read;
@ -379,21 +374,21 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
priv->ports[pn].phy = PHY_RTL930X_SDS; priv->ports[pn].phy = PHY_RTL930X_SDS;
} }
} else { } else {
if (of_property_read_bool(phy_node, "phy-is-integrated") if (of_property_read_bool(phy_node, "phy-is-integrated") &&
&& !of_property_read_bool(phy_node, "sfp")) { !of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8218B_INT; priv->ports[pn].phy = PHY_RTL8218B_INT;
continue; continue;
} }
} }
if (!of_property_read_bool(phy_node, "phy-is-integrated") if (!of_property_read_bool(phy_node, "phy-is-integrated") &&
&& of_property_read_bool(phy_node, "sfp")) { of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8214FC; priv->ports[pn].phy = PHY_RTL8214FC;
continue; continue;
} }
if (!of_property_read_bool(phy_node, "phy-is-integrated") if (!of_property_read_bool(phy_node, "phy-is-integrated") &&
&& !of_property_read_bool(phy_node, "sfp")) { !of_property_read_bool(phy_node, "sfp")) {
priv->ports[pn].phy = PHY_RTL8218B_EXT; priv->ports[pn].phy = PHY_RTL8218B_EXT;
continue; continue;
} }
@ -419,6 +414,7 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
} }
pr_debug("%s done\n", __func__); pr_debug("%s done\n", __func__);
return 0; return 0;
} }
@ -435,6 +431,7 @@ static int __init rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv)
pr_debug("L2 AGING time: %d sec\n", t); 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)); pr_debug("Dynamic aging for ports: %x\n", sw_r32(priv->r->l2_port_aging_out));
return t; return t;
} }
@ -469,6 +466,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); pr_err("%s: Port %d already member of LAG %d.\n", __func__, port, i);
return -ENOSPC; return -ENOSPC;
} }
switch(info->hash_type) { switch(info->hash_type) {
case NETDEV_LAG_HASH_L2: case NETDEV_LAG_HASH_L2:
algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT; algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
@ -497,6 +495,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", pr_info("%s: Added port %d to LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]); __func__, port, group, priv->lags_port_members[group]);
return 0; return 0;
} }
@ -526,12 +525,11 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n", pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]); __func__, port, group, priv->lags_port_members[group]);
return 0; 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) static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
{ {
int idx; int idx;
@ -550,8 +548,7 @@ static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
return idx; 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 * 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 * Initially there are no free packet counters and 2 new ones need to be freed
* by allocating the corresponding octet counter * by allocating the corresponding octet counter
@ -585,8 +582,7 @@ int rtl83xx_packet_cntr_alloc(struct rtl838x_switch_priv *priv)
return idx; 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 * 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 * or mark an existing entry as a nexthop by setting it's nexthop bit
* Called from the L3 layer * Called from the L3 layer
@ -655,8 +651,7 @@ int rtl83xx_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl83xx_next
return 0; 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 * If it was static, the entire entry is removed, otherwise the nexthop bit is cleared
* and we wait until the entry ages out * and we wait until the entry ages out
*/ */
@ -733,11 +728,11 @@ static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv,
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return 0; 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 * Unfortunately we cannot just follow dev->dsa_prt as this is only set for the
* DSA master device. * DSA master device.
*/ */
@ -757,6 +752,7 @@ int rtl83xx_port_is_under(const struct net_device * dev, struct rtl838x_switch_p
if (priv->ports[i].dp->slave == dev) if (priv->ports[i].dp->slave == dev)
return i; return i;
} }
return -EINVAL; return -EINVAL;
} }
@ -791,9 +787,7 @@ const static struct rhashtable_params route_ht_params = {
.head_offset = offsetof(struct rtl83xx_route, linkage), .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) static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 ip_addr, u64 mac)
{ {
struct rtl83xx_route *r; struct rtl83xx_route *r;
@ -865,6 +859,7 @@ static int rtl83xx_l3_nexthop_update(struct rtl838x_switch_priv *priv, __be32 i
} }
} }
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
} }
@ -895,6 +890,7 @@ static int rtl83xx_port_ipv4_resolve(struct rtl838x_switch_priv *priv,
} }
neigh_release(n); neigh_release(n);
return err; return err;
} }
@ -970,6 +966,7 @@ static struct rtl83xx_route *rtl83xx_route_alloc(struct rtl838x_switch_priv *pri
out_free: out_free:
kfree(r); kfree(r);
return NULL; return NULL;
} }
@ -991,7 +988,8 @@ 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 /* 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->id = idx + MAX_ROUTES;
r->gw_ip = ip; r->gw_ip = ip;
@ -1013,6 +1011,7 @@ static struct rtl83xx_route *rtl83xx_host_route_alloc(struct rtl838x_switch_priv
out_free: out_free:
kfree(r); kfree(r);
return NULL; return NULL;
} }
@ -1082,8 +1081,7 @@ static int rtl83xx_fib4_del(struct rtl838x_switch_priv *priv,
return 0; 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. * for packets to be routed needs to be allocated.
*/ */
static int rtl83xx_alloc_router_mac(struct rtl838x_switch_priv *priv, u64 mac) static int rtl83xx_alloc_router_mac(struct rtl838x_switch_priv *priv, u64 mac)
@ -1269,6 +1267,7 @@ static int rtl83xx_fib6_add(struct rtl838x_switch_priv *priv,
{ {
pr_debug("In %s\n", __func__); pr_debug("In %s\n", __func__);
// nh->fib_nh_flags |= RTNH_F_OFFLOAD; // nh->fib_nh_flags |= RTNH_F_OFFLOAD;
return 0; return 0;
} }
@ -1557,14 +1556,14 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
*/ */
return err; return err;
} }
err = dsa_register_switch(priv->ds); err = dsa_register_switch(priv->ds);
if (err) { if (err) {
dev_err(dev, "Error registering switch: %d\n", err); dev_err(dev, "Error registering switch: %d\n", err);
return 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 * dsa_switch_tree, the tree is built when the switch
* is registered by dsa_register_switch * is registered by dsa_register_switch
*/ */
@ -1582,19 +1581,19 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
switch (priv->family_id) { switch (priv->family_id) {
case RTL8380_FAMILY_ID: case RTL8380_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl838x_switch_irq, 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; break;
case RTL8390_FAMILY_ID: case RTL8390_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl839x_switch_irq, 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; break;
case RTL9300_FAMILY_ID: case RTL9300_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl930x_switch_irq, 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; break;
case RTL9310_FAMILY_ID: case RTL9310_FAMILY_ID:
err = request_irq(priv->link_state_irq, rtl931x_switch_irq, 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; break;
} }
if (err) { if (err) {
@ -1616,9 +1615,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
priv->mirror_group_ports[i] = -1; 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; priv->nb.notifier_call = rtl83xx_netdevice_event;
if (register_netdevice_notifier(&priv->nb)) { if (register_netdevice_notifier(&priv->nb)) {
priv->nb.notifier_call = NULL; priv->nb.notifier_call = NULL;
@ -1629,8 +1626,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
// Initialize hash table for L3 routing // Initialize hash table for L3 routing
rhltable_init(&priv->routes, &route_ht_params); 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. * changes to update nexthop entries for L3 routing.
*/ */
priv->ne_nb.notifier_call = rtl83xx_netevent_event; priv->ne_nb.notifier_call = rtl83xx_netevent_event;
@ -1642,8 +1638,7 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev)
priv->fib_nb.notifier_call = rtl83xx_fib_event; 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 * where possible
* Only FIBs pointing to our own netdevs are programmed into * Only FIBs pointing to our own netdevs are programmed into
* the device, so no need to pass a callback. * the device, so no need to pass a callback.
@ -1680,6 +1675,7 @@ static int rtl83xx_sw_remove(struct platform_device *pdev)
{ {
// TODO: // TODO:
pr_debug("Removing platform driver for rtl83xx-sw\n"); pr_debug("Removing platform driver for rtl83xx-sw\n");
return 0; return 0;
} }

View file

@ -2,8 +2,8 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
#define RTL838X_DRIVER_NAME "rtl838x" #define RTL838X_DRIVER_NAME "rtl838x"

View file

@ -2,14 +2,12 @@
#include <net/dsa.h> #include <net/dsa.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
extern struct rtl83xx_soc_info soc_info; extern struct rtl83xx_soc_info soc_info;
static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv) static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv)
{ {
mutex_lock(&priv->reg_mutex); mutex_lock(&priv->reg_mutex);
@ -111,9 +109,7 @@ static enum dsa_tag_protocol rtl83xx_get_tag_protocol(struct dsa_switch *ds,
return DSA_TAG_PROTO_TRAILER; return DSA_TAG_PROTO_TRAILER;
} }
/* /* Initialize all VLANS */
* Initialize all VLANS
*/
static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv) static void rtl83xx_vlan_setup(struct rtl838x_switch_priv *priv)
{ {
struct rtl838x_vlan_info info; struct rtl838x_vlan_info info;
@ -218,8 +214,7 @@ static int rtl83xx_setup(struct dsa_switch *ds)
rtl83xx_port_set_salrn(priv, priv->cpu_port, false); rtl83xx_port_set_salrn(priv, priv->cpu_port, false);
ds->assisted_learning_on_cpu_port = true; 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 * 0: FWD, 1: DROP, 2: TRAP2CPU
*/ */
if (priv->family_id == RTL8380_FAMILY_ID) if (priv->family_id == RTL8380_FAMILY_ID)
@ -414,8 +409,8 @@ static void rtl93xx_phylink_validate(struct dsa_switch *ds, int port,
} }
// Internal phys of the RTL93xx family provide 10G // Internal phys of the RTL93xx family provide 10G
if (priv->ports[port].phy_is_integrated if (priv->ports[port].phy_is_integrated &&
&& state->interface == PHY_INTERFACE_MODE_1000BASEX) { state->interface == PHY_INTERFACE_MODE_1000BASEX) {
phylink_set(mask, 1000baseX_Full); phylink_set(mask, 1000baseX_Full);
} else if (priv->ports[port].phy_is_integrated) { } else if (priv->ports[port].phy_is_integrated) {
phylink_set(mask, 1000baseX_Full); phylink_set(mask, 1000baseX_Full);
@ -492,6 +487,7 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
state->pause |= MLO_PAUSE_RX; state->pause |= MLO_PAUSE_RX;
if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port)) if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
state->pause |= MLO_PAUSE_TX; state->pause |= MLO_PAUSE_TX;
return 1; return 1;
} }
@ -506,8 +502,7 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
if (port < 0 || port > priv->cpu_port) if (port < 0 || port > priv->cpu_port)
return -EINVAL; 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. * 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 * This would not be necessary for ports connected e.g. to RTL8218D
* PHYs. * PHYs.
@ -574,6 +569,7 @@ static int rtl93xx_phylink_mac_link_state(struct dsa_switch *ds, int port,
state->pause |= MLO_PAUSE_RX; state->pause |= MLO_PAUSE_RX;
if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port)) if (priv->r->get_port_reg_le(priv->r->mac_tx_pause_sts) & BIT_ULL(port))
state->pause |= MLO_PAUSE_TX; state->pause |= MLO_PAUSE_TX;
return 1; return 1;
} }
@ -1134,6 +1130,7 @@ static int rtl83xx_set_mac_eee(struct dsa_switch *ds, int port,
pr_info("Enabled EEE for port %d\n", port); pr_info("Enabled EEE for port %d\n", port);
else else
pr_info("Disabled EEE for port %d\n", port); pr_info("Disabled EEE for port %d\n", port);
return 0; return 0;
} }
@ -1158,8 +1155,9 @@ static int rtl93xx_get_mac_eee(struct dsa_switch *ds, int port,
{ {
struct rtl838x_switch_priv *priv = ds->priv; struct rtl838x_switch_priv *priv = ds->priv;
e->supported = SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full e->supported = SUPPORTED_100baseT_Full |
| SUPPORTED_2500baseX_Full; SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full;
priv->r->eee_port_ability(priv, e, port); priv->r->eee_port_ability(priv, e, port);
@ -1175,6 +1173,7 @@ static int rtl83xx_set_ageing_time(struct dsa_switch *ds, unsigned int msec)
struct rtl838x_switch_priv *priv = ds->priv; struct rtl838x_switch_priv *priv = ds->priv;
priv->r->set_ageing_time(msec); priv->r->set_ageing_time(msec);
return 0; return 0;
} }
@ -1306,7 +1305,7 @@ void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
case BR_STATE_LEARNING: /* 2 */ case BR_STATE_LEARNING: /* 2 */
port_state[index] |= (2 << bit); port_state[index] |= (2 << bit);
break; break;
case BR_STATE_FORWARDING: /* 3*/ case BR_STATE_FORWARDING: /* 3 */
port_state[index] |= (3 << bit); port_state[index] |= (3 << bit);
default: default:
break; break;
@ -1463,9 +1462,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_INNER, vlan->vid);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, vlan->vid); priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, vlan->vid);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, 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, 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; priv->ports[port].pvid = vlan->vid;
} }
@ -1523,9 +1522,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_INNER, 0);
priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, 0); priv->r->vlan_port_pvid_set(port, PBVLAN_TYPE_OUTER, 0);
priv->r->vlan_port_pvidmode_set(port, PBVLAN_TYPE_INNER, 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, 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 */ /* Get port memberships of this vlan */
priv->r->vlan_tables_read(vlan->vid, &info); priv->r->vlan_tables_read(vlan->vid, &info);
@ -1576,8 +1575,7 @@ static void rtl83xx_setup_l2_mc_entry(struct rtl838x_l2_entry *e, int vid, u64 m
u64_to_ether_addr(mac, e->mac); 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 * 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 * 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 * when an empty slot was found and must exist is false, the index of the slot is returned
@ -1606,8 +1604,7 @@ static int rtl83xx_find_l2_hash_entry(struct rtl838x_switch_priv *priv, u64 seed
return idx; 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 * 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 an empty slot was found the index of the slot is returned
* when no slots are available returns -1 * when no slots are available returns -1
@ -1630,6 +1627,7 @@ static int rtl83xx_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed,
break; break;
} }
} }
return idx; return idx;
} }
@ -1668,8 +1666,10 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port,
} }
err = -ENOTSUPP; err = -ENOTSUPP;
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return err; return err;
} }
@ -1703,8 +1703,10 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port,
goto out; goto out;
} }
err = -ENOENT; err = -ENOENT;
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return err; return err;
} }
@ -1741,6 +1743,7 @@ static int rtl83xx_port_fdb_dump(struct dsa_switch *ds, int port,
} }
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return 0; return 0;
} }
@ -1810,6 +1813,7 @@ static int rtl83xx_port_mdb_add(struct dsa_switch *ds, int port,
} }
err = -ENOTSUPP; err = -ENOTSUPP;
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
if (err) if (err)
@ -1862,8 +1866,10 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port,
goto out; goto out;
} }
// TODO: Re-enable with a newer kernel: err = -ENOENT; // TODO: Re-enable with a newer kernel: err = -ENOENT;
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return err; return err;
} }
@ -1923,6 +1929,7 @@ static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port,
priv->mirror_group_ports[group] = mirror->to_local_port; priv->mirror_group_ports[group] = mirror->to_local_port;
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return 0; return 0;
} }
@ -2054,8 +2061,8 @@ static int rtl83xx_port_lag_join(struct dsa_switch *ds, int port,
if (!priv->lag_devs[i]) if (!priv->lag_devs[i])
priv->lag_devs[i] = lag; priv->lag_devs[i] = lag;
if (priv->lag_primary[i]==-1) { if (priv->lag_primary[i] == -1) {
priv->lag_primary[i]=port; priv->lag_primary[i] = port;
} else } else
priv->is_lagmember[port] = 1; priv->is_lagmember[port] = 1;
@ -2070,8 +2077,8 @@ static int rtl83xx_port_lag_join(struct dsa_switch *ds, int port,
out: out:
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return err;
return err;
} }
static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port, static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port,
@ -2081,7 +2088,7 @@ static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port,
struct rtl838x_switch_priv *priv = ds->priv; struct rtl838x_switch_priv *priv = ds->priv;
mutex_lock(&priv->reg_mutex); 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)) { if (priv->lags_port_members[i] & BIT_ULL(port)) {
group = i; group = i;
break; break;
@ -2122,8 +2129,9 @@ int dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg)
u32 offset = 0; u32 offset = 0;
struct rtl838x_switch_priv *priv = ds->priv; struct rtl838x_switch_priv *priv = ds->priv;
if (phy_addr >= 24 && phy_addr <= 27 if ((phy_addr >= 24) &&
&& priv->ports[24].phy == PHY_RTL838X_SDS) { (phy_addr <= 27) &&
(priv->ports[24].phy == PHY_RTL838X_SDS)) {
if (phy_addr == 26) if (phy_addr == 26)
offset = 0x100; offset = 0x100;
val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff; val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff;
@ -2139,8 +2147,9 @@ int dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val)
u32 offset = 0; u32 offset = 0;
struct rtl838x_switch_priv *priv = ds->priv; struct rtl838x_switch_priv *priv = ds->priv;
if (phy_addr >= 24 && phy_addr <= 27 if ((phy_addr >= 24) &&
&& priv->ports[24].phy == PHY_RTL838X_SDS) { (phy_addr <= 27) &&
(priv->ports[24].phy == PHY_RTL838X_SDS)) {
if (phy_addr == 26) if (phy_addr == 26)
offset = 0x100; offset = 0x100;
sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)); sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2));

View file

@ -2,8 +2,8 @@
#include <net/dsa.h> #include <net/dsa.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
static struct rtl838x_switch_priv *switch_priv; static struct rtl838x_switch_priv *switch_priv;
@ -20,28 +20,28 @@ int dot1p_priority_remapping[] = {0, 1, 2, 3, 4, 5, 6, 7};
static void rtl839x_read_scheduling_table(int port) static void rtl839x_read_scheduling_table(int port)
{ {
u32 cmd = 1 << 9 /* Execute cmd */ u32 cmd = 1 << 9 | /* Execute cmd */
| 0 << 8 /* Read */ 0 << 8 | /* Read */
| 0 << 6 /* Table type 0b00 */ 0 << 6 | /* Table type 0b00 */
| (port & 0x3f); (port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd); rtl839x_exec_tbl2_cmd(cmd);
} }
static void rtl839x_write_scheduling_table(int port) static void rtl839x_write_scheduling_table(int port)
{ {
u32 cmd = 1 << 9 /* Execute cmd */ u32 cmd = 1 << 9 | /* Execute cmd */
| 1 << 8 /* Write */ 1 << 8 | /* Write */
| 0 << 6 /* Table type 0b00 */ 0 << 6 | /* Table type 0b00 */
| (port & 0x3f); (port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd); rtl839x_exec_tbl2_cmd(cmd);
} }
static void rtl839x_read_out_q_table(int port) static void rtl839x_read_out_q_table(int port)
{ {
u32 cmd = 1 << 9 /* Execute cmd */ u32 cmd = 1 << 9 | /* Execute cmd */
| 0 << 8 /* Read */ 0 << 8 | /* Read */
| 2 << 6 /* Table type 0b10 */ 2 << 6 | /* Table type 0b10 */
| (port & 0x3f); (port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd); rtl839x_exec_tbl2_cmd(cmd);
} }
@ -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 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
{ {
u32 rate;
if (port > priv->cpu_port) if (port > priv->cpu_port)
return 0; 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 */ /* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
@ -86,8 +84,10 @@ void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
{ {
if (port > priv->cpu_port) if (port > priv->cpu_port)
return; return;
if (queue > 7) if (queue > 7)
return; return;
sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue)); sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue));
} }
@ -118,7 +118,8 @@ static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv)
sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR); sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR);
/* Enable storm control on all ports with a PHY and limit rates, /* Enable storm control on all ports with a PHY and limit rates,
* for UC and MC for both known and unknown addresses */ * for UC and MC for both known and unknown addresses
*/
for (i = 0; i < priv->cpu_port; i++) { for (i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) { 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_UC(i));
@ -351,7 +352,6 @@ void rtl83xx_set_ingress_priority(int port, int priority)
sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port)); sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port));
else else
sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port)); sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port));
} }
int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port) int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
@ -367,6 +367,7 @@ int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
if (v & BIT(19)) if (v & BIT(19))
return WEIGHTED_ROUND_ROBIN; return WEIGHTED_ROUND_ROBIN;
return WEIGHTED_FAIR_QUEUE; return WEIGHTED_FAIR_QUEUE;
} }
@ -572,5 +573,4 @@ void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv)
rtl838x_rate_control_init(priv); rtl838x_rate_control_init(priv);
else if (priv->family_id == RTL8390_FAMILY_ID) else if (priv->family_id == RTL8390_FAMILY_ID)
rtl839x_rate_control_init(priv); rtl839x_rate_control_init(priv);
} }

View file

@ -75,8 +75,7 @@ enum template_field_id {
TEMPLATE_FIELD_FLOW_LABEL = 41, TEMPLATE_FIELD_FLOW_LABEL = 41,
}; };
/* /* The RTL838X SoCs use 5 fixed templates with definitions for which data fields are to
* The RTL838X SoCs use 5 fixed templates with definitions for which data fields are to
* be copied from the Ethernet Frame header into the 12 User-definable fields of the Packet * be copied from the Ethernet Frame header into the 12 User-definable fields of the Packet
* Inspection Engine's buffer. The following defines the field contents for each of the fixed * Inspection Engine's buffer. The following defines the field contents for each of the fixed
* templates. Additionally, 3 user-definable templates can be set up via the definitions * templates. Additionally, 3 user-definable templates can be set up via the definitions
@ -216,8 +215,7 @@ static u64 rtl838x_l2_hash_seed(u64 mac, u32 vid)
return mac << 12 | vid; return mac << 12 | vid;
} }
/* /* Applies the same hash algorithm as the one used currently by the ASIC to the seed
* Applies the same hash algorithm as the one used currently by the ASIC to the seed
* and returns a key into the L2 hash table * and returns a key into the L2 hash table
*/ */
static u32 rtl838x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed) static u32 rtl838x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
@ -237,9 +235,9 @@ static u32 rtl838x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
h = h1 ^ h2 ^ h3 ^ ((seed >> 55) & 0x1ff); h = h1 ^ h2 ^ h3 ^ ((seed >> 55) & 0x1ff);
h ^= ((seed >> 22) & 0x7ff) ^ (seed & 0x7ff); h ^= ((seed >> 22) & 0x7ff) ^ (seed & 0x7ff);
} else { } else {
h = ((seed >> 55) & 0x1ff) ^ ((seed >> 44) & 0x7ff) h = ((seed >> 55) & 0x1ff) ^ ((seed >> 44) & 0x7ff) ^
^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) ^
^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff); ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff);
} }
return h; return h;
@ -275,9 +273,7 @@ inline static int rtl838x_trk_mbr_ctr(int group)
return RTL838X_TRK_MBR_CTR + (group << 2); return RTL838X_TRK_MBR_CTR + (group << 2);
} }
/* /* Fills an L2 entry structure from the SoC registers */
* Fills an L2 entry structure from the SoC registers
*/
static void rtl838x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) static void rtl838x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
{ {
/* Table contains different entry types, we need to identify the right one: /* Table contains different entry types, we need to identify the right one:
@ -318,7 +314,8 @@ static void rtl838x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
e->valid = true; e->valid = true;
/* A valid entry has one of mutli-cast, aging, sa/da-blocking, /* A valid entry has one of mutli-cast, aging, sa/da-blocking,
* next-hop or static entry bit set */ * next-hop or static entry bit set
*/
if (!(r[0] & 0x007c0000) && !(r[1] & 0xd0000000)) if (!(r[0] & 0x007c0000) && !(r[1] & 0xd0000000))
e->valid = false; e->valid = false;
else else
@ -341,9 +338,7 @@ static void rtl838x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
e->type = IP6_MULTICAST; e->type = IP6_MULTICAST;
} }
/* /* 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 rtl838x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) static void rtl838x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
{ {
u64 mac = ether_addr_to_u64(e->mac); u64 mac = ether_addr_to_u64(e->mac);
@ -389,21 +384,19 @@ static void rtl838x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
} }
} }
/* /* 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 * 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 * The data read from the SoC is filled into rtl838x_l2_entry
*/ */
static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e)
{ {
u64 entry;
u32 r[3]; u32 r[3];
struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 0); // Access L2 Table 0 struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 0); // Access L2 Table 0
u32 idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket u32 idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket
int i; int i;
rtl_table_read(q, idx); rtl_table_read(q, idx);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
r[i] = sw_r32(rtl_table_data(q, i)); r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q); rtl_table_release(q);
@ -412,8 +405,7 @@ static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
if (!e->valid) if (!e->valid)
return 0; return 0;
entry = (((u64) r[1]) << 32) | (r[2]); // mac and vid concatenated as hash seed return (((u64) r[1]) << 32) | (r[2]); // mac and vid concatenated as hash seed
return entry;
} }
static void rtl838x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e) static void rtl838x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e)
@ -426,7 +418,7 @@ static void rtl838x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
rtl838x_fill_l2_row(r, e); rtl838x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -435,13 +427,12 @@ static void rtl838x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e) static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e)
{ {
u64 entry;
u32 r[3]; u32 r[3];
struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 1); // Access L2 Table 1 struct table_reg *q = rtl_table_get(RTL8380_TBL_L2, 1); // Access L2 Table 1
int i; int i;
rtl_table_read(q, idx); rtl_table_read(q, idx);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
r[i] = sw_r32(rtl_table_data(q, i)); r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q); rtl_table_release(q);
@ -453,8 +444,7 @@ static u64 rtl838x_read_cam(int idx, struct rtl838x_l2_entry *e)
pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]);
// Return MAC with concatenated VID ac concatenated ID // Return MAC with concatenated VID ac concatenated ID
entry = (((u64) r[1]) << 32) | r[2]; return (((u64) r[1]) << 32) | r[2];
return entry;
} }
static void rtl838x_write_cam(int idx, struct rtl838x_l2_entry *e) static void rtl838x_write_cam(int idx, struct rtl838x_l2_entry *e)
@ -465,7 +455,7 @@ static void rtl838x_write_cam(int idx, struct rtl838x_l2_entry *e)
rtl838x_fill_l2_row(r, e); rtl838x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -539,8 +529,7 @@ static void rtl838x_enable_learning(int port, bool enable)
static void rtl838x_enable_flood(int port, bool enable) static void rtl838x_enable_flood(int port, bool enable)
{ {
/* /* 0: Forward
* 0: Forward
* 1: Disable * 1: Disable
* 2: to CPU * 2: to CPU
* 3: Copy to CPU * 3: Copy to CPU
@ -562,10 +551,10 @@ static void rtl838x_enable_bcast_flood(int port, bool enable)
static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 15 /* Execute cmd */ u32 cmd = 1 << 15 | /* Execute cmd */
| 1 << 14 /* Read */ 1 << 14 | /* Read */
| 2 << 12 /* Table type 0b10 */ 2 << 12 | /* Table type 0b10 */
| (msti & 0xfff); (msti & 0xfff);
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
@ -575,10 +564,10 @@ static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port
static void rtl838x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl838x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 15 /* Execute cmd */ u32 cmd = 1 << 15 | /* Execute cmd */
| 0 << 14 /* Write */ 0 << 14 | /* Write */
| 2 << 12 /* Table type 0b10 */ 2 << 12 | /* Table type 0b10 */
| (msti & 0xfff); (msti & 0xfff);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); sw_w32(port_state[i], priv->r->tbl_access_data_0(i));
@ -605,9 +594,7 @@ void rtl838x_traffic_disable(int source, int dest)
rtl838x_mask_port_reg(BIT(dest), 0, rtl838x_port_iso_ctrl(source)); rtl838x_mask_port_reg(BIT(dest), 0, rtl838x_port_iso_ctrl(source));
} }
/* /* Enables or disables the EEE/EEEP capability of a port */
* Enables or disables the EEE/EEEP capability of a port
*/
static void rtl838x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) static void rtl838x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable)
{ {
u32 v; u32 v;
@ -634,9 +621,7 @@ static void rtl838x_port_eee_set(struct rtl838x_switch_priv *priv, int port, boo
} }
/* /* Get EEE own capabilities and negotiation result */
* Get EEE own capabilities and negotiation result
*/
static int rtl838x_eee_port_ability(struct rtl838x_switch_priv *priv, static int rtl838x_eee_port_ability(struct rtl838x_switch_priv *priv,
struct ethtool_eee *e, int port) struct ethtool_eee *e, int port)
{ {
@ -729,8 +714,7 @@ static void rtl838x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_fro
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
} }
/* /* 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 * PIE rule in the pie_rule structure and fills in the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -826,7 +810,6 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->sip_m >> 16; data_m = pr->sip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_SIP2: case TEMPLATE_FIELD_SIP2:
case TEMPLATE_FIELD_SIP3: case TEMPLATE_FIELD_SIP3:
case TEMPLATE_FIELD_SIP4: case TEMPLATE_FIELD_SIP4:
@ -836,7 +819,6 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
break; break;
case TEMPLATE_FIELD_DIP0: case TEMPLATE_FIELD_DIP0:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[7]; data = pr->dip6.s6_addr16[7];
@ -846,7 +828,6 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m; data_m = pr->dip_m;
} }
break; break;
case TEMPLATE_FIELD_DIP1: case TEMPLATE_FIELD_DIP1:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[6]; data = pr->dip6.s6_addr16[6];
@ -856,7 +837,6 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m >> 16; data_m = pr->dip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_DIP2: case TEMPLATE_FIELD_DIP2:
case TEMPLATE_FIELD_DIP3: case TEMPLATE_FIELD_DIP3:
case TEMPLATE_FIELD_DIP4: case TEMPLATE_FIELD_DIP4:
@ -866,7 +846,6 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
break; break;
case TEMPLATE_FIELD_IP_TOS_PROTO: case TEMPLATE_FIELD_IP_TOS_PROTO:
data = pr->tos_proto; data = pr->tos_proto;
data_m = pr->tos_proto_m; data_m = pr->tos_proto_m;
@ -897,8 +876,7 @@ static void rtl838x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
} }
} }
/* /* Creates the intermediate representation of the templated match-fields of the
* Creates the intermediate representation of the templated match-fields of the
* PIE rule in the pie_rule structure by reading the raw data fields in the * PIE rule in the pie_rule structure by reading the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1002,7 +980,6 @@ static void rtl838x_read_pie_templated(u32 r[], struct pie_rule *pr, enum templa
case TEMPLATE_FIELD_SIP6: case TEMPLATE_FIELD_SIP6:
case TEMPLATE_FIELD_SIP7: case TEMPLATE_FIELD_SIP7:
break; break;
case TEMPLATE_FIELD_DIP0: case TEMPLATE_FIELD_DIP0:
pr->dip = data; pr->dip = data;
pr->dip_m = data_m; pr->dip_m = data_m;
@ -1434,13 +1411,17 @@ static int rtl838x_pie_verify_template(struct rtl838x_switch_priv *priv,
return -1; return -1;
if (pr->is_ipv6) { if (pr->is_ipv6) {
if ((pr->sip6_m.s6_addr32[0] || pr->sip6_m.s6_addr32[1] if ((pr->sip6_m.s6_addr32[0] ||
|| pr->sip6_m.s6_addr32[2] || pr->sip6_m.s6_addr32[3]) pr->sip6_m.s6_addr32[1] ||
&& !rtl838x_pie_templ_has(t, TEMPLATE_FIELD_SIP2)) pr->sip6_m.s6_addr32[2] ||
pr->sip6_m.s6_addr32[3]) &&
!rtl838x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
return -1; return -1;
if ((pr->dip6_m.s6_addr32[0] || pr->dip6_m.s6_addr32[1] if ((pr->dip6_m.s6_addr32[0] ||
|| pr->dip6_m.s6_addr32[2] || pr->dip6_m.s6_addr32[3]) pr->dip6_m.s6_addr32[1] ||
&& !rtl838x_pie_templ_has(t, TEMPLATE_FIELD_DIP2)) pr->dip6_m.s6_addr32[2] ||
pr->dip6_m.s6_addr32[3]) &&
!rtl838x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
return -1; return -1;
} }
@ -1497,6 +1478,7 @@ static int rtl838x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
rtl838x_pie_rule_write(priv, idx, pr); rtl838x_pie_rule_write(priv, idx, pr);
mutex_unlock(&priv->pie_mutex); mutex_unlock(&priv->pie_mutex);
return 0; return 0;
} }
@ -1508,8 +1490,7 @@ static void rtl838x_pie_rule_rm(struct rtl838x_switch_priv *priv, struct pie_rul
clear_bit(idx, priv->pie_use_bm); clear_bit(idx, priv->pie_use_bm);
} }
/* /* Initializes the Packet Inspection Engine:
* Initializes the Packet Inspection Engine:
* powers it up, enables default matching templates for all blocks * powers it up, enables default matching templates for all blocks
* and clears all rules possibly installed by u-boot * and clears all rules possibly installed by u-boot
*/ */
@ -1695,17 +1676,17 @@ void rtl838x_set_receive_management_action(int port, rma_ctrl_t type, action_typ
case BPDU: case BPDU:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL838X_RMA_BPDU_CTRL + ((port >> 4) << 2)); RTL838X_RMA_BPDU_CTRL + ((port >> 4) << 2));
break; break;
case PTP: case PTP:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL838X_RMA_PTP_CTRL + ((port >> 4) << 2)); RTL838X_RMA_PTP_CTRL + ((port >> 4) << 2));
break; break;
case LLTP: case LLTP:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL838X_RMA_LLTP_CTRL + ((port >> 4) << 2)); RTL838X_RMA_LLTP_CTRL + ((port >> 4) << 2));
break; break;
default: default:
break; break;
} }
} }
@ -1816,6 +1797,7 @@ irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
dsa_port_phylink_mac_change(ds, i, false); dsa_port_phylink_mac_change(ds, i, false);
} }
} }
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -1832,11 +1814,10 @@ int rtl838x_smi_wait_op(int timeout)
return ret; return ret;
} }
/* /* Reads a register in a page from the PHY */
* Reads a register in a page from the PHY
*/
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val) int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
{ {
int err = -ETIMEDOUT;
u32 v; u32 v;
u32 park_page; u32 park_page;
@ -1865,19 +1846,18 @@ int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff; *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
mutex_unlock(&smi_lock); err = 0;
return 0;
timeout: timeout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/* /* Write to a register in a page of the PHY */
* Write to a register in a page of the PHY
*/
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val) int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
{ {
int err = -ETIMEDOUT;
u32 v; u32 v;
u32 park_page; u32 park_page;
@ -1902,19 +1882,18 @@ int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val)
if (rtl838x_smi_wait_op(100000)) if (rtl838x_smi_wait_op(100000))
goto timeout; goto timeout;
mutex_unlock(&smi_lock); err = 0;
return 0;
timeout: timeout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/* /* Read an mmd register of a PHY */
* Read an mmd register of a PHY
*/
int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val) int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
{ {
int err = -ETIMEDOUT;
u32 v; u32 v;
mutex_lock(&smi_lock); mutex_lock(&smi_lock);
@ -1939,19 +1918,18 @@ int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val)
*val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff; *val = sw_r32(RTL838X_SMI_ACCESS_PHY_CTRL_2) & 0xffff;
mutex_unlock(&smi_lock); err = 0;
return 0;
timeout: timeout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return -ETIMEDOUT;
return err;
} }
/* /* Write to an mmd register of a PHY */
* Write to an mmd register of a PHY
*/
int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val) int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
{ {
int err = -ETIMEDOUT;
u32 v; u32 v;
pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val); pr_debug("MMD write: port %d, dev %d, reg %d, val %x\n", port, addr, reg, val);
@ -1975,12 +1953,11 @@ int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val)
if (rtl838x_smi_wait_op(100000)) if (rtl838x_smi_wait_op(100000))
goto timeout; goto timeout;
mutex_unlock(&smi_lock); err = 0;
return 0;
timeout: timeout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return -ETIMEDOUT; return err;
} }
void rtl8380_get_version(struct rtl838x_switch_priv *priv) void rtl8380_get_version(struct rtl838x_switch_priv *priv)

View file

@ -5,9 +5,7 @@
#include <net/dsa.h> #include <net/dsa.h>
/* /* Register definition */
* Register definition
*/
#define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7))) #define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7)))
#define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7))) #define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7)))
#define RTL930X_MAC_PORT_CTRL(port) (0x3260 + (((port) << 6))) #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_SWITCH_IPV4_ADDR_CTRL (0x106C)
#define RTL839X_SPCL_TRAP_CRC_CTRL (0x1070) #define RTL839X_SPCL_TRAP_CRC_CTRL (0x1070)
/* special port action controls */ /* special port action controls */
/* /* values:
values: * 0 = FORWARD (default)
0 = FORWARD (default) * 1 = DROP
1 = DROP * 2 = TRAP2CPU
2 = TRAP2CPU * 3 = FLOOD IN ALL PORT
3 = FLOOD IN ALL PORT *
* Register encoding.
Register encoding. * offset = CTRL + (port >> 4) << 2
offset = CTRL + (port >> 4) << 2 * value/mask = 3 << ((port & 0xF) << 1)
value/mask = 3 << ((port&0xF) << 1) */
*/
typedef enum { typedef enum {
BPDU = 0, BPDU = 0,
@ -871,8 +868,7 @@ struct rtl838x_l3_intf {
u8 ip6_pbr_icmp_redirect; 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 * for the L3 routing system. Packets arriving and matching an entry in this table
* will be considered for routing. * will be considered for routing.
* Mask fields state whether the corresponding data fields matter for matching * Mask fields state whether the corresponding data fields matter for matching

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
#define RTL839X_VLAN_PORT_TAG_STS_UNTAG 0x0 #define RTL839X_VLAN_PORT_TAG_STS_UNTAG 0x0
@ -228,8 +229,7 @@ static void rtl839x_vlan_set_untagged(u32 vlan, u64 portmask)
rtl_table_release(r); rtl_table_release(r);
} }
/* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer /* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer */
*/
static void rtl839x_vlan_fwd_on_inner(int port, bool is_set) static void rtl839x_vlan_fwd_on_inner(int port, bool is_set)
{ {
if (is_set) if (is_set)
@ -238,9 +238,7 @@ static void rtl839x_vlan_fwd_on_inner(int port, bool is_set)
rtl839x_mask_port_reg_be(0ULL, BIT_ULL(port), RTL839X_VLAN_PORT_FWD); rtl839x_mask_port_reg_be(0ULL, BIT_ULL(port), RTL839X_VLAN_PORT_FWD);
} }
/* /* Hash seed is vid (actually rvid) concatenated with the MAC address */
* Hash seed is vid (actually rvid) concatenated with the MAC address
*/
static u64 rtl839x_l2_hash_seed(u64 mac, u32 vid) static u64 rtl839x_l2_hash_seed(u64 mac, u32 vid)
{ {
u64 v = vid; u64 v = vid;
@ -251,8 +249,7 @@ static u64 rtl839x_l2_hash_seed(u64 mac, u32 vid)
return v; return v;
} }
/* /* Applies the same hash algorithm as the one used currently by the ASIC to the seed
* Applies the same hash algorithm as the one used currently by the ASIC to the seed
* and returns a key into the L2 hash table * and returns a key into the L2 hash table
*/ */
static u32 rtl839x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed) static u32 rtl839x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
@ -260,18 +257,18 @@ static u32 rtl839x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
u32 h1, h2, h; u32 h1, h2, h;
if (sw_r32(priv->r->l2_ctrl_0) & 1) { if (sw_r32(priv->r->l2_ctrl_0) & 1) {
h1 = (u32) (((seed >> 60) & 0x3f) ^ ((seed >> 54) & 0x3f) h1 = (u32) (((seed >> 60) & 0x3f) ^ ((seed >> 54) & 0x3f) ^
^ ((seed >> 36) & 0x3f) ^ ((seed >> 30) & 0x3f) ((seed >> 36) & 0x3f) ^ ((seed >> 30) & 0x3f) ^
^ ((seed >> 12) & 0x3f) ^ ((seed >> 6) & 0x3f)); ((seed >> 12) & 0x3f) ^ ((seed >> 6) & 0x3f));
h2 = (u32) (((seed >> 48) & 0x3f) ^ ((seed >> 42) & 0x3f) h2 = (u32) (((seed >> 48) & 0x3f) ^ ((seed >> 42) & 0x3f) ^
^ ((seed >> 24) & 0x3f) ^ ((seed >> 18) & 0x3f) ((seed >> 24) & 0x3f) ^ ((seed >> 18) & 0x3f) ^
^ (seed & 0x3f)); (seed & 0x3f));
h = (h1 << 6) | h2; h = (h1 << 6) | h2;
} else { } else {
h = (seed >> 60) h = (seed >> 60) ^
^ ((((seed >> 48) & 0x3f) << 6) | ((seed >> 54) & 0x3f)) ((((seed >> 48) & 0x3f) << 6) | ((seed >> 54) & 0x3f)) ^
^ ((seed >> 36) & 0xfff) ^ ((seed >> 24) & 0xfff) ((seed >> 36) & 0xfff) ^ ((seed >> 24) & 0xfff) ^
^ ((seed >> 12) & 0xfff) ^ (seed & 0xfff); ((seed >> 12) & 0xfff) ^ (seed & 0xfff);
} }
return h; return h;
@ -368,9 +365,7 @@ static void rtl839x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
// pr_info("%s: vid %d, rvid: %d\n", __func__, e->vid, e->rvid); // pr_info("%s: vid %d, rvid: %d\n", __func__, e->vid, e->rvid);
} }
/* /* Fills the 3 SoC table registers r[] with the information in the rtl838x_l2_entry */
* Fills the 3 SoC table registers r[] with the information in the rtl838x_l2_entry
*/
static void rtl839x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) static void rtl839x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
{ {
if (!e->valid) { if (!e->valid) {
@ -417,8 +412,7 @@ static void rtl839x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
} }
} }
/* /* 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 * 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 * The data read from the SoC is filled into rtl838x_l2_entry
*/ */
@ -430,7 +424,7 @@ static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
int i; int i;
rtl_table_read(q, idx); rtl_table_read(q, idx);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
r[i] = sw_r32(rtl_table_data(q, i)); r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q); rtl_table_release(q);
@ -452,7 +446,7 @@ static void rtl839x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
rtl839x_fill_l2_row(r, e); rtl839x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -466,7 +460,7 @@ static u64 rtl839x_read_cam(int idx, struct rtl838x_l2_entry *e)
int i; int i;
rtl_table_read(q, idx); rtl_table_read(q, idx);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
r[i] = sw_r32(rtl_table_data(q, i)); r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q); rtl_table_release(q);
@ -489,7 +483,7 @@ static void rtl839x_write_cam(int idx, struct rtl838x_l2_entry *e)
rtl839x_fill_l2_row(r, e); rtl839x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -583,8 +577,7 @@ static void rtl839x_enable_learning(int port, bool enable)
static void rtl839x_enable_flood(int port, bool enable) static void rtl839x_enable_flood(int port, bool enable)
{ {
/* /* 0: Forward
* 0: Forward
* 1: Disable * 1: Disable
* 2: to CPU * 2: to CPU
* 3: Copy to CPU * 3: Copy to CPU
@ -623,6 +616,7 @@ irqreturn_t rtl839x_switch_irq(int irq, void *dev_id)
dsa_port_phylink_mac_change(ds, i, false); dsa_port_phylink_mac_change(ds, i, false);
} }
} }
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -689,6 +683,7 @@ int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
errout: errout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
@ -729,12 +724,11 @@ int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val)
errout: errout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
/* /* Read an mmd register of the PHY */
* Read an mmd register of the PHY
*/
int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{ {
int err = 0; int err = 0;
@ -765,12 +759,11 @@ int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
errout: errout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
/* /* Write to an mmd register of the PHY */
* Write to an mmd register of the PHY
*/
int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{ {
int err = 0; int err = 0;
@ -802,6 +795,7 @@ int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
errout: errout:
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
@ -838,10 +832,10 @@ void rtl839x_vlan_profile_dump(int profile)
static void rtl839x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl839x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 16 /* Execute cmd */ u32 cmd = 1 << 16 | /* Execute cmd */
| 0 << 15 /* Read */ 0 << 15 | /* Read */
| 5 << 12 /* Table type 0b101 */ 5 << 12 | /* Table type 0b101 */
| (msti & 0xfff); (msti & 0xfff);
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -851,18 +845,16 @@ static void rtl839x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port
static void rtl839x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl839x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 16 /* Execute cmd */ u32 cmd = 1 << 16 | /* Execute cmd */
| 1 << 15 /* Write */ 1 << 15 | /* Write */
| 5 << 12 /* Table type 0b101 */ 5 << 12 | /* Table type 0b101 */
| (msti & 0xfff); (msti & 0xfff);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); sw_w32(port_state[i], priv->r->tbl_access_data_0(i));
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
} }
/* /* Enables or disables the EEE/EEEP capability of a port */
* Enables or disables the EEE/EEEP capability of a port
*/
void rtl839x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) void rtl839x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable)
{ {
u32 v; u32 v;
@ -885,9 +877,7 @@ void rtl839x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enabl
priv->ports[port].eee_enabled = enable; priv->ports[port].eee_enabled = enable;
} }
/* /* Get EEE own capabilities and negotiation result */
* Get EEE own capabilities and negotiation result
*/
int rtl839x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port) int rtl839x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port)
{ {
u64 link, a; u64 link, a;
@ -944,9 +934,7 @@ static void rtl839x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int inde
sw_w32_mask(0, BIT(block), RTL839X_ACL_BLK_LOOKUP_CTRL); sw_w32_mask(0, BIT(block), RTL839X_ACL_BLK_LOOKUP_CTRL);
} }
/* /* Delete a range of Packet Inspection Engine rules */
* Delete a range of Packet Inspection Engine rules
*/
static int rtl839x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) static int rtl839x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to)
{ {
u32 v = (index_from << 1)| (index_to << 13 ) | BIT(0); u32 v = (index_from << 1)| (index_to << 13 ) | BIT(0);
@ -962,11 +950,11 @@ static int rtl839x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from
} while (sw_r32(RTL839X_ACL_CLR_CTRL) & BIT(0)); } while (sw_r32(RTL839X_ACL_CLR_CTRL) & BIT(0));
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return 0; 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 * PIE rule in the pie_rule structure and fills in the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1067,7 +1055,6 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->sip_m >> 16; data_m = pr->sip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_SIP2: case TEMPLATE_FIELD_SIP2:
case TEMPLATE_FIELD_SIP3: case TEMPLATE_FIELD_SIP3:
case TEMPLATE_FIELD_SIP4: case TEMPLATE_FIELD_SIP4:
@ -1077,7 +1064,6 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
break; break;
case TEMPLATE_FIELD_DIP0: case TEMPLATE_FIELD_DIP0:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[7]; data = pr->dip6.s6_addr16[7];
@ -1087,7 +1073,6 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m; data_m = pr->dip_m;
} }
break; break;
case TEMPLATE_FIELD_DIP1: case TEMPLATE_FIELD_DIP1:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[6]; data = pr->dip6.s6_addr16[6];
@ -1097,7 +1082,6 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m >> 16; data_m = pr->dip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_DIP2: case TEMPLATE_FIELD_DIP2:
case TEMPLATE_FIELD_DIP3: case TEMPLATE_FIELD_DIP3:
case TEMPLATE_FIELD_DIP4: case TEMPLATE_FIELD_DIP4:
@ -1107,7 +1091,6 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
break; break;
case TEMPLATE_FIELD_IP_TOS_PROTO: case TEMPLATE_FIELD_IP_TOS_PROTO:
data = pr->tos_proto; data = pr->tos_proto;
data_m = pr->tos_proto_m; data_m = pr->tos_proto_m;
@ -1140,8 +1123,7 @@ static void rtl839x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
} }
} }
/* /* Creates the intermediate representation of the templated match-fields of the
* Creates the intermediate representation of the templated match-fields of the
* PIE rule in the pie_rule structure by reading the raw data fields in the * PIE rule in the pie_rule structure by reading the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1541,13 +1523,17 @@ static int rtl839x_pie_verify_template(struct rtl838x_switch_priv *priv,
return -1; return -1;
if (pr->is_ipv6) { if (pr->is_ipv6) {
if ((pr->sip6_m.s6_addr32[0] || pr->sip6_m.s6_addr32[1] if ((pr->sip6_m.s6_addr32[0] ||
|| pr->sip6_m.s6_addr32[2] || pr->sip6_m.s6_addr32[3]) pr->sip6_m.s6_addr32[1] ||
&& !rtl839x_pie_templ_has(t, TEMPLATE_FIELD_SIP2)) pr->sip6_m.s6_addr32[2] ||
pr->sip6_m.s6_addr32[3]) &&
!rtl839x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
return -1; return -1;
if ((pr->dip6_m.s6_addr32[0] || pr->dip6_m.s6_addr32[1] if ((pr->dip6_m.s6_addr32[0] ||
|| pr->dip6_m.s6_addr32[2] || pr->dip6_m.s6_addr32[3]) pr->dip6_m.s6_addr32[1] ||
&& !rtl839x_pie_templ_has(t, TEMPLATE_FIELD_DIP2)) pr->dip6_m.s6_addr32[2] ||
pr->dip6_m.s6_addr32[3]) &&
!rtl839x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
return -1; return -1;
} }
@ -1607,6 +1593,7 @@ static int rtl839x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
rtl839x_pie_rule_write(priv, idx, pr); rtl839x_pie_rule_write(priv, idx, pr);
mutex_unlock(&priv->pie_mutex); mutex_unlock(&priv->pie_mutex);
return 0; return 0;
} }
@ -1743,9 +1730,7 @@ static void rtl839x_route_write(int idx, struct rtl83xx_route *rt)
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Configure the switch's own MAC addresses used when routing packets */
* Configure the switch's own MAC addresses used when routing packets
*/
static void rtl839x_setup_port_macs(struct rtl838x_switch_priv *priv) static void rtl839x_setup_port_macs(struct rtl838x_switch_priv *priv)
{ {
int i; int i;
@ -1836,17 +1821,17 @@ void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, action_typ
case BPDU: case BPDU:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL839X_RMA_BPDU_CTRL + ((port >> 4) << 2)); RTL839X_RMA_BPDU_CTRL + ((port >> 4) << 2));
break; break;
case PTP: case PTP:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL839X_RMA_PTP_CTRL + ((port >> 4) << 2)); RTL839X_RMA_PTP_CTRL + ((port >> 4) << 2));
break; break;
case LLTP: case LLTP:
sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1), sw_w32_mask(3 << ((port & 0xf) << 1), (action & 0x3) << ((port & 0xf) << 1),
RTL839X_RMA_LLTP_CTRL + ((port >> 4) << 2)); RTL839X_RMA_LLTP_CTRL + ((port >> 4) << 2));
break; break;
default: default:
break; break;
} }
} }

View file

@ -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); int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port);
#endif /* _NET_DSA_RTL83XX_H */ #endif /* _NET_DSA_RTL83XX_H */

View file

@ -242,8 +242,7 @@ static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask)
rtl_table_release(r); rtl_table_release(r);
} }
/* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer /* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer */
*/
static void rtl930x_vlan_fwd_on_inner(int port, bool is_set) static void rtl930x_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
@ -289,10 +288,10 @@ static void rtl930x_l2_learning_setup(void)
static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 17 /* Execute cmd */ u32 cmd = 1 << 17 | /* Execute cmd */
| 0 << 16 /* Read */ 0 << 16 | /* Read */
| 4 << 12 /* Table type 0b10 */ 4 << 12 | /* Table type 0b10 */
| (msti & 0xfff); (msti & 0xfff);
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
@ -303,10 +302,10 @@ static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port
static void rtl930x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl930x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 17 /* Execute cmd */ u32 cmd = 1 << 17 | /* Execute cmd */
| 1 << 16 /* Write */ 1 << 16 | /* Write */
| 4 << 12 /* Table type 4 */ 4 << 12 | /* Table type 4 */
| (msti & 0xfff); (msti & 0xfff);
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
sw_w32(port_state[i], RTL930X_TBL_ACCESS_DATA_0(i)); sw_w32(port_state[i], RTL930X_TBL_ACCESS_DATA_0(i));
@ -338,8 +337,7 @@ static u64 rtl930x_l2_hash_seed(u64 mac, u32 vid)
return v; 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 * 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 * both hashes in the lower and higher word of the return value since only 12 bit of
* the hash are significant * the hash are significant
@ -348,9 +346,12 @@ static u32 rtl930x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
{ {
u32 k0, k1, h1, h2, h; u32 k0, k1, h1, h2, h;
k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) k0 = (u32) (((seed >> 55) & 0x1f) ^
^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) ((seed >> 44) & 0x7ff) ^
^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff)); ((seed >> 33) & 0x7ff) ^
((seed >> 22) & 0x7ff) ^
((seed >> 11) & 0x7ff) ^
(seed & 0x7ff));
h1 = (seed >> 11) & 0x7ff; h1 = (seed >> 11) & 0x7ff;
h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f);
@ -358,9 +359,12 @@ static u32 rtl930x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
h2 = (seed >> 33) & 0x7ff; h2 = (seed >> 33) & 0x7ff;
h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f); h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f);
k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2 k1 = (u32) (((seed << 55) & 0x1f) ^
^ ((seed >> 22) & 0x7ff) ^ h1 ((seed >> 44) & 0x7ff) ^
^ (seed & 0x7ff)); h2 ^
((seed >> 22) & 0x7ff) ^
h1 ^
(seed & 0x7ff));
// Algorithm choice for block 0 // Algorithm choice for block 0
if (sw_r32(RTL930X_L2_CTRL) & BIT(0)) if (sw_r32(RTL930X_L2_CTRL) & BIT(0))
@ -382,9 +386,7 @@ static u32 rtl930x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
return h; return h;
} }
/* /* Fills an L2 entry structure from the SoC registers */
* Fills an L2 entry structure from the SoC registers
*/
static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
{ {
pr_debug("In %s valid?\n", __func__); pr_debug("In %s valid?\n", __func__);
@ -443,9 +445,7 @@ static void rtl930x_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 rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e) static void rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
{ {
u32 port; u32 port;
@ -457,9 +457,12 @@ static void rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
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 r[0] = ((u32)e->mac[0]) << 24 |
| ((u32)e->mac[2]) << 8 | ((u32)e->mac[3]); ((u32)e->mac[1]) << 16 |
r[1] = ((u32)e->mac[4]) << 24 | ((u32)e->mac[5]) << 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; r[2] |= e->next_hop ? BIT(12) : 0;
@ -490,8 +493,7 @@ static void rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
} }
} }
/* /* 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 * 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 * The data read from the SoC is filled into rtl838x_l2_entry
*/ */
@ -506,9 +508,10 @@ static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
pr_debug("%s: hash %08x, pos: %d\n", __func__, hash, pos); pr_debug("%s: hash %08x, pos: %d\n", __func__, hash, pos);
/* On the RTL93xx, 2 different hash algorithms are used making it a total of /* On the RTL93xx, 2 different hash algorithms are used making it a
* 8 buckets that need to be searched, 4 for each hash-half * 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) { if (pos >= 4) {
pos -= 4; pos -= 4;
hash >>= 16; hash >>= 16;
@ -531,11 +534,16 @@ static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
if (!e->valid) if (!e->valid)
return 0; return 0;
mac = ((u64)e->mac[0]) << 40 | ((u64)e->mac[1]) << 32 | ((u64)e->mac[2]) << 24 mac = ((u64)e->mac[0]) << 40 |
| ((u64)e->mac[3]) << 16 | ((u64)e->mac[4]) << 8 | ((u64)e->mac[5]); ((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 = rtl930x_l2_hash_seed(mac, e->rvid); seed = rtl930x_l2_hash_seed(mac, e->rvid);
pr_debug("%s: mac %016llx, seed %016llx\n", __func__, mac, seed); 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; return seed;
} }
@ -553,7 +561,7 @@ static void rtl930x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
rtl930x_fill_l2_row(r, e); rtl930x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -567,7 +575,7 @@ static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e)
int i; int i;
rtl_table_read(q, idx); rtl_table_read(q, idx);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
r[i] = sw_r32(rtl_table_data(q, i)); r[i] = sw_r32(rtl_table_data(q, i));
rtl_table_release(q); rtl_table_release(q);
@ -588,7 +596,7 @@ static void rtl930x_write_cam(int idx, struct rtl838x_l2_entry *e)
rtl930x_fill_l2_row(r, e); rtl930x_fill_l2_row(r, e);
for (i= 0; i < 3; i++) for (i = 0; i < 3; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
@ -607,6 +615,7 @@ static u64 rtl930x_read_mcast_pmask(int idx)
rtl_table_release(q); rtl_table_release(q);
pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, portmask); pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, portmask);
return portmask; return portmask;
} }
@ -632,12 +641,12 @@ u64 rtl930x_traffic_get(int source)
rtl_table_read(r, source); rtl_table_read(r, source);
v = sw_r32(rtl_table_data(r, 0)); v = sw_r32(rtl_table_data(r, 0));
rtl_table_release(r); 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 rtl930x_traffic_set(int source, u64 dest_matrix) void rtl930x_traffic_set(int source, u64 dest_matrix)
{ {
struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
@ -698,7 +707,8 @@ irqreturn_t rtl930x_switch_irq(int irq, void *dev_id)
for (i = 0; i < 28; i++) { for (i = 0; i < 28; i++) {
if (ports & BIT(i)) { if (ports & BIT(i)) {
/* Read the register twice because of issues with latency at least /* Read the register twice because of issues with latency at least
* with the external RTL8226 PHY on the XGS1210 */ * with the external RTL8226 PHY on the XGS1210
*/
link = sw_r32(RTL930X_MAC_LINK_STS); link = sw_r32(RTL930X_MAC_LINK_STS);
link = sw_r32(RTL930X_MAC_LINK_STS); link = sw_r32(RTL930X_MAC_LINK_STS);
if (link & BIT(i)) if (link & BIT(i))
@ -772,9 +782,7 @@ int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
return err; return err;
} }
/* /* Write to an mmd register of the PHY */
* Write to an mmd register of the PHY
*/
int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{ {
int err = 0; int err = 0;
@ -803,9 +811,7 @@ int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
return err; return err;
} }
/* /* Read an mmd register of the PHY */
* Read an mmd register of the PHY
*/
int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{ {
int err = 0; int err = 0;
@ -834,8 +840,7 @@ int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
return err; return err;
} }
/* /* Calculate both the block 0 and the block 1 hash, and return in
* Calculate both the block 0 and the block 1 hash, and return in
* lower and higher word of the return value since only 12 bit of * lower and higher word of the return value since only 12 bit of
* the hash are significant * the hash are significant
*/ */
@ -843,19 +848,25 @@ u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed)
{ {
u32 k0, k1, h1, h2, h; u32 k0, k1, h1, h2, h;
k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) k0 = (u32) (((seed >> 55) & 0x1f) ^
^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) ((seed >> 44) & 0x7ff) ^
^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff)); ((seed >> 33) & 0x7ff) ^
((seed >> 22) & 0x7ff) ^
((seed >> 11) & 0x7ff) ^
(seed & 0x7ff));
h1 = (seed >> 11) & 0x7ff; h1 = (seed >> 11) & 0x7ff;
h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f);
h2 = (seed >> 33) & 0x7ff; h2 = (seed >> 33) & 0x7ff;
h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f); h2 = ((h2 & 0x3f) << 5) | ((h2 >> 6) & 0x3f);
k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2 k1 = (u32) (((seed << 55) & 0x1f) ^
^ ((seed >> 22) & 0x7ff) ^ h1 ((seed >> 44) & 0x7ff) ^
^ (seed & 0x7ff)); h2 ^
((seed >> 22) & 0x7ff) ^
h1 ^
(seed & 0x7ff));
// Algorithm choice for block 0 // Algorithm choice for block 0
if (sw_r32(RTL930X_L2_CTRL) & BIT(0)) if (sw_r32(RTL930X_L2_CTRL) & BIT(0))
@ -877,9 +888,7 @@ u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed)
return h; return h;
} }
/* /* Enables or disables the EEE/EEEP capability of a port */
* Enables or disables the EEE/EEEP capability of a port
*/
void rtl930x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable) void rtl930x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable)
{ {
u32 v; u32 v;
@ -901,9 +910,7 @@ void rtl930x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enabl
priv->ports[port].eee_enabled = enable; priv->ports[port].eee_enabled = enable;
} }
/* /* Get EEE own capabilities and negotiation result */
* Get EEE own capabilities and negotiation result
*/
int rtl930x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port) int rtl930x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port)
{ {
u32 link, a; u32 link, a;
@ -1012,41 +1019,41 @@ static u32 rtl930x_l3_hash6(struct in6_addr *ip6, int algorithm, bool move_dip)
rows[9] = (HASH_PICK(ip6->s6_addr[9], 0, 6) << 3) | HASH_PICK(ip6->s6_addr[10], 5, 3); rows[9] = (HASH_PICK(ip6->s6_addr[9], 0, 6) << 3) | HASH_PICK(ip6->s6_addr[10], 5, 3);
rows[10] = (HASH_PICK(ip6->s6_addr[10], 0, 5) << 4) | HASH_PICK(ip6->s6_addr[11], 4, 4); rows[10] = (HASH_PICK(ip6->s6_addr[10], 0, 5) << 4) | HASH_PICK(ip6->s6_addr[11], 4, 4);
if (!algorithm) { if (!algorithm) {
rows[11] = (HASH_PICK(ip6->s6_addr[11], 0, 4) << 5) rows[11] = (HASH_PICK(ip6->s6_addr[11], 0, 4) << 5) |
| (HASH_PICK(ip6->s6_addr[12], 3, 5) << 0); (HASH_PICK(ip6->s6_addr[12], 3, 5) << 0);
rows[12] = (HASH_PICK(ip6->s6_addr[12], 0, 3) << 6) rows[12] = (HASH_PICK(ip6->s6_addr[12], 0, 3) << 6) |
| (HASH_PICK(ip6->s6_addr[13], 2, 6) << 0); (HASH_PICK(ip6->s6_addr[13], 2, 6) << 0);
rows[13] = (HASH_PICK(ip6->s6_addr[13], 0, 2) << 7) rows[13] = (HASH_PICK(ip6->s6_addr[13], 0, 2) << 7) |
| (HASH_PICK(ip6->s6_addr[14], 1, 7) << 0); (HASH_PICK(ip6->s6_addr[14], 1, 7) << 0);
if (!move_dip) { if (!move_dip) {
rows[14] = (HASH_PICK(ip6->s6_addr[14], 0, 1) << 8) rows[14] = (HASH_PICK(ip6->s6_addr[14], 0, 1) << 8) |
| (HASH_PICK(ip6->s6_addr[15], 0, 8) << 0); (HASH_PICK(ip6->s6_addr[15], 0, 8) << 0);
} }
hash = rows[0] ^ rows[1] ^ rows[2] ^ rows[3] ^ rows[4] ^ rows[5] ^ rows[6] hash = rows[0] ^ rows[1] ^ rows[2] ^ rows[3] ^ rows[4] ^
^ rows[7] ^ rows[8] ^ rows[9] ^ rows[10] ^ rows[11] ^ rows[12] rows[5] ^ rows[6] ^ rows[7] ^ rows[8] ^ rows[9] ^
^ rows[13] ^ rows[14]; rows[10] ^ rows[11] ^ rows[12] ^ rows[13] ^ rows[14];
} else { } else {
rows[11] = (HASH_PICK(ip6->s6_addr[11], 0, 4) << 5); rows[11] = (HASH_PICK(ip6->s6_addr[11], 0, 4) << 5);
rows[12] = (HASH_PICK(ip6->s6_addr[12], 3, 5) << 0); rows[12] = (HASH_PICK(ip6->s6_addr[12], 3, 5) << 0);
rows[13] = (HASH_PICK(ip6->s6_addr[12], 0, 3) << 6) rows[13] = (HASH_PICK(ip6->s6_addr[12], 0, 3) << 6) |
| HASH_PICK(ip6->s6_addr[13], 2, 6); HASH_PICK(ip6->s6_addr[13], 2, 6);
rows[14] = (HASH_PICK(ip6->s6_addr[13], 0, 2) << 7) rows[14] = (HASH_PICK(ip6->s6_addr[13], 0, 2) << 7) |
| HASH_PICK(ip6->s6_addr[14], 1, 7); HASH_PICK(ip6->s6_addr[14], 1, 7);
if (!move_dip) { if (!move_dip) {
rows[15] = (HASH_PICK(ip6->s6_addr[14], 0, 1) << 8) rows[15] = (HASH_PICK(ip6->s6_addr[14], 0, 1) << 8) |
| (HASH_PICK(ip6->s6_addr[15], 0, 8) << 0); (HASH_PICK(ip6->s6_addr[15], 0, 8) << 0);
} }
s0 = rows[12] + rows[13] + rows[14]; s0 = rows[12] + rows[13] + rows[14];
s1 = (s0 & 0x1ff) + ((s0 & (0x1ff << 9)) >> 9); s1 = (s0 & 0x1ff) + ((s0 & (0x1ff << 9)) >> 9);
pH = (s1 & 0x1ff) + ((s1 & (0x1ff << 9)) >> 9); pH = (s1 & 0x1ff) + ((s1 & (0x1ff << 9)) >> 9);
hash = rows[0] ^ rows[1] ^ rows[2] ^ rows[3] ^ rows[4] ^ rows[5] ^ rows[6] hash = rows[0] ^ rows[1] ^ rows[2] ^ rows[3] ^ rows[4] ^
^ rows[7] ^ rows[8] ^ rows[9] ^ rows[10] ^ rows[11] ^ pH ^ rows[15]; rows[5] ^ rows[6] ^ rows[7] ^ rows[8] ^ rows[9] ^
rows[10] ^ rows[11] ^ pH ^ rows[15];
} }
return hash; return hash;
} }
/* /* Read a prefix route entry from the L3_PREFIX_ROUTE_IPUC table
* Read a prefix route entry from the L3_PREFIX_ROUTE_IPUC table
* We currently only support IPv4 and IPv6 unicast route * We currently only support IPv4 and IPv6 unicast route
*/ */
static void rtl930x_route_read(int idx, struct rtl83xx_route *rt) static void rtl930x_route_read(int idx, struct rtl83xx_route *rt)
@ -1128,8 +1135,7 @@ static void rtl930x_net6_mask(int prefix_len, struct in6_addr *ip6_m)
ip6_m->s6_addr[o] |= b ? 0xff00 >> b : 0x00; ip6_m->s6_addr[o] |= b ? 0xff00 >> b : 0x00;
} }
/* /* Read a host route entry from the table using its index
* Read a host route entry from the table using its index
* We currently only support IPv4 and IPv6 unicast route * We currently only support IPv4 and IPv6 unicast route
*/ */
static void rtl930x_host_route_read(int idx, struct rtl83xx_route *rt) static void rtl930x_host_route_read(int idx, struct rtl83xx_route *rt)
@ -1181,8 +1187,7 @@ out:
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Write a host route entry from the table using its index
* Write a host route entry from the table using its index
* We currently only support IPv4 and IPv6 unicast route * We currently only support IPv4 and IPv6 unicast route
*/ */
static void rtl930x_host_route_write(int idx, struct rtl83xx_route *rt) static void rtl930x_host_route_write(int idx, struct rtl83xx_route *rt)
@ -1237,8 +1242,7 @@ out:
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Look up the index of a prefix route in the routing table CAM for unicast IPv4/6 routes
* Look up the index of a prefix route in the routing table CAM for unicast IPv4/6 routes
* using hardware offload. * using hardware offload.
*/ */
static int rtl930x_route_lookup_hw(struct rtl83xx_route *rt) static int rtl930x_route_lookup_hw(struct rtl83xx_route *rt)
@ -1317,8 +1321,7 @@ static int rtl930x_find_l3_slot(struct rtl83xx_route *rt, bool must_exist)
return -1; return -1;
} }
/* /* Write a prefix route into the routing table CAM at position idx
* Write a prefix route into the routing table CAM at position idx
* Currently only IPv4 and IPv6 unicast routes are supported * Currently only IPv4 and IPv6 unicast routes are supported
*/ */
static void rtl930x_route_write(int idx, struct rtl83xx_route *rt) static void rtl930x_route_write(int idx, struct rtl83xx_route *rt)
@ -1400,8 +1403,7 @@ static void rtl930x_route_write(int idx, struct rtl83xx_route *rt)
} }
/* /* Get the destination MAC and L3 egress interface ID of a nexthop entry from
* Get the destination MAC and L3 egress interface ID of a nexthop entry from
* the SoC's L3_NEXTHOP table * the SoC's L3_NEXTHOP table
*/ */
static void rtl930x_get_l3_nexthop(int idx, u16 *dmac_id, u16 *interface) static void rtl930x_get_l3_nexthop(int idx, u16 *dmac_id, u16 *interface)
@ -1467,9 +1469,7 @@ static int rtl930x_l3_mtu_add(struct rtl838x_switch_priv *priv, int mtu)
return mtu_id; return mtu_id;
} }
/* /* Creates an interface for a route by setting up the HW tables in the SoC */
* Creates an interface for a route by setting up the HW tables in the SoC
*/
static int rtl930x_l3_intf_add(struct rtl838x_switch_priv *priv, struct rtl838x_l3_intf *intf) static int rtl930x_l3_intf_add(struct rtl838x_switch_priv *priv, struct rtl838x_l3_intf *intf)
{ {
int i, intf_id, mtu_id; int i, intf_id, mtu_id;
@ -1501,8 +1501,7 @@ static int rtl930x_l3_intf_add(struct rtl838x_switch_priv *priv, struct rtl838x_
} }
} }
/* /* Set the destination MAC and L3 egress interface ID for a nexthop entry in the SoC's
* Set the destination MAC and L3 egress interface ID for a nexthop entry in the SoC's
* L3_NEXTHOP table. The nexthop entry is identified by idx. * L3_NEXTHOP table. The nexthop entry is identified by idx.
* dmac_id is the reference to the L2 entry in the L2 forwarding table, special values are * dmac_id is the reference to the L2 entry in the L2 forwarding table, special values are
* 0x7ffe: TRAP2CPU * 0x7ffe: TRAP2CPU
@ -1530,8 +1529,7 @@ static void rtl930x_pie_lookup_enable(struct rtl838x_switch_priv *priv, int inde
sw_w32_mask(0, BIT(block), RTL930X_PIE_BLK_LOOKUP_CTRL); sw_w32_mask(0, BIT(block), RTL930X_PIE_BLK_LOOKUP_CTRL);
} }
/* /* 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 * PIE rule in the pie_rule structure and fills in the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1624,7 +1622,6 @@ static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->sip_m >> 16; data_m = pr->sip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_SIP2: case TEMPLATE_FIELD_SIP2:
case TEMPLATE_FIELD_SIP3: case TEMPLATE_FIELD_SIP3:
case TEMPLATE_FIELD_SIP4: case TEMPLATE_FIELD_SIP4:
@ -1634,7 +1631,6 @@ static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
break; break;
case TEMPLATE_FIELD_DIP0: case TEMPLATE_FIELD_DIP0:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[7]; data = pr->dip6.s6_addr16[7];
@ -1644,7 +1640,6 @@ static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m; data_m = pr->dip_m;
} }
break; break;
case TEMPLATE_FIELD_DIP1: case TEMPLATE_FIELD_DIP1:
if (pr->is_ipv6) { if (pr->is_ipv6) {
data = pr->dip6.s6_addr16[6]; data = pr->dip6.s6_addr16[6];
@ -1654,7 +1649,6 @@ static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data_m = pr->dip_m >> 16; data_m = pr->dip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_DIP2: case TEMPLATE_FIELD_DIP2:
case TEMPLATE_FIELD_DIP3: case TEMPLATE_FIELD_DIP3:
case TEMPLATE_FIELD_DIP4: case TEMPLATE_FIELD_DIP4:
@ -1664,7 +1658,6 @@ static void rtl930x_write_pie_templated(u32 r[], struct pie_rule *pr, enum templ
data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
break; break;
case TEMPLATE_FIELD_IP_TOS_PROTO: case TEMPLATE_FIELD_IP_TOS_PROTO:
data = pr->tos_proto; data = pr->tos_proto;
data_m = pr->tos_proto_m; data_m = pr->tos_proto_m;
@ -1900,8 +1893,7 @@ static bool rtl930x_pie_templ_has(int t, enum template_field_id field_type)
return false; 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 * Note that this function is SoC specific since the values of e.g. TEMPLATE_FIELD_SIP0
* depend on the SoC * depend on the SoC
*/ */
@ -1917,13 +1909,17 @@ static int rtl930x_pie_verify_template(struct rtl838x_switch_priv *priv,
return -1; return -1;
if (pr->is_ipv6) { if (pr->is_ipv6) {
if ((pr->sip6_m.s6_addr32[0] || pr->sip6_m.s6_addr32[1] if ((pr->sip6_m.s6_addr32[0] ||
|| pr->sip6_m.s6_addr32[2] || pr->sip6_m.s6_addr32[3]) pr->sip6_m.s6_addr32[1] ||
&& !rtl930x_pie_templ_has(t, TEMPLATE_FIELD_SIP2)) pr->sip6_m.s6_addr32[2] ||
pr->sip6_m.s6_addr32[3]) &&
!rtl930x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
return -1; return -1;
if ((pr->dip6_m.s6_addr32[0] || pr->dip6_m.s6_addr32[1] if ((pr->dip6_m.s6_addr32[0] ||
|| pr->dip6_m.s6_addr32[2] || pr->dip6_m.s6_addr32[3]) pr->dip6_m.s6_addr32[1] ||
&& !rtl930x_pie_templ_has(t, TEMPLATE_FIELD_DIP2)) pr->dip6_m.s6_addr32[2] ||
pr->dip6_m.s6_addr32[3]) &&
!rtl930x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
return -1; return -1;
} }
@ -1991,9 +1987,7 @@ static int rtl930x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
return 0; return 0;
} }
/* /* Delete a range of Packet Inspection Engine rules */
* Delete a range of Packet Inspection Engine rules
*/
static int rtl930x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to) static int rtl930x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from, int index_to)
{ {
u32 v = (index_from << 1)| (index_to << 12 ) | BIT(0); u32 v = (index_from << 1)| (index_to << 12 ) | BIT(0);
@ -2063,8 +2057,7 @@ static void rtl930x_pie_init(struct rtl838x_switch_priv *priv)
} }
/* /* Sets up an egress interface for L3 actions
* Sets up an egress interface for L3 actions
* Actions for ip4/6_icmp_redirect, ip4/6_pbr_icmp_redirect are: * Actions for ip4/6_icmp_redirect, ip4/6_pbr_icmp_redirect are:
* 0: FORWARD, 1: DROP, 2: TRAP2CPU, 3: COPY2CPU, 4: TRAP2MASTERCPU 5: COPY2MASTERCPU * 0: FORWARD, 1: DROP, 2: TRAP2CPU, 3: COPY2CPU, 4: TRAP2MASTERCPU 5: COPY2MASTERCPU
* 6: HARDDROP * 6: HARDDROP
@ -2097,8 +2090,7 @@ static void rtl930x_set_l3_egress_intf(int idx, struct rtl838x_l3_intf *intf)
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Reads a MAC entry for L3 termination as entry point for routing
* Reads a MAC entry for L3 termination as entry point for routing
* from the hardware table * from the hardware table
* idx is the index into the L3_ROUTER_MAC table * idx is the index into the L3_ROUTER_MAC table
*/ */
@ -2121,18 +2113,17 @@ static void rtl930x_get_l3_router_mac(u32 idx, struct rtl93xx_rt_mac *m)
m->vid = v & 0xfff; m->vid = v & 0xfff;
m->vid_mask = w & 0xfff; m->vid_mask = w & 0xfff;
m->action = sw_r32(rtl_table_data(r, 6)) & 0x7; m->action = sw_r32(rtl_table_data(r, 6)) & 0x7;
m->mac_mask = ((((u64)sw_r32(rtl_table_data(r, 5))) << 32) & 0xffffffffffffULL) m->mac_mask = ((((u64)sw_r32(rtl_table_data(r, 5))) << 32) & 0xffffffffffffULL) |
| (sw_r32(rtl_table_data(r, 4))); (sw_r32(rtl_table_data(r, 4)));
m->mac = ((((u64)sw_r32(rtl_table_data(r, 1))) << 32) & 0xffffffffffffULL) m->mac = ((((u64)sw_r32(rtl_table_data(r, 1))) << 32) & 0xffffffffffffULL) |
| (sw_r32(rtl_table_data(r, 2))); (sw_r32(rtl_table_data(r, 2)));
// Bits L3_INTF and BMSK_L3_INTF are 0 // Bits L3_INTF and BMSK_L3_INTF are 0
out: out:
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Writes a MAC entry for L3 termination as entry point for routing
* Writes a MAC entry for L3 termination as entry point for routing
* into the hardware table * into the hardware table
* idx is the index into the L3_ROUTER_MAC table * idx is the index into the L3_ROUTER_MAC table
*/ */
@ -2172,8 +2163,7 @@ static void rtl930x_set_l3_router_mac(u32 idx, struct rtl93xx_rt_mac *m)
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Get the Destination-MAC of an L3 egress interface or the Source MAC for routed packets
* Get the Destination-MAC of an L3 egress interface or the Source MAC for routed packets
* from the SoC's L3_EGR_INTF_MAC table * from the SoC's L3_EGR_INTF_MAC table
* Indexes 0-2047 are DMACs, 2048+ are SMACs * Indexes 0-2047 are DMACs, 2048+ are SMACs
*/ */
@ -2192,8 +2182,8 @@ static u64 rtl930x_get_l3_egress_mac(u32 idx)
return mac; return mac;
} }
/*
* Set the Destination-MAC of a route or the Source MAC of an L3 egress interface /* Set the Destination-MAC of a route or the Source MAC of an L3 egress interface
* in the SoC's L3_EGR_INTF_MAC table * in the SoC's L3_EGR_INTF_MAC table
* Indexes 0-2047 are DMACs, 2048+ are SMACs * Indexes 0-2047 are DMACs, 2048+ are SMACs
*/ */
@ -2211,8 +2201,7 @@ static void rtl930x_set_l3_egress_mac(u32 idx, u64 mac)
rtl_table_release(r); rtl_table_release(r);
} }
/* /* Configure L3 routing settings of the device:
* Configure L3 routing settings of the device:
* - MTUs * - MTUs
* - Egress interface * - Egress interface
* - The router's MAC address on which routed packets are expected * - The router's MAC address on which routed packets are expected
@ -2425,7 +2414,7 @@ static void rtl930x_led_init(struct rtl838x_switch_priv *priv)
return; return;
} }
for (i= 0; i < priv->cpu_port; i++) { for (i = 0; i < priv->cpu_port; i++) {
pos = (i << 1) % 32; pos = (i << 1) % 32;
sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i)); sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i));
sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i)); sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i));

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
#define RTL931X_VLAN_PORT_TAG_STS_INTERNAL 0x0 #define RTL931X_VLAN_PORT_TAG_STS_INTERNAL 0x0
@ -142,12 +143,12 @@ void rtl931x_vlan_profile_dump(int index)
return; return;
profile[0] = sw_r32(RTL931X_VLAN_PROFILE_SET(index)); profile[0] = sw_r32(RTL931X_VLAN_PROFILE_SET(index));
profile[1] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 4) & 0x1FFFFFFFULL) << 32 profile[1] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 4) & 0x1FFFFFFFULL) << 32 |
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 8) & 0xFFFFFFFF); (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 8) & 0xFFFFFFFF);
profile[2] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFFULL) << 32 profile[2] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFFULL) << 32 |
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 12) & 0xFFFFFFFF); (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 12) & 0xFFFFFFFF);
profile[3] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 20) & 0x1FFFFFFFULL) << 32 profile[3] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 20) & 0x1FFFFFFFULL) << 32 |
| (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 24) & 0xFFFFFFFF); (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 24) & 0xFFFFFFFF);
pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %llx, \ pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %llx, \
IPv4 Unknown MultiCast Field %llx, IPv6 Unknown MultiCast Field: %llx", IPv4 Unknown MultiCast Field %llx, IPv6 Unknown MultiCast Field: %llx",
@ -157,10 +158,10 @@ void rtl931x_vlan_profile_dump(int index)
static void rtl931x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl931x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 20 /* Execute cmd */ u32 cmd = 1 << 20 | /* Execute cmd */
| 0 << 19 /* Read */ 0 << 19 | /* Read */
| 5 << 15 /* Table type 0b101 */ 5 << 15 | /* Table type 0b101 */
| (msti & 0x3fff); (msti & 0x3fff);
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -170,10 +171,10 @@ static void rtl931x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port
static void rtl931x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) static void rtl931x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
{ {
int i; int i;
u32 cmd = 1 << 20 /* Execute cmd */ u32 cmd = 1 << 20 | /* Execute cmd */
| 1 << 19 /* Write */ 1 << 19 | /* Write */
| 5 << 15 /* Table type 0b101 */ 5 << 15 | /* Table type 0b101 */
| (msti & 0x3fff); (msti & 0x3fff);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); sw_w32(port_state[i], priv->r->tbl_access_data_0(i));
priv->r->exec_tbl0_cmd(cmd); priv->r->exec_tbl0_cmd(cmd);
@ -316,6 +317,7 @@ irqreturn_t rtl931x_switch_irq(int irq, void *dev_id)
} }
} }
} }
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -352,6 +354,7 @@ int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val)
err = -EIO; err = -EIO;
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
@ -380,12 +383,11 @@ int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
__func__, port, page, reg, *val, v); __func__, port, page, reg, *val, v);
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return 0; 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 rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
{ {
int err = 0; int err = 0;
@ -427,9 +429,7 @@ int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
return err; 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 rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
{ {
int err = 0; int err = 0;
@ -460,6 +460,7 @@ 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__, pr_debug("%s: port %d, dev: %x, regnum: %x, val: %x (err %d)\n", __func__,
port, devnum, mdiobus_c45_regad(regnum), val, err); port, devnum, mdiobus_c45_regad(regnum), val, err);
mutex_unlock(&smi_lock); mutex_unlock(&smi_lock);
return err; return err;
} }
@ -538,12 +539,12 @@ u64 rtl931x_traffic_get(int source)
rtl_table_read(r, source); rtl_table_read(r, source);
v = sw_r32(rtl_table_data(r, 0)); v = sw_r32(rtl_table_data(r, 0));
rtl_table_release(r); 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) void rtl931x_traffic_set(int source, u64 dest_matrix)
{ {
struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 6); struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 6);
@ -581,8 +582,7 @@ static u64 rtl931x_l2_hash_seed(u64 mac, u32 vid)
return v; 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 * 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 * both hashes in the lower and higher word of the return value since only 12 bit of
* the hash are significant. * the hash are significant.
@ -629,9 +629,7 @@ static u32 rtl931x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
return h; 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) static void rtl931x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
{ {
pr_debug("In %s valid?\n", __func__); pr_debug("In %s valid?\n", __func__);
@ -697,9 +695,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) static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
{ {
u32 port; u32 port;
@ -711,9 +707,12 @@ static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
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 r[0] = ((u32)e->mac[0]) << 24 |
| ((u32)e->mac[2]) << 8 | ((u32)e->mac[3]); ((u32)e->mac[1]) << 16 |
r[1] = ((u32)e->mac[4]) << 24 | ((u32)e->mac[5]) << 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; r[2] |= e->next_hop ? BIT(12) : 0;
@ -744,8 +743,7 @@ static void rtl931x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
} }
} }
/* /* 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 * 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 * The data read from the SoC is filled into rtl838x_l2_entry
*/ */
@ -762,7 +760,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 /* 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 * 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) { if (pos >= 4) {
pos -= 4; pos -= 4;
hash >>= 16; hash >>= 16;
@ -785,18 +784,23 @@ static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2
if (!e->valid) if (!e->valid)
return 0; return 0;
mac = ((u64)e->mac[0]) << 40 | ((u64)e->mac[1]) << 32 | ((u64)e->mac[2]) << 24 mac = ((u64)e->mac[0]) << 40 |
| ((u64)e->mac[3]) << 16 | ((u64)e->mac[4]) << 8 | ((u64)e->mac[5]); ((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); seed = rtl931x_l2_hash_seed(mac, e->rvid);
pr_debug("%s: mac %016llx, seed %016llx\n", __func__, mac, seed); 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; return seed;
} }
static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e) 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) static void rtl931x_write_cam(int idx, struct rtl838x_l2_entry *e)
@ -817,12 +821,11 @@ static void rtl931x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_
rtl931x_fill_l2_row(r, e); rtl931x_fill_l2_row(r, e);
pr_info("%s: %d: %08x %08x %08x\n", __func__, idx, r[0], r[1], r[2]); pr_info("%s: %d: %08x %08x %08x\n", __func__, idx, r[0], r[1], r[2]);
for (i= 0; i < 4; i++) for (i = 0; i < 4; i++)
sw_w32(r[i], rtl_table_data(q, i)); sw_w32(r[i], rtl_table_data(q, i));
rtl_table_write(q, idx); rtl_table_write(q, idx);
rtl_table_release(q); rtl_table_release(q);
} }
static void rtl931x_vlan_fwd_on_inner(int port, bool is_set) static void rtl931x_vlan_fwd_on_inner(int port, bool is_set)
@ -857,7 +860,7 @@ static void rtl931x_vlan_profile_setup(int profile)
p[5] = 0x1FFFFFF; // IPv6 unknwon MC flooding portmask p[5] = 0x1FFFFFF; // IPv6 unknwon MC flooding portmask
p[6] = 0xFFFFFFFF; 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); sw_w32(p[i], RTL931X_VLAN_PROFILE_SET(profile) + i * 4);
pr_info("Leaving %s\n", __func__); pr_info("Leaving %s\n", __func__);
} }
@ -888,6 +891,7 @@ static u64 rtl931x_read_mcast_pmask(int idx)
rtl_table_release(q); rtl_table_release(q);
pr_debug("%s: Index idx %d has portmask %016llx\n", __func__, idx, portmask); pr_debug("%s: Index idx %d has portmask %016llx\n", __func__, idx, portmask);
return portmask; return portmask;
} }
@ -919,6 +923,7 @@ static int rtl931x_set_ageing_time(unsigned long msec)
t = t > 0x1FFFFF ? 0x1FFFFF : t; t = t > 0x1FFFFF ? 0x1FFFFF : t;
sw_w32_mask(0x1FFFFF, t, RTL931X_L2_AGE_CTRL); sw_w32_mask(0x1FFFFF, t, RTL931X_L2_AGE_CTRL);
pr_debug("Dynamic aging for ports: %x\n", sw_r32(RTL931X_L2_PORT_AGE_CTRL)); pr_debug("Dynamic aging for ports: %x\n", sw_r32(RTL931X_L2_PORT_AGE_CTRL));
return 0; return 0;
} }
void rtl931x_sw_init(struct rtl838x_switch_priv *priv) void rtl931x_sw_init(struct rtl838x_switch_priv *priv)
@ -933,8 +938,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); 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 * into a data field for a given template field field_type
* TODO: This function looks very similar to the function of the rtl9300, but * 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 * since it uses the physical template_field_id, which are different for each
@ -1031,7 +1035,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 = pr->sip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
*data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)]; *data_m = pr->sip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_SIP2)];
break; break;
case TEMPLATE_FIELD_DIP0: case TEMPLATE_FIELD_DIP0:
if (pr->is_ipv6) { if (pr->is_ipv6) {
*data = pr->dip6.s6_addr16[7]; *data = pr->dip6.s6_addr16[7];
@ -1050,7 +1053,6 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
*data_m = pr->dip_m >> 16; *data_m = pr->dip_m >> 16;
} }
break; break;
case TEMPLATE_FIELD_DIP2: case TEMPLATE_FIELD_DIP2:
case TEMPLATE_FIELD_DIP3: case TEMPLATE_FIELD_DIP3:
case TEMPLATE_FIELD_DIP4: case TEMPLATE_FIELD_DIP4:
@ -1060,7 +1062,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 = pr->dip6.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
*data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)]; *data_m = pr->dip6_m.s6_addr16[5 - (field_type - TEMPLATE_FIELD_DIP2)];
break; break;
case TEMPLATE_FIELD_IP_TOS_PROTO: case TEMPLATE_FIELD_IP_TOS_PROTO:
*data = pr->tos_proto; *data = pr->tos_proto;
*data_m = pr->tos_proto_m; *data_m = pr->tos_proto_m;
@ -1092,8 +1093,7 @@ int rtl931x_pie_data_fill(enum template_field_id field_type, struct pie_rule *pr
return 0; 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 * PIE rule in the pie_rule structure and fills in the raw data fields in the
* raw register space r[]. * raw register space r[].
* The register space configuration size is identical for the RTL8380/90 and RTL9300, * The register space configuration size is identical for the RTL8380/90 and RTL9300,
@ -1310,8 +1310,7 @@ static bool rtl931x_pie_templ_has(int t, enum template_field_id field_type)
return false; 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 * Note that this function is SoC specific since the values of e.g. TEMPLATE_FIELD_SIP0
* depend on the SoC * depend on the SoC
*/ */
@ -1327,13 +1326,17 @@ static int rtl931x_pie_verify_template(struct rtl838x_switch_priv *priv,
return -1; return -1;
if (pr->is_ipv6) { if (pr->is_ipv6) {
if ((pr->sip6_m.s6_addr32[0] || pr->sip6_m.s6_addr32[1] if ((pr->sip6_m.s6_addr32[0] ||
|| pr->sip6_m.s6_addr32[2] || pr->sip6_m.s6_addr32[3]) pr->sip6_m.s6_addr32[1] ||
&& !rtl931x_pie_templ_has(t, TEMPLATE_FIELD_SIP2)) pr->sip6_m.s6_addr32[2] ||
pr->sip6_m.s6_addr32[3]) &&
!rtl931x_pie_templ_has(t, TEMPLATE_FIELD_SIP2))
return -1; return -1;
if ((pr->dip6_m.s6_addr32[0] || pr->dip6_m.s6_addr32[1] if ((pr->dip6_m.s6_addr32[0] ||
|| pr->dip6_m.s6_addr32[2] || pr->dip6_m.s6_addr32[3]) pr->dip6_m.s6_addr32[1] ||
&& !rtl931x_pie_templ_has(t, TEMPLATE_FIELD_DIP2)) pr->dip6_m.s6_addr32[2] ||
pr->dip6_m.s6_addr32[3]) &&
!rtl931x_pie_templ_has(t, TEMPLATE_FIELD_DIP2))
return -1; return -1;
} }
@ -1398,12 +1401,11 @@ static int rtl931x_pie_rule_add(struct rtl838x_switch_priv *priv, struct pie_rul
rtl931x_pie_rule_write(priv, idx, pr); rtl931x_pie_rule_write(priv, idx, pr);
mutex_unlock(&priv->pie_mutex); mutex_unlock(&priv->pie_mutex);
return 0; 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) 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); u32 v = (index_from << 1)| (index_to << 13 ) | BIT(0);
@ -1419,6 +1421,7 @@ static int rtl931x_pie_rule_del(struct rtl838x_switch_priv *priv, int index_from
} while (sw_r32(RTL931X_PIE_CLR_CTRL) & BIT(0)); } while (sw_r32(RTL931X_PIE_CLR_CTRL) & BIT(0));
mutex_unlock(&priv->reg_mutex); mutex_unlock(&priv->reg_mutex);
return 0; return 0;
} }
@ -1533,7 +1536,7 @@ void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
u32 newmask = 0; u32 newmask = 0;
/* TODO: for now we set algoidx to 0 */ /* TODO: for now we set algoidx to 0 */
algoidx=0; algoidx = 0;
if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) { if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) {
l3shift = 4; l3shift = 4;
@ -1584,7 +1587,7 @@ static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
return; return;
} }
for (i= 0; i < priv->cpu_port; i++) { for (i = 0; i < priv->cpu_port; i++) {
pos = (i << 1) % 32; pos = (i << 1) % 32;
sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i)); 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)); sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
@ -1626,7 +1629,6 @@ static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
pr_info("%s %08x: %08x\n",__func__, 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4)); pr_info("%s %08x: %08x\n",__func__, 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4));
} }
const struct rtl838x_reg rtl931x_reg = { const struct rtl838x_reg rtl931x_reg = {
@ -1698,4 +1700,3 @@ const struct rtl838x_reg rtl931x_reg = {
.l3_setup = rtl931x_l3_setup, .l3_setup = rtl931x_l3_setup,
.led_init = rtl931x_led_init, .led_init = rtl931x_led_init,
}; };

View file

@ -5,14 +5,12 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <net/flow_offload.h> #include <net/flow_offload.h>
#include <linux/rhashtable.h> #include <linux/rhashtable.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h> #include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h" #include "rtl83xx.h"
#include "rtl838x.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, static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
struct flow_rule *rule, struct rtl83xx_flow *flow) 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; flow->rule.frame_type_l4 = 0;
if (match.key->ip_proto == IPPROTO_TCP) if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 1; flow->rule.frame_type_l4 = 1;
if (match.key->ip_proto == IPPROTO_ICMP if (match.key->ip_proto == IPPROTO_ICMP || match.key->ip_proto == IPPROTO_ICMPV6)
|| match.key->ip_proto ==IPPROTO_ICMPV6)
flow->rule.frame_type_l4 = 2; flow->rule.frame_type_l4 = 2;
if (match.key->ip_proto == IPPROTO_TCP) if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 3; flow->rule.frame_type_l4 = 3;
@ -288,6 +285,7 @@ out_free:
kfree(flow); kfree(flow);
out: out:
pr_err("%s: error %d\n", __func__, err); pr_err("%s: error %d\n", __func__, err);
return err; return err;
} }
@ -311,6 +309,7 @@ static int rtl83xx_delete_flower(struct rtl838x_switch_priv *priv,
kfree_rcu(flow, rcu_head); kfree_rcu(flow, rcu_head);
rcu_read_unlock(); rcu_read_unlock();
return 0; return 0;
} }
@ -335,7 +334,8 @@ static int rtl83xx_stats_flower(struct rtl838x_switch_priv *priv,
// 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_stats_update(&cls_flower->stats, 100 * new_packets, new_packets, 0, lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE); FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0; return 0;
} }

View file

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /* linux/drivers/net/ethernet/rtl838x_eth.c
* linux/drivers/net/ethernet/rtl838x_eth.c
* Copyright (C) 2020 B. Koblitz * Copyright (C) 2020 B. Koblitz
*/ */
@ -26,8 +25,7 @@
extern struct rtl83xx_soc_info soc_info; extern struct rtl83xx_soc_info soc_info;
/* /* Maximum number of RX rings is 8 on RTL83XX and 32 on the 93XX
* Maximum number of RX rings is 8 on RTL83XX and 32 on the 93XX
* The ring is assigned by switch based on packet/port priortity * The ring is assigned by switch based on packet/port priortity
* Maximum number of TX rings is 2, Ring 2 being the high priority * Maximum number of TX rings is 2, Ring 2 being the high priority
* ring on the RTL93xx SoCs. MAX_RXLEN gives the maximum length * ring on the RTL93xx SoCs. MAX_RXLEN gives the maximum length
@ -179,9 +177,9 @@ struct rtl838x_rx_q {
struct rtl838x_eth_priv { struct rtl838x_eth_priv {
struct net_device *netdev; struct net_device *netdev;
struct platform_device *pdev; struct platform_device *pdev;
void *membase; void *membase;
spinlock_t lock; spinlock_t lock;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
struct rtl838x_rx_q rx_qs[MAX_RXRINGS]; struct rtl838x_rx_q rx_qs[MAX_RXRINGS];
struct phylink *phylink; struct phylink *phylink;
struct phylink_config phylink_config; struct phylink_config phylink_config;
@ -213,8 +211,7 @@ extern int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
extern int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); extern int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
extern int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val); extern int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
/* /* On the RTL93XX, the RTL93XX_DMA_IF_RX_RING_CNTR track the fill level of
* On the RTL93XX, the RTL93XX_DMA_IF_RX_RING_CNTR track the fill level of
* the rings. Writing x into these registers substracts x from its content. * the rings. Writing x into these registers substracts x from its content.
* When the content reaches the ring size, the ASIC no longer adds * When the content reaches the ring size, the ASIC no longer adds
* packets to this receive queue. * packets to this receive queue.
@ -329,8 +326,7 @@ bool rtl931x_decode_tag(struct p_hdr *h, struct dsa_tag *t)
return t->l2_offloaded; return t->l2_offloaded;
} }
/* /* Discard the RX ring-buffers, called as part of the net-ISR
* Discard the RX ring-buffers, called as part of the net-ISR
* when the buffer runs over * when the buffer runs over
*/ */
static void rtl838x_rb_cleanup(struct rtl838x_eth_priv *priv, int status) static void rtl838x_rb_cleanup(struct rtl838x_eth_priv *priv, int status)
@ -349,15 +345,16 @@ static void rtl838x_rb_cleanup(struct rtl838x_eth_priv *priv, int status)
pr_debug("Got something: %d\n", ring->c_rx[r]); pr_debug("Got something: %d\n", ring->c_rx[r]);
h = &ring->rx_header[r][ring->c_rx[r]]; h = &ring->rx_header[r][ring->c_rx[r]];
memset(h, 0, sizeof(struct p_hdr)); memset(h, 0, sizeof(struct p_hdr));
h->buf = (u8 *)KSEG1ADDR(ring->rx_space h->buf = (u8 *)KSEG1ADDR(ring->rx_space +
+ r * priv->rxringlen * RING_BUFFER r * priv->rxringlen * RING_BUFFER +
+ ring->c_rx[r] * RING_BUFFER); ring->c_rx[r] * RING_BUFFER);
h->size = RING_BUFFER; h->size = RING_BUFFER;
/* make sure the header is visible to the ASIC */ /* make sure the header is visible to the ASIC */
mb(); mb();
ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 | (ring->c_rx[r] == (priv->rxringlen - 1) ?
| (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP : 0x1); WRAP :
0x1);
ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen; ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen;
} while (&ring->rx_r[r][ring->c_rx[r]] != last); } while (&ring->rx_r[r][ring->c_rx[r]] != last);
} }
@ -520,7 +517,7 @@ static irqreturn_t rtl93xx_net_irq(int irq, void *dev_id)
/* RX buffer overrun */ /* RX buffer overrun */
if (status_rx_r) { if (status_rx_r) {
pr_debug("RX buffer overrun: status %x, mask: %x\n", pr_debug("RX buffer overrun: status %x, mask: %x\n",
status_rx_r, sw_r32(priv->r->dma_if_intr_rx_runout_msk)); status_rx_r, sw_r32(priv->r->dma_if_intr_rx_runout_msk));
sw_w32(status_rx_r, priv->r->dma_if_intr_rx_runout_sts); sw_w32(status_rx_r, priv->r->dma_if_intr_rx_runout_sts);
rtl838x_rb_cleanup(priv, status_rx_r); rtl838x_rb_cleanup(priv, status_rx_r);
} }
@ -699,7 +696,7 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv)
pos = (i % 3) * 10; pos = (i % 3) * 10;
sw_w32_mask(0x3ff << pos, 0, priv->r->dma_if_rx_ring_size(i)); sw_w32_mask(0x3ff << pos, 0, priv->r->dma_if_rx_ring_size(i));
sw_w32_mask(0x3ff << pos, priv->rxringlen, sw_w32_mask(0x3ff << pos, priv->rxringlen,
priv->r->dma_if_rx_ring_cntr(i)); priv->r->dma_if_rx_ring_cntr(i));
} }
} }
@ -821,20 +818,20 @@ static void rtl93xx_hw_en_rxtx(struct rtl838x_eth_priv *priv)
static void rtl838x_setup_ring_buffer(struct rtl838x_eth_priv *priv, struct ring_b *ring) static void rtl838x_setup_ring_buffer(struct rtl838x_eth_priv *priv, struct ring_b *ring)
{ {
int i, j; int i, j;
struct p_hdr *h; struct p_hdr *h;
for (i = 0; i < priv->rxrings; i++) { for (i = 0; i < priv->rxrings; i++) {
for (j = 0; j < priv->rxringlen; j++) { for (j = 0; j < priv->rxringlen; j++) {
h = &ring->rx_header[i][j]; h = &ring->rx_header[i][j];
memset(h, 0, sizeof(struct p_hdr)); memset(h, 0, sizeof(struct p_hdr));
h->buf = (u8 *)KSEG1ADDR(ring->rx_space h->buf = (u8 *)KSEG1ADDR(ring->rx_space +
+ i * priv->rxringlen * RING_BUFFER i * priv->rxringlen * RING_BUFFER +
+ j * RING_BUFFER); j * RING_BUFFER);
h->size = RING_BUFFER; h->size = RING_BUFFER;
/* All rings owned by switch, last one wraps */ /* All rings owned by switch, last one wraps */
ring->rx_r[i][j] = KSEG1ADDR(h) | 1 ring->rx_r[i][j] = KSEG1ADDR(h) | 1 | (j == (priv->rxringlen - 1) ?
| (j == (priv->rxringlen - 1) ? WRAP : 0); WRAP :
0);
} }
ring->c_rx[i] = 0; ring->c_rx[i] = 0;
} }
@ -843,14 +840,14 @@ static void rtl838x_setup_ring_buffer(struct rtl838x_eth_priv *priv, struct ring
for (j = 0; j < TXRINGLEN; j++) { for (j = 0; j < TXRINGLEN; j++) {
h = &ring->tx_header[i][j]; h = &ring->tx_header[i][j];
memset(h, 0, sizeof(struct p_hdr)); memset(h, 0, sizeof(struct p_hdr));
h->buf = (u8 *)KSEG1ADDR(ring->tx_space h->buf = (u8 *)KSEG1ADDR(ring->tx_space +
+ i * TXRINGLEN * RING_BUFFER i * TXRINGLEN * RING_BUFFER +
+ j * RING_BUFFER); j * RING_BUFFER);
h->size = RING_BUFFER; h->size = RING_BUFFER;
ring->tx_r[i][j] = KSEG1ADDR(&ring->tx_header[i][j]); ring->tx_r[i][j] = KSEG1ADDR(&ring->tx_header[i][j]);
} }
/* Last header is wrapping around */ /* Last header is wrapping around */
ring->tx_r[i][j-1] |= WRAP; ring->tx_r[i][j - 1] |= WRAP;
ring->c_tx[i] = 0; ring->c_tx[i] = 0;
} }
} }
@ -1032,8 +1029,7 @@ static int rtl838x_eth_stop(struct net_device *ndev)
static void rtl838x_eth_set_multicast_list(struct net_device *ndev) static void rtl838x_eth_set_multicast_list(struct net_device *ndev)
{ {
/* /* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* CTRL_0_FULL = GENMASK(21, 0) = 0x3FFFFF * CTRL_0_FULL = GENMASK(21, 0) = 0x3FFFFF
*/ */
if (!(ndev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { if (!(ndev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
@ -1050,8 +1046,7 @@ static void rtl838x_eth_set_multicast_list(struct net_device *ndev)
static void rtl839x_eth_set_multicast_list(struct net_device *ndev) static void rtl839x_eth_set_multicast_list(struct net_device *ndev)
{ {
/* /* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC * CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC
* Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00 * Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00
* CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0) * CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0)
@ -1077,8 +1072,7 @@ static void rtl839x_eth_set_multicast_list(struct net_device *ndev)
static void rtl930x_eth_set_multicast_list(struct net_device *ndev) static void rtl930x_eth_set_multicast_list(struct net_device *ndev)
{ {
/* /* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC * CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC
* Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00 * Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00
* CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0) * CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0)
@ -1096,8 +1090,7 @@ static void rtl930x_eth_set_multicast_list(struct net_device *ndev)
static void rtl931x_eth_set_multicast_list(struct net_device *ndev) static void rtl931x_eth_set_multicast_list(struct net_device *ndev)
{ {
/* /* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* Flood all classes of RMA addresses (01-80-C2-00-00-{01..2F})
* CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC * CTRL_0_FULL = GENMASK(31, 2) = 0xFFFFFFFC
* Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00. * Lower two bits are reserved, corresponding to RMA 01-80-C2-00-00-00.
* CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0) * CTRL_1_FULL = CTRL_2_FULL = GENMASK(31, 0)
@ -1147,13 +1140,14 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
len = skb->len; len = skb->len;
/* Check for DSA tagging at the end of the buffer */ /* Check for DSA tagging at the end of the buffer */
if (netdev_uses_dsa(dev) && skb->data[len-4] == 0x80 if (netdev_uses_dsa(dev) &&
&& skb->data[len-3] < priv->cpu_port skb->data[len - 4] == 0x80 &&
&& skb->data[len-2] == 0x10 skb->data[len - 3] < priv->cpu_port &&
&& skb->data[len-1] == 0x00) { skb->data[len - 2] == 0x10 &&
skb->data[len - 1] == 0x00) {
/* Reuse tag space for CRC if possible */ /* Reuse tag space for CRC if possible */
dest_port = skb->data[len-3]; dest_port = skb->data[len - 3];
skb->data[len-4] = skb->data[len-3] = skb->data[len-2] = skb->data[len-1] = 0x00; skb->data[len - 4] = skb->data[len - 3] = skb->data[len - 2] = skb->data[len - 1] = 0x00;
len -= 4; len -= 4;
} }
@ -1198,8 +1192,7 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
} }
/* Tell switch to send data */ /* Tell switch to send data */
if (priv->family_id == RTL9310_FAMILY_ID if (priv->family_id == RTL9310_FAMILY_ID || priv->family_id == RTL9300_FAMILY_ID) {
|| priv->family_id == RTL9300_FAMILY_ID) {
// Ring ID q == 0: Low priority, Ring ID = 1: High prio queue // Ring ID q == 0: Low priority, Ring ID = 1: High prio queue
if (!q) if (!q)
sw_w32_mask(0, BIT(2), priv->r->dma_if_ctrl); sw_w32_mask(0, BIT(2), priv->r->dma_if_ctrl);
@ -1218,13 +1211,14 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev)
dev_warn(&priv->pdev->dev, "Data is owned by switch\n"); dev_warn(&priv->pdev->dev, "Data is owned by switch\n");
ret = NETDEV_TX_BUSY; ret = NETDEV_TX_BUSY;
} }
txdone: txdone:
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
return ret; return ret;
} }
/* /* Return queue number for TX. On the RTL83XX, these queues have equal priority
* Return queue number for TX. On the RTL83XX, these queues have equal priority
* so we do round-robin * so we do round-robin
*/ */
u16 rtl83xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb, u16 rtl83xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb,
@ -1236,14 +1230,14 @@ u16 rtl83xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb,
return last % TXRINGS; return last % TXRINGS;
} }
/* /* Return queue number for TX. On the RTL93XX, queue 1 is the high priority queue
* Return queue number for TX. On the RTL93XX, queue 1 is the high priority queue
*/ */
u16 rtl93xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb, u16 rtl93xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev) struct net_device *sb_dev)
{ {
if (skb->priority >= TC_PRIO_CONTROL) if (skb->priority >= TC_PRIO_CONTROL)
return 1; return 1;
return 0; return 0;
} }
@ -1291,7 +1285,7 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
skb_reserve(skb, NET_IP_ALIGN); skb_reserve(skb, NET_IP_ALIGN);
if (likely(skb)) { if (likely(skb)) {
/* BUG: Prevent bug on RTL838x SoCs*/ /* BUG: Prevent bug on RTL838x SoCs */
if (priv->family_id == RTL8380_FAMILY_ID) { if (priv->family_id == RTL8380_FAMILY_ID) {
sw_w32(0xffffffff, priv->r->dma_if_rx_ring_size(0)); sw_w32(0xffffffff, priv->r->dma_if_rx_ring_size(0));
for (i = 0; i < priv->rxrings; i++) { for (i = 0; i < priv->rxrings; i++) {
@ -1308,12 +1302,12 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
/* Overwrite CRC with cpu_tag */ /* Overwrite CRC with cpu_tag */
if (dsa) { if (dsa) {
priv->r->decode_tag(h, &tag); priv->r->decode_tag(h, &tag);
skb->data[len-4] = 0x80; skb->data[len - 4] = 0x80;
skb->data[len-3] = tag.port; skb->data[len - 3] = tag.port;
skb->data[len-2] = 0x10; skb->data[len - 2] = 0x10;
skb->data[len-1] = 0x00; skb->data[len - 1] = 0x00;
if (tag.l2_offloaded) if (tag.l2_offloaded)
skb->data[len-3] |= 0x40; skb->data[len - 3] |= 0x40;
} }
if (tag.queue >= 0) if (tag.queue >= 0)
@ -1342,8 +1336,9 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget)
h->buf = data; h->buf = data;
h->size = RING_BUFFER; h->size = RING_BUFFER;
ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 | (ring->c_rx[r] == (priv->rxringlen - 1) ?
| (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP : 0x1); WRAP :
0x1);
ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen; ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen;
last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4)); last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4));
} while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget); } while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget);
@ -1382,6 +1377,7 @@ static int rtl838x_poll_rx(struct napi_struct *napi, int budget)
else else
sw_w32_mask(0, 0xf00ff | BIT(r + 8), priv->r->dma_if_intr_msk); sw_w32_mask(0, 0xf00ff | BIT(r + 8), priv->r->dma_if_intr_msk);
} }
return work_done; return work_done;
} }
@ -1568,6 +1564,7 @@ static int rtl838x_set_mac_address(struct net_device *dev, void *p)
rtl838x_set_mac_hw(dev, mac); rtl838x_set_mac_hw(dev, mac);
pr_info("Using MAC %08x%08x\n", sw_r32(priv->r->mac), sw_r32(priv->r->mac + 4)); pr_info("Using MAC %08x%08x\n", sw_r32(priv->r->mac), sw_r32(priv->r->mac + 4));
return 0; return 0;
} }
@ -1584,7 +1581,7 @@ static int rtl8380_init_mac(struct rtl838x_eth_priv *priv)
if (priv->family_id == 0x8390) if (priv->family_id == 0x8390)
return rtl8390_init_mac(priv); return rtl8390_init_mac(priv);
// At present we do not know how to set up EEE on any other SoC than RTL8380 /* At present we do not know how to set up EEE on any other SoC than RTL8380 */
if (priv->family_id != 0x8380) if (priv->family_id != 0x8380)
return 0; return 0;
@ -1602,6 +1599,7 @@ static int rtl8380_init_mac(struct rtl838x_eth_priv *priv)
for (i = 8; i <= 28; i++) for (i = 8; i <= 28; i++)
sw_w32(0, 0xd57c + i * 0x80); sw_w32(0, 0xd57c + i * 0x80);
} }
return 0; return 0;
} }
@ -1611,6 +1609,7 @@ static int rtl838x_get_link_ksettings(struct net_device *ndev,
struct rtl838x_eth_priv *priv = netdev_priv(ndev); struct rtl838x_eth_priv *priv = netdev_priv(ndev);
pr_debug("%s called\n", __func__); pr_debug("%s called\n", __func__);
return phylink_ethtool_ksettings_get(priv->phylink, cmd); return phylink_ethtool_ksettings_get(priv->phylink, cmd);
} }
@ -1620,6 +1619,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
struct rtl838x_eth_priv *priv = netdev_priv(ndev); struct rtl838x_eth_priv *priv = netdev_priv(ndev);
pr_debug("%s called\n", __func__); pr_debug("%s called\n", __func__);
return phylink_ethtool_ksettings_set(priv->phylink, cmd); return phylink_ethtool_ksettings_set(priv->phylink, cmd);
} }
@ -1645,6 +1645,7 @@ static int rtl838x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, in
} }
if (err) if (err)
return err; return err;
return val; return val;
} }
@ -1673,8 +1674,10 @@ static int rtl839x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, in
err = rtl839x_read_phy(mii_id, page, regnum, &val); err = rtl839x_read_phy(mii_id, page, regnum, &val);
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err); pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
} }
if (err)
if (err)
return err; return err;
return val; return val;
} }
@ -1703,8 +1706,10 @@ static int rtl930x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, in
err = rtl930x_read_phy(mii_id, page, regnum, &val); err = rtl930x_read_phy(mii_id, page, regnum, &val);
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err); pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
} }
if (err) if (err)
return err; return err;
return val; return val;
} }
@ -1744,6 +1749,7 @@ static int rtl931x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, in
if (err) if (err)
return err; return err;
return val; return val;
} }
@ -1777,6 +1783,7 @@ static int rtl838x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
} }
err = rtl838x_write_phy(mii_id, page, regnum, value); err = rtl838x_write_phy(mii_id, page, regnum, value);
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err); pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
return err; return err;
} }
@ -1807,6 +1814,7 @@ static int rtl839x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
err = rtl839x_write_phy(mii_id, page, regnum, value); err = rtl839x_write_phy(mii_id, page, regnum, value);
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err); pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
return err; return err;
} }
@ -1831,6 +1839,7 @@ static int rtl930x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
err = rtl930x_write_phy(mii_id, page, regnum, value); err = rtl930x_write_phy(mii_id, page, regnum, value);
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err); pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
return err; return err;
} }
@ -1861,6 +1870,7 @@ static int rtl931x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
err = rtl931x_write_phy(mii_id, page, regnum, value); err = rtl931x_write_phy(mii_id, page, regnum, value);
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err); pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
return err; return err;
} }
@ -1951,7 +1961,6 @@ static int rtl930x_mdio_reset(struct mii_bus *bus)
switch (priv->interfaces[i]) { switch (priv->interfaces[i]) {
case PHY_INTERFACE_MODE_10GBASER: case PHY_INTERFACE_MODE_10GBASER:
break; // Serdes: Value = 0 break; // Serdes: Value = 0
case PHY_INTERFACE_MODE_HSGMII: case PHY_INTERFACE_MODE_HSGMII:
private_poll_mask |= BIT(i); private_poll_mask |= BIT(i);
// fallthrough // fallthrough
@ -1959,12 +1968,10 @@ static int rtl930x_mdio_reset(struct mii_bus *bus)
v |= BIT(mac_type_bit[i]); v |= BIT(mac_type_bit[i]);
uses_usxgmii = true; uses_usxgmii = true;
break; break;
case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QSGMII:
private_poll_mask |= BIT(i); private_poll_mask |= BIT(i);
v |= 3 << mac_type_bit[i]; v |= 3 << mac_type_bit[i];
break; break;
default: default:
break; break;
} }
@ -1976,7 +1983,8 @@ static int rtl930x_mdio_reset(struct mii_bus *bus)
/* The following magic values are found in the port configuration, they seem to /* The following magic values are found in the port configuration, they seem to
* define different ways of polling a PHY. The below is for the Aquantia PHYs of * define different ways of polling a PHY. The below is for the Aquantia PHYs of
* the XGS1250 and the RTL8226 of the XGS1210 */ * the XGS1250 and the RTL8226 of the XGS1210
*/
if (uses_usxgmii) { if (uses_usxgmii) {
sw_w32(0x01010000, RTL930X_SMI_10GPHY_POLLING_REG0_CFG); sw_w32(0x01010000, RTL930X_SMI_10GPHY_POLLING_REG0_CFG);
sw_w32(0x01E7C400, RTL930X_SMI_10GPHY_POLLING_REG9_CFG); sw_w32(0x01E7C400, RTL930X_SMI_10GPHY_POLLING_REG9_CFG);
@ -2004,6 +2012,7 @@ static int rtl930x_mdio_reset(struct mii_bus *bus)
sw_r32(RTL930X_SMI_10GPHY_POLLING_REG10_CFG)); sw_r32(RTL930X_SMI_10GPHY_POLLING_REG10_CFG));
pr_debug("%s: RTL930X_SMI_PRVTE_POLLING_CTRL %08x\n", __func__, pr_debug("%s: RTL930X_SMI_PRVTE_POLLING_CTRL %08x\n", __func__,
sw_r32(RTL930X_SMI_PRVTE_POLLING_CTRL)); sw_r32(RTL930X_SMI_PRVTE_POLLING_CTRL));
return 0; return 0;
} }
@ -2057,10 +2066,10 @@ static int rtl931x_mdio_reset(struct mii_bus *bus)
pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0)); pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0));
/* We have a 10G PHY enable polling /* We have a 10G PHY enable polling
sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2); * sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2);
sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3); * sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3);
sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4); * sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4);
*/ */
sw_w32_mask(0xff, c45_mask, RTL931X_SMI_GLB_CTRL1); sw_w32_mask(0xff, c45_mask, RTL931X_SMI_GLB_CTRL1);
return 0; return 0;
@ -2221,6 +2230,7 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
err_put_node: err_put_node:
of_node_put(mii_np); of_node_put(mii_np);
return ret; return ret;
} }
@ -2392,9 +2402,9 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
} }
/* Allocate buffer memory */ /* Allocate buffer memory */
priv->membase = dmam_alloc_coherent(&pdev->dev, rxrings * rxringlen * RING_BUFFER priv->membase = dmam_alloc_coherent(&pdev->dev, rxrings * rxringlen * RING_BUFFER +
+ sizeof(struct ring_b) + sizeof(struct notify_b), sizeof(struct ring_b) + sizeof(struct notify_b),
(void *)&dev->mem_start, GFP_KERNEL); (void *)&dev->mem_start, GFP_KERNEL);
if (!priv->membase) { if (!priv->membase) {
dev_err(&pdev->dev, "cannot allocate DMA buffer\n"); dev_err(&pdev->dev, "cannot allocate DMA buffer\n");
err = -ENOMEM; err = -ENOMEM;
@ -2469,7 +2479,7 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
rtl8380_init_mac(priv); rtl8380_init_mac(priv);
/* try to get mac address in the following order: /* Try to get mac address in the following order:
* 1) from device tree data * 1) from device tree data
* 2) from internal registers set by bootloader * 2) from internal registers set by bootloader
*/ */
@ -2540,6 +2550,7 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev)
err_free: err_free:
pr_err("Error setting up netdev, freeing it again.\n"); pr_err("Error setting up netdev, freeing it again.\n");
free_netdev(dev); free_netdev(dev);
return err; return err;
} }
@ -2562,6 +2573,7 @@ static int rtl838x_eth_remove(struct platform_device *pdev)
unregister_netdev(dev); unregister_netdev(dev);
free_netdev(dev); free_netdev(dev);
} }
return 0; return 0;
} }

View file

@ -3,9 +3,7 @@
#ifndef _RTL838X_ETH_H #ifndef _RTL838X_ETH_H
#define _RTL838X_ETH_H #define _RTL838X_ETH_H
/* /* Register definition */
* Register definition
*/
/* Per port MAC control */ /* Per port MAC control */
#define RTL838X_MAC_PORT_CTRL (0xd560) #define RTL838X_MAC_PORT_CTRL (0xd560)

View file

@ -36,8 +36,7 @@ extern struct mutex smi_lock;
#define RTL821X_PAGE_STATE 0x0b80 #define RTL821X_PAGE_STATE 0x0b80
#define RTL821X_PAGE_PATCH 0x0b82 #define RTL821X_PAGE_PATCH 0x0b82
/* /* Using the special page 0xfff with the MDIO controller found in
* Using the special page 0xfff with the MDIO controller found in
* RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing * RealTek SoCs allows to access the PHY in RAW mode, ie. bypassing
* the cache and paging engine of the MDIO controller. * the cache and paging engine of the MDIO controller.
*/ */
@ -55,8 +54,7 @@ extern struct mutex smi_lock;
#define RTL9300_PHY_ID_MASK 0xf0ffffff #define RTL9300_PHY_ID_MASK 0xf0ffffff
/* /* This lock protects the state of the SoC automatically polling the PHYs over the SMI
* This lock protects the state of the SoC automatically polling the PHYs over the SMI
* bus to detect e.g. link and media changes. For operations on the PHYs such as * bus to detect e.g. link and media changes. For operations on the PHYs such as
* patching or other configuration changes such as EEE, polling needs to be disabled * patching or other configuration changes such as EEE, polling needs to be disabled
* since otherwise these operations may fails or lead to unpredictable results. * since otherwise these operations may fails or lead to unpredictable results.
@ -83,7 +81,7 @@ static u64 disable_polling(int port)
saved_state <<= 32; saved_state <<= 32;
saved_state |= sw_r32(RTL839X_SMI_PORT_POLLING_CTRL); saved_state |= sw_r32(RTL839X_SMI_PORT_POLLING_CTRL);
sw_w32_mask(BIT(port % 32), 0, sw_w32_mask(BIT(port % 32), 0,
RTL839X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2)); RTL839X_SMI_PORT_POLLING_CTRL + ((port >> 5) << 2));
break; break;
case RTL9300_FAMILY_ID: case RTL9300_FAMILY_ID:
saved_state = sw_r32(RTL930X_SMI_POLL_CTRL); saved_state = sw_r32(RTL930X_SMI_POLL_CTRL);
@ -150,8 +148,7 @@ u16 rtl9300_sds_regs[] = { 0x0194, 0x0194, 0x0194, 0x0194, 0x02a0, 0x02a0, 0x02a
0x02A4, 0x02A4, 0x0198, 0x0198 }; 0x02A4, 0x02A4, 0x0198, 0x0198 };
u8 rtl9300_sds_lsb[] = { 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 0, 6}; u8 rtl9300_sds_lsb[] = { 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 0, 6};
/* /* Reset the SerDes by powering it off and set a new operations mode
* Reset the SerDes by powering it off and set a new operations mode
* of the SerDes. 0x1f is off. Other modes are * of the SerDes. 0x1f is off. Other modes are
* 0x02: SGMII 0x04: 1000BX_FIBER 0x05: FIBER100 * 0x02: SGMII 0x04: 1000BX_FIBER 0x05: FIBER100
* 0x06: QSGMII 0x09: RSGMII 0x0d: USXGMII * 0x06: QSGMII 0x09: RSGMII 0x0d: USXGMII
@ -176,7 +173,7 @@ void rtl9300_sds_rst(int sds_num, u32 mode)
mdelay(10); mdelay(10);
pr_debug("%s: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n", __func__, pr_debug("%s: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n", __func__,
sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4)); sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4));
} }
void rtl9300_sds_set(int sds_num, u32 mode) void rtl9300_sds_set(int sds_num, u32 mode)
@ -192,7 +189,7 @@ void rtl9300_sds_set(int sds_num, u32 mode)
mdelay(10); mdelay(10);
pr_debug("%s: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n", __func__, pr_debug("%s: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n", __func__,
sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4)); sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4));
} }
u32 rtl9300_sds_mode_get(int sds_num) u32 rtl9300_sds_mode_get(int sds_num)
@ -210,8 +207,7 @@ u32 rtl9300_sds_mode_get(int sds_num)
return v & 0x1f; return v & 0x1f;
} }
/* /* On the RTL839x family of SoCs with inbuilt SerDes, these SerDes are accessed through
* On the RTL839x family of SoCs with inbuilt SerDes, these SerDes are accessed through
* a 2048 bit register that holds the contents of the PHY being simulated by the SoC. * a 2048 bit register that holds the contents of the PHY being simulated by the SoC.
*/ */
int rtl839x_read_sds_phy(int phy_addr, int phy_reg) int rtl839x_read_sds_phy(int phy_addr, int phy_reg)
@ -223,8 +219,7 @@ int rtl839x_read_sds_phy(int phy_addr, int phy_reg)
if (phy_addr == 49) if (phy_addr == 49)
offset = 0x100; offset = 0x100;
/* /* For the RTL8393 internal SerDes, we simulate a PHY ID in registers 2/3
* For the RTL8393 internal SerDes, we simulate a PHY ID in registers 2/3
* which would otherwise read as 0. * which would otherwise read as 0.
*/ */
if (soc_info.id == 0x8393) { if (soc_info.id == 0x8393) {
@ -234,8 +229,7 @@ int rtl839x_read_sds_phy(int phy_addr, int phy_reg)
return 0x8393; return 0x8393;
} }
/* /* Register RTL839X_SDS12_13_XSG0 is 2048 bit broad, the MSB (bit 15) of the
* Register RTL839X_SDS12_13_XSG0 is 2048 bit broad, the MSB (bit 15) of the
* 0th PHY register is bit 1023 (in byte 0x80). Because PHY-registers are 16 * 0th PHY register is bit 1023 (in byte 0x80). Because PHY-registers are 16
* bit broad, we offset by reg << 1. In the SoC 2 registers are stored in * bit broad, we offset by reg << 1. In the SoC 2 registers are stored in
* one 32 bit register. * one 32 bit register.
@ -247,11 +241,11 @@ int rtl839x_read_sds_phy(int phy_addr, int phy_reg)
val = (val >> 16) & 0xffff; val = (val >> 16) & 0xffff;
else else
val &= 0xffff; val &= 0xffff;
return val; return val;
} }
/* /* On the RTL930x family of SoCs, the internal SerDes are accessed through an IO
* On the RTL930x family of SoCs, the internal SerDes are accessed through an IO
* register which simulates commands to an internal MDIO bus. * register which simulates commands to an internal MDIO bus.
*/ */
int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg) int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg)
@ -314,6 +308,7 @@ int rtl931x_read_sds_phy(int phy_addr, int page, int phy_reg)
return -EIO; return -EIO;
pr_debug("%s: returning %04x\n", __func__, sw_r32(RTL931X_SERDES_INDRT_DATA_CTRL) & 0xffff); pr_debug("%s: returning %04x\n", __func__, sw_r32(RTL931X_SERDES_INDRT_DATA_CTRL) & 0xffff);
return sw_r32(RTL931X_SERDES_INDRT_DATA_CTRL) & 0xffff; return sw_r32(RTL931X_SERDES_INDRT_DATA_CTRL) & 0xffff;
} }
@ -342,8 +337,7 @@ int rtl931x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v)
return 0; return 0;
} }
/* /* On the RTL838x SoCs, the internal SerDes is accessed through direct access to
* On the RTL838x SoCs, the internal SerDes is accessed through direct access to
* standard PHY registers, where a 32 bit register holds a 16 bit word as found * standard PHY registers, where a 32 bit register holds a 16 bit word as found
* in a standard page 0 of a PHY * in a standard page 0 of a PHY
*/ */
@ -449,9 +443,9 @@ static int rtl8226_read_status(struct phy_device *phydev)
// } // }
// Link status must be read twice // Link status must be read twice
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++)
val = phy_read_mmd(phydev, MMD_VEND2, 0xA402); val = phy_read_mmd(phydev, MMD_VEND2, 0xA402);
}
phydev->link = val & BIT(2) ? 1 : 0; phydev->link = val & BIT(2) ? 1 : 0;
if (!phydev->link) if (!phydev->link)
goto out; goto out;
@ -486,6 +480,7 @@ static int rtl8226_read_status(struct phy_device *phydev)
default: default:
break; break;
} }
out: out:
return ret; return ret;
} }
@ -566,7 +561,7 @@ out:
} }
static int rtl8226_get_eee(struct phy_device *phydev, static int rtl8226_get_eee(struct phy_device *phydev,
struct ethtool_eee *e) struct ethtool_eee *e)
{ {
u32 val; u32 val;
int addr = phydev->mdio.addr; int addr = phydev->mdio.addr;
@ -706,6 +701,7 @@ static int rtl8390_configure_generic(struct phy_device *phydev)
/* Internal RTL8218B, version 2 */ /* Internal RTL8218B, version 2 */
phydev_info(phydev, "Detected unknown %x\n", val); phydev_info(phydev, "Detected unknown %x\n", val);
return 0; return 0;
} }
@ -744,11 +740,8 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
return -1; return -1;
} }
rtl838x_6275B_intPhy_perport = (void *)h + sizeof(struct fw_header) rtl838x_6275B_intPhy_perport = (void *)h + sizeof(struct fw_header) + h->parts[8].start;
+ h->parts[8].start; rtl8218b_6276B_hwEsd_perport = (void *)h + sizeof(struct fw_header) + h->parts[9].start;
rtl8218b_6276B_hwEsd_perport = (void *)h + sizeof(struct fw_header)
+ h->parts[9].start;
if (sw_r32(RTL838X_DMY_REG31) == 0x1) if (sw_r32(RTL838X_DMY_REG31) == 0x1)
ipd_flag = 1; ipd_flag = 1;
@ -774,8 +767,8 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
} }
if (i >= 100) { if (i >= 100) {
phydev_err(phydev, phydev_err(phydev,
"ERROR: Port %d not ready for patch.\n", "ERROR: Port %d not ready for patch.\n",
mac + p); mac + p);
return -1; return -1;
} }
} }
@ -783,18 +776,19 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
i = 0; i = 0;
while (rtl838x_6275B_intPhy_perport[i * 2]) { while (rtl838x_6275B_intPhy_perport[i * 2]) {
phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW, phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW,
rtl838x_6275B_intPhy_perport[i * 2], rtl838x_6275B_intPhy_perport[i * 2],
rtl838x_6275B_intPhy_perport[i * 2 + 1]); rtl838x_6275B_intPhy_perport[i * 2 + 1]);
i++; i++;
} }
i = 0; i = 0;
while (rtl8218b_6276B_hwEsd_perport[i * 2]) { while (rtl8218b_6276B_hwEsd_perport[i * 2]) {
phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW, phy_package_port_write_paged(phydev, p, RTL83XX_PAGE_RAW,
rtl8218b_6276B_hwEsd_perport[i * 2], rtl8218b_6276B_hwEsd_perport[i * 2],
rtl8218b_6276B_hwEsd_perport[i * 2 + 1]); rtl8218b_6276B_hwEsd_perport[i * 2 + 1]);
i++; i++;
} }
} }
return 0; return 0;
} }
@ -836,14 +830,9 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
return -1; return -1;
} }
rtl8380_rtl8218b_perchip = (void *)h + sizeof(struct fw_header) rtl8380_rtl8218b_perchip = (void *)h + sizeof(struct fw_header) + h->parts[0].start;
+ h->parts[0].start; rtl8218B_6276B_rtl8380_perport = (void *)h + sizeof(struct fw_header) + h->parts[1].start;
rtl8380_rtl8218b_perport = (void *)h + sizeof(struct fw_header) + h->parts[2].start;
rtl8218B_6276B_rtl8380_perport = (void *)h + sizeof(struct fw_header)
+ h->parts[1].start;
rtl8380_rtl8218b_perport = (void *)h + sizeof(struct fw_header)
+ h->parts[2].start;
val = phy_read(phydev, 0); val = phy_read(phydev, 0);
if (val & (1 << 11)) if (val & (1 << 11))
@ -861,11 +850,11 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
phydev_info(phydev, "Detected chip revision %04x\n", val); phydev_info(phydev, "Detected chip revision %04x\n", val);
i = 0; i = 0;
while (rtl8380_rtl8218b_perchip[i * 3] while (rtl8380_rtl8218b_perchip[i * 3] &&
&& rtl8380_rtl8218b_perchip[i * 3 + 1]) { rtl8380_rtl8218b_perchip[i * 3 + 1]) {
phy_package_port_write_paged(phydev, rtl8380_rtl8218b_perchip[i * 3], phy_package_port_write_paged(phydev, rtl8380_rtl8218b_perchip[i * 3],
RTL83XX_PAGE_RAW, rtl8380_rtl8218b_perchip[i * 3 + 1], RTL83XX_PAGE_RAW, rtl8380_rtl8218b_perchip[i * 3 + 1],
rtl8380_rtl8218b_perchip[i * 3 + 2]); rtl8380_rtl8218b_perchip[i * 3 + 2]);
i++; i++;
} }
@ -911,11 +900,11 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
i = 0; i = 0;
while (rtl8218B_6276B_rtl8380_perport[i * 2]) { while (rtl8218B_6276B_rtl8380_perport[i * 2]) {
phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8218B_6276B_rtl8380_perport[i * 2], phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8218B_6276B_rtl8380_perport[i * 2],
rtl8218B_6276B_rtl8380_perport[i * 2 + 1]); rtl8218B_6276B_rtl8380_perport[i * 2 + 1]);
i++; i++;
} }
/*Disable broadcast ID*/ /* Disable broadcast ID */
rtl821x_phy_setup_package_broadcast(phydev, false); rtl821x_phy_setup_package_broadcast(phydev, false);
return 0; return 0;
@ -1036,6 +1025,7 @@ static int rtl8214fc_set_port(struct phy_device *phydev, int port)
pr_debug("%s port %d to %d\n", __func__, addr, port); pr_debug("%s port %d to %d\n", __func__, addr, port);
rtl8214fc_media_set(phydev, is_fibre); rtl8214fc_media_set(phydev, is_fibre);
return 0; return 0;
} }
@ -1046,11 +1036,11 @@ static int rtl8214fc_get_port(struct phy_device *phydev)
pr_debug("%s: port %d\n", __func__, addr); pr_debug("%s: port %d\n", __func__, addr);
if (rtl8214fc_media_is_fibre(phydev)) if (rtl8214fc_media_is_fibre(phydev))
return PORT_FIBRE; return PORT_FIBRE;
return PORT_MII; return PORT_MII;
} }
/* /* Enable EEE on the RTL8218B PHYs
* Enable EEE on the RTL8218B PHYs
* The method used is not the preferred way (which would be based on the MAC-EEE state, * The method used is not the preferred way (which would be based on the MAC-EEE state,
* but the only way that works since the kernel first enables EEE in the MAC * but the only way that works since the kernel first enables EEE in the MAC
* and then sets up the PHY. The MAC-based approach would require the oppsite. * and then sets up the PHY. The MAC-based approach would require the oppsite.
@ -1087,12 +1077,12 @@ void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
phy_write(phydev, 0, val); phy_write(phydev, 0, val);
} }
/* GPHY page back to auto*/ /* GPHY page back to auto */
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
} }
static int rtl8218b_get_eee(struct phy_device *phydev, static int rtl8218b_get_eee(struct phy_device *phydev,
struct ethtool_eee *e) struct ethtool_eee *e)
{ {
u32 val; u32 val;
int addr = phydev->mdio.addr; int addr = phydev->mdio.addr;
@ -1120,7 +1110,7 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
} }
static int rtl8218d_get_eee(struct phy_device *phydev, static int rtl8218d_get_eee(struct phy_device *phydev,
struct ethtool_eee *e) struct ethtool_eee *e)
{ {
u32 val; u32 val;
int addr = phydev->mdio.addr; int addr = phydev->mdio.addr;
@ -1142,7 +1132,7 @@ static int rtl8218d_get_eee(struct phy_device *phydev,
} }
static int rtl8214fc_set_eee(struct phy_device *phydev, static int rtl8214fc_set_eee(struct phy_device *phydev,
struct ethtool_eee *e) struct ethtool_eee *e)
{ {
u32 poll_state; u32 poll_state;
int port = phydev->mdio.addr; int port = phydev->mdio.addr;
@ -1190,7 +1180,7 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
phy_write(phydev, 0, val); phy_write(phydev, 0, val);
} }
/* GPHY page back to auto*/ /* GPHY page back to auto */
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
resume_polling(poll_state); resume_polling(poll_state);
@ -1199,7 +1189,7 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
} }
static int rtl8214fc_get_eee(struct phy_device *phydev, static int rtl8214fc_get_eee(struct phy_device *phydev,
struct ethtool_eee *e) struct ethtool_eee *e)
{ {
int addr = phydev->mdio.addr; int addr = phydev->mdio.addr;
@ -1257,7 +1247,7 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
phy_write(phydev, 0, val); phy_write(phydev, 0, val);
} }
/* GPHY page back to auto*/ /* GPHY page back to auto */
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
pr_info("%s done\n", __func__); pr_info("%s done\n", __func__);
@ -1302,6 +1292,7 @@ static int rtl8380_configure_rtl8214c(struct phy_device *phydev)
/* GPHY auto conf */ /* GPHY auto conf */
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO); phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
return 0; return 0;
} }
@ -1339,11 +1330,9 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
return -1; return -1;
} }
rtl8380_rtl8214fc_perchip = (void *)h + sizeof(struct fw_header) rtl8380_rtl8214fc_perchip = (void *)h + sizeof(struct fw_header) + h->parts[0].start;
+ h->parts[0].start;
rtl8380_rtl8214fc_perport = (void *)h + sizeof(struct fw_header) rtl8380_rtl8214fc_perport = (void *)h + sizeof(struct fw_header) + h->parts[1].start;
+ h->parts[1].start;
/* detect phy version */ /* detect phy version */
phy_write_paged(phydev, RTL83XX_PAGE_RAW, 27, 0x0004); phy_write_paged(phydev, RTL83XX_PAGE_RAW, 27, 0x0004);
@ -1359,14 +1348,13 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
phy_write_paged(phydev, 0, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER); phy_write_paged(phydev, 0, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
i = 0; i = 0;
while (rtl8380_rtl8214fc_perchip[i * 3] while (rtl8380_rtl8214fc_perchip[i * 3] &&
&& rtl8380_rtl8214fc_perchip[i * 3 + 1]) { rtl8380_rtl8214fc_perchip[i * 3 + 1]) {
if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x1f) if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x1f)
page = rtl8380_rtl8214fc_perchip[i * 3 + 2]; page = rtl8380_rtl8214fc_perchip[i * 3 + 2];
if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x13 && page == 0x260) { if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x13 && page == 0x260) {
val = phy_read_paged(phydev, 0x260, 13); val = phy_read_paged(phydev, 0x260, 13);
val = (val & 0x1f00) | (rtl8380_rtl8214fc_perchip[i * 3 + 2] val = (val & 0x1f00) | (rtl8380_rtl8214fc_perchip[i * 3 + 2] & 0xe0ff);
& 0xe0ff);
phy_write_paged(phydev, RTL83XX_PAGE_RAW, phy_write_paged(phydev, RTL83XX_PAGE_RAW,
rtl8380_rtl8214fc_perchip[i * 3 + 1], val); rtl8380_rtl8214fc_perchip[i * 3 + 1], val);
} else { } else {
@ -1428,11 +1416,11 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
i = 0; i = 0;
while (rtl8380_rtl8214fc_perport[i * 2]) { while (rtl8380_rtl8214fc_perport[i * 2]) {
phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8380_rtl8214fc_perport[i * 2], phy_write_paged(phydev, RTL83XX_PAGE_RAW, rtl8380_rtl8214fc_perport[i * 2],
rtl8380_rtl8214fc_perport[i * 2 + 1]); rtl8380_rtl8214fc_perport[i * 2 + 1]);
i++; i++;
} }
/*Disable broadcast ID*/ /* Disable broadcast ID */
rtl821x_phy_setup_package_broadcast(phydev, false); rtl821x_phy_setup_package_broadcast(phydev, false);
/* Auto medium selection */ /* Auto medium selection */
@ -1477,29 +1465,21 @@ static int rtl8380_configure_serdes(struct phy_device *phydev)
return -1; return -1;
} }
rtl8380_sds_take_reset = (void *)h + sizeof(struct fw_header) rtl8380_sds_take_reset = (void *)h + sizeof(struct fw_header) + h->parts[0].start;
+ h->parts[0].start;
rtl8380_sds_common = (void *)h + sizeof(struct fw_header) rtl8380_sds_common = (void *)h + sizeof(struct fw_header) + h->parts[1].start;
+ h->parts[1].start;
rtl8380_sds01_qsgmii_6275b = (void *)h + sizeof(struct fw_header) rtl8380_sds01_qsgmii_6275b = (void *)h + sizeof(struct fw_header) + h->parts[2].start;
+ h->parts[2].start;
rtl8380_sds23_qsgmii_6275b = (void *)h + sizeof(struct fw_header) rtl8380_sds23_qsgmii_6275b = (void *)h + sizeof(struct fw_header) + h->parts[3].start;
+ h->parts[3].start;
rtl8380_sds4_fiber_6275b = (void *)h + sizeof(struct fw_header) rtl8380_sds4_fiber_6275b = (void *)h + sizeof(struct fw_header) + h->parts[4].start;
+ h->parts[4].start;
rtl8380_sds5_fiber_6275b = (void *)h + sizeof(struct fw_header) rtl8380_sds5_fiber_6275b = (void *)h + sizeof(struct fw_header) + h->parts[5].start;
+ h->parts[5].start;
rtl8380_sds_reset = (void *)h + sizeof(struct fw_header) rtl8380_sds_reset = (void *)h + sizeof(struct fw_header) + h->parts[6].start;
+ h->parts[6].start;
rtl8380_sds_release_reset = (void *)h + sizeof(struct fw_header) rtl8380_sds_release_reset = (void *)h + sizeof(struct fw_header) + h->parts[7].start;
+ h->parts[7].start;
/* Back up serdes power off value */ /* Back up serdes power off value */
sds_conf_value = sw_r32(RTL838X_SDS_CFG_REG); sds_conf_value = sw_r32(RTL838X_SDS_CFG_REG);
@ -1538,7 +1518,7 @@ static int rtl8380_configure_serdes(struct phy_device *phydev)
i = 0; i = 0;
while (rtl8380_sds01_qsgmii_6275b[2 * i]) { while (rtl8380_sds01_qsgmii_6275b[2 * i]) {
sw_w32(rtl8380_sds01_qsgmii_6275b[2 * i + 1], sw_w32(rtl8380_sds01_qsgmii_6275b[2 * i + 1],
rtl8380_sds01_qsgmii_6275b[2 * i]); rtl8380_sds01_qsgmii_6275b[2 * i]);
i++; i++;
} }
@ -1576,6 +1556,7 @@ static int rtl8380_configure_serdes(struct phy_device *phydev)
sw_w32(sds_conf_value, RTL838X_SDS_CFG_REG); sw_w32(sds_conf_value, RTL838X_SDS_CFG_REG);
pr_info("Configuration of SERDES done\n"); pr_info("Configuration of SERDES done\n");
return 0; return 0;
} }
@ -1647,7 +1628,7 @@ static int rtl9300_read_status(struct phy_device *phydev)
mode = rtl9300_sds_mode_get(sds_num); mode = rtl9300_sds_mode_get(sds_num);
pr_info("%s got SDS mode %02x\n", __func__, mode); pr_info("%s got SDS mode %02x\n", __func__, mode);
if (mode == 0x1a) { // 10GR mode if (mode == 0x1a) { // 10GR mode
status = rtl9300_sds_field_r(sds_num, 0x5, 0, 12, 12); status = rtl9300_sds_field_r(sds_num, 0x5, 0, 12, 12);
latch_status = rtl9300_sds_field_r(sds_num, 0x4, 1, 2, 2); latch_status = rtl9300_sds_field_r(sds_num, 0x4, 1, 2, 2);
status |= rtl9300_sds_field_r(sds_num, 0x5, 0, 12, 12); status |= rtl9300_sds_field_r(sds_num, 0x5, 0, 12, 12);
@ -1686,8 +1667,7 @@ void rtl930x_sds_rx_rst(int sds_num, phy_interface_t phy_if)
rtl9300_sds_field_w(sds_num, page, 0x15, 4, 4, 0x0); rtl9300_sds_field_w(sds_num, page, 0x15, 4, 4, 0x0);
} }
/* /* Force PHY modes on 10GBit Serdes
* Force PHY modes on 10GBit Serdes
*/ */
void rtl9300_force_sds_mode(int sds, phy_interface_t phy_if) void rtl9300_force_sds_mode(int sds, phy_interface_t phy_if)
{ {
@ -1803,6 +1783,7 @@ void rtl9300_force_sds_mode(int sds, phy_interface_t phy_if)
if (cr_0 && cr_1 && cr_2) { if (cr_0 && cr_1 && cr_2) {
u32 t; u32 t;
if (phy_if != PHY_INTERFACE_MODE_10GBASER) if (phy_if != PHY_INTERFACE_MODE_10GBASER)
break; break;
@ -1874,16 +1855,15 @@ void rtl9300_sds_tx_config(int sds, phy_interface_t phy_if)
return; return;
} }
rtl9300_sds_field_w(sds, page, 0x1, 15, 11, pre_amp); rtl9300_sds_field_w(sds, page, 0x01, 15, 11, pre_amp);
rtl9300_sds_field_w(sds, page, 0x7, 0, 0, pre_en); rtl9300_sds_field_w(sds, page, 0x06, 4, 0, post_amp);
rtl9300_sds_field_w(sds, page, 0x7, 8, 4, main_amp); rtl9300_sds_field_w(sds, page, 0x07, 0, 0, pre_en);
rtl9300_sds_field_w(sds, page, 0x6, 4, 0, post_amp); rtl9300_sds_field_w(sds, page, 0x07, 3, 3, post_en);
rtl9300_sds_field_w(sds, page, 0x7, 3, 3, post_en); rtl9300_sds_field_w(sds, page, 0x07, 8, 4, main_amp);
rtl9300_sds_field_w(sds, page, 0x18, 15, 12, impedance); rtl9300_sds_field_w(sds, page, 0x18, 15, 12, impedance);
} }
/* /* Wait for clock ready, this assumes the SerDes is in XGMII mode
* Wait for clock ready, this assumes the SerDes is in XGMII mode
* timeout is in ms * timeout is in ms
*/ */
int rtl9300_sds_clock_wait(int timeout) int rtl9300_sds_clock_wait(int timeout)
@ -1932,8 +1912,8 @@ void rtl9300_sds_rxcal_dcvs_manual(u32 sds_num, u32 dcvs_id, bool manual, u32 dv
switch(dcvs_id) { switch(dcvs_id) {
case 0: case 0:
rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 14, 14, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 14, 14, 0x1);
rtl9300_sds_field_w(sds_num, 0x2f, 0x03, 5, 5, dvcs_list[0]); rtl9300_sds_field_w(sds_num, 0x2f, 0x03, 5, 5, dvcs_list[0]);
rtl9300_sds_field_w(sds_num, 0x2f, 0x03, 4, 0, dvcs_list[1]); rtl9300_sds_field_w(sds_num, 0x2f, 0x03, 4, 0, dvcs_list[1]);
break; break;
case 1: case 1:
rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 13, 13, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 13, 13, 0x1);
@ -1943,22 +1923,22 @@ void rtl9300_sds_rxcal_dcvs_manual(u32 sds_num, u32 dcvs_id, bool manual, u32 dv
case 2: case 2:
rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 12, 12, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 12, 12, 0x1);
rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 10, 10, dvcs_list[0]); rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 10, 10, dvcs_list[0]);
rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 9, 6, dvcs_list[1]); rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 9, 6, dvcs_list[1]);
break; break;
case 3: case 3:
rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 11, 11, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x1e, 11, 11, 0x1);
rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 5, 5, dvcs_list[0]); rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 5, 5, dvcs_list[0]);
rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 4, 1, dvcs_list[1]); rtl9300_sds_field_w(sds_num, 0x2e, 0x1d, 4, 1, dvcs_list[1]);
break; break;
case 4: case 4:
rtl9300_sds_field_w(sds_num, 0x2e, 0x01, 15, 15, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x01, 15, 15, 0x1);
rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 10, 10, dvcs_list[0]); rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 10, 10, dvcs_list[0]);
rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 9, 6, dvcs_list[1]); rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 9, 6, dvcs_list[1]);
break; break;
case 5: case 5:
rtl9300_sds_field_w(sds_num, 0x2e, 0x02, 11, 11, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x02, 11, 11, 0x1);
rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 4, 4, dvcs_list[0]); rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 4, 4, dvcs_list[0]);
rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 3, 0, dvcs_list[1]); rtl9300_sds_field_w(sds_num, 0x2e, 0x11, 3, 0, dvcs_list[1]);
break; break;
default: default:
break; break;
@ -2012,8 +1992,8 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 14, 14); dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 14, 14);
break; break;
@ -2022,8 +2002,8 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 13, 13); dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 13, 13);
break; break;
@ -2032,8 +2012,8 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 12, 12); dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 12, 12);
break; break;
case 3: case 3:
@ -2041,9 +2021,9 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 11, 11); dcvs_manual = rtl9300_sds_field_r(sds_num, 0x2e, 0x1e, 11, 11);
break; break;
case 4: case 4:
@ -2051,8 +2031,8 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x01, 15, 15); dcvs_manual = !!rtl9300_sds_field_r(sds_num, 0x2e, 0x01, 15, 15);
break; break;
@ -2061,9 +2041,9 @@ void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[])
mdelay(1); mdelay(1);
// ##DCVS0 Read Out // ##DCVS0 Read Out
dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4); dcvs_sign_out = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 4, 4);
dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0); dcvs_coef_bin = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 3, 0);
dcvs_manual = rtl9300_sds_field_r(sds_num, 0x2e, 0x02, 11, 11); dcvs_manual = rtl9300_sds_field_r(sds_num, 0x2e, 0x02, 11, 11);
break; break;
default: default:
@ -2162,8 +2142,8 @@ void rtl9300_sds_rxcal_vth_manual(u32 sds_num, bool manual, u32 vth_list[])
{ {
if (manual) { if (manual) {
rtl9300_sds_field_w(sds_num, 0x2e, 0x0f, 13, 13, 0x1); rtl9300_sds_field_w(sds_num, 0x2e, 0x0f, 13, 13, 0x1);
rtl9300_sds_field_w(sds_num, 0x2e, 0x13, 5, 3, vth_list[0]); rtl9300_sds_field_w(sds_num, 0x2e, 0x13, 5, 3, vth_list[0]);
rtl9300_sds_field_w(sds_num, 0x2e, 0x13, 2, 0, vth_list[1]); rtl9300_sds_field_w(sds_num, 0x2e, 0x13, 2, 0, vth_list[1]);
} else { } else {
rtl9300_sds_field_w(sds_num, 0x2e, 0x0f, 13, 13, 0x0); rtl9300_sds_field_w(sds_num, 0x2e, 0x0f, 13, 13, 0x0);
mdelay(10); mdelay(10);
@ -2329,72 +2309,72 @@ void rtl9300_sds_rxcal_tap_get(u32 sds_num, u32 tap_id, u32 tap_list[])
void rtl9300_do_rx_calibration_1(int sds, phy_interface_t phy_mode) void rtl9300_do_rx_calibration_1(int sds, phy_interface_t phy_mode)
{ {
// From both rtl9300_rxCaliConf_serdes_myParam and rtl9300_rxCaliConf_phy_myParam // From both rtl9300_rxCaliConf_serdes_myParam and rtl9300_rxCaliConf_phy_myParam
int tap0_init_val = 0x1f; // Initial Decision Fed Equalizer 0 tap int tap0_init_val = 0x1f; // Initial Decision Fed Equalizer 0 tap
int vth_min = 0x0; int vth_min = 0x0;
pr_info("start_1.1.1 initial value for sds %d\n", sds); pr_info("start_1.1.1 initial value for sds %d\n", sds);
rtl930x_write_sds_phy(sds, 6, 0, 0); rtl930x_write_sds_phy(sds, 6, 0, 0);
// FGCAL // FGCAL
rtl9300_sds_field_w(sds, 0x2e, 0x01, 14, 14, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x01, 14, 14, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x1c, 10, 5, 0x20); rtl9300_sds_field_w(sds, 0x2e, 0x1c, 10, 5, 0x20);
rtl9300_sds_field_w(sds, 0x2f, 0x02, 0, 0, 0x1); rtl9300_sds_field_w(sds, 0x2f, 0x02, 0, 0, 0x01);
// DCVS // DCVS
rtl9300_sds_field_w(sds, 0x2e, 0x1e, 14, 11, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x1e, 14, 11, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x01, 15, 15, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x01, 15, 15, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x02, 11, 11, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x02, 11, 11, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x1c, 4, 0, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x1c, 4, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x1d, 15, 11, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x1d, 15, 11, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x1d, 10, 6, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x1d, 10, 6, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x1d, 5, 1, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x1d, 5, 1, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x02, 10, 6, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x02, 10, 6, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x11, 4, 0, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x11, 4, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2f, 0x00, 3, 0, 0xf); rtl9300_sds_field_w(sds, 0x2f, 0x00, 3, 0, 0x0f);
rtl9300_sds_field_w(sds, 0x2e, 0x04, 6, 6, 0x1); rtl9300_sds_field_w(sds, 0x2e, 0x04, 6, 6, 0x01);
rtl9300_sds_field_w(sds, 0x2e, 0x04, 7, 7, 0x1); rtl9300_sds_field_w(sds, 0x2e, 0x04, 7, 7, 0x01);
// LEQ (Long Term Equivalent signal level) // LEQ (Long Term Equivalent signal level)
rtl9300_sds_field_w(sds, 0x2e, 0x16, 14, 8, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x16, 14, 8, 0x00);
// DFE (Decision Fed Equalizer) // DFE (Decision Fed Equalizer)
rtl9300_sds_field_w(sds, 0x2f, 0x03, 5, 0, tap0_init_val); rtl9300_sds_field_w(sds, 0x2f, 0x03, 5, 0, tap0_init_val);
rtl9300_sds_field_w(sds, 0x2e, 0x09, 11, 6, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x09, 11, 6, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x09, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x09, 5, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x0a, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x0a, 5, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2f, 0x01, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2f, 0x01, 5, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2f, 0x12, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2f, 0x12, 5, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x0a, 11, 6, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x0a, 11, 6, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x06, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x06, 5, 0, 0x00);
rtl9300_sds_field_w(sds, 0x2f, 0x01, 5, 0, 0x0); rtl9300_sds_field_w(sds, 0x2f, 0x01, 5, 0, 0x00);
// Vth // Vth
rtl9300_sds_field_w(sds, 0x2e, 0x13, 5, 3, 0x7); rtl9300_sds_field_w(sds, 0x2e, 0x13, 5, 3, 0x07);
rtl9300_sds_field_w(sds, 0x2e, 0x13, 2, 0, 0x7); rtl9300_sds_field_w(sds, 0x2e, 0x13, 2, 0, 0x07);
rtl9300_sds_field_w(sds, 0x2f, 0x0b, 5, 3, vth_min); rtl9300_sds_field_w(sds, 0x2f, 0x0b, 5, 3, vth_min);
pr_info("end_1.1.1 --\n"); pr_info("end_1.1.1 --\n");
pr_info("start_1.1.2 Load DFE init. value\n"); pr_info("start_1.1.2 Load DFE init. value\n");
rtl9300_sds_field_w(sds, 0x2e, 0x0f, 13, 7, 0x7f); rtl9300_sds_field_w(sds, 0x2e, 0x0f, 13, 7, 0x7f);
pr_info("end_1.1.2\n"); pr_info("end_1.1.2\n");
pr_info("start_1.1.3 disable LEQ training,enable DFE clock\n"); pr_info("start_1.1.3 disable LEQ training,enable DFE clock\n");
rtl9300_sds_field_w(sds, 0x2e, 0x17, 7, 7, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x17, 7, 7, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x17, 6, 2, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x17, 6, 2, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x0c, 8, 8, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x0c, 8, 8, 0x00);
rtl9300_sds_field_w(sds, 0x2e, 0x0b, 4, 4, 0x1); rtl9300_sds_field_w(sds, 0x2e, 0x0b, 4, 4, 0x01);
rtl9300_sds_field_w(sds, 0x2e, 0x12, 14, 14, 0x0); rtl9300_sds_field_w(sds, 0x2e, 0x12, 14, 14, 0x00);
rtl9300_sds_field_w(sds, 0x2f, 0x02, 15, 15, 0x0); rtl9300_sds_field_w(sds, 0x2f, 0x02, 15, 15, 0x00);
pr_info("end_1.1.3 --\n"); pr_info("end_1.1.3 --\n");
pr_info("start_1.1.4 offset cali setting\n"); pr_info("start_1.1.4 offset cali setting\n");
rtl9300_sds_field_w(sds, 0x2e, 0x0f, 15, 14, 0x3); rtl9300_sds_field_w(sds, 0x2e, 0x0f, 15, 14, 0x03);
pr_info("end_1.1.4\n"); pr_info("end_1.1.4\n");
@ -2403,18 +2383,18 @@ void rtl9300_do_rx_calibration_1(int sds, phy_interface_t phy_mode)
// TODO: make this work for DAC cables of different lengths // TODO: make this work for DAC cables of different lengths
// For a 10GBit serdes wit Fibre, SDS 8 or 9 // For a 10GBit serdes wit Fibre, SDS 8 or 9
if (phy_mode == PHY_INTERFACE_MODE_10GBASER || PHY_INTERFACE_MODE_1000BASEX) if (phy_mode == PHY_INTERFACE_MODE_10GBASER || PHY_INTERFACE_MODE_1000BASEX)
rtl9300_sds_field_w(sds, 0x2e, 0x16, 3, 2, 0x2); rtl9300_sds_field_w(sds, 0x2e, 0x16, 3, 2, 0x02);
else else
pr_err("%s not PHY-based or SerDes, implement DAC!\n", __func__); pr_err("%s not PHY-based or SerDes, implement DAC!\n", __func__);
// No serdes, check for Aquantia PHYs // No serdes, check for Aquantia PHYs
rtl9300_sds_field_w(sds, 0x2e, 0x16, 3, 2, 0x2); rtl9300_sds_field_w(sds, 0x2e, 0x16, 3, 2, 0x02);
rtl9300_sds_field_w(sds, 0x2e, 0x0f, 6, 0, 0x5f); rtl9300_sds_field_w(sds, 0x2e, 0x0f, 6, 0, 0x5f);
rtl9300_sds_field_w(sds, 0x2f, 0x05, 7, 2, 0x1f); rtl9300_sds_field_w(sds, 0x2f, 0x05, 7, 2, 0x1f);
rtl9300_sds_field_w(sds, 0x2e, 0x19, 9, 5, 0x1f); rtl9300_sds_field_w(sds, 0x2e, 0x19, 9, 5, 0x1f);
rtl9300_sds_field_w(sds, 0x2f, 0x0b, 15, 9, 0x3c); rtl9300_sds_field_w(sds, 0x2f, 0x0b, 15, 9, 0x3c);
rtl9300_sds_field_w(sds, 0x2e, 0x0b, 1, 0, 0x3); rtl9300_sds_field_w(sds, 0x2e, 0x0b, 1, 0, 0x03);
pr_info("end_1.1.5\n"); pr_info("end_1.1.5\n");
} }
@ -2424,10 +2404,10 @@ void rtl9300_do_rx_calibration_2_1(u32 sds_num)
pr_info("start_1.2.1 ForegroundOffsetCal_Manual\n"); pr_info("start_1.2.1 ForegroundOffsetCal_Manual\n");
// Gray config endis to 1 // Gray config endis to 1
rtl9300_sds_field_w(sds_num, 0x2f, 0x02, 2, 2, 0x1); rtl9300_sds_field_w(sds_num, 0x2f, 0x02, 2, 2, 0x01);
// ForegroundOffsetCal_Manual(auto mode) // ForegroundOffsetCal_Manual(auto mode)
rtl9300_sds_field_w(sds_num, 0x2e, 0x01, 14, 14, 0x0); rtl9300_sds_field_w(sds_num, 0x2e, 0x01, 14, 14, 0x00);
pr_info("end_1.2.1"); pr_info("end_1.2.1");
} }
@ -2467,7 +2447,7 @@ void rtl9300_do_rx_calibration_2_3(int sds_num)
fgcal_binary = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 5, 0); fgcal_binary = rtl9300_sds_field_r(sds_num, 0x1f, 0x14, 5, 0);
pr_info("%s: fgcal_gray: %d, fgcal_binary %d\n", pr_info("%s: fgcal_gray: %d, fgcal_binary %d\n",
__func__, fgcal_gray, fgcal_binary); __func__, fgcal_gray, fgcal_binary);
offset_range = rtl9300_sds_field_r(sds_num, 0x2e, 0x15, 15, 14); offset_range = rtl9300_sds_field_r(sds_num, 0x2e, 0x15, 15, 14);
@ -2739,8 +2719,8 @@ int rtl9300_sds_check_calibration(int sds_num, phy_interface_t phy_mode)
switch (phy_mode) { switch (phy_mode) {
case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_XGMII:
if ((errors2 - errors1 > 100) if ((errors2 - errors1 > 100) ||
|| (errors1 >= 0xffff00) || (errors2 >= 0xffff00)) { (errors1 >= 0xffff00) || (errors2 >= 0xffff00)) {
pr_info("%s XSGMII error rate too high\n", __func__); pr_info("%s XSGMII error rate too high\n", __func__);
return 1; return 1;
} }
@ -2754,6 +2734,7 @@ int rtl9300_sds_check_calibration(int sds_num, phy_interface_t phy_mode)
default: default:
return 1; return 1;
} }
return 0; return 0;
} }
@ -2813,11 +2794,11 @@ int rtl9300_serdes_setup(int sds_num, phy_interface_t phy_mode)
// Maybe use dal_longan_sds_init // Maybe use dal_longan_sds_init
// dal_longan_construct_serdesConfig_init // Serdes Construct // dal_longan_construct_serdesConfig_init // Serdes Construct
rtl9300_phy_enable_10g_1g(sds_num); rtl9300_phy_enable_10g_1g(sds_num);
// Set Serdes Mode // Set Serdes Mode
rtl9300_sds_set(sds_num, 0x1a); // 0x1b: RTK_MII_10GR1000BX_AUTO rtl9300_sds_set(sds_num, 0x1a); // 0x1b: RTK_MII_10GR1000BX_AUTO
// Do RX calibration // Do RX calibration
do { do {
@ -2838,7 +2819,7 @@ typedef struct {
sds_config rtl9300_a_sds_10gr_lane0[] = sds_config rtl9300_a_sds_10gr_lane0[] =
{ {
/*1G*/ /* 1G */
{0x00, 0x0E, 0x3053}, {0x01, 0x14, 0x0100}, {0x21, 0x03, 0x8206}, {0x00, 0x0E, 0x3053}, {0x01, 0x14, 0x0100}, {0x21, 0x03, 0x8206},
{0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010}, {0x21, 0x07, 0xF09F}, {0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010}, {0x21, 0x07, 0xF09F},
{0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009}, {0x21, 0x0E, 0x0000}, {0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009}, {0x21, 0x0E, 0x0000},
@ -2855,7 +2836,7 @@ sds_config rtl9300_a_sds_10gr_lane0[] =
{0x2D, 0x18, 0x8E88}, {0x2D, 0x19, 0x4902}, {0x2D, 0x1D, 0x2641}, {0x2D, 0x18, 0x8E88}, {0x2D, 0x19, 0x4902}, {0x2D, 0x1D, 0x2641},
{0x2F, 0x13, 0x0050}, {0x2F, 0x18, 0x8E88}, {0x2F, 0x19, 0x4902}, {0x2F, 0x13, 0x0050}, {0x2F, 0x18, 0x8E88}, {0x2F, 0x19, 0x4902},
{0x2F, 0x1D, 0x66E1}, {0x2F, 0x1D, 0x66E1},
/*3.125G*/ /* 3.125G */
{0x28, 0x00, 0x0668}, {0x28, 0x02, 0xD020}, {0x28, 0x06, 0xC000}, {0x28, 0x00, 0x0668}, {0x28, 0x02, 0xD020}, {0x28, 0x06, 0xC000},
{0x28, 0x0B, 0x1892}, {0x28, 0x0F, 0xFFDF}, {0x28, 0x12, 0x01C4}, {0x28, 0x0B, 0x1892}, {0x28, 0x0F, 0xFFDF}, {0x28, 0x12, 0x01C4},
{0x28, 0x13, 0x027F}, {0x28, 0x14, 0x1311}, {0x28, 0x16, 0x00C9}, {0x28, 0x13, 0x027F}, {0x28, 0x14, 0x1311}, {0x28, 0x16, 0x00C9},
@ -2864,7 +2845,7 @@ sds_config rtl9300_a_sds_10gr_lane0[] =
{0x29, 0x05, 0x7F7C}, {0x29, 0x07, 0x8100}, {0x29, 0x08, 0x0001}, {0x29, 0x05, 0x7F7C}, {0x29, 0x07, 0x8100}, {0x29, 0x08, 0x0001},
{0x29, 0x09, 0xFFD4}, {0x29, 0x0A, 0x7C2F}, {0x29, 0x0E, 0x003F}, {0x29, 0x09, 0xFFD4}, {0x29, 0x0A, 0x7C2F}, {0x29, 0x0E, 0x003F},
{0x29, 0x0F, 0x0121}, {0x29, 0x10, 0x0020}, {0x29, 0x11, 0x8840}, {0x29, 0x0F, 0x0121}, {0x29, 0x10, 0x0020}, {0x29, 0x11, 0x8840},
/*10G*/ /* 10G */
{0x06, 0x0D, 0x0F00}, {0x06, 0x00, 0x0000}, {0x06, 0x01, 0xC800}, {0x06, 0x0D, 0x0F00}, {0x06, 0x00, 0x0000}, {0x06, 0x01, 0xC800},
{0x21, 0x03, 0x8206}, {0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010}, {0x21, 0x03, 0x8206}, {0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010},
{0x21, 0x07, 0xF09F}, {0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009}, {0x21, 0x07, 0xF09F}, {0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009},
@ -2886,7 +2867,7 @@ sds_config rtl9300_a_sds_10gr_lane0[] =
sds_config rtl9300_a_sds_10gr_lane1[] = sds_config rtl9300_a_sds_10gr_lane1[] =
{ {
/*1G*/ /* 1G */
{0x00, 0x0E, 0x3053}, {0x01, 0x14, 0x0100}, {0x21, 0x03, 0x8206}, {0x00, 0x0E, 0x3053}, {0x01, 0x14, 0x0100}, {0x21, 0x03, 0x8206},
{0x21, 0x06, 0x0010}, {0x21, 0x07, 0xF09F}, {0x21, 0x0A, 0x0003}, {0x21, 0x06, 0x0010}, {0x21, 0x07, 0xF09F}, {0x21, 0x0A, 0x0003},
{0x21, 0x0B, 0x0005}, {0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009}, {0x21, 0x0B, 0x0005}, {0x21, 0x0C, 0x0007}, {0x21, 0x0D, 0x6009},
@ -2901,7 +2882,7 @@ sds_config rtl9300_a_sds_10gr_lane1[] =
{0x25, 0x0F, 0x0121}, {0x25, 0x10, 0x0020}, {0x25, 0x11, 0x8840}, {0x25, 0x0F, 0x0121}, {0x25, 0x10, 0x0020}, {0x25, 0x11, 0x8840},
{0x2B, 0x13, 0x3D87}, {0x2B, 0x14, 0x3108}, {0x2D, 0x13, 0x3C87}, {0x2B, 0x13, 0x3D87}, {0x2B, 0x14, 0x3108}, {0x2D, 0x13, 0x3C87},
{0x2D, 0x14, 0x1808}, {0x2D, 0x14, 0x1808},
/*3.125G*/ /* 3.125G */
{0x28, 0x00, 0x0668}, {0x28, 0x02, 0xD020}, {0x28, 0x06, 0xC000}, {0x28, 0x00, 0x0668}, {0x28, 0x02, 0xD020}, {0x28, 0x06, 0xC000},
{0x28, 0x0B, 0x1892}, {0x28, 0x0F, 0xFFDF}, {0x28, 0x12, 0x01C4}, {0x28, 0x0B, 0x1892}, {0x28, 0x0F, 0xFFDF}, {0x28, 0x12, 0x01C4},
{0x28, 0x13, 0x027F}, {0x28, 0x14, 0x1311}, {0x28, 0x16, 0x00C9}, {0x28, 0x13, 0x027F}, {0x28, 0x14, 0x1311}, {0x28, 0x16, 0x00C9},
@ -2910,7 +2891,7 @@ sds_config rtl9300_a_sds_10gr_lane1[] =
{0x29, 0x03, 0xFFDF}, {0x29, 0x05, 0x7F7C}, {0x29, 0x07, 0x8100}, {0x29, 0x03, 0xFFDF}, {0x29, 0x05, 0x7F7C}, {0x29, 0x07, 0x8100},
{0x29, 0x08, 0x0001}, {0x29, 0x0A, 0x7C2F}, {0x29, 0x0E, 0x003F}, {0x29, 0x08, 0x0001}, {0x29, 0x0A, 0x7C2F}, {0x29, 0x0E, 0x003F},
{0x29, 0x0F, 0x0121}, {0x29, 0x10, 0x0020}, {0x29, 0x11, 0x8840}, {0x29, 0x0F, 0x0121}, {0x29, 0x10, 0x0020}, {0x29, 0x11, 0x8840},
/*10G*/ /* 10G */
{0x06, 0x0D, 0x0F00}, {0x06, 0x00, 0x0000}, {0x06, 0x01, 0xC800}, {0x06, 0x0D, 0x0F00}, {0x06, 0x00, 0x0000}, {0x06, 0x01, 0xC800},
{0x21, 0x03, 0x8206}, {0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010}, {0x21, 0x03, 0x8206}, {0x21, 0x05, 0x40B0}, {0x21, 0x06, 0x0010},
{0x21, 0x07, 0xF09F}, {0x21, 0x0A, 0x0003}, {0x21, 0x0B, 0x0005}, {0x21, 0x07, 0xF09F}, {0x21, 0x0A, 0x0003}, {0x21, 0x0B, 0x0005},
@ -3007,14 +2988,14 @@ int rtl9300_configure_serdes(struct phy_device *phydev)
if (sds_num % 2) { if (sds_num % 2) {
for (i = 0; i < sizeof(rtl9300_a_sds_10gr_lane1) / sizeof(sds_config); ++i) { for (i = 0; i < sizeof(rtl9300_a_sds_10gr_lane1) / sizeof(sds_config); ++i) {
rtl930x_write_sds_phy(sds_num, rtl9300_a_sds_10gr_lane1[i].page, rtl930x_write_sds_phy(sds_num, rtl9300_a_sds_10gr_lane1[i].page,
rtl9300_a_sds_10gr_lane1[i].reg, rtl9300_a_sds_10gr_lane1[i].reg,
rtl9300_a_sds_10gr_lane1[i].data); rtl9300_a_sds_10gr_lane1[i].data);
} }
} else { } else {
for (i = 0; i < sizeof(rtl9300_a_sds_10gr_lane0) / sizeof(sds_config); ++i) { for (i = 0; i < sizeof(rtl9300_a_sds_10gr_lane0) / sizeof(sds_config); ++i) {
rtl930x_write_sds_phy(sds_num, rtl9300_a_sds_10gr_lane0[i].page, rtl930x_write_sds_phy(sds_num, rtl9300_a_sds_10gr_lane0[i].page,
rtl9300_a_sds_10gr_lane0[i].reg, rtl9300_a_sds_10gr_lane0[i].reg,
rtl9300_a_sds_10gr_lane0[i].data); rtl9300_a_sds_10gr_lane0[i].data);
} }
} }
@ -3074,7 +3055,6 @@ void rtl9310_sds_field_w(int sds, u32 page, u32 reg, int end_bit, int start_bit,
rtl931x_write_sds_phy(sds, page, reg, data); rtl931x_write_sds_phy(sds, page, reg, data);
} }
u32 rtl9310_sds_field_r(int sds, u32 page, u32 reg, int end_bit, int start_bit) u32 rtl9310_sds_field_r(int sds, u32 page, u32 reg, int end_bit, int start_bit)
{ {
int l = end_bit - start_bit + 1; int l = end_bit - start_bit + 1;
@ -3121,15 +3101,15 @@ static void rtl931x_symerr_clear(u32 sds, phy_interface_t mode)
xsg_sdsid_1 = xsg_sdsid_0 + 1; xsg_sdsid_1 = xsg_sdsid_0 + 1;
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 24, 2, 0, i); rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 24, 2, 0, i);
rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 3, 15, 8, 0x0); rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 3, 15, 8, 0x0);
rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 2, 15, 0, 0x0); rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 2, 15, 0, 0x0);
} }
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 24, 2, 0, i); rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 24, 2, 0, i);
rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 3, 15, 8, 0x0); rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 3, 15, 8, 0x0);
rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 2, 15, 0, 0x0); rtl9310_sds_field_w(xsg_sdsid_1, 0x1, 2, 15, 0, 0x0);
} }
rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 0, 15, 0, 0x0); rtl9310_sds_field_w(xsg_sdsid_0, 0x1, 0, 15, 0, 0x0);
@ -3150,6 +3130,7 @@ static u32 rtl931x_get_analog_sds(u32 sds)
if (sds < 14) if (sds < 14)
return sds_map[sds]; return sds_map[sds];
return sds; return sds;
} }
@ -3225,6 +3206,7 @@ static int rtl931x_sds_cmu_page_get(phy_interface_t mode)
default: default:
return -1; return -1;
} }
return -1; return -1;
} }
@ -3300,7 +3282,7 @@ static void rtl931x_cmu_type_set(u32 asds, phy_interface_t mode, int chiptype)
evenSds = asds - lane; evenSds = asds - lane;
pr_info("%s: cmu_type %0d cmu_page %x frc_cmu_spd %d lane %d asds %d\n", pr_info("%s: cmu_type %0d cmu_page %x frc_cmu_spd %d lane %d asds %d\n",
__func__, cmu_type, cmu_page, frc_cmu_spd, lane, asds); __func__, cmu_type, cmu_page, frc_cmu_spd, lane, asds);
if (cmu_type == 1) { if (cmu_type == 1) {
pr_info("%s A CMU page 0x28 0x7 %08x\n", __func__, rtl931x_read_sds_phy(asds, 0x28, 0x7)); pr_info("%s A CMU page 0x28 0x7 %08x\n", __func__, rtl931x_read_sds_phy(asds, 0x28, 0x7));
@ -3405,19 +3387,18 @@ static sds_config sds_config_10p3125g_cmu_type1[] = {
void rtl931x_sds_init(u32 sds, phy_interface_t mode) void rtl931x_sds_init(u32 sds, phy_interface_t mode)
{ {
u32 board_sds_tx_type1[] = {
u32 board_sds_tx_type1[] = { 0x1C3, 0x1C3, 0x1C3, 0x1A3, 0x1A3, 0x01c3, 0x01c3, 0x01c3, 0x01a3, 0x01a3, 0x01a3,
0x1A3, 0x143, 0x143, 0x143, 0x143, 0x163, 0x163 0x0143, 0x0143, 0x0143, 0x0143, 0x0163, 0x0163,
}; };
u32 board_sds_tx[] = {
u32 board_sds_tx[] = { 0x1A00, 0x1A00, 0x200, 0x200, 0x200, 0x1a00, 0x1a00, 0x0200, 0x0200, 0x0200, 0x0200,
0x200, 0x1A3, 0x1A3, 0x1A3, 0x1A3, 0x1E3, 0x1E3 0x01a3, 0x01a3, 0x01a3, 0x01a3, 0x01e3, 0x01e3
}; };
u32 board_sds_tx2[] = {
u32 board_sds_tx2[] = { 0xDC0, 0x1C0, 0x200, 0x180, 0x160, 0x0dc0, 0x01c0, 0x0200, 0x0180, 0x0160, 0x0123,
0x123, 0x123, 0x163, 0x1A3, 0x1A0, 0x1C3, 0x9C3 0x0123, 0x0163, 0x01a3, 0x01a0, 0x01c3, 0x09c3,
}; };
u32 asds, dSds, ori, model_info, val; u32 asds, dSds, ori, model_info, val;
int chiptype = 0; int chiptype = 0;
@ -3456,7 +3437,7 @@ void rtl931x_sds_init(u32 sds, phy_interface_t mode)
dSds = (sds - 1) * 2; dSds = (sds - 1) * 2;
pr_info("%s: 2.5gbit %08X dsds %d", __func__, pr_info("%s: 2.5gbit %08X dsds %d", __func__,
rtl931x_read_sds_phy(dSds, 0x1, 0x14), dSds); rtl931x_read_sds_phy(dSds, 0x1, 0x14), dSds);
pr_info("%s: RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR 0x%08X\n", __func__, sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR)); pr_info("%s: RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR 0x%08X\n", __func__, sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR));
ori = sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR); ori = sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR);
@ -3500,7 +3481,7 @@ void rtl931x_sds_init(u32 sds, phy_interface_t mode)
for (i = 0; i < sizeof(sds_config_10p3125g_cmu_type1) / sizeof(sds_config); ++i) { for (i = 0; i < sizeof(sds_config_10p3125g_cmu_type1) / sizeof(sds_config); ++i) {
rtl931x_write_sds_phy(evenSds, rtl931x_write_sds_phy(evenSds,
sds_config_10p3125g_cmu_type1[i].page - 0x4, sds_config_10p3125g_cmu_type1[i].reg, sds_config_10p3125g_cmu_type1[i].data); sds_config_10p3125g_cmu_type1[i].page - 0x4, sds_config_10p3125g_cmu_type1[i].reg, sds_config_10p3125g_cmu_type1[i].data);
} }
rtl9310_sds_field_w(asds, 0x6, 0x2, 12, 12, 0); rtl9310_sds_field_w(asds, 0x6, 0x2, 12, 12, 0);
@ -3527,7 +3508,7 @@ void rtl931x_sds_init(u32 sds, phy_interface_t mode)
break; break;
case PHY_INTERFACE_MODE_10GBASER: // MII_10GR / MII_10GR1000BX_AUTO: case PHY_INTERFACE_MODE_10GBASER: // MII_10GR / MII_10GR1000BX_AUTO:
// configure 10GR fiber mode=1 // configure 10GR fiber mode=1
rtl9310_sds_field_w(asds, 0x1f, 0xb, 1, 1, 1); rtl9310_sds_field_w(asds, 0x1f, 0xb, 1, 1, 1);
// init fiber_1g // init fiber_1g
@ -3566,7 +3547,7 @@ void rtl931x_sds_init(u32 sds, phy_interface_t mode)
case PHY_INTERFACE_MODE_QSGMII: case PHY_INTERFACE_MODE_QSGMII:
default: default:
pr_info("%s: PHY mode %s not supported by SerDes %d\n", pr_info("%s: PHY mode %s not supported by SerDes %d\n",
__func__, phy_modes(mode), sds); __func__, phy_modes(mode), sds);
return; return;
} }
@ -3594,9 +3575,11 @@ void rtl931x_sds_init(u32 sds, phy_interface_t mode)
sw_w32(val, RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR); sw_w32(val, RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR);
pr_debug("%s: RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR 0x%08X\n", __func__, sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR)); pr_debug("%s: RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR 0x%08X\n", __func__, sw_r32(RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR));
if (mode == PHY_INTERFACE_MODE_XGMII || mode == PHY_INTERFACE_MODE_QSGMII if (mode == PHY_INTERFACE_MODE_XGMII ||
|| mode == PHY_INTERFACE_MODE_HSGMII || mode == PHY_INTERFACE_MODE_SGMII mode == PHY_INTERFACE_MODE_QSGMII ||
|| mode == PHY_INTERFACE_MODE_USXGMII) { mode == PHY_INTERFACE_MODE_HSGMII ||
mode == PHY_INTERFACE_MODE_SGMII ||
mode == PHY_INTERFACE_MODE_USXGMII) {
if (mode == PHY_INTERFACE_MODE_XGMII) if (mode == PHY_INTERFACE_MODE_XGMII)
rtl931x_sds_mii_mode_set(sds, mode); rtl931x_sds_mii_mode_set(sds, mode);
else else
@ -3674,6 +3657,7 @@ int rtl931x_link_sts_get(u32 sds)
pr_info("%s: serdes %d sts %d, sts1 %d, latch_sts %d, latch_sts1 %d\n", __func__, pr_info("%s: serdes %d sts %d, sts1 %d, latch_sts %d, latch_sts1 %d\n", __func__,
sds, sts, sts1, latch_sts, latch_sts1); sds, sts, sts1, latch_sts, latch_sts1);
return sts1; return sts1;
} }
@ -3741,6 +3725,7 @@ static int rtl8214c_phy_probe(struct phy_device *phydev)
/* Configuration must be done whil patching still possible */ /* Configuration must be done whil patching still possible */
return rtl8380_configure_rtl8214c(phydev); return rtl8380_configure_rtl8214c(phydev);
} }
return 0; return 0;
} }
@ -3807,6 +3792,7 @@ static int rtl8218d_phy_probe(struct phy_device *phydev)
/* Configuration must be done while patching still possible */ /* Configuration must be done while patching still possible */
// TODO: return configure_rtl8218d(phydev); // TODO: return configure_rtl8218d(phydev);
} }
return 0; return 0;
} }
@ -3825,6 +3811,7 @@ static int rtl838x_serdes_probe(struct phy_device *phydev)
return rtl8380_configure_serdes(phydev); return rtl8380_configure_serdes(phydev);
return 0; return 0;
} }
return -ENODEV; return -ENODEV;
} }

View file

@ -60,7 +60,7 @@ struct __attribute__ ((__packed__)) fw_header {
#define RTL930X_SDS_INDACS_DATA (0x03B4) #define RTL930X_SDS_INDACS_DATA (0x03B4)
#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C) #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_ACCESS_CTRL (0x5638)
#define RTL931X_SERDES_INDRT_DATA_CTRL (0x563C) #define RTL931X_SERDES_INDRT_DATA_CTRL (0x563C)
#define RTL931X_SERDES_MODE_CTRL (0x13cc) #define RTL931X_SERDES_MODE_CTRL (0x13cc)