Skip to content

Commit 1da6df8

Browse files
ffainellidavem330
authored andcommitted
net: dsa: b53: Implement ARL add/del/dump operations
Adds support for FDB add/delete/dump using the ARL read/write logic and the ARL search logic for faster dumps. The code is made flexible enough it could support devices with a different register layout like BCM5325 and BCM5365 which have fewer number of entries or pack values into a single 64 bits register. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0830c98 commit 1da6df8

File tree

3 files changed

+382
-0
lines changed

3 files changed

+382
-0
lines changed

drivers/net/dsa/b53/b53_common.c

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
#include <linux/module.h>
2727
#include <linux/platform_data/b53.h>
2828
#include <linux/phy.h>
29+
#include <linux/etherdevice.h>
2930
#include <net/dsa.h>
31+
#include <net/switchdev.h>
3032

3133
#include "b53_regs.h"
3234
#include "b53_priv.h"
@@ -777,6 +779,246 @@ static void b53_adjust_link(struct dsa_switch *ds, int port,
777779
}
778780
}
779781

782+
/* Address Resolution Logic routines */
783+
static int b53_arl_op_wait(struct b53_device *dev)
784+
{
785+
unsigned int timeout = 10;
786+
u8 reg;
787+
788+
do {
789+
b53_read8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, &reg);
790+
if (!(reg & ARLTBL_START_DONE))
791+
return 0;
792+
793+
usleep_range(1000, 2000);
794+
} while (timeout--);
795+
796+
dev_warn(dev->dev, "timeout waiting for ARL to finish: 0x%02x\n", reg);
797+
798+
return -ETIMEDOUT;
799+
}
800+
801+
static int b53_arl_rw_op(struct b53_device *dev, unsigned int op)
802+
{
803+
u8 reg;
804+
805+
if (op > ARLTBL_RW)
806+
return -EINVAL;
807+
808+
b53_read8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, &reg);
809+
reg |= ARLTBL_START_DONE;
810+
if (op)
811+
reg |= ARLTBL_RW;
812+
else
813+
reg &= ~ARLTBL_RW;
814+
b53_write8(dev, B53_ARLIO_PAGE, B53_ARLTBL_RW_CTRL, reg);
815+
816+
return b53_arl_op_wait(dev);
817+
}
818+
819+
static int b53_arl_read(struct b53_device *dev, u64 mac,
820+
u16 vid, struct b53_arl_entry *ent, u8 *idx,
821+
bool is_valid)
822+
{
823+
unsigned int i;
824+
int ret;
825+
826+
ret = b53_arl_op_wait(dev);
827+
if (ret)
828+
return ret;
829+
830+
/* Read the bins */
831+
for (i = 0; i < dev->num_arl_entries; i++) {
832+
u64 mac_vid;
833+
u32 fwd_entry;
834+
835+
b53_read64(dev, B53_ARLIO_PAGE,
836+
B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid);
837+
b53_read32(dev, B53_ARLIO_PAGE,
838+
B53_ARLTBL_DATA_ENTRY(i), &fwd_entry);
839+
b53_arl_to_entry(ent, mac_vid, fwd_entry);
840+
841+
if (!(fwd_entry & ARLTBL_VALID))
842+
continue;
843+
if ((mac_vid & ARLTBL_MAC_MASK) != mac)
844+
continue;
845+
*idx = i;
846+
}
847+
848+
return -ENOENT;
849+
}
850+
851+
static int b53_arl_op(struct b53_device *dev, int op, int port,
852+
const unsigned char *addr, u16 vid, bool is_valid)
853+
{
854+
struct b53_arl_entry ent;
855+
u32 fwd_entry;
856+
u64 mac, mac_vid = 0;
857+
u8 idx = 0;
858+
int ret;
859+
860+
/* Convert the array into a 64-bit MAC */
861+
mac = b53_mac_to_u64(addr);
862+
863+
/* Perform a read for the given MAC and VID */
864+
b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac);
865+
b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid);
866+
867+
/* Issue a read operation for this MAC */
868+
ret = b53_arl_rw_op(dev, 1);
869+
if (ret)
870+
return ret;
871+
872+
ret = b53_arl_read(dev, mac, vid, &ent, &idx, is_valid);
873+
/* If this is a read, just finish now */
874+
if (op)
875+
return ret;
876+
877+
/* We could not find a matching MAC, so reset to a new entry */
878+
if (ret) {
879+
fwd_entry = 0;
880+
idx = 1;
881+
}
882+
883+
memset(&ent, 0, sizeof(ent));
884+
ent.port = port;
885+
ent.is_valid = is_valid;
886+
ent.vid = vid;
887+
ent.is_static = true;
888+
memcpy(ent.mac, addr, ETH_ALEN);
889+
b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
890+
891+
b53_write64(dev, B53_ARLIO_PAGE,
892+
B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid);
893+
b53_write32(dev, B53_ARLIO_PAGE,
894+
B53_ARLTBL_DATA_ENTRY(idx), fwd_entry);
895+
896+
return b53_arl_rw_op(dev, 0);
897+
}
898+
899+
static int b53_fdb_prepare(struct dsa_switch *ds, int port,
900+
const struct switchdev_obj_port_fdb *fdb,
901+
struct switchdev_trans *trans)
902+
{
903+
struct b53_device *priv = ds_to_priv(ds);
904+
905+
/* 5325 and 5365 require some more massaging, but could
906+
* be supported eventually
907+
*/
908+
if (is5325(priv) || is5365(priv))
909+
return -EOPNOTSUPP;
910+
911+
return 0;
912+
}
913+
914+
static void b53_fdb_add(struct dsa_switch *ds, int port,
915+
const struct switchdev_obj_port_fdb *fdb,
916+
struct switchdev_trans *trans)
917+
{
918+
struct b53_device *priv = ds_to_priv(ds);
919+
920+
if (b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, true))
921+
pr_err("%s: failed to add MAC address\n", __func__);
922+
}
923+
924+
static int b53_fdb_del(struct dsa_switch *ds, int port,
925+
const struct switchdev_obj_port_fdb *fdb)
926+
{
927+
struct b53_device *priv = ds_to_priv(ds);
928+
929+
return b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
930+
}
931+
932+
static int b53_arl_search_wait(struct b53_device *dev)
933+
{
934+
unsigned int timeout = 1000;
935+
u8 reg;
936+
937+
do {
938+
b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, &reg);
939+
if (!(reg & ARL_SRCH_STDN))
940+
return 0;
941+
942+
if (reg & ARL_SRCH_VLID)
943+
return 0;
944+
945+
usleep_range(1000, 2000);
946+
} while (timeout--);
947+
948+
return -ETIMEDOUT;
949+
}
950+
951+
static void b53_arl_search_rd(struct b53_device *dev, u8 idx,
952+
struct b53_arl_entry *ent)
953+
{
954+
u64 mac_vid;
955+
u32 fwd_entry;
956+
957+
b53_read64(dev, B53_ARLIO_PAGE,
958+
B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid);
959+
b53_read32(dev, B53_ARLIO_PAGE,
960+
B53_ARL_SRCH_RSTL(idx), &fwd_entry);
961+
b53_arl_to_entry(ent, mac_vid, fwd_entry);
962+
}
963+
964+
static int b53_fdb_copy(struct net_device *dev, int port,
965+
const struct b53_arl_entry *ent,
966+
struct switchdev_obj_port_fdb *fdb,
967+
int (*cb)(struct switchdev_obj *obj))
968+
{
969+
if (!ent->is_valid)
970+
return 0;
971+
972+
if (port != ent->port)
973+
return 0;
974+
975+
ether_addr_copy(fdb->addr, ent->mac);
976+
fdb->vid = ent->vid;
977+
fdb->ndm_state = ent->is_static ? NUD_NOARP : NUD_REACHABLE;
978+
979+
return cb(&fdb->obj);
980+
}
981+
982+
static int b53_fdb_dump(struct dsa_switch *ds, int port,
983+
struct switchdev_obj_port_fdb *fdb,
984+
int (*cb)(struct switchdev_obj *obj))
985+
{
986+
struct b53_device *priv = ds_to_priv(ds);
987+
struct net_device *dev = ds->ports[port].netdev;
988+
struct b53_arl_entry results[2];
989+
unsigned int count = 0;
990+
int ret;
991+
u8 reg;
992+
993+
/* Start search operation */
994+
reg = ARL_SRCH_STDN;
995+
b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg);
996+
997+
do {
998+
ret = b53_arl_search_wait(priv);
999+
if (ret)
1000+
return ret;
1001+
1002+
b53_arl_search_rd(priv, 0, &results[0]);
1003+
ret = b53_fdb_copy(dev, port, &results[0], fdb, cb);
1004+
if (ret)
1005+
return ret;
1006+
1007+
if (priv->num_arl_entries > 2) {
1008+
b53_arl_search_rd(priv, 1, &results[1]);
1009+
ret = b53_fdb_copy(dev, port, &results[1], fdb, cb);
1010+
if (ret)
1011+
return ret;
1012+
1013+
if (!results[0].is_valid && !results[1].is_valid)
1014+
break;
1015+
}
1016+
1017+
} while (count++ < 1024);
1018+
1019+
return 0;
1020+
}
1021+
7801022
static struct dsa_switch_driver b53_switch_ops = {
7811023
.tag_protocol = DSA_TAG_PROTO_NONE,
7821024
.setup = b53_setup,
@@ -789,6 +1031,10 @@ static struct dsa_switch_driver b53_switch_ops = {
7891031
.adjust_link = b53_adjust_link,
7901032
.port_enable = b53_enable_port,
7911033
.port_disable = b53_disable_port,
1034+
.port_fdb_prepare = b53_fdb_prepare,
1035+
.port_fdb_dump = b53_fdb_dump,
1036+
.port_fdb_add = b53_fdb_add,
1037+
.port_fdb_del = b53_fdb_del,
7921038
};
7931039

7941040
struct b53_chip_data {
@@ -798,6 +1044,7 @@ struct b53_chip_data {
7981044
u16 enabled_ports;
7991045
u8 cpu_port;
8001046
u8 vta_regs[3];
1047+
u8 arl_entries;
8011048
u8 duplex_reg;
8021049
u8 jumbo_pm_reg;
8031050
u8 jumbo_size_reg;
@@ -816,6 +1063,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8161063
.dev_name = "BCM5325",
8171064
.vlans = 16,
8181065
.enabled_ports = 0x1f,
1066+
.arl_entries = 2,
8191067
.cpu_port = B53_CPU_PORT_25,
8201068
.duplex_reg = B53_DUPLEX_STAT_FE,
8211069
},
@@ -824,6 +1072,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8241072
.dev_name = "BCM5365",
8251073
.vlans = 256,
8261074
.enabled_ports = 0x1f,
1075+
.arl_entries = 2,
8271076
.cpu_port = B53_CPU_PORT_25,
8281077
.duplex_reg = B53_DUPLEX_STAT_FE,
8291078
},
@@ -832,6 +1081,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8321081
.dev_name = "BCM5395",
8331082
.vlans = 4096,
8341083
.enabled_ports = 0x1f,
1084+
.arl_entries = 4,
8351085
.cpu_port = B53_CPU_PORT,
8361086
.vta_regs = B53_VTA_REGS,
8371087
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -843,6 +1093,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8431093
.dev_name = "BCM5397",
8441094
.vlans = 4096,
8451095
.enabled_ports = 0x1f,
1096+
.arl_entries = 4,
8461097
.cpu_port = B53_CPU_PORT,
8471098
.vta_regs = B53_VTA_REGS_9798,
8481099
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -854,6 +1105,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8541105
.dev_name = "BCM5398",
8551106
.vlans = 4096,
8561107
.enabled_ports = 0x7f,
1108+
.arl_entries = 4,
8571109
.cpu_port = B53_CPU_PORT,
8581110
.vta_regs = B53_VTA_REGS_9798,
8591111
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -865,6 +1117,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8651117
.dev_name = "BCM53115",
8661118
.vlans = 4096,
8671119
.enabled_ports = 0x1f,
1120+
.arl_entries = 4,
8681121
.vta_regs = B53_VTA_REGS,
8691122
.cpu_port = B53_CPU_PORT,
8701123
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -887,6 +1140,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8871140
.dev_name = "BCM53128",
8881141
.vlans = 4096,
8891142
.enabled_ports = 0x1ff,
1143+
.arl_entries = 4,
8901144
.cpu_port = B53_CPU_PORT,
8911145
.vta_regs = B53_VTA_REGS,
8921146
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -898,6 +1152,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
8981152
.dev_name = "BCM63xx",
8991153
.vlans = 4096,
9001154
.enabled_ports = 0, /* pdata must provide them */
1155+
.arl_entries = 4,
9011156
.cpu_port = B53_CPU_PORT,
9021157
.vta_regs = B53_VTA_REGS_63XX,
9031158
.duplex_reg = B53_DUPLEX_STAT_63XX,
@@ -909,6 +1164,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
9091164
.dev_name = "BCM53010",
9101165
.vlans = 4096,
9111166
.enabled_ports = 0x1f,
1167+
.arl_entries = 4,
9121168
.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
9131169
.vta_regs = B53_VTA_REGS,
9141170
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -920,6 +1176,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
9201176
.dev_name = "BCM53011",
9211177
.vlans = 4096,
9221178
.enabled_ports = 0x1bf,
1179+
.arl_entries = 4,
9231180
.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
9241181
.vta_regs = B53_VTA_REGS,
9251182
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -931,6 +1188,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
9311188
.dev_name = "BCM53012",
9321189
.vlans = 4096,
9331190
.enabled_ports = 0x1bf,
1191+
.arl_entries = 4,
9341192
.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
9351193
.vta_regs = B53_VTA_REGS,
9361194
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -942,6 +1200,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
9421200
.dev_name = "BCM53018",
9431201
.vlans = 4096,
9441202
.enabled_ports = 0x1f,
1203+
.arl_entries = 4,
9451204
.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
9461205
.vta_regs = B53_VTA_REGS,
9471206
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -953,6 +1212,7 @@ static const struct b53_chip_data b53_switch_chips[] = {
9531212
.dev_name = "BCM53019",
9541213
.vlans = 4096,
9551214
.enabled_ports = 0x1f,
1215+
.arl_entries = 4,
9561216
.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
9571217
.vta_regs = B53_VTA_REGS,
9581218
.duplex_reg = B53_DUPLEX_STAT_GE,
@@ -982,6 +1242,7 @@ static int b53_switch_init(struct b53_device *dev)
9821242
ds->drv = &b53_switch_ops;
9831243
dev->cpu_port = chip->cpu_port;
9841244
dev->num_vlans = chip->vlans;
1245+
dev->num_arl_entries = chip->arl_entries;
9851246
break;
9861247
}
9871248
}

0 commit comments

Comments
 (0)