From patchwork Sat Mar 21 15:46:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guenter Roeck X-Patchwork-Id: 452972 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 7C58A1400DD for ; Sun, 22 Mar 2015 02:51:22 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=roeck-us.net header.i=@roeck-us.net header.b=YXOdKOIb; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751855AbbCUPsA (ORCPT ); Sat, 21 Mar 2015 11:48:00 -0400 Received: from bh-25.webhostbox.net ([208.91.199.152]:40345 "EHLO bh-25.webhostbox.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751822AbbCUPr5 (ORCPT ); Sat, 21 Mar 2015 11:47:57 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=roeck-us.net; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=RZJ6ap38TLN5VVqVwnbhod4W5Rc+qPLfpLu87Y9hsk0=; b=YXOdKOIbg6nwE+hIRBU6blFz1vTnSqfeAWlBdkZdWnUfZlp2OjRy6MHfyEFtYP5zoMz/2EuYD9hxA6H9eV24lZpMc5sb2HhKNfIfiwVZ6NPF0NJXaCD+kzsPYVQXhMh6h0XwHXOfudyw0mhaW1qrLW7AZAZnB/reNmlfTw/o+rk=; Received: from mailnull by bh-25.webhostbox.net with sa-checked (Exim 4.82) (envelope-from ) id 1YZLcx-0001dE-5I for netdev@vger.kernel.org; Sat, 21 Mar 2015 15:47:56 +0000 Received: from 108-223-40-66.lightspeed.sntcca.sbcglobal.net ([108.223.40.66]:38853 helo=localhost) by bh-25.webhostbox.net with esmtpa (Exim 4.82) (envelope-from ) id 1YZLcw-0001cd-J2; Sat, 21 Mar 2015 15:47:55 +0000 From: Guenter Roeck To: netdev@vger.kernel.org Cc: "David S. Miller" , Andrew Lunn , Florian Fainelli , linux-kernel@vger.kernel.org, Guenter Roeck Subject: [PATCH 11/18] net: dsa: mv88e6xxx: Add support for fdb_add, fdb_del, and fdb_getnext Date: Sat, 21 Mar 2015 08:46:48 -0700 Message-Id: <1426952815-4642-12-git-send-email-linux@roeck-us.net> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1426952815-4642-1-git-send-email-linux@roeck-us.net> References: <1426952815-4642-1-git-send-email-linux@roeck-us.net> X-Authenticated_sender: guenter@roeck-us.net X-OutGoing-Spam-Status: No, score=-1.0 X-Spam-Checker-Version: spamc_ctasd client on localost X-Spam-Level: X-Spam-Status: No, score=0.0 required=50.0 tests=SpamClass_Unknown, VirusClass_Unknown autolearn=disabled version=1.0.0 X-CTCH-PVer: 0000001 X-CTCH-Spam: Unknown X-CTCH-VOD: Unknown X-CTCH-Flags: 0 X-CTCH-RefID: str=0001.0A020204.550D92AB.0139, ss=1, re=0.001, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-CTCH-Score: 0.001 X-CTCH-ScoreCust: 0.000 X-CTCH-Rules: C_4847, X-CTCH-SenderID: linux@roeck-us.net X-CTCH-SenderID-Flags: 0 X-CTCH-SenderID-TotalMessages: 51 X-CTCH-SenderID-TotalSpam: 0 X-CTCH-SenderID-TotalSuspected: 0 X-CTCH-SenderID-TotalConfirmed: 0 X-CTCH-SenderID-TotalBulk: 0 X-CTCH-SenderID-TotalVirus: 0 X-CTCH-SenderID-TotalRecipients: 0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - bh-25.webhostbox.net X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - roeck-us.net X-Get-Message-Sender-Via: bh-25.webhostbox.net: mailgid no entry from get_relayhosts_entry X-Source: X-Source-Args: X-Source-Dir: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org No vlan support at this time. Signed-off-by: Guenter Roeck --- drivers/net/dsa/mv88e6xxx.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx.h | 22 +++++++ 2 files changed, 158 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 17aa74f..0388022 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -953,6 +954,141 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state) return 0; } +static int __mv88e6xxx_write_addr(struct dsa_switch *ds, + const unsigned char *addr) +{ + int i, ret; + + for (i = 0; i < 3; i++) { + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0d + i, + (addr[i * 2] << 8) | addr[i * 2 + 1]); + if (ret < 0) + return ret; + } + + return 0; +} + +static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) +{ + int i, ret; + + for (i = 0; i < 3; i++) { + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0d + i); + if (ret < 0) + return ret; + addr[i * 2] = ret >> 8; + addr[i * 2 + 1] = ret & 0xff; + } + + return 0; +} + +static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, + const unsigned char *addr, int state) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u8 fid = ps->fid[port]; + int ret; + + ret = _mv88e6xxx_atu_wait(ds); + if (ret < 0) + return ret; + + ret = __mv88e6xxx_write_addr(ds, addr); + if (ret < 0) + return ret; + + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0c, + (0x10 << port) | state); + if (ret) + return ret; + + ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_LOAD_FID); + + return ret; +} + +int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + int state = is_multicast_ether_addr(addr) ? + FDB_STATE_MC_STATIC : FDB_STATE_STATIC; + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->smi_mutex); + ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + +int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->smi_mutex); + ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, FDB_STATE_UNUSED); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + +static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, + unsigned char *addr, bool *is_static) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u8 fid = ps->fid[port]; + int ret, state; + + ret = _mv88e6xxx_atu_wait(ds); + if (ret < 0) + return ret; + + ret = __mv88e6xxx_write_addr(ds, addr); + if (ret < 0) + return ret; + + do { + ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_GETNEXT_FID); + if (ret < 0) + return ret; + + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0c); + if (ret < 0) + return ret; + state = ret & FDB_STATE_MASK; + if (state == FDB_STATE_UNUSED) + return -ENOENT; + } while (!(((ret >> 4) & 0xff) & (1 << port))); + + ret = __mv88e6xxx_read_addr(ds, addr); + if (ret < 0) + return ret; + + *is_static = state == (is_multicast_ether_addr(addr) ? + FDB_STATE_MC_STATIC : FDB_STATE_STATIC); + + return 0; +} + +/* get next entry for port */ +int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, + unsigned char *addr, bool *is_static) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->smi_mutex); + ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + static void mv88e6xxx_bridge_work(struct work_struct *work) { struct mv88e6xxx_priv_state *ps; diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 8e215eb..48ecefc 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -29,6 +29,22 @@ #define PSTATE_LEARNING 0x02 #define PSTATE_FORWARDING 0x03 +/* ATU commands */ + +#define ATU_BUSY 0x8000 + +#define ATU_CMD_LOAD_FID (ATU_BUSY | 0x3000) +#define ATU_CMD_GETNEXT_FID (ATU_BUSY | 0x4000) +#define ATU_CMD_FLUSH_NONSTATIC_FID (ATU_BUSY | 0x6000) + +/* FDB states */ + +#define FDB_STATE_MASK 0x0f + +#define FDB_STATE_UNUSED 0x00 +#define FDB_STATE_MC_STATIC 0x07 /* static multicast */ +#define FDB_STATE_STATIC 0x0e /* static unicast */ + struct mv88e6xxx_priv_state { /* When using multi-chip addressing, this mutex protects * access to the indirect access registers. (In single-chip @@ -121,6 +137,12 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask); int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask); int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state); +int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid); +int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid); +int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, + unsigned char *addr, bool *is_static); extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver;