Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /* Texas Instruments K3 AM65 Ethernet Switchdev Driver
0003  *
0004  * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/
0005  *
0006  */
0007 
0008 #include <linux/etherdevice.h>
0009 #include <linux/if_bridge.h>
0010 #include <linux/netdevice.h>
0011 #include <linux/workqueue.h>
0012 #include <net/switchdev.h>
0013 
0014 #include "am65-cpsw-nuss.h"
0015 #include "am65-cpsw-switchdev.h"
0016 #include "cpsw_ale.h"
0017 
0018 struct am65_cpsw_switchdev_event_work {
0019     struct work_struct work;
0020     struct switchdev_notifier_fdb_info fdb_info;
0021     struct am65_cpsw_port *port;
0022     unsigned long event;
0023 };
0024 
0025 static int am65_cpsw_port_stp_state_set(struct am65_cpsw_port *port, u8 state)
0026 {
0027     struct am65_cpsw_common *cpsw = port->common;
0028     u8 cpsw_state;
0029     int ret = 0;
0030 
0031     switch (state) {
0032     case BR_STATE_FORWARDING:
0033         cpsw_state = ALE_PORT_STATE_FORWARD;
0034         break;
0035     case BR_STATE_LEARNING:
0036         cpsw_state = ALE_PORT_STATE_LEARN;
0037         break;
0038     case BR_STATE_DISABLED:
0039         cpsw_state = ALE_PORT_STATE_DISABLE;
0040         break;
0041     case BR_STATE_LISTENING:
0042     case BR_STATE_BLOCKING:
0043         cpsw_state = ALE_PORT_STATE_BLOCK;
0044         break;
0045     default:
0046         return -EOPNOTSUPP;
0047     }
0048 
0049     ret = cpsw_ale_control_set(cpsw->ale, port->port_id,
0050                    ALE_PORT_STATE, cpsw_state);
0051     netdev_dbg(port->ndev, "ale state: %u\n", cpsw_state);
0052 
0053     return ret;
0054 }
0055 
0056 static int am65_cpsw_port_attr_br_flags_set(struct am65_cpsw_port *port,
0057                         struct net_device *orig_dev,
0058                         struct switchdev_brport_flags flags)
0059 {
0060     struct am65_cpsw_common *cpsw = port->common;
0061 
0062     if (flags.mask & BR_MCAST_FLOOD) {
0063         bool unreg_mcast_add = false;
0064 
0065         if (flags.val & BR_MCAST_FLOOD)
0066             unreg_mcast_add = true;
0067 
0068         netdev_dbg(port->ndev, "BR_MCAST_FLOOD: %d port %u\n",
0069                unreg_mcast_add, port->port_id);
0070 
0071         cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(port->port_id),
0072                      unreg_mcast_add);
0073     }
0074 
0075     return 0;
0076 }
0077 
0078 static int am65_cpsw_port_attr_br_flags_pre_set(struct net_device *netdev,
0079                         struct switchdev_brport_flags flags)
0080 {
0081     if (flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD))
0082         return -EINVAL;
0083 
0084     return 0;
0085 }
0086 
0087 static int am65_cpsw_port_attr_set(struct net_device *ndev, const void *ctx,
0088                    const struct switchdev_attr *attr,
0089                    struct netlink_ext_ack *extack)
0090 {
0091     struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
0092     int ret;
0093 
0094     netdev_dbg(ndev, "attr: id %u port: %u\n", attr->id, port->port_id);
0095 
0096     switch (attr->id) {
0097     case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
0098         ret = am65_cpsw_port_attr_br_flags_pre_set(ndev,
0099                                attr->u.brport_flags);
0100         break;
0101     case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
0102         ret = am65_cpsw_port_stp_state_set(port, attr->u.stp_state);
0103         netdev_dbg(ndev, "stp state: %u\n", attr->u.stp_state);
0104         break;
0105     case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
0106         ret = am65_cpsw_port_attr_br_flags_set(port, attr->orig_dev,
0107                                attr->u.brport_flags);
0108         break;
0109     default:
0110         ret = -EOPNOTSUPP;
0111         break;
0112     }
0113 
0114     return ret;
0115 }
0116 
0117 static u16 am65_cpsw_get_pvid(struct am65_cpsw_port *port)
0118 {
0119     struct am65_cpsw_common *cpsw = port->common;
0120     struct am65_cpsw_host *host_p = am65_common_get_host(cpsw);
0121     u32 pvid;
0122 
0123     if (port->port_id)
0124         pvid = readl(port->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
0125     else
0126         pvid = readl(host_p->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
0127 
0128     pvid = pvid & 0xfff;
0129 
0130     return pvid;
0131 }
0132 
0133 static void am65_cpsw_set_pvid(struct am65_cpsw_port *port, u16 vid, bool cfi, u32 cos)
0134 {
0135     struct am65_cpsw_common *cpsw = port->common;
0136     struct am65_cpsw_host *host_p = am65_common_get_host(cpsw);
0137     u32 pvid;
0138 
0139     pvid = vid;
0140     pvid |= cfi ? BIT(12) : 0;
0141     pvid |= (cos & 0x7) << 13;
0142 
0143     if (port->port_id)
0144         writel(pvid, port->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
0145     else
0146         writel(pvid, host_p->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
0147 }
0148 
0149 static int am65_cpsw_port_vlan_add(struct am65_cpsw_port *port, bool untag, bool pvid,
0150                    u16 vid, struct net_device *orig_dev)
0151 {
0152     bool cpu_port = netif_is_bridge_master(orig_dev);
0153     struct am65_cpsw_common *cpsw = port->common;
0154     int unreg_mcast_mask = 0;
0155     int reg_mcast_mask = 0;
0156     int untag_mask = 0;
0157     int port_mask;
0158     int ret = 0;
0159     u32 flags;
0160 
0161     if (cpu_port) {
0162         port_mask = BIT(HOST_PORT_NUM);
0163         flags = orig_dev->flags;
0164         unreg_mcast_mask = port_mask;
0165     } else {
0166         port_mask = BIT(port->port_id);
0167         flags = port->ndev->flags;
0168     }
0169 
0170     if (flags & IFF_MULTICAST)
0171         reg_mcast_mask = port_mask;
0172 
0173     if (untag)
0174         untag_mask = port_mask;
0175 
0176     ret = cpsw_ale_vlan_add_modify(cpsw->ale, vid, port_mask, untag_mask,
0177                        reg_mcast_mask, unreg_mcast_mask);
0178     if (ret) {
0179         netdev_err(port->ndev, "Unable to add vlan\n");
0180         return ret;
0181     }
0182 
0183     if (cpu_port)
0184         cpsw_ale_add_ucast(cpsw->ale, port->slave.mac_addr,
0185                    HOST_PORT_NUM, ALE_VLAN | ALE_SECURE, vid);
0186     if (!pvid)
0187         return ret;
0188 
0189     am65_cpsw_set_pvid(port, vid, 0, 0);
0190 
0191     netdev_dbg(port->ndev, "VID add: %s: vid:%u ports:%X\n",
0192            port->ndev->name, vid, port_mask);
0193 
0194     return ret;
0195 }
0196 
0197 static int am65_cpsw_port_vlan_del(struct am65_cpsw_port *port, u16 vid,
0198                    struct net_device *orig_dev)
0199 {
0200     bool cpu_port = netif_is_bridge_master(orig_dev);
0201     struct am65_cpsw_common *cpsw = port->common;
0202     int port_mask;
0203     int ret = 0;
0204 
0205     if (cpu_port)
0206         port_mask = BIT(HOST_PORT_NUM);
0207     else
0208         port_mask = BIT(port->port_id);
0209 
0210     ret = cpsw_ale_del_vlan(cpsw->ale, vid, port_mask);
0211     if (ret != 0)
0212         return ret;
0213 
0214     /* We don't care for the return value here, error is returned only if
0215      * the unicast entry is not present
0216      */
0217     if (cpu_port)
0218         cpsw_ale_del_ucast(cpsw->ale, port->slave.mac_addr,
0219                    HOST_PORT_NUM, ALE_VLAN, vid);
0220 
0221     if (vid == am65_cpsw_get_pvid(port))
0222         am65_cpsw_set_pvid(port, 0, 0, 0);
0223 
0224     /* We don't care for the return value here, error is returned only if
0225      * the multicast entry is not present
0226      */
0227     cpsw_ale_del_mcast(cpsw->ale, port->ndev->broadcast, port_mask,
0228                ALE_VLAN, vid);
0229     netdev_dbg(port->ndev, "VID del: %s: vid:%u ports:%X\n",
0230            port->ndev->name, vid, port_mask);
0231 
0232     return ret;
0233 }
0234 
0235 static int am65_cpsw_port_vlans_add(struct am65_cpsw_port *port,
0236                     const struct switchdev_obj_port_vlan *vlan)
0237 {
0238     bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
0239     struct net_device *orig_dev = vlan->obj.orig_dev;
0240     bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
0241 
0242     netdev_dbg(port->ndev, "VID add: %s: vid:%u flags:%X\n",
0243            port->ndev->name, vlan->vid, vlan->flags);
0244 
0245     return am65_cpsw_port_vlan_add(port, untag, pvid, vlan->vid, orig_dev);
0246 }
0247 
0248 static int am65_cpsw_port_vlans_del(struct am65_cpsw_port *port,
0249                     const struct switchdev_obj_port_vlan *vlan)
0250 
0251 {
0252     return am65_cpsw_port_vlan_del(port, vlan->vid, vlan->obj.orig_dev);
0253 }
0254 
0255 static int am65_cpsw_port_mdb_add(struct am65_cpsw_port *port,
0256                   struct switchdev_obj_port_mdb *mdb)
0257 
0258 {
0259     struct net_device *orig_dev = mdb->obj.orig_dev;
0260     bool cpu_port = netif_is_bridge_master(orig_dev);
0261     struct am65_cpsw_common *cpsw = port->common;
0262     int port_mask;
0263     int err;
0264 
0265     if (cpu_port)
0266         port_mask = BIT(HOST_PORT_NUM);
0267     else
0268         port_mask = BIT(port->port_id);
0269 
0270     err = cpsw_ale_add_mcast(cpsw->ale, mdb->addr, port_mask,
0271                  ALE_VLAN, mdb->vid, 0);
0272     netdev_dbg(port->ndev, "MDB add: %s: vid %u:%pM  ports: %X\n",
0273            port->ndev->name, mdb->vid, mdb->addr, port_mask);
0274 
0275     return err;
0276 }
0277 
0278 static int am65_cpsw_port_mdb_del(struct am65_cpsw_port *port,
0279                   struct switchdev_obj_port_mdb *mdb)
0280 
0281 {
0282     struct net_device *orig_dev = mdb->obj.orig_dev;
0283     bool cpu_port = netif_is_bridge_master(orig_dev);
0284     struct am65_cpsw_common *cpsw = port->common;
0285     int del_mask;
0286 
0287     if (cpu_port)
0288         del_mask = BIT(HOST_PORT_NUM);
0289     else
0290         del_mask = BIT(port->port_id);
0291 
0292     /* Ignore error as error code is returned only when entry is already removed */
0293     cpsw_ale_del_mcast(cpsw->ale, mdb->addr, del_mask,
0294                ALE_VLAN, mdb->vid);
0295     netdev_dbg(port->ndev, "MDB del: %s: vid %u:%pM  ports: %X\n",
0296            port->ndev->name, mdb->vid, mdb->addr, del_mask);
0297 
0298     return 0;
0299 }
0300 
0301 static int am65_cpsw_port_obj_add(struct net_device *ndev, const void *ctx,
0302                   const struct switchdev_obj *obj,
0303                   struct netlink_ext_ack *extack)
0304 {
0305     struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
0306     struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
0307     struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
0308     int err = 0;
0309 
0310     netdev_dbg(ndev, "obj_add: id %u port: %u\n", obj->id, port->port_id);
0311 
0312     switch (obj->id) {
0313     case SWITCHDEV_OBJ_ID_PORT_VLAN:
0314         err = am65_cpsw_port_vlans_add(port, vlan);
0315         break;
0316     case SWITCHDEV_OBJ_ID_PORT_MDB:
0317     case SWITCHDEV_OBJ_ID_HOST_MDB:
0318         err = am65_cpsw_port_mdb_add(port, mdb);
0319         break;
0320     default:
0321         err = -EOPNOTSUPP;
0322         break;
0323     }
0324 
0325     return err;
0326 }
0327 
0328 static int am65_cpsw_port_obj_del(struct net_device *ndev, const void *ctx,
0329                   const struct switchdev_obj *obj)
0330 {
0331     struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
0332     struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
0333     struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
0334     int err = 0;
0335 
0336     netdev_dbg(ndev, "obj_del: id %u port: %u\n", obj->id, port->port_id);
0337 
0338     switch (obj->id) {
0339     case SWITCHDEV_OBJ_ID_PORT_VLAN:
0340         err = am65_cpsw_port_vlans_del(port, vlan);
0341         break;
0342     case SWITCHDEV_OBJ_ID_PORT_MDB:
0343     case SWITCHDEV_OBJ_ID_HOST_MDB:
0344         err = am65_cpsw_port_mdb_del(port, mdb);
0345         break;
0346     default:
0347         err = -EOPNOTSUPP;
0348         break;
0349     }
0350 
0351     return err;
0352 }
0353 
0354 static void am65_cpsw_fdb_offload_notify(struct net_device *ndev,
0355                      struct switchdev_notifier_fdb_info *rcv)
0356 {
0357     struct switchdev_notifier_fdb_info info = {};
0358 
0359     info.addr = rcv->addr;
0360     info.vid = rcv->vid;
0361     info.offloaded = true;
0362     call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
0363                  ndev, &info.info, NULL);
0364 }
0365 
0366 static void am65_cpsw_switchdev_event_work(struct work_struct *work)
0367 {
0368     struct am65_cpsw_switchdev_event_work *switchdev_work =
0369         container_of(work, struct am65_cpsw_switchdev_event_work, work);
0370     struct am65_cpsw_port *port = switchdev_work->port;
0371     struct switchdev_notifier_fdb_info *fdb;
0372     struct am65_cpsw_common *cpsw = port->common;
0373     int port_id = port->port_id;
0374 
0375     rtnl_lock();
0376     switch (switchdev_work->event) {
0377     case SWITCHDEV_FDB_ADD_TO_DEVICE:
0378         fdb = &switchdev_work->fdb_info;
0379 
0380         netdev_dbg(port->ndev, "cpsw_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
0381                fdb->addr, fdb->vid, fdb->added_by_user,
0382                fdb->offloaded, port_id);
0383 
0384         if (!fdb->added_by_user || fdb->is_local)
0385             break;
0386         if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
0387             port_id = HOST_PORT_NUM;
0388 
0389         cpsw_ale_add_ucast(cpsw->ale, (u8 *)fdb->addr, port_id,
0390                    fdb->vid ? ALE_VLAN : 0, fdb->vid);
0391         am65_cpsw_fdb_offload_notify(port->ndev, fdb);
0392         break;
0393     case SWITCHDEV_FDB_DEL_TO_DEVICE:
0394         fdb = &switchdev_work->fdb_info;
0395 
0396         netdev_dbg(port->ndev, "cpsw_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n",
0397                fdb->addr, fdb->vid, fdb->added_by_user,
0398                fdb->offloaded, port_id);
0399 
0400         if (!fdb->added_by_user || fdb->is_local)
0401             break;
0402         if (memcmp(port->slave.mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
0403             port_id = HOST_PORT_NUM;
0404 
0405         cpsw_ale_del_ucast(cpsw->ale, (u8 *)fdb->addr, port_id,
0406                    fdb->vid ? ALE_VLAN : 0, fdb->vid);
0407         break;
0408     default:
0409         break;
0410     }
0411     rtnl_unlock();
0412 
0413     kfree(switchdev_work->fdb_info.addr);
0414     kfree(switchdev_work);
0415     dev_put(port->ndev);
0416 }
0417 
0418 /* called under rcu_read_lock() */
0419 static int am65_cpsw_switchdev_event(struct notifier_block *unused,
0420                      unsigned long event, void *ptr)
0421 {
0422     struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
0423     struct am65_cpsw_switchdev_event_work *switchdev_work;
0424     struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
0425     struct switchdev_notifier_fdb_info *fdb_info = ptr;
0426     int err;
0427 
0428     if (event == SWITCHDEV_PORT_ATTR_SET) {
0429         err = switchdev_handle_port_attr_set(ndev, ptr,
0430                              am65_cpsw_port_dev_check,
0431                              am65_cpsw_port_attr_set);
0432         return notifier_from_errno(err);
0433     }
0434 
0435     if (!am65_cpsw_port_dev_check(ndev))
0436         return NOTIFY_DONE;
0437 
0438     switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
0439     if (WARN_ON(!switchdev_work))
0440         return NOTIFY_BAD;
0441 
0442     INIT_WORK(&switchdev_work->work, am65_cpsw_switchdev_event_work);
0443     switchdev_work->port = port;
0444     switchdev_work->event = event;
0445 
0446     switch (event) {
0447     case SWITCHDEV_FDB_ADD_TO_DEVICE:
0448     case SWITCHDEV_FDB_DEL_TO_DEVICE:
0449         memcpy(&switchdev_work->fdb_info, ptr,
0450                sizeof(switchdev_work->fdb_info));
0451         switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
0452         if (!switchdev_work->fdb_info.addr)
0453             goto err_addr_alloc;
0454         ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
0455                 fdb_info->addr);
0456         dev_hold(ndev);
0457         break;
0458     default:
0459         kfree(switchdev_work);
0460         return NOTIFY_DONE;
0461     }
0462 
0463     queue_work(system_long_wq, &switchdev_work->work);
0464 
0465     return NOTIFY_DONE;
0466 
0467 err_addr_alloc:
0468     kfree(switchdev_work);
0469     return NOTIFY_BAD;
0470 }
0471 
0472 static struct notifier_block cpsw_switchdev_notifier = {
0473     .notifier_call = am65_cpsw_switchdev_event,
0474 };
0475 
0476 static int am65_cpsw_switchdev_blocking_event(struct notifier_block *unused,
0477                           unsigned long event, void *ptr)
0478 {
0479     struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
0480     int err;
0481 
0482     switch (event) {
0483     case SWITCHDEV_PORT_OBJ_ADD:
0484         err = switchdev_handle_port_obj_add(dev, ptr,
0485                             am65_cpsw_port_dev_check,
0486                             am65_cpsw_port_obj_add);
0487         return notifier_from_errno(err);
0488     case SWITCHDEV_PORT_OBJ_DEL:
0489         err = switchdev_handle_port_obj_del(dev, ptr,
0490                             am65_cpsw_port_dev_check,
0491                             am65_cpsw_port_obj_del);
0492         return notifier_from_errno(err);
0493     case SWITCHDEV_PORT_ATTR_SET:
0494         err = switchdev_handle_port_attr_set(dev, ptr,
0495                              am65_cpsw_port_dev_check,
0496                              am65_cpsw_port_attr_set);
0497         return notifier_from_errno(err);
0498     default:
0499         break;
0500     }
0501 
0502     return NOTIFY_DONE;
0503 }
0504 
0505 static struct notifier_block cpsw_switchdev_bl_notifier = {
0506     .notifier_call = am65_cpsw_switchdev_blocking_event,
0507 };
0508 
0509 int am65_cpsw_switchdev_register_notifiers(struct am65_cpsw_common *cpsw)
0510 {
0511     int ret = 0;
0512 
0513     ret = register_switchdev_notifier(&cpsw_switchdev_notifier);
0514     if (ret) {
0515         dev_err(cpsw->dev, "register switchdev notifier fail ret:%d\n",
0516             ret);
0517         return ret;
0518     }
0519 
0520     ret = register_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier);
0521     if (ret) {
0522         dev_err(cpsw->dev, "register switchdev blocking notifier ret:%d\n",
0523             ret);
0524         unregister_switchdev_notifier(&cpsw_switchdev_notifier);
0525     }
0526 
0527     return ret;
0528 }
0529 
0530 void am65_cpsw_switchdev_unregister_notifiers(struct am65_cpsw_common *cpsw)
0531 {
0532     unregister_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier);
0533     unregister_switchdev_notifier(&cpsw_switchdev_notifier);
0534 }