2016-06-04 21:17:07 +02:00
/*
* net / dsa / dsa2 . c - Hardware switch handling , binding version 2
* Copyright ( c ) 2008 - 2009 Marvell Semiconductor
* Copyright ( c ) 2013 Florian Fainelli < florian @ openwrt . org >
* Copyright ( c ) 2016 Andrew Lunn < andrew @ lunn . ch >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/device.h>
# include <linux/err.h>
# include <linux/list.h>
2017-03-28 23:45:06 +02:00
# include <linux/netdevice.h>
2016-06-04 21:17:07 +02:00
# include <linux/slab.h>
# include <linux/rtnetlink.h>
# include <linux/of.h>
# include <linux/of_net.h>
2017-05-17 15:46:03 -04:00
2016-06-04 21:17:07 +02:00
# include "dsa_priv.h"
2017-11-03 19:05:24 -04:00
static LIST_HEAD ( dsa_tree_list ) ;
2016-06-04 21:17:07 +02:00
static DEFINE_MUTEX ( dsa2_mutex ) ;
2017-03-28 23:45:07 +02:00
static const struct devlink_ops dsa_devlink_ops = {
} ;
2017-11-03 19:05:24 -04:00
static struct dsa_switch_tree * dsa_tree_find ( int index )
2016-06-04 21:17:07 +02:00
{
struct dsa_switch_tree * dst ;
2017-11-03 19:05:24 -04:00
list_for_each_entry ( dst , & dsa_tree_list , list )
2017-11-03 19:05:22 -04:00
if ( dst - > index = = index )
2016-06-04 21:17:07 +02:00
return dst ;
2017-11-03 19:05:22 -04:00
2016-06-04 21:17:07 +02:00
return NULL ;
}
2017-11-03 19:05:24 -04:00
static struct dsa_switch_tree * dsa_tree_alloc ( int index )
2016-06-04 21:17:07 +02:00
{
struct dsa_switch_tree * dst ;
dst = kzalloc ( sizeof ( * dst ) , GFP_KERNEL ) ;
if ( ! dst )
return NULL ;
2017-11-03 19:05:24 -04:00
2017-11-03 19:05:21 -04:00
dst - > index = index ;
2017-11-03 19:05:24 -04:00
2016-06-04 21:17:07 +02:00
INIT_LIST_HEAD ( & dst - > list ) ;
2017-11-03 19:05:24 -04:00
list_add_tail ( & dsa_tree_list , & dst - > list ) ;
2017-11-03 19:05:22 -04:00
/* Initialize the reference counter to the number of switches, not 1 */
2016-06-04 21:17:07 +02:00
kref_init ( & dst - > refcount ) ;
2017-11-03 19:05:22 -04:00
refcount_set ( & dst - > refcount . refcount , 0 ) ;
2016-06-04 21:17:07 +02:00
return dst ;
}
2017-11-03 19:05:23 -04:00
static void dsa_tree_free ( struct dsa_switch_tree * dst )
{
list_del ( & dst - > list ) ;
kfree ( dst ) ;
}
2017-11-03 19:05:24 -04:00
static struct dsa_switch_tree * dsa_tree_touch ( int index )
{
struct dsa_switch_tree * dst ;
dst = dsa_tree_find ( index ) ;
if ( ! dst )
dst = dsa_tree_alloc ( index ) ;
return dst ;
}
2017-11-03 19:05:23 -04:00
static void dsa_tree_get ( struct dsa_switch_tree * dst )
{
kref_get ( & dst - > refcount ) ;
}
static void dsa_tree_release ( struct kref * ref )
{
struct dsa_switch_tree * dst ;
dst = container_of ( ref , struct dsa_switch_tree , refcount ) ;
dsa_tree_free ( dst ) ;
}
static void dsa_tree_put ( struct dsa_switch_tree * dst )
{
kref_put ( & dst - > refcount , dsa_tree_release ) ;
}
2017-02-04 13:02:43 -08:00
/* For platform data configurations, we need to have a valid name argument to
* differentiate a disabled port from an enabled one
*/
2017-01-26 10:45:52 -08:00
static bool dsa_port_is_valid ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-10-27 15:55:15 -04:00
return port - > type ! = DSA_PORT_TYPE_UNUSED ;
2016-06-04 21:17:07 +02:00
}
2017-01-26 10:45:52 -08:00
static bool dsa_port_is_dsa ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-10-27 15:55:15 -04:00
return port - > type = = DSA_PORT_TYPE_DSA ;
2017-01-26 10:45:52 -08:00
}
static bool dsa_port_is_cpu ( struct dsa_port * port )
{
2017-10-27 15:55:15 -04:00
return port - > type = = DSA_PORT_TYPE_CPU ;
2016-06-04 21:17:07 +02:00
}
2017-01-26 10:45:53 -08:00
static bool dsa_ds_find_port_dn ( struct dsa_switch * ds ,
struct device_node * port )
2016-06-04 21:17:07 +02:00
{
u32 index ;
2017-01-27 15:29:37 -05:00
for ( index = 0 ; index < ds - > num_ports ; index + + )
2016-06-04 21:17:07 +02:00
if ( ds - > ports [ index ] . dn = = port )
return true ;
return false ;
}
2017-01-26 10:45:53 -08:00
static struct dsa_switch * dsa_dst_find_port_dn ( struct dsa_switch_tree * dst ,
struct device_node * port )
2016-06-04 21:17:07 +02:00
{
struct dsa_switch * ds ;
u32 index ;
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
2017-01-26 10:45:53 -08:00
if ( dsa_ds_find_port_dn ( ds , port ) )
2016-06-04 21:17:07 +02:00
return ds ;
}
return NULL ;
}
static int dsa_port_complete ( struct dsa_switch_tree * dst ,
struct dsa_switch * src_ds ,
2017-01-26 10:45:52 -08:00
struct dsa_port * port ,
2016-06-04 21:17:07 +02:00
u32 src_port )
{
struct device_node * link ;
int index ;
struct dsa_switch * dst_ds ;
for ( index = 0 ; ; index + + ) {
2017-01-26 10:45:52 -08:00
link = of_parse_phandle ( port - > dn , " link " , index ) ;
2016-06-04 21:17:07 +02:00
if ( ! link )
break ;
2017-01-26 10:45:53 -08:00
dst_ds = dsa_dst_find_port_dn ( dst , link ) ;
2016-06-04 21:17:07 +02:00
of_node_put ( link ) ;
if ( ! dst_ds )
return 1 ;
src_ds - > rtable [ dst_ds - > index ] = src_port ;
}
return 0 ;
}
/* A switch is complete if all the DSA ports phandles point to ports
* known in the tree . A return value of 1 means the tree is not
* complete . This is not an error condition . A value of 0 is
* success .
*/
static int dsa_ds_complete ( struct dsa_switch_tree * dst , struct dsa_switch * ds )
{
2017-01-26 10:45:52 -08:00
struct dsa_port * port ;
2016-06-04 21:17:07 +02:00
u32 index ;
int err ;
2017-01-27 15:29:37 -05:00
for ( index = 0 ; index < ds - > num_ports ; index + + ) {
2017-01-26 10:45:52 -08:00
port = & ds - > ports [ index ] ;
if ( ! dsa_port_is_valid ( port ) )
2016-06-04 21:17:07 +02:00
continue ;
if ( ! dsa_port_is_dsa ( port ) )
continue ;
err = dsa_port_complete ( dst , ds , port , index ) ;
if ( err ! = 0 )
return err ;
}
return 0 ;
}
/* A tree is complete if all the DSA ports phandles point to ports
* known in the tree . A return value of 1 means the tree is not
* complete . This is not an error condition . A value of 0 is
* success .
*/
static int dsa_dst_complete ( struct dsa_switch_tree * dst )
{
struct dsa_switch * ds ;
u32 index ;
int err ;
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
err = dsa_ds_complete ( dst , ds ) ;
if ( err ! = 0 )
return err ;
}
return 0 ;
}
2017-06-02 12:31:22 -07:00
static int dsa_dsa_port_apply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
struct dsa_switch * ds = port - > ds ;
2016-06-04 21:17:07 +02:00
int err ;
2017-10-26 10:50:07 -04:00
err = dsa_port_fixed_link_register_of ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err ) {
dev_warn ( ds - > dev , " Failed to setup dsa port %d: %d \n " ,
2017-06-02 12:31:22 -07:00
port - > index , err ) ;
2016-06-04 21:17:07 +02:00
return err ;
}
2017-06-02 12:31:22 -07:00
memset ( & port - > devlink_port , 0 , sizeof ( port - > devlink_port ) ) ;
2017-03-28 23:45:07 +02:00
2017-06-02 12:31:22 -07:00
return devlink_port_register ( ds - > devlink , & port - > devlink_port ,
port - > index ) ;
2016-06-04 21:17:07 +02:00
}
2017-06-02 12:31:22 -07:00
static void dsa_dsa_port_unapply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
devlink_port_unregister ( & port - > devlink_port ) ;
2017-10-26 10:50:07 -04:00
dsa_port_fixed_link_unregister_of ( port ) ;
2016-06-04 21:17:07 +02:00
}
2017-06-02 12:31:22 -07:00
static int dsa_cpu_port_apply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
struct dsa_switch * ds = port - > ds ;
2016-06-04 21:17:07 +02:00
int err ;
2017-10-26 10:50:07 -04:00
err = dsa_port_fixed_link_register_of ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err ) {
dev_warn ( ds - > dev , " Failed to setup cpu port %d: %d \n " ,
2017-06-02 12:31:22 -07:00
port - > index , err ) ;
2016-06-04 21:17:07 +02:00
return err ;
}
2017-06-02 12:31:22 -07:00
memset ( & port - > devlink_port , 0 , sizeof ( port - > devlink_port ) ) ;
err = devlink_port_register ( ds - > devlink , & port - > devlink_port ,
port - > index ) ;
2017-03-28 23:45:07 +02:00
return err ;
2016-06-04 21:17:07 +02:00
}
2017-06-02 12:31:22 -07:00
static void dsa_cpu_port_unapply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
devlink_port_unregister ( & port - > devlink_port ) ;
2017-10-26 10:50:07 -04:00
dsa_port_fixed_link_unregister_of ( port ) ;
2016-06-04 21:17:07 +02:00
}
2017-06-02 12:31:22 -07:00
static int dsa_user_port_apply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
struct dsa_switch * ds = port - > ds ;
2016-06-04 21:17:07 +02:00
int err ;
2017-10-27 15:55:19 -04:00
err = dsa_slave_create ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err ) {
dev_warn ( ds - > dev , " Failed to create slave %d: %d \n " ,
2017-06-02 12:31:22 -07:00
port - > index , err ) ;
2017-10-16 11:12:18 -04:00
port - > slave = NULL ;
2016-06-04 21:17:07 +02:00
return err ;
}
2017-06-02 12:31:22 -07:00
memset ( & port - > devlink_port , 0 , sizeof ( port - > devlink_port ) ) ;
err = devlink_port_register ( ds - > devlink , & port - > devlink_port ,
port - > index ) ;
2017-03-28 23:45:07 +02:00
if ( err )
return err ;
2017-10-16 11:12:18 -04:00
devlink_port_type_eth_set ( & port - > devlink_port , port - > slave ) ;
2017-03-28 23:45:07 +02:00
2016-06-04 21:17:07 +02:00
return 0 ;
}
2017-06-02 12:31:22 -07:00
static void dsa_user_port_unapply ( struct dsa_port * port )
2016-06-04 21:17:07 +02:00
{
2017-06-02 12:31:22 -07:00
devlink_port_unregister ( & port - > devlink_port ) ;
2017-10-16 11:12:18 -04:00
if ( port - > slave ) {
dsa_slave_destroy ( port - > slave ) ;
port - > slave = NULL ;
2016-06-04 21:17:07 +02:00
}
}
static int dsa_ds_apply ( struct dsa_switch_tree * dst , struct dsa_switch * ds )
{
2017-01-26 10:45:52 -08:00
struct dsa_port * port ;
2016-06-04 21:17:07 +02:00
u32 index ;
int err ;
2016-06-07 16:32:39 -07:00
/* Initialize ds->phys_mii_mask before registering the slave MDIO bus
2016-08-23 12:38:56 -04:00
* driver and before ops - > setup ( ) has run , since the switch drivers and
2016-06-07 16:32:39 -07:00
* the slave MDIO bus driver rely on these values for probing PHY
* devices or not
*/
2017-10-26 11:22:56 -04:00
ds - > phys_mii_mask | = dsa_user_ports ( ds ) ;
2016-06-07 16:32:39 -07:00
2017-03-28 23:45:07 +02:00
/* Add the switch to devlink before calling setup, so that setup can
* add dpipe tables
*/
ds - > devlink = devlink_alloc ( & dsa_devlink_ops , 0 ) ;
if ( ! ds - > devlink )
return - ENOMEM ;
err = devlink_register ( ds - > devlink , ds - > dev ) ;
if ( err )
return err ;
2016-08-23 12:38:56 -04:00
err = ds - > ops - > setup ( ds ) ;
2016-06-04 21:17:07 +02:00
if ( err < 0 )
return err ;
2017-02-03 13:20:20 -05:00
err = dsa_switch_register_notifier ( ds ) ;
if ( err )
return err ;
2016-08-23 12:38:56 -04:00
if ( ! ds - > slave_mii_bus & & ds - > ops - > phy_read ) {
2016-06-07 16:32:40 -07:00
ds - > slave_mii_bus = devm_mdiobus_alloc ( ds - > dev ) ;
if ( ! ds - > slave_mii_bus )
return - ENOMEM ;
dsa_slave_mii_bus_init ( ds ) ;
err = mdiobus_register ( ds - > slave_mii_bus ) ;
if ( err < 0 )
return err ;
}
2017-01-27 15:29:37 -05:00
for ( index = 0 ; index < ds - > num_ports ; index + + ) {
2017-01-26 10:45:52 -08:00
port = & ds - > ports [ index ] ;
if ( ! dsa_port_is_valid ( port ) )
2016-06-04 21:17:07 +02:00
continue ;
if ( dsa_port_is_dsa ( port ) ) {
2017-06-02 12:31:22 -07:00
err = dsa_dsa_port_apply ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err )
return err ;
continue ;
}
if ( dsa_port_is_cpu ( port ) ) {
2017-06-02 12:31:22 -07:00
err = dsa_cpu_port_apply ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err )
return err ;
continue ;
}
2017-06-02 12:31:22 -07:00
err = dsa_user_port_apply ( port ) ;
2016-06-04 21:17:07 +02:00
if ( err )
continue ;
}
return 0 ;
}
static void dsa_ds_unapply ( struct dsa_switch_tree * dst , struct dsa_switch * ds )
{
2017-01-26 10:45:52 -08:00
struct dsa_port * port ;
2016-06-04 21:17:07 +02:00
u32 index ;
2017-01-27 15:29:37 -05:00
for ( index = 0 ; index < ds - > num_ports ; index + + ) {
2017-01-26 10:45:52 -08:00
port = & ds - > ports [ index ] ;
if ( ! dsa_port_is_valid ( port ) )
2016-06-04 21:17:07 +02:00
continue ;
if ( dsa_port_is_dsa ( port ) ) {
2017-06-02 12:31:22 -07:00
dsa_dsa_port_unapply ( port ) ;
2016-06-04 21:17:07 +02:00
continue ;
}
if ( dsa_port_is_cpu ( port ) ) {
2017-06-02 12:31:22 -07:00
dsa_cpu_port_unapply ( port ) ;
2016-06-04 21:17:07 +02:00
continue ;
}
2017-06-02 12:31:22 -07:00
dsa_user_port_unapply ( port ) ;
2016-06-04 21:17:07 +02:00
}
2016-06-07 16:32:40 -07:00
2016-08-23 12:38:56 -04:00
if ( ds - > slave_mii_bus & & ds - > ops - > phy_read )
2016-06-07 16:32:40 -07:00
mdiobus_unregister ( ds - > slave_mii_bus ) ;
2017-02-03 13:20:20 -05:00
dsa_switch_unregister_notifier ( ds ) ;
2017-03-28 23:45:07 +02:00
if ( ds - > devlink ) {
devlink_unregister ( ds - > devlink ) ;
devlink_free ( ds - > devlink ) ;
ds - > devlink = NULL ;
}
2016-06-04 21:17:07 +02:00
}
static int dsa_dst_apply ( struct dsa_switch_tree * dst )
{
struct dsa_switch * ds ;
u32 index ;
int err ;
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
err = dsa_ds_apply ( dst , ds ) ;
if ( err )
return err ;
}
/* If we use a tagging format that doesn't have an ethertype
* field , make sure that all packets from this point on get
* sent to the tag format ' s receive function .
*/
wmb ( ) ;
2017-10-16 11:12:18 -04:00
dst - > cpu_dp - > master - > dsa_ptr = dst - > cpu_dp ;
2017-09-19 11:56:59 -04:00
2017-10-16 11:12:18 -04:00
err = dsa_master_ethtool_setup ( dst - > cpu_dp - > master ) ;
2017-09-19 11:56:59 -04:00
if ( err )
return err ;
2016-06-04 21:17:07 +02:00
dst - > applied = true ;
return 0 ;
}
static void dsa_dst_unapply ( struct dsa_switch_tree * dst )
{
struct dsa_switch * ds ;
u32 index ;
if ( ! dst - > applied )
return ;
2017-10-16 11:12:18 -04:00
dsa_master_ethtool_restore ( dst - > cpu_dp - > master ) ;
2017-09-19 11:56:59 -04:00
2017-10-16 11:12:18 -04:00
dst - > cpu_dp - > master - > dsa_ptr = NULL ;
2016-06-04 21:17:07 +02:00
/* If we used a tagging format that doesn't have an ethertype
* field , make sure that all packets from this point get sent
* without the tag and go through the regular receive path .
*/
wmb ( ) ;
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
dsa_ds_unapply ( dst , ds ) ;
}
2017-09-19 11:56:58 -04:00
dst - > cpu_dp = NULL ;
2016-06-07 16:32:42 -07:00
2017-11-03 19:05:21 -04:00
pr_info ( " DSA: tree %d unapplied \n " , dst - > index ) ;
2016-06-04 21:17:07 +02:00
dst - > applied = false ;
}
2017-11-03 19:05:25 -04:00
static void dsa_tree_remove_switch ( struct dsa_switch_tree * dst ,
unsigned int index )
{
dst - > ds [ index ] = NULL ;
dsa_tree_put ( dst ) ;
}
static int dsa_tree_add_switch ( struct dsa_switch_tree * dst ,
struct dsa_switch * ds )
{
unsigned int index = ds - > index ;
if ( dst - > ds [ index ] )
return - EBUSY ;
dsa_tree_get ( dst ) ;
dst - > ds [ index ] = ds ;
return 0 ;
}
2017-01-26 10:45:52 -08:00
static int dsa_cpu_parse ( struct dsa_port * port , u32 index ,
2016-06-04 21:17:07 +02:00
struct dsa_switch_tree * dst ,
struct dsa_switch * ds )
{
2017-09-29 17:19:17 -04:00
const struct dsa_device_ops * tag_ops ;
2016-08-22 16:01:01 +02:00
enum dsa_tag_protocol tag_protocol ;
2016-06-04 21:17:07 +02:00
2017-10-27 15:55:17 -04:00
if ( ! dst - > cpu_dp )
2017-05-16 14:10:33 -04:00
dst - > cpu_dp = port ;
2016-06-04 21:17:07 +02:00
2016-08-23 12:38:56 -04:00
tag_protocol = ds - > ops - > get_tag_protocol ( ds ) ;
2017-09-29 17:19:17 -04:00
tag_ops = dsa_resolve_tag_protocol ( tag_protocol ) ;
if ( IS_ERR ( tag_ops ) ) {
2016-06-04 21:17:07 +02:00
dev_warn ( ds - > dev , " No tagger for this switch \n " ) ;
2017-09-29 17:19:17 -04:00
return PTR_ERR ( tag_ops ) ;
2016-06-04 21:17:07 +02:00
}
2017-09-29 17:19:18 -04:00
dst - > cpu_dp - > tag_ops = tag_ops ;
2017-09-29 17:19:19 -04:00
/* Make a few copies for faster access in master receive hot path */
dst - > cpu_dp - > rcv = dst - > cpu_dp - > tag_ops - > rcv ;
dst - > cpu_dp - > dst = dst ;
2016-06-04 21:17:07 +02:00
return 0 ;
}
static int dsa_ds_parse ( struct dsa_switch_tree * dst , struct dsa_switch * ds )
{
2017-01-26 10:45:52 -08:00
struct dsa_port * port ;
2016-06-04 21:17:07 +02:00
u32 index ;
int err ;
2017-01-27 15:29:37 -05:00
for ( index = 0 ; index < ds - > num_ports ; index + + ) {
2017-01-26 10:45:52 -08:00
port = & ds - > ports [ index ] ;
2017-06-02 12:31:23 -07:00
if ( ! dsa_port_is_valid ( port ) | |
dsa_port_is_dsa ( port ) )
2016-06-04 21:17:07 +02:00
continue ;
if ( dsa_port_is_cpu ( port ) ) {
err = dsa_cpu_parse ( port , index , dst , ds ) ;
if ( err )
return err ;
}
2017-06-02 12:31:23 -07:00
2016-06-04 21:17:07 +02:00
}
2017-11-03 19:05:21 -04:00
pr_info ( " DSA: switch %d %d parsed \n " , dst - > index , ds - > index ) ;
2016-06-04 21:17:07 +02:00
return 0 ;
}
static int dsa_dst_parse ( struct dsa_switch_tree * dst )
{
struct dsa_switch * ds ;
2017-06-15 15:06:54 -04:00
struct dsa_port * dp ;
2016-06-04 21:17:07 +02:00
u32 index ;
2017-06-15 15:06:54 -04:00
int port ;
2016-06-04 21:17:07 +02:00
int err ;
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
err = dsa_ds_parse ( dst , ds ) ;
if ( err )
return err ;
}
2017-08-28 17:10:51 -07:00
if ( ! dst - > cpu_dp ) {
2016-06-04 21:17:07 +02:00
pr_warn ( " Tree has no master device \n " ) ;
return - EINVAL ;
}
2017-06-15 15:06:54 -04:00
/* Assign the default CPU port to all ports of the fabric */
for ( index = 0 ; index < DSA_MAX_SWITCHES ; index + + ) {
ds = dst - > ds [ index ] ;
if ( ! ds )
continue ;
for ( port = 0 ; port < ds - > num_ports ; port + + ) {
dp = & ds - > ports [ port ] ;
if ( ! dsa_port_is_valid ( dp ) | |
dsa_port_is_dsa ( dp ) | |
dsa_port_is_cpu ( dp ) )
continue ;
dp - > cpu_dp = dst - > cpu_dp ;
}
}
2017-11-03 19:05:21 -04:00
pr_info ( " DSA: tree %d parsed \n " , dst - > index ) ;
2016-06-04 21:17:07 +02:00
return 0 ;
}
2017-10-27 15:55:14 -04:00
static int dsa_port_parse_of ( struct dsa_port * dp , struct device_node * dn )
{
2017-10-27 15:55:15 -04:00
struct device_node * ethernet = of_parse_phandle ( dn , " ethernet " , 0 ) ;
struct device_node * link = of_parse_phandle ( dn , " link " , 0 ) ;
2017-10-27 15:55:18 -04:00
const char * name = of_get_property ( dn , " label " , NULL ) ;
2017-10-27 15:55:15 -04:00
if ( ethernet ) {
2017-10-27 15:55:17 -04:00
struct net_device * master ;
master = of_find_net_device_by_node ( ethernet ) ;
if ( ! master )
return - EPROBE_DEFER ;
2017-10-27 15:55:15 -04:00
dp - > type = DSA_PORT_TYPE_CPU ;
2017-10-27 15:55:17 -04:00
dp - > master = master ;
2017-10-27 15:55:15 -04:00
} else if ( link ) {
dp - > type = DSA_PORT_TYPE_DSA ;
} else {
2017-10-27 15:55:18 -04:00
if ( ! name )
name = " eth%d " ;
2017-10-27 15:55:15 -04:00
dp - > type = DSA_PORT_TYPE_USER ;
2017-10-27 15:55:18 -04:00
dp - > name = name ;
2017-10-27 15:55:15 -04:00
}
2017-10-27 15:55:14 -04:00
dp - > dn = dn ;
return 0 ;
}
2017-10-27 15:55:13 -04:00
static int dsa_parse_ports_of ( struct device_node * dn , struct dsa_switch * ds )
2016-06-04 21:17:07 +02:00
{
2017-10-27 15:55:13 -04:00
struct device_node * ports , * port ;
2017-10-27 15:55:14 -04:00
struct dsa_port * dp ;
2016-06-04 21:17:07 +02:00
u32 reg ;
2017-10-27 15:55:13 -04:00
int err ;
ports = of_get_child_by_name ( dn , " ports " ) ;
if ( ! ports ) {
dev_err ( ds - > dev , " no ports child node found \n " ) ;
return - EINVAL ;
}
2016-06-04 21:17:07 +02:00
for_each_available_child_of_node ( ports , port ) {
err = of_property_read_u32 ( port , " reg " , & reg ) ;
if ( err )
return err ;
2017-01-27 15:29:37 -05:00
if ( reg > = ds - > num_ports )
2016-06-04 21:17:07 +02:00
return - EINVAL ;
2017-10-27 15:55:14 -04:00
dp = & ds - > ports [ reg ] ;
err = dsa_port_parse_of ( dp , port ) ;
if ( err )
return err ;
2016-06-04 21:17:07 +02:00
}
return 0 ;
}
2017-10-27 15:55:14 -04:00
static int dsa_port_parse ( struct dsa_port * dp , const char * name ,
struct device * dev )
{
2017-10-27 15:55:15 -04:00
if ( ! strcmp ( name , " cpu " ) ) {
2017-10-27 15:55:17 -04:00
struct net_device * master ;
master = dsa_dev_to_net_device ( dev ) ;
if ( ! master )
return - EPROBE_DEFER ;
dev_put ( master ) ;
2017-10-27 15:55:15 -04:00
dp - > type = DSA_PORT_TYPE_CPU ;
2017-10-27 15:55:17 -04:00
dp - > master = master ;
2017-10-27 15:55:15 -04:00
} else if ( ! strcmp ( name , " dsa " ) ) {
dp - > type = DSA_PORT_TYPE_DSA ;
} else {
dp - > type = DSA_PORT_TYPE_USER ;
}
2017-10-27 15:55:14 -04:00
dp - > name = name ;
return 0 ;
}
2017-02-04 13:02:43 -08:00
static int dsa_parse_ports ( struct dsa_chip_data * cd , struct dsa_switch * ds )
{
bool valid_name_found = false ;
2017-10-27 15:55:14 -04:00
struct dsa_port * dp ;
struct device * dev ;
const char * name ;
2017-02-04 13:02:43 -08:00
unsigned int i ;
2017-10-27 15:55:14 -04:00
int err ;
2017-02-04 13:02:43 -08:00
for ( i = 0 ; i < DSA_MAX_PORTS ; i + + ) {
2017-10-27 15:55:14 -04:00
name = cd - > port_names [ i ] ;
dev = cd - > netdev [ i ] ;
dp = & ds - > ports [ i ] ;
if ( ! name )
2017-02-04 13:02:43 -08:00
continue ;
2017-10-27 15:55:14 -04:00
err = dsa_port_parse ( dp , name , dev ) ;
if ( err )
return err ;
2017-02-04 13:02:43 -08:00
valid_name_found = true ;
}
if ( ! valid_name_found & & i = = DSA_MAX_PORTS )
return - EINVAL ;
return 0 ;
}
2017-01-26 10:45:53 -08:00
static int dsa_parse_member_dn ( struct device_node * np , u32 * tree , u32 * index )
2016-06-04 21:17:07 +02:00
{
int err ;
* tree = * index = 0 ;
err = of_property_read_u32_index ( np , " dsa,member " , 0 , tree ) ;
if ( err ) {
/* Does not exist, but it is optional */
if ( err = = - EINVAL )
return 0 ;
return err ;
}
err = of_property_read_u32_index ( np , " dsa,member " , 1 , index ) ;
if ( err )
return err ;
if ( * index > = DSA_MAX_SWITCHES )
return - EINVAL ;
return 0 ;
}
2017-02-04 13:02:43 -08:00
static int dsa_parse_member ( struct dsa_chip_data * pd , u32 * tree , u32 * index )
{
if ( ! pd )
return - ENODEV ;
/* We do not support complex trees with dsa_chip_data */
* tree = 0 ;
* index = 0 ;
return 0 ;
}
2017-05-26 18:12:51 -04:00
static int _dsa_register_switch ( struct dsa_switch * ds )
2016-06-04 21:17:07 +02:00
{
2017-05-26 18:12:51 -04:00
struct dsa_chip_data * pdata = ds - > dev - > platform_data ;
struct device_node * np = ds - > dev - > of_node ;
2016-06-04 21:17:07 +02:00
struct dsa_switch_tree * dst ;
u32 tree , index ;
2016-07-06 20:03:54 -04:00
int i , err ;
2016-06-04 21:17:07 +02:00
2017-02-04 13:02:43 -08:00
if ( np ) {
err = dsa_parse_member_dn ( np , & tree , & index ) ;
if ( err )
return err ;
} else {
err = dsa_parse_member ( pdata , & tree , & index ) ;
if ( err )
return err ;
}
2016-06-04 21:17:07 +02:00
2017-11-03 19:05:24 -04:00
dst = dsa_tree_touch ( tree ) ;
if ( ! dst )
return - ENOMEM ;
2016-06-04 21:17:07 +02:00
ds - > dst = dst ;
ds - > index = index ;
2017-02-04 13:02:43 -08:00
ds - > cd = pdata ;
2016-07-06 20:03:54 -04:00
2017-11-03 19:05:26 -04:00
if ( np ) {
err = dsa_parse_ports_of ( np , ds ) ;
if ( err )
return err ;
} else {
err = dsa_parse_ports ( pdata , ds ) ;
if ( err )
return err ;
}
2016-07-06 20:03:54 -04:00
/* Initialize the routing table */
for ( i = 0 ; i < DSA_MAX_SWITCHES ; + + i )
ds - > rtable [ i ] = DSA_RTABLE_NONE ;
2017-11-03 19:05:25 -04:00
err = dsa_tree_add_switch ( dst , ds ) ;
if ( err )
return err ;
2016-06-04 21:17:07 +02:00
err = dsa_dst_complete ( dst ) ;
if ( err < 0 )
goto out_del_dst ;
2017-11-03 19:05:22 -04:00
/* Not all switches registered yet */
if ( err = = 1 )
return 0 ;
2016-06-04 21:17:07 +02:00
if ( dst - > applied ) {
pr_info ( " DSA: Disjoint trees? \n " ) ;
return - EINVAL ;
}
err = dsa_dst_parse ( dst ) ;
2017-10-27 15:55:17 -04:00
if ( err )
2016-06-04 21:17:07 +02:00
goto out_del_dst ;
err = dsa_dst_apply ( dst ) ;
if ( err ) {
dsa_dst_unapply ( dst ) ;
goto out_del_dst ;
}
return 0 ;
out_del_dst :
2017-11-03 19:05:25 -04:00
dsa_tree_remove_switch ( dst , index ) ;
2016-06-04 21:17:07 +02:00
return err ;
}
2017-01-27 15:29:36 -05:00
struct dsa_switch * dsa_switch_alloc ( struct device * dev , size_t n )
{
size_t size = sizeof ( struct dsa_switch ) + n * sizeof ( struct dsa_port ) ;
struct dsa_switch * ds ;
2017-01-27 15:29:38 -05:00
int i ;
2017-01-27 15:29:36 -05:00
ds = devm_kzalloc ( dev , size , GFP_KERNEL ) ;
if ( ! ds )
return NULL ;
ds - > dev = dev ;
ds - > num_ports = n ;
2017-01-27 15:29:38 -05:00
for ( i = 0 ; i < ds - > num_ports ; + + i ) {
ds - > ports [ i ] . index = i ;
ds - > ports [ i ] . ds = ds ;
}
2017-01-27 15:29:36 -05:00
return ds ;
}
EXPORT_SYMBOL_GPL ( dsa_switch_alloc ) ;
2017-05-26 18:12:51 -04:00
int dsa_register_switch ( struct dsa_switch * ds )
2016-06-04 21:17:07 +02:00
{
int err ;
mutex_lock ( & dsa2_mutex ) ;
2017-05-26 18:12:51 -04:00
err = _dsa_register_switch ( ds ) ;
2016-06-04 21:17:07 +02:00
mutex_unlock ( & dsa2_mutex ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( dsa_register_switch ) ;
2016-07-12 15:24:10 +00:00
static void _dsa_unregister_switch ( struct dsa_switch * ds )
2016-06-04 21:17:07 +02:00
{
struct dsa_switch_tree * dst = ds - > dst ;
2017-11-03 19:05:25 -04:00
unsigned int index = ds - > index ;
2016-06-04 21:17:07 +02:00
dsa_dst_unapply ( dst ) ;
2017-11-03 19:05:25 -04:00
dsa_tree_remove_switch ( dst , index ) ;
2016-06-04 21:17:07 +02:00
}
void dsa_unregister_switch ( struct dsa_switch * ds )
{
mutex_lock ( & dsa2_mutex ) ;
_dsa_unregister_switch ( ds ) ;
mutex_unlock ( & dsa2_mutex ) ;
}
EXPORT_SYMBOL_GPL ( dsa_unregister_switch ) ;