summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/hirschmann/hellcreek.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/hirschmann/hellcreek.c')
-rw-r--r--drivers/net/dsa/hirschmann/hellcreek.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c
index a4965a23db20..eb177f43ff16 100644
--- a/drivers/net/dsa/hirschmann/hellcreek.c
+++ b/drivers/net/dsa/hirschmann/hellcreek.c
@@ -25,6 +25,7 @@
#include <net/dsa.h>
#include "hellcreek.h"
+#include "hellcreek_ptp.h"
static const struct hellcreek_counter hellcreek_counter[] = {
{ 0x00, "RxFiltered", },
@@ -959,6 +960,43 @@ static void hellcreek_setup_tc_identity_mapping(struct hellcreek *hellcreek)
}
}
+static int hellcreek_setup_fdb(struct hellcreek *hellcreek)
+{
+ static struct hellcreek_fdb_entry ptp = {
+ /* MAC: 01-1B-19-00-00-00 */
+ .mac = { 0x01, 0x1b, 0x19, 0x00, 0x00, 0x00 },
+ .portmask = 0x03, /* Management ports */
+ .age = 0,
+ .is_obt = 0,
+ .pass_blocked = 0,
+ .is_static = 1,
+ .reprio_tc = 6, /* TC: 6 as per IEEE 802.1AS */
+ .reprio_en = 1,
+ };
+ static struct hellcreek_fdb_entry p2p = {
+ /* MAC: 01-80-C2-00-00-0E */
+ .mac = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e },
+ .portmask = 0x03, /* Management ports */
+ .age = 0,
+ .is_obt = 0,
+ .pass_blocked = 0,
+ .is_static = 1,
+ .reprio_tc = 6, /* TC: 6 as per IEEE 802.1AS */
+ .reprio_en = 1,
+ };
+ int ret;
+
+ mutex_lock(&hellcreek->reg_lock);
+ ret = __hellcreek_fdb_add(hellcreek, &ptp);
+ if (ret)
+ goto out;
+ ret = __hellcreek_fdb_add(hellcreek, &p2p);
+out:
+ mutex_unlock(&hellcreek->reg_lock);
+
+ return ret;
+}
+
static int hellcreek_setup(struct dsa_switch *ds)
{
struct hellcreek *hellcreek = ds->priv;
@@ -1009,6 +1047,14 @@ static int hellcreek_setup(struct dsa_switch *ds)
*/
ds->vlan_filtering_is_global = true;
+ /* Intercept _all_ PTP multicast traffic */
+ ret = hellcreek_setup_fdb(hellcreek);
+ if (ret) {
+ dev_err(hellcreek->dev,
+ "Failed to insert static PTP FDB entries\n");
+ return ret;
+ }
+
return 0;
}
@@ -1160,6 +1206,7 @@ static int hellcreek_probe(struct platform_device *pdev)
mutex_init(&hellcreek->reg_lock);
mutex_init(&hellcreek->vlan_lock);
+ mutex_init(&hellcreek->ptp_lock);
hellcreek->dev = dev;
@@ -1175,6 +1222,18 @@ static int hellcreek_probe(struct platform_device *pdev)
return PTR_ERR(hellcreek->base);
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ptp");
+ if (!res) {
+ dev_err(dev, "No PTP memory region provided!\n");
+ return -ENODEV;
+ }
+
+ hellcreek->ptp_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hellcreek->ptp_base)) {
+ dev_err(dev, "No memory available!\n");
+ return PTR_ERR(hellcreek->ptp_base);
+ }
+
ret = hellcreek_detect(hellcreek);
if (ret) {
dev_err(dev, "No (known) chip found!\n");
@@ -1205,15 +1264,27 @@ static int hellcreek_probe(struct platform_device *pdev)
return ret;
}
+ ret = hellcreek_ptp_setup(hellcreek);
+ if (ret) {
+ dev_err(dev, "Failed to setup PTP!\n");
+ goto err_ptp_setup;
+ }
+
platform_set_drvdata(pdev, hellcreek);
return 0;
+
+err_ptp_setup:
+ dsa_unregister_switch(hellcreek->ds);
+
+ return ret;
}
static int hellcreek_remove(struct platform_device *pdev)
{
struct hellcreek *hellcreek = platform_get_drvdata(pdev);
+ hellcreek_ptp_free(hellcreek);
dsa_unregister_switch(hellcreek->ds);
platform_set_drvdata(pdev, NULL);