OpenWrt Forum Archive

Topic: Support for Marvell 88F5xx81 based routers

The content of this topic has been archived between 18 Jan 2014 and 6 May 2018. Unfortunately there are posts – most likely complete pages – missing.

With changeset #25620 the kernel watchdog driver for marvell orion has been added.

kmod-wdt-orion can be found in Kernel modules/Other modules.

yea, seems to load without problems smile but i dunno how to configure it ... and what exactly this module do... i get in dmesg :

Orion Watchdog Timer: Initial timeout 25 sec

If you don't "kick the dog" between 25 seconds the dog reboot the router. Only happens when already hung.

nice, tx for the info smile updated my release (r26044) : http://tanguy.wdscript.fr/?q=wnr854t

made as module to test it... i will add it as default in Makefile

Looking at #8325, there is a patch that mirror software bridge into hardware bridge: Faster switch speeds, CPU offload.

@Nilfred Does it work?

mrk wrote:

@Nilfred Does it work?

Short answer: No. Long answer:

opkg install kmod-mvswitch wrote:

Installing kmod-mvswitch (2.6.37.1-1) to root...
Downloading http:// ... packages/kmod-mvswitch_2.6.37.1-1_orion.ipk.
Collected errors:
* satisfy_dependencies_for: Cannot satisfy the following dependencies for kmod-mvswitch:
*      kmod-libphy *
* opkg_install_cmd: Cannot install package kmod-mvswitch.

There is no spoon.

I move my focus to mwl8k AP (hack against 8366 instead of 8363). Will come back to this later, as some pieces are missing, but it should work.

you can try to untargz the package... you will have the module (data) and install script (control)

I mislead, these aren't needed, so I modified the patch to work against current trunk r26185 as follow:

cd ~/build/openwrt/trunk
svn up -r 26185
cd feeds/packages
svn up -r 26185
cd ~/build/openwrt/trunk
make menuconfig
make world
cd build_dir/linux-orion_generic/linux-2.6.37.3
patch -p1 < RFC-hardware-bridging-support-for-DSA-switches.patch

--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -739,6 +739,12 @@ struct net_device_ops {
                              struct rtnl_link_stats64 *storage);
     struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
 
+    void            (*ndo_bridge_join)(struct net_device *dev,
+                           void *bridge);
+    void            (*ndo_bridge_set_stp_state)(struct net_device *dev,
+                            int state);
+    void            (*ndo_bridge_leave)(struct net_device *dev);
+
     void            (*ndo_vlan_rx_register)(struct net_device *dev,
                                 struct vlan_group *grp);
     void            (*ndo_vlan_rx_add_vid)(struct net_device *dev,
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -138,6 +138,9 @@ static void del_nbp(struct net_bridge_po
     br_stp_disable_port(p);
     spin_unlock_bh(&br->lock);
 
+    if (dev->netdev_ops->ndo_bridge_leave != NULL)
+        dev->netdev_ops->ndo_bridge_leave(dev);
+
     br_ifinfo_notify(RTM_DELLINK, p);
 
     br_fdb_delete_by_port(br, p, 1);
@@ -443,6 +446,9 @@ int br_add_if(struct net_bridge *br, str
     br_stp_recalculate_bridge_id(br);
     br_features_recompute(br);
 
+    if (dev->netdev_ops->ndo_bridge_join != NULL)
+        dev->netdev_ops->ndo_bridge_join(dev, (void *)br);
+
     if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
         (br->dev->flags & IFF_UP))
         br_stp_enable_port(p);
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -34,6 +34,8 @@ void br_log_state(const struct net_bridg
     br_info(p->br, "port %u(%s) entering %s state\n",
         (unsigned) p->port_no, p->dev->name,
         br_port_state_names[p->state]);
+    if (p->dev->netdev_ops->ndo_bridge_set_stp_state != NULL)
+        p->dev->netdev_ops->ndo_bridge_set_stp_state(p->dev, p->state);
 }
 
 /* called under bridge lock */
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -94,11 +94,10 @@ void br_stp_disable_port(struct net_brid
     struct net_bridge *br = p->br;
     int wasroot;
 
-    br_log_state(p);
-
     wasroot = br_is_root_bridge(br);
     br_become_designated_port(p);
     p->state = BR_STATE_DISABLED;
+    br_log_state(p);
     p->topology_change_ack = 0;
     p->config_pending = 0;
 
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -155,6 +155,15 @@ struct dsa_switch_driver {
     void    (*get_ethtool_stats)(struct dsa_switch *ds,
                      int port, uint64_t *data);
     int    (*get_sset_count)(struct dsa_switch *ds);
+
+    /*
+     * Hardware bridging.
+     */
+    void    (*bridge_join)(struct dsa_switch *ds, int port,
+                   void *bridge);
+    void    (*bridge_set_stp_state)(struct dsa_switch *ds, int port,
+                    int state);
+    void    (*bridge_leave)(struct dsa_switch *ds, int port);
 };
 
 /* dsa.c */
--- a/net/dsa/mv88e6123_61_65.c
+++ b/net/dsa/mv88e6123_61_65.c
@@ -8,6 +8,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/if_bridge.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/phy.h>
@@ -232,10 +233,9 @@ static int mv88e6123_61_65_setup_port(st
     REG_WRITE(addr, 0x04, val);
 
     /*
-     * Port Control 1: disable trunking.  Also, if this is the
-     * CPU port, enable learn messages to be sent to this port.
+     * Port Control 1: disable trunking.
      */
-    REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
+    REG_WRITE(addr, 0x05, 0x0000);
 
     /*
      * Port based VLAN map: give each port its own address
@@ -316,6 +316,8 @@ static int mv88e6123_61_65_setup_port(st
     return 0;
 }
 
+static void mv88e6123_61_65_hw_bridge_sync_work(struct work_struct *ugly);
+
 static int mv88e6123_61_65_setup(struct dsa_switch *ds)
 {
     struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
@@ -324,6 +326,8 @@ static int mv88e6123_61_65_setup(struct 
 
     mutex_init(&ps->smi_mutex);
     mutex_init(&ps->stats_mutex);
+    spin_lock_init(&ps->hw_bridge_state);
+    INIT_WORK(&ps->hw_bridge_work, mv88e6123_61_65_hw_bridge_sync_work);
 
     ret = mv88e6123_61_65_switch_reset(ds);
     if (ret < 0)
@@ -339,6 +343,10 @@ static int mv88e6123_61_65_setup(struct 
         ret = mv88e6123_61_65_setup_port(ds, i);
         if (ret < 0)
             return ret;
+
+        // @@@
+        ps->fid[i] = i;
+        ps->stp_state[i] = 3;
     }
 
     return 0;
@@ -419,6 +427,159 @@ static int mv88e6123_61_65_get_sset_coun
     return ARRAY_SIZE(mv88e6123_61_65_hw_stats);
 }
 
+static void mv88e6123_61_65_hw_bridge_sync_work(struct work_struct *ugly)
+{
+    struct mv88e6xxx_priv_state *ps;
+    struct dsa_switch *ds;
+    int i;
+
+    ps = container_of(ugly, struct mv88e6xxx_priv_state, hw_bridge_work);
+    ds = ((struct dsa_switch *)ps) - 1;
+
+    spin_lock(&ps->hw_bridge_state);
+    for (i = 0; i < MV88E6XXX_MAX_PORTS; i++) {
+        if (ps->fid_dirty[i]) {
+            int reg;
+            int j;
+
+            reg = (ps->fid[i] << 12) | (1 << ds->cpu_port);
+            ps->fid_dirty[i] = 0;
+
+            for (j = 0; j < MV88E6XXX_MAX_PORTS; j++) {
+                if (i != j && ps->bridge[i] != NULL &&
+                    ps->bridge[i] == ps->bridge[j]) {
+                    reg |= 1 << j;
+                }
+            }
+
+            spin_unlock(&ps->hw_bridge_state);
+            mv88e6xxx_reg_write(ds, REG_PORT(i), 6, reg);
+            spin_lock(&ps->hw_bridge_state);
+        }
+
+        if (ps->stp_state_dirty[i]) {
+            int new_state;
+            int reg;
+
+            new_state = ps->stp_state[i];
+            ps->stp_state_dirty[i] = 0;
+            spin_unlock(&ps->hw_bridge_state);
+            reg = mv88e6xxx_reg_read(ds, REG_PORT(i), 4);
+            if (reg >= 0) {
+                reg &= ~0x0003;
+                reg |= new_state;
+                mv88e6xxx_reg_write(ds, REG_PORT(i), 4, reg);
+            }
+            spin_lock(&ps->hw_bridge_state);
+        }
+    }
+    spin_unlock(&ps->hw_bridge_state);
+}
+
+static void
+set_stp_state(struct dsa_switch *ds, int port, int state)
+{
+    struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+    int hw_state = 0;
+
+    switch (state) {
+    case BR_STATE_DISABLED:
+        hw_state = 0;
+        break;
+    case BR_STATE_BLOCKING:
+    case BR_STATE_LISTENING:
+        hw_state = 1;
+        break;
+    case BR_STATE_LEARNING:
+        hw_state = 2;
+        break;
+    case BR_STATE_FORWARDING:
+        hw_state = 3;
+        break;
+    default:
+        BUG();
+    }
+
+    if (ps->stp_state[port] != hw_state) {
+        ps->stp_state_dirty[port] = 1;
+        ps->stp_state[port] = hw_state;
+    }
+}
+
+static void
+mv88e6123_61_65_bridge_join(struct dsa_switch *ds, int port, void *bridge)
+{
+    struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+    int fid;
+    int i;
+
+    spin_lock(&ps->hw_bridge_state);
+
+    fid = 65536;
+    for (i = 0; i < MV88E6XXX_MAX_PORTS; i++) {
+        if (ps->bridge[i] == bridge) {
+            if (ps->fid[i] < fid)
+                fid = ps->fid[i];
+            ps->fid_dirty[i] = 1;
+        }
+    }
+
+    ps->bridge[port] = bridge;
+
+    ps->fid_dirty[port] = 1;
+    if (fid != 65536)
+        ps->fid[port] = fid;
+
+    set_stp_state(ds, port, BR_STATE_DISABLED);
+
+    spin_unlock(&ps->hw_bridge_state);
+
+    schedule_work(&ps->hw_bridge_work);
+}
+
+static void
+mv88e6123_61_65_bridge_set_stp_state(struct dsa_switch *ds, int port, int state)
+{
+    struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+
+    spin_lock(&ps->hw_bridge_state);
+    set_stp_state(ds, port, state);
+    spin_unlock(&ps->hw_bridge_state);
+
+    schedule_work(&ps->hw_bridge_work);
+}
+
+static void mv88e6123_61_65_bridge_leave(struct dsa_switch *ds, int port)
+{
+    struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
+    u16 free_fids;
+    int i;
+    int fid;
+
+    spin_lock(&ps->hw_bridge_state);
+
+    free_fids = 0xffff;
+    for (i = 0; i < MV88E6XXX_MAX_PORTS; i++) {
+        if (i == ds->cpu_port || ds->valid_port_mask & (1 << i)) {
+            if (ps->bridge[i] == ps->bridge[port])
+                ps->fid_dirty[i] = 1;
+            if (i != port)
+                free_fids &= ~(1 << ps->fid[i]);
+        }
+    }
+
+    fid = ffs(free_fids) - 1;
+
+    ps->fid[port] = fid;
+    ps->bridge[port] = NULL;
+
+    set_stp_state(ds, port, BR_STATE_FORWARDING);
+
+    spin_unlock(&ps->hw_bridge_state);
+
+    schedule_work(&ps->hw_bridge_work);
+}
+
 static struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
     .tag_protocol        = cpu_to_be16(ETH_P_EDSA),
     .priv_size        = sizeof(struct mv88e6xxx_priv_state),
@@ -431,6 +592,9 @@ static struct dsa_switch_driver mv88e612
     .get_strings        = mv88e6123_61_65_get_strings,
     .get_ethtool_stats    = mv88e6123_61_65_get_ethtool_stats,
     .get_sset_count        = mv88e6123_61_65_get_sset_count,
+    .bridge_join        = mv88e6123_61_65_bridge_join,
+    .bridge_set_stp_state    = mv88e6123_61_65_bridge_set_stp_state,
+    .bridge_leave        = mv88e6123_61_65_bridge_leave,
 };
 
 static int __init mv88e6123_61_65_init(void)
--- a/net/dsa/mv88e6xxx.h
+++ b/net/dsa/mv88e6xxx.h
@@ -15,6 +15,8 @@
 #define REG_GLOBAL        0x1b
 #define REG_GLOBAL2        0x1c
 
+#define MV88E6XXX_MAX_PORTS    11
+
 struct mv88e6xxx_priv_state {
     /*
      * When using multi-chip addressing, this mutex protects
@@ -39,6 +41,17 @@ struct mv88e6xxx_priv_state {
      * Hold this mutex over snapshot + dump sequences.
      */
     struct mutex    stats_mutex;
+
+    /*
+     * Hardware bridging state.
+     */
+    spinlock_t    hw_bridge_state;
+    struct work_struct    hw_bridge_work;
+    void        *bridge[MV88E6XXX_MAX_PORTS];
+    int        fid_dirty[MV88E6XXX_MAX_PORTS];
+    int        fid[MV88E6XXX_MAX_PORTS];
+    int        stp_state_dirty[MV88E6XXX_MAX_PORTS];
+    int        stp_state[MV88E6XXX_MAX_PORTS];
 };
 
 struct mv88e6xxx_hw_stat {
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -171,6 +171,33 @@ static int dsa_slave_ioctl(struct net_de
     return -EOPNOTSUPP;
 }
 
+static void dsa_bridge_join(struct net_device *dev, void *bridge)
+{
+    struct dsa_slave_priv *p = netdev_priv(dev);
+    struct dsa_switch *ds = p->parent;
+
+    if (ds->drv->bridge_join != NULL)
+        ds->drv->bridge_join(ds, p->port, bridge);
+}
+
+static void dsa_bridge_set_stp_state(struct net_device *dev, int state)
+{
+    struct dsa_slave_priv *p = netdev_priv(dev);
+    struct dsa_switch *ds = p->parent;
+
+    if (ds->drv->bridge_set_stp_state != NULL)
+        ds->drv->bridge_set_stp_state(ds, p->port, state);
+}
+
+static void dsa_bridge_leave(struct net_device *dev)
+{
+    struct dsa_slave_priv *p = netdev_priv(dev);
+    struct dsa_switch *ds = p->parent;
+
+    if (ds->drv->bridge_leave != NULL)
+        ds->drv->bridge_leave(ds, p->port);
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -305,6 +332,9 @@ static const struct net_device_ops dsa_n
     .ndo_set_multicast_list = dsa_slave_set_rx_mode,
     .ndo_set_mac_address    = dsa_slave_set_mac_address,
     .ndo_do_ioctl        = dsa_slave_ioctl,
+    .ndo_bridge_join    = dsa_bridge_join,
+    .ndo_bridge_set_stp_state    = dsa_bridge_set_stp_state,
+    .ndo_bridge_leave    = dsa_bridge_leave,
 };
 #endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA

cd ~/build/openwrt/trunk
make V=99 target/install

The firmware start just as normal, uptime 07:53:20. How do I test the change? Which standard speed test?
Could someone double check if my code changes are OK? Just in case.

(Last edited by Nilfred on 18 Mar 2011, 12:03)

Hello
I have the router wrt350nv2. My router is working with the backfire 10.03. This firmware does not have the functionality macfilter.

How can I install macfilter?

Thanks!

@mrk: It works, I tested against r26185 and now against r26358, 2.6.37.4. Test You too, please:
RFC-hardware-bridging-support-for-DSA-switches.patch

@buytenh: It's your baby refreshed to 2.6.37.4: I would like if you can check code changes from your original patch are OK to you.

@all: kmod-crypto-mv-cesa has support for hmac and sha1 from some time ago. To enable these too:

make kernel_menuconfig wrote:

Cryptographic API  --->
SHA1 digest algorithm
MD5 digest algorithm
HMAC support

On your way:

make kernel_menuconfig wrote:

Device Divers -> Real Time Clock

Mere cosmetic to:

dmesg wrote:

drivers/rtc/hctosys.c: unable to open rtc device (rtc0)

If You tempted to touch something else and all goes bad, use svn revert:

cd target/linux/<arch>
svn revert config-2.6.37

The XOR engine is also there, will make the compiler happy if I enable any raid, but I didn't. Should I?

the WNR854T SoC doesnt have MVCESA features, the wrt350nv2 has it, its not exactly the same SoC

(Last edited by Tanguy on 9 Apr 2011, 20:45)

I doubled my old AES score compiling libopenssl with hardware acceleration (same and here)
So I think mv-cesa is there, despite what You say.

There are no ID traces of CESA in lsmod nor cat /proc/crypto. Are another way to probe it?

oh... weird, ive read that in marvell kernel sources, but maybe some algorythms are optimized by other ARM features ...

Ive made some tests with my build, r26588 with openssl crypto acceleration selected :
My build is different from trunk, ive selected "armv5te" instead of default "armv5t" for kernel and all tools

only kmod-crypto-hash :
| 1.0.0d |  21976010 |  7905690 |  5491800 |  2373350 |  3337420 |  1188390 |  5577360 |  4867940 |  4359760 |  5.8 |  205.2 |  20.6 |  16.8 |
only kmod-crypto-hash, sha1, md5 kernel modules
| 1.0.0d |  22273550 |  7945620 |  5482870 |  2359650 |  3345180 |  1189280 |  5565680 |  4875680 |  4351140 |  5.8 |  204.6 |  20.6 |  16.7 |
all kmod crypto (kmod aes is 2x slower !) :
| 1.0.0d |  23025910 |  7937200 |  5468980 |  2371300 |  3304450 |  1188050 |  4118600 |  3218580 |  2857920 |  5.8 |  205.7 |  20.7 |  16.8 |
kmod aes + kmod mv_cesa (need kmod aes)
| 1.0.0d |  22025970 |  7871740 |  5465690 |  2359320 |  3299060 |  1191220 |  4608690 |  4000820 |  3556600 |  5.8 |  205.1 |  20.6 |  16.8 |

(Last edited by Tanguy on 11 Apr 2011, 05:39)

I copied your results to Wiki to clarify some interesting points:
Please use the feature code for best explanation of what exactly You enabled for the highest score. I already put what I figure out about.
Also note that cesa is default enabled in kernel_menuconfig.

While hunting down rtc error I found another obscure corner:

make kernel_menuconfig
Device Drivers
    Real Time Clock
        -Set system time from RTC on startup and resume
        -Intersil ISL1208
        -PC-style 'CMOS'
    DMA Engine support
        +Marvell XOR engine support (NEW)
            +Network: TCP receive copy offload (NEW)
            +Async_tx: Offload support for the async_tx api

Will make now, upload tomorrow, fingers crossed...
make success while typing this post. Anyway will upload later, now I have to sleep.

Tanguy wrote:

My build is different from trunk, ive selected "armv5te" instead of default "armv5t" for kernel and all tools

Why not "armv5tej"?
Where do I change that? Here?:

make menuconfig wrote:

Advanced configuration options (for developers)
Target Options
-Os -pipe -march=armv5t -mtune=xscale -fno-caller-saves

yea here smile -march=armv5te

the j is for java optimisation, nothing usefull for us... usefull for android

set it also in target/linux/orion/Makefile

(Last edited by Tanguy on 11 Apr 2011, 09:47)

@tanguy

I've flashed your r26588 build onto my WNR854T and it seems to work well - green LEDs make me happy.

I've been able to install kmod-ipv6, but can't install kmod-ip6tables as it doesn't exist! Is there a good reason for this, or does it just need compiling?

@all - Thanks for all your input - reading the 41 pages has been informative if exhausting...

alexhulse wrote:

I've been able to install kmod-ipv6, but can't install kmod-ip6tables as it doesn't exist! Is there a good reason for this, or does it just need compiling?

no, its just i dont have really tested the ipv6... my ISP doesnt use it for the moment... thanks for the report, i will select it next time

I have finally taken the step and installed OpenWRT on my WRT350N v2.1

I installed the webupgrade, and everything except Wifi seems to be running.

Do I need any further steps to get the Wifi working, or have I done something wrong in the config?

I have it set to 20Mhz to begin with... then when that works I will start playing with 40Mhz

I am not very familiar with Linux, but I am pretty good on windows.

If anyone can help me, I will be very thankfull

Martin

Looks like I bricked the WRT350N when I tried to upgrade it to the latest beta in an attempt to get the wifi working.

Tanguy wrote:
alexhulse wrote:

I've been able to install kmod-ipv6, but can't install kmod-ip6tables as it doesn't exist! Is there a good reason for this, or does it just need compiling?

no, its just i dont have really tested the ipv6... my ISP doesnt use it for the moment... thanks for the report, i will select it next time

I've installed your r27011 build and it's working with IPv6 fine now - thanks!

On the previous build I had a little play with the built in wireless, but still had no joy. I assume the current advice is to swap out the wireless card inside the WNR854T with one of the ones mentioned on the wiki?

alexhulse wrote:
Tanguy wrote:
alexhulse wrote:

I've been able to install kmod-ipv6, but can't install kmod-ip6tables as it doesn't exist! Is there a good reason for this, or does it just need compiling?

no, its just i dont have really tested the ipv6... my ISP doesnt use it for the moment... thanks for the report, i will select it next time

I've installed your r27011 build and it's working with IPv6 fine now - thanks!

On the previous build I had a little play with the built in wireless, but still had no joy. I assume the current advice is to swap out the wireless card inside the WNR854T with one of the ones mentioned on the wiki?

Yes, and you have some wireless config to do the first time...only one file

Sorry to ask this - as it might be answered somewhere but I can't find.

I've just taken the plunge and gone from stock to OpenWRT on my WRT-350N.

All is working except Wireless - I can't get it to work at all, using Luci mostly.

If I change it to disabled and then enabled, the wireless light turns on for a moment, then stays off.

I'm just trying to bridge LAN & Wireless for now, just to get it into a stable (like stock) state, then may try other things.

my wireless config file is like this:

config 'wifi-device' 'radio0'
        option 'type' 'mac80211'
        option 'macaddr' '00:1a:73:27:97:38'
        list 'ht_capab' 'SHORT-GI-40'
        list 'ht_capab' 'DSSS_CCK-40'
        option 'channel' 'auto'
        option 'txpower' '20'
        option 'country' 'GB'
        option 'hwmode' '11ng'
        option 'htmode' 'HT20'
        option 'disabled' '0'

config 'wifi-iface'
        option 'device' 'radio0'
        option 'mode' 'ap'
        option 'ssid' 'Stevellion'
        option 'encryption' 'psk2'
        option 'key' 'mycode'
        option 'network' 'lan'

I get these (and others) from lsusb
ath9k                         76176  0
ath9k_common           1060  1 ath9k
ath9k_hw                    295964  2 ath9k,ath9k_common
ath                             13056  2 ath9k,ath9k_hw
mac80211                  203532  1 ath9k
crc_ccitt                      928  1 ppp_async
cfg80211                    127980  3 ath9k,ath,mac80211
compat_firmware_class     4256  0
compat                        8868  3 ath9k,mac80211,cfg80211

Any suggestions (on what I'm missing) - I'm just struggling and can't get it to do much on the wireless side yet.