net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
/*
* Copyright Gavin Shan , IBM Corporation 2016.
*
* 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/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/netlink.h>
# include <net/ncsi.h>
# include <net/net_namespace.h>
# include <net/sock.h>
2016-07-19 04:54:19 +03:00
# include <net/addrconf.h>
# include <net/ipv6.h>
# include <net/if_inet6.h>
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
# include "internal.h"
2016-07-19 04:54:19 +03:00
# include "ncsi-pkt.h"
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
LIST_HEAD ( ncsi_dev_list ) ;
DEFINE_SPINLOCK ( ncsi_dev_lock ) ;
static inline int ncsi_filter_size ( int table )
{
int sizes [ ] = { 2 , 6 , 6 , 6 } ;
BUILD_BUG_ON ( ARRAY_SIZE ( sizes ) ! = NCSI_FILTER_MAX ) ;
if ( table < NCSI_FILTER_BASE | | table > = NCSI_FILTER_MAX )
return - EINVAL ;
return sizes [ table ] ;
}
int ncsi_find_filter ( struct ncsi_channel * nc , int table , void * data )
{
struct ncsi_channel_filter * ncf ;
void * bitmap ;
int index , size ;
unsigned long flags ;
ncf = nc - > filters [ table ] ;
if ( ! ncf )
return - ENXIO ;
size = ncsi_filter_size ( table ) ;
if ( size < 0 )
return size ;
spin_lock_irqsave ( & nc - > lock , flags ) ;
bitmap = ( void * ) & ncf - > bitmap ;
index = - 1 ;
while ( ( index = find_next_bit ( bitmap , ncf - > total , index + 1 ) )
< ncf - > total ) {
if ( ! memcmp ( ncf - > data + size * index , data , size ) ) {
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return index ;
}
}
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return - ENOENT ;
}
int ncsi_add_filter ( struct ncsi_channel * nc , int table , void * data )
{
struct ncsi_channel_filter * ncf ;
int index , size ;
void * bitmap ;
unsigned long flags ;
size = ncsi_filter_size ( table ) ;
if ( size < 0 )
return size ;
index = ncsi_find_filter ( nc , table , data ) ;
if ( index > = 0 )
return index ;
ncf = nc - > filters [ table ] ;
if ( ! ncf )
return - ENODEV ;
spin_lock_irqsave ( & nc - > lock , flags ) ;
bitmap = ( void * ) & ncf - > bitmap ;
do {
index = find_next_zero_bit ( bitmap , ncf - > total , 0 ) ;
if ( index > = ncf - > total ) {
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return - ENOSPC ;
}
} while ( test_and_set_bit ( index , bitmap ) ) ;
memcpy ( ncf - > data + size * index , data , size ) ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return index ;
}
int ncsi_remove_filter ( struct ncsi_channel * nc , int table , int index )
{
struct ncsi_channel_filter * ncf ;
int size ;
void * bitmap ;
unsigned long flags ;
size = ncsi_filter_size ( table ) ;
if ( size < 0 )
return size ;
ncf = nc - > filters [ table ] ;
if ( ! ncf | | index > = ncf - > total )
return - ENODEV ;
spin_lock_irqsave ( & nc - > lock , flags ) ;
bitmap = ( void * ) & ncf - > bitmap ;
if ( test_and_clear_bit ( index , bitmap ) )
memset ( ncf - > data + size * index , 0 , size ) ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return 0 ;
}
2016-07-19 04:54:19 +03:00
static void ncsi_report_link ( struct ncsi_dev_priv * ndp , bool force_down )
{
struct ncsi_dev * nd = & ndp - > ndev ;
struct ncsi_package * np ;
struct ncsi_channel * nc ;
2016-10-04 03:25:47 +03:00
unsigned long flags ;
2016-07-19 04:54:19 +03:00
nd - > state = ncsi_dev_state_functional ;
if ( force_down ) {
nd - > link_up = 0 ;
goto report ;
}
nd - > link_up = 0 ;
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
if ( ! list_empty ( & nc - > link ) | |
2016-10-04 03:25:47 +03:00
nc - > state ! = NCSI_CHANNEL_ACTIVE ) {
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
continue ;
2016-10-04 03:25:47 +03:00
}
2016-07-19 04:54:19 +03:00
if ( nc - > modes [ NCSI_MODE_LINK ] . data [ 2 ] & 0x1 ) {
2016-10-04 03:25:47 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
nd - > link_up = 1 ;
goto report ;
}
2016-10-04 03:25:47 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
}
}
report :
nd - > handler ( nd ) ;
}
static void ncsi_channel_monitor ( unsigned long data )
{
struct ncsi_channel * nc = ( struct ncsi_channel * ) data ;
struct ncsi_package * np = nc - > package ;
struct ncsi_dev_priv * ndp = np - > ndp ;
struct ncsi_cmd_arg nca ;
2016-10-04 03:25:47 +03:00
bool enabled , chained ;
2016-10-04 03:25:52 +03:00
unsigned int monitor_state ;
2016-07-19 04:54:19 +03:00
unsigned long flags ;
2016-10-04 03:25:47 +03:00
int state , ret ;
2016-07-19 04:54:19 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-10-04 03:25:47 +03:00
state = nc - > state ;
chained = ! list_empty ( & nc - > link ) ;
2016-10-04 03:25:52 +03:00
enabled = nc - > monitor . enabled ;
monitor_state = nc - > monitor . state ;
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-10-04 03:25:47 +03:00
if ( ! enabled | | chained )
2016-07-19 04:54:19 +03:00
return ;
2016-10-04 03:25:47 +03:00
if ( state ! = NCSI_CHANNEL_INACTIVE & &
state ! = NCSI_CHANNEL_ACTIVE )
2016-07-19 04:54:19 +03:00
return ;
2016-10-04 03:25:52 +03:00
switch ( monitor_state ) {
case NCSI_CHANNEL_MONITOR_START :
case NCSI_CHANNEL_MONITOR_RETRY :
2016-07-19 04:54:19 +03:00
nca . ndp = ndp ;
nca . package = np - > id ;
nca . channel = nc - > id ;
nca . type = NCSI_PKT_CMD_GLS ;
2016-10-04 03:25:51 +03:00
nca . req_flags = 0 ;
2016-07-19 04:54:19 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret ) {
netdev_err ( ndp - > ndev . dev , " Error %d sending GLS \n " ,
ret ) ;
return ;
}
2016-10-04 03:25:52 +03:00
break ;
case NCSI_CHANNEL_MONITOR_WAIT . . . NCSI_CHANNEL_MONITOR_WAIT_MAX :
break ;
default :
2016-07-19 04:54:19 +03:00
if ( ! ( ndp - > flags & NCSI_DEV_HWA ) & &
2016-10-04 03:25:52 +03:00
state = = NCSI_CHANNEL_ACTIVE ) {
2016-07-19 04:54:19 +03:00
ncsi_report_link ( ndp , true ) ;
2016-10-04 03:25:52 +03:00
ndp - > flags | = NCSI_DEV_RESHUFFLE ;
}
2016-07-19 04:54:19 +03:00
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
nc - > state = NCSI_CHANNEL_INVISIBLE ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
spin_lock_irqsave ( & ndp - > lock , flags ) ;
2016-10-04 03:25:47 +03:00
nc - > state = NCSI_CHANNEL_INACTIVE ;
2016-07-19 04:54:19 +03:00
list_add_tail_rcu ( & nc - > link , & ndp - > channel_queue ) ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
ncsi_process_next_channel ( ndp ) ;
return ;
}
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
nc - > monitor . state + + ;
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
mod_timer ( & nc - > monitor . timer , jiffies + HZ ) ;
2016-07-19 04:54:19 +03:00
}
void ncsi_start_channel_monitor ( struct ncsi_channel * nc )
{
unsigned long flags ;
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
WARN_ON_ONCE ( nc - > monitor . enabled ) ;
nc - > monitor . enabled = true ;
nc - > monitor . state = NCSI_CHANNEL_MONITOR_START ;
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
mod_timer ( & nc - > monitor . timer , jiffies + HZ ) ;
2016-07-19 04:54:19 +03:00
}
void ncsi_stop_channel_monitor ( struct ncsi_channel * nc )
{
unsigned long flags ;
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
if ( ! nc - > monitor . enabled ) {
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
return ;
}
2016-10-04 03:25:52 +03:00
nc - > monitor . enabled = false ;
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-10-04 03:25:52 +03:00
del_timer_sync ( & nc - > monitor . timer ) ;
2016-07-19 04:54:19 +03:00
}
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
struct ncsi_channel * ncsi_find_channel ( struct ncsi_package * np ,
unsigned char id )
{
struct ncsi_channel * nc ;
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
if ( nc - > id = = id )
return nc ;
}
return NULL ;
}
struct ncsi_channel * ncsi_add_channel ( struct ncsi_package * np , unsigned char id )
{
struct ncsi_channel * nc , * tmp ;
int index ;
unsigned long flags ;
nc = kzalloc ( sizeof ( * nc ) , GFP_ATOMIC ) ;
if ( ! nc )
return NULL ;
nc - > id = id ;
nc - > package = np ;
nc - > state = NCSI_CHANNEL_INACTIVE ;
2016-10-04 03:25:52 +03:00
nc - > monitor . enabled = false ;
setup_timer ( & nc - > monitor . timer ,
ncsi_channel_monitor , ( unsigned long ) nc ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
spin_lock_init ( & nc - > lock ) ;
2016-07-19 04:54:19 +03:00
INIT_LIST_HEAD ( & nc - > link ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
for ( index = 0 ; index < NCSI_CAP_MAX ; index + + )
nc - > caps [ index ] . index = index ;
for ( index = 0 ; index < NCSI_MODE_MAX ; index + + )
nc - > modes [ index ] . index = index ;
spin_lock_irqsave ( & np - > lock , flags ) ;
tmp = ncsi_find_channel ( np , id ) ;
if ( tmp ) {
spin_unlock_irqrestore ( & np - > lock , flags ) ;
kfree ( nc ) ;
return tmp ;
}
list_add_tail_rcu ( & nc - > node , & np - > channels ) ;
np - > channel_num + + ;
spin_unlock_irqrestore ( & np - > lock , flags ) ;
return nc ;
}
static void ncsi_remove_channel ( struct ncsi_channel * nc )
{
struct ncsi_package * np = nc - > package ;
struct ncsi_channel_filter * ncf ;
unsigned long flags ;
int i ;
/* Release filters */
spin_lock_irqsave ( & nc - > lock , flags ) ;
for ( i = 0 ; i < NCSI_FILTER_MAX ; i + + ) {
ncf = nc - > filters [ i ] ;
if ( ! ncf )
continue ;
nc - > filters [ i ] = NULL ;
kfree ( ncf ) ;
}
nc - > state = NCSI_CHANNEL_INACTIVE ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
ncsi_stop_channel_monitor ( nc ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
/* Remove and free channel */
spin_lock_irqsave ( & np - > lock , flags ) ;
list_del_rcu ( & nc - > node ) ;
np - > channel_num - - ;
spin_unlock_irqrestore ( & np - > lock , flags ) ;
kfree ( nc ) ;
}
struct ncsi_package * ncsi_find_package ( struct ncsi_dev_priv * ndp ,
unsigned char id )
{
struct ncsi_package * np ;
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
if ( np - > id = = id )
return np ;
}
return NULL ;
}
struct ncsi_package * ncsi_add_package ( struct ncsi_dev_priv * ndp ,
unsigned char id )
{
struct ncsi_package * np , * tmp ;
unsigned long flags ;
np = kzalloc ( sizeof ( * np ) , GFP_ATOMIC ) ;
if ( ! np )
return NULL ;
np - > id = id ;
np - > ndp = ndp ;
spin_lock_init ( & np - > lock ) ;
INIT_LIST_HEAD ( & np - > channels ) ;
spin_lock_irqsave ( & ndp - > lock , flags ) ;
tmp = ncsi_find_package ( ndp , id ) ;
if ( tmp ) {
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
kfree ( np ) ;
return tmp ;
}
list_add_tail_rcu ( & np - > node , & ndp - > packages ) ;
ndp - > package_num + + ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
return np ;
}
void ncsi_remove_package ( struct ncsi_package * np )
{
struct ncsi_dev_priv * ndp = np - > ndp ;
struct ncsi_channel * nc , * tmp ;
unsigned long flags ;
/* Release all child channels */
list_for_each_entry_safe ( nc , tmp , & np - > channels , node )
ncsi_remove_channel ( nc ) ;
/* Remove and free package */
spin_lock_irqsave ( & ndp - > lock , flags ) ;
list_del_rcu ( & np - > node ) ;
ndp - > package_num - - ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
kfree ( np ) ;
}
void ncsi_find_package_and_channel ( struct ncsi_dev_priv * ndp ,
unsigned char id ,
struct ncsi_package * * np ,
struct ncsi_channel * * nc )
{
struct ncsi_package * p ;
struct ncsi_channel * c ;
p = ncsi_find_package ( ndp , NCSI_PACKAGE_INDEX ( id ) ) ;
c = p ? ncsi_find_channel ( p , NCSI_CHANNEL_INDEX ( id ) ) : NULL ;
if ( np )
* np = p ;
if ( nc )
* nc = c ;
}
/* For two consecutive NCSI commands, the packet IDs shouldn't
* be same . Otherwise , the bogus response might be replied . So
* the available IDs are allocated in round - robin fashion .
*/
2016-10-04 03:25:51 +03:00
struct ncsi_request * ncsi_alloc_request ( struct ncsi_dev_priv * ndp ,
unsigned int req_flags )
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
{
struct ncsi_request * nr = NULL ;
int i , limit = ARRAY_SIZE ( ndp - > requests ) ;
unsigned long flags ;
/* Check if there is one available request until the ceiling */
spin_lock_irqsave ( & ndp - > lock , flags ) ;
2016-10-04 03:25:50 +03:00
for ( i = ndp - > request_id ; i < limit ; i + + ) {
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
if ( ndp - > requests [ i ] . used )
continue ;
nr = & ndp - > requests [ i ] ;
nr - > used = true ;
2016-10-04 03:25:51 +03:00
nr - > flags = req_flags ;
2016-10-04 03:25:50 +03:00
ndp - > request_id = i + 1 ;
goto found ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
}
/* Fail back to check from the starting cursor */
2016-10-04 03:25:50 +03:00
for ( i = NCSI_REQ_START_IDX ; i < ndp - > request_id ; i + + ) {
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
if ( ndp - > requests [ i ] . used )
continue ;
nr = & ndp - > requests [ i ] ;
nr - > used = true ;
2016-10-04 03:25:51 +03:00
nr - > flags = req_flags ;
2016-10-04 03:25:50 +03:00
ndp - > request_id = i + 1 ;
goto found ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
}
2016-10-04 03:25:50 +03:00
found :
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
return nr ;
}
void ncsi_free_request ( struct ncsi_request * nr )
{
struct ncsi_dev_priv * ndp = nr - > ndp ;
struct sk_buff * cmd , * rsp ;
unsigned long flags ;
2016-07-19 04:54:19 +03:00
bool driven ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
if ( nr - > enabled ) {
nr - > enabled = false ;
del_timer_sync ( & nr - > timer ) ;
}
spin_lock_irqsave ( & ndp - > lock , flags ) ;
cmd = nr - > cmd ;
rsp = nr - > rsp ;
nr - > cmd = NULL ;
nr - > rsp = NULL ;
nr - > used = false ;
2016-10-04 03:25:51 +03:00
driven = ! ! ( nr - > flags & NCSI_REQ_FLAG_EVENT_DRIVEN ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
if ( driven & & cmd & & - - ndp - > pending_req_num = = 0 )
schedule_work ( & ndp - > work ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
/* Release command and response */
consume_skb ( cmd ) ;
consume_skb ( rsp ) ;
}
struct ncsi_dev * ncsi_find_dev ( struct net_device * dev )
{
struct ncsi_dev_priv * ndp ;
NCSI_FOR_EACH_DEV ( ndp ) {
if ( ndp - > ndev . dev = = dev )
return & ndp - > ndev ;
}
return NULL ;
}
static void ncsi_request_timeout ( unsigned long data )
{
struct ncsi_request * nr = ( struct ncsi_request * ) data ;
struct ncsi_dev_priv * ndp = nr - > ndp ;
unsigned long flags ;
/* If the request already had associated response,
* let the response handler to release it .
*/
spin_lock_irqsave ( & ndp - > lock , flags ) ;
nr - > enabled = false ;
if ( nr - > rsp | | ! nr - > cmd ) {
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
return ;
}
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
/* Release the request */
ncsi_free_request ( nr ) ;
}
2016-07-19 04:54:19 +03:00
static void ncsi_suspend_channel ( struct ncsi_dev_priv * ndp )
{
struct ncsi_dev * nd = & ndp - > ndev ;
struct ncsi_package * np = ndp - > active_package ;
struct ncsi_channel * nc = ndp - > active_channel ;
struct ncsi_cmd_arg nca ;
2016-10-04 03:25:47 +03:00
unsigned long flags ;
2016-07-19 04:54:19 +03:00
int ret ;
nca . ndp = ndp ;
2016-10-04 03:25:51 +03:00
nca . req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN ;
2016-07-19 04:54:19 +03:00
switch ( nd - > state ) {
case ncsi_dev_state_suspend :
nd - > state = ncsi_dev_state_suspend_select ;
/* Fall through */
case ncsi_dev_state_suspend_select :
2016-10-20 03:45:49 +03:00
ndp - > pending_req_num = 1 ;
nca . type = NCSI_PKT_CMD_SP ;
nca . package = np - > id ;
nca . channel = NCSI_RESERVED_CHANNEL ;
if ( ndp - > flags & NCSI_DEV_HWA )
nca . bytes [ 0 ] = 0 ;
else
nca . bytes [ 0 ] = 1 ;
2016-10-20 03:45:50 +03:00
/* To retrieve the last link states of channels in current
* package when current active channel needs fail over to
* another one . It means we will possibly select another
* channel as next active one . The link states of channels
* are most important factor of the selection . So we need
* accurate link states . Unfortunately , the link states on
* inactive channels can ' t be updated with LSC AEN in time .
*/
if ( ndp - > flags & NCSI_DEV_RESHUFFLE )
nd - > state = ncsi_dev_state_suspend_gls ;
else
nd - > state = ncsi_dev_state_suspend_dcnt ;
2016-10-20 03:45:49 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
2016-10-20 03:45:50 +03:00
break ;
case ncsi_dev_state_suspend_gls :
ndp - > pending_req_num = np - > channel_num ;
nca . type = NCSI_PKT_CMD_GLS ;
nca . package = np - > id ;
nd - > state = ncsi_dev_state_suspend_dcnt ;
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
nca . channel = nc - > id ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
2016-10-20 03:45:49 +03:00
break ;
2016-07-19 04:54:19 +03:00
case ncsi_dev_state_suspend_dcnt :
2016-10-20 03:45:49 +03:00
ndp - > pending_req_num = 1 ;
nca . type = NCSI_PKT_CMD_DCNT ;
nca . package = np - > id ;
nca . channel = nc - > id ;
nd - > state = ncsi_dev_state_suspend_dc ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
break ;
2016-07-19 04:54:19 +03:00
case ncsi_dev_state_suspend_dc :
2016-10-20 03:45:49 +03:00
ndp - > pending_req_num = 1 ;
nca . type = NCSI_PKT_CMD_DC ;
nca . package = np - > id ;
nca . channel = nc - > id ;
nca . bytes [ 0 ] = 1 ;
nd - > state = ncsi_dev_state_suspend_deselect ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
break ;
2016-07-19 04:54:19 +03:00
case ncsi_dev_state_suspend_deselect :
ndp - > pending_req_num = 1 ;
2016-10-20 03:45:49 +03:00
nca . type = NCSI_PKT_CMD_DP ;
2016-07-19 04:54:19 +03:00
nca . package = np - > id ;
2016-10-20 03:45:49 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
2016-10-20 03:45:49 +03:00
nd - > state = ncsi_dev_state_suspend_done ;
2016-07-19 04:54:19 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
2016-10-20 03:45:49 +03:00
if ( ret )
goto error ;
2016-07-19 04:54:19 +03:00
break ;
case ncsi_dev_state_suspend_done :
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
nc - > state = NCSI_CHANNEL_INACTIVE ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
ncsi_process_next_channel ( ndp ) ;
break ;
default :
netdev_warn ( nd - > dev , " Wrong NCSI state 0x%x in suspend \n " ,
nd - > state ) ;
}
2016-10-20 03:45:49 +03:00
return ;
error :
nd - > state = ncsi_dev_state_functional ;
2016-07-19 04:54:19 +03:00
}
static void ncsi_configure_channel ( struct ncsi_dev_priv * ndp )
{
struct ncsi_dev * nd = & ndp - > ndev ;
struct net_device * dev = nd - > dev ;
struct ncsi_package * np = ndp - > active_package ;
struct ncsi_channel * nc = ndp - > active_channel ;
2016-10-20 03:45:51 +03:00
struct ncsi_channel * hot_nc = NULL ;
2016-07-19 04:54:19 +03:00
struct ncsi_cmd_arg nca ;
unsigned char index ;
2016-10-04 03:25:47 +03:00
unsigned long flags ;
2016-07-19 04:54:19 +03:00
int ret ;
nca . ndp = ndp ;
2016-10-04 03:25:51 +03:00
nca . req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN ;
2016-07-19 04:54:19 +03:00
switch ( nd - > state ) {
case ncsi_dev_state_config :
case ncsi_dev_state_config_sp :
ndp - > pending_req_num = 1 ;
/* Select the specific package */
nca . type = NCSI_PKT_CMD_SP ;
if ( ndp - > flags & NCSI_DEV_HWA )
nca . bytes [ 0 ] = 0 ;
else
nca . bytes [ 0 ] = 1 ;
nca . package = np - > id ;
2016-10-04 03:25:48 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
nd - > state = ncsi_dev_state_config_cis ;
break ;
case ncsi_dev_state_config_cis :
ndp - > pending_req_num = 1 ;
/* Clear initial state */
nca . type = NCSI_PKT_CMD_CIS ;
nca . package = np - > id ;
nca . channel = nc - > id ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
nd - > state = ncsi_dev_state_config_sma ;
break ;
case ncsi_dev_state_config_sma :
case ncsi_dev_state_config_ebf :
# if IS_ENABLED(CONFIG_IPV6)
case ncsi_dev_state_config_egmf :
# endif
case ncsi_dev_state_config_ecnt :
case ncsi_dev_state_config_ec :
case ncsi_dev_state_config_ae :
case ncsi_dev_state_config_gls :
ndp - > pending_req_num = 1 ;
nca . package = np - > id ;
nca . channel = nc - > id ;
/* Use first entry in unicast filter table. Note that
* the MAC filter table starts from entry 1 instead of
* 0.
*/
if ( nd - > state = = ncsi_dev_state_config_sma ) {
nca . type = NCSI_PKT_CMD_SMA ;
for ( index = 0 ; index < 6 ; index + + )
nca . bytes [ index ] = dev - > dev_addr [ index ] ;
nca . bytes [ 6 ] = 0x1 ;
nca . bytes [ 7 ] = 0x1 ;
nd - > state = ncsi_dev_state_config_ebf ;
} else if ( nd - > state = = ncsi_dev_state_config_ebf ) {
nca . type = NCSI_PKT_CMD_EBF ;
nca . dwords [ 0 ] = nc - > caps [ NCSI_CAP_BC ] . cap ;
nd - > state = ncsi_dev_state_config_ecnt ;
# if IS_ENABLED(CONFIG_IPV6)
if ( ndp - > inet6_addr_num > 0 & &
( nc - > caps [ NCSI_CAP_GENERIC ] . cap &
NCSI_CAP_GENERIC_MC ) )
nd - > state = ncsi_dev_state_config_egmf ;
else
nd - > state = ncsi_dev_state_config_ecnt ;
} else if ( nd - > state = = ncsi_dev_state_config_egmf ) {
nca . type = NCSI_PKT_CMD_EGMF ;
nca . dwords [ 0 ] = nc - > caps [ NCSI_CAP_MC ] . cap ;
nd - > state = ncsi_dev_state_config_ecnt ;
# endif /* CONFIG_IPV6 */
} else if ( nd - > state = = ncsi_dev_state_config_ecnt ) {
nca . type = NCSI_PKT_CMD_ECNT ;
nd - > state = ncsi_dev_state_config_ec ;
} else if ( nd - > state = = ncsi_dev_state_config_ec ) {
/* Enable AEN if it's supported */
nca . type = NCSI_PKT_CMD_EC ;
nd - > state = ncsi_dev_state_config_ae ;
if ( ! ( nc - > caps [ NCSI_CAP_AEN ] . cap & NCSI_CAP_AEN_MASK ) )
nd - > state = ncsi_dev_state_config_gls ;
} else if ( nd - > state = = ncsi_dev_state_config_ae ) {
nca . type = NCSI_PKT_CMD_AE ;
nca . bytes [ 0 ] = 0 ;
nca . dwords [ 1 ] = nc - > caps [ NCSI_CAP_AEN ] . cap ;
nd - > state = ncsi_dev_state_config_gls ;
} else if ( nd - > state = = ncsi_dev_state_config_gls ) {
nca . type = NCSI_PKT_CMD_GLS ;
nd - > state = ncsi_dev_state_config_done ;
}
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
break ;
case ncsi_dev_state_config_done :
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-10-20 03:45:51 +03:00
if ( nc - > modes [ NCSI_MODE_LINK ] . data [ 2 ] & 0x1 ) {
hot_nc = nc ;
2016-10-04 03:25:47 +03:00
nc - > state = NCSI_CHANNEL_ACTIVE ;
2016-10-20 03:45:51 +03:00
} else {
hot_nc = NULL ;
2016-10-04 03:25:47 +03:00
nc - > state = NCSI_CHANNEL_INACTIVE ;
2016-10-20 03:45:51 +03:00
}
2016-10-04 03:25:47 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
2016-10-20 03:45:51 +03:00
/* Update the hot channel */
spin_lock_irqsave ( & ndp - > lock , flags ) ;
ndp - > hot_channel = hot_nc ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
ncsi_start_channel_monitor ( nc ) ;
ncsi_process_next_channel ( ndp ) ;
break ;
default :
netdev_warn ( dev , " Wrong NCSI state 0x%x in config \n " ,
nd - > state ) ;
}
return ;
error :
ncsi_report_link ( ndp , true ) ;
}
static int ncsi_choose_active_channel ( struct ncsi_dev_priv * ndp )
{
struct ncsi_package * np ;
2016-10-20 03:45:51 +03:00
struct ncsi_channel * nc , * found , * hot_nc ;
2016-07-19 04:54:19 +03:00
struct ncsi_channel_mode * ncm ;
unsigned long flags ;
2016-10-20 03:45:51 +03:00
spin_lock_irqsave ( & ndp - > lock , flags ) ;
hot_nc = ndp - > hot_channel ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
/* The search is done once an inactive channel with up
* link is found .
*/
found = NULL ;
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
if ( ! list_empty ( & nc - > link ) | |
2016-10-04 03:25:47 +03:00
nc - > state ! = NCSI_CHANNEL_INACTIVE ) {
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
continue ;
2016-10-04 03:25:47 +03:00
}
2016-07-19 04:54:19 +03:00
if ( ! found )
found = nc ;
2016-10-20 03:45:51 +03:00
if ( nc = = hot_nc )
found = nc ;
2016-07-19 04:54:19 +03:00
ncm = & nc - > modes [ NCSI_MODE_LINK ] ;
if ( ncm - > data [ 2 ] & 0x1 ) {
2016-10-04 03:25:47 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
found = nc ;
goto out ;
}
2016-10-04 03:25:47 +03:00
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
}
}
if ( ! found ) {
ncsi_report_link ( ndp , true ) ;
return - ENODEV ;
}
out :
spin_lock_irqsave ( & ndp - > lock , flags ) ;
list_add_tail_rcu ( & found - > link , & ndp - > channel_queue ) ;
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
return ncsi_process_next_channel ( ndp ) ;
}
static bool ncsi_check_hwa ( struct ncsi_dev_priv * ndp )
{
struct ncsi_package * np ;
struct ncsi_channel * nc ;
unsigned int cap ;
/* The hardware arbitration is disabled if any one channel
* doesn ' t support explicitly .
*/
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
cap = nc - > caps [ NCSI_CAP_GENERIC ] . cap ;
if ( ! ( cap & NCSI_CAP_GENERIC_HWA ) | |
( cap & NCSI_CAP_GENERIC_HWA_MASK ) ! =
NCSI_CAP_GENERIC_HWA_SUPPORT ) {
ndp - > flags & = ~ NCSI_DEV_HWA ;
return false ;
}
}
}
ndp - > flags | = NCSI_DEV_HWA ;
return true ;
}
static int ncsi_enable_hwa ( struct ncsi_dev_priv * ndp )
{
struct ncsi_package * np ;
struct ncsi_channel * nc ;
unsigned long flags ;
/* Move all available channels to processing queue */
spin_lock_irqsave ( & ndp - > lock , flags ) ;
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
WARN_ON_ONCE ( nc - > state ! = NCSI_CHANNEL_INACTIVE | |
! list_empty ( & nc - > link ) ) ;
ncsi_stop_channel_monitor ( nc ) ;
list_add_tail_rcu ( & nc - > link , & ndp - > channel_queue ) ;
}
}
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
/* We can have no channels in extremely case */
if ( list_empty ( & ndp - > channel_queue ) ) {
ncsi_report_link ( ndp , false ) ;
return - ENOENT ;
}
return ncsi_process_next_channel ( ndp ) ;
}
static void ncsi_probe_channel ( struct ncsi_dev_priv * ndp )
{
struct ncsi_dev * nd = & ndp - > ndev ;
struct ncsi_package * np ;
struct ncsi_channel * nc ;
struct ncsi_cmd_arg nca ;
unsigned char index ;
int ret ;
nca . ndp = ndp ;
2016-10-04 03:25:51 +03:00
nca . req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN ;
2016-07-19 04:54:19 +03:00
switch ( nd - > state ) {
case ncsi_dev_state_probe :
nd - > state = ncsi_dev_state_probe_deselect ;
/* Fall through */
case ncsi_dev_state_probe_deselect :
ndp - > pending_req_num = 8 ;
/* Deselect all possible packages */
nca . type = NCSI_PKT_CMD_DP ;
2016-10-04 03:25:48 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
for ( index = 0 ; index < 8 ; index + + ) {
nca . package = index ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
nd - > state = ncsi_dev_state_probe_package ;
break ;
case ncsi_dev_state_probe_package :
ndp - > pending_req_num = 16 ;
/* Select all possible packages */
nca . type = NCSI_PKT_CMD_SP ;
nca . bytes [ 0 ] = 1 ;
2016-10-04 03:25:48 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
for ( index = 0 ; index < 8 ; index + + ) {
nca . package = index ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
/* Disable all possible packages */
nca . type = NCSI_PKT_CMD_DP ;
for ( index = 0 ; index < 8 ; index + + ) {
nca . package = index ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
nd - > state = ncsi_dev_state_probe_channel ;
break ;
case ncsi_dev_state_probe_channel :
if ( ! ndp - > active_package )
ndp - > active_package = list_first_or_null_rcu (
& ndp - > packages , struct ncsi_package , node ) ;
else if ( list_is_last ( & ndp - > active_package - > node ,
& ndp - > packages ) )
ndp - > active_package = NULL ;
else
ndp - > active_package = list_next_entry (
ndp - > active_package , node ) ;
/* All available packages and channels are enumerated. The
* enumeration happens for once when the NCSI interface is
* started . So we need continue to start the interface after
* the enumeration .
*
* We have to choose an active channel before configuring it .
* Note that we possibly don ' t have active channel in extreme
* situation .
*/
if ( ! ndp - > active_package ) {
ndp - > flags | = NCSI_DEV_PROBED ;
if ( ncsi_check_hwa ( ndp ) )
ncsi_enable_hwa ( ndp ) ;
else
ncsi_choose_active_channel ( ndp ) ;
return ;
}
/* Select the active package */
ndp - > pending_req_num = 1 ;
nca . type = NCSI_PKT_CMD_SP ;
nca . bytes [ 0 ] = 1 ;
nca . package = ndp - > active_package - > id ;
2016-10-04 03:25:48 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
nd - > state = ncsi_dev_state_probe_cis ;
break ;
case ncsi_dev_state_probe_cis :
2016-10-04 03:25:49 +03:00
ndp - > pending_req_num = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
/* Clear initial state */
nca . type = NCSI_PKT_CMD_CIS ;
nca . package = ndp - > active_package - > id ;
2016-10-04 03:25:49 +03:00
for ( index = 0 ; index < NCSI_RESERVED_CHANNEL ; index + + ) {
2016-07-19 04:54:19 +03:00
nca . channel = index ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
nd - > state = ncsi_dev_state_probe_gvi ;
break ;
case ncsi_dev_state_probe_gvi :
case ncsi_dev_state_probe_gc :
case ncsi_dev_state_probe_gls :
np = ndp - > active_package ;
ndp - > pending_req_num = np - > channel_num ;
/* Retrieve version, capability or link status */
if ( nd - > state = = ncsi_dev_state_probe_gvi )
nca . type = NCSI_PKT_CMD_GVI ;
else if ( nd - > state = = ncsi_dev_state_probe_gc )
nca . type = NCSI_PKT_CMD_GC ;
else
nca . type = NCSI_PKT_CMD_GLS ;
nca . package = np - > id ;
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
nca . channel = nc - > id ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
}
if ( nd - > state = = ncsi_dev_state_probe_gvi )
nd - > state = ncsi_dev_state_probe_gc ;
else if ( nd - > state = = ncsi_dev_state_probe_gc )
nd - > state = ncsi_dev_state_probe_gls ;
else
nd - > state = ncsi_dev_state_probe_dp ;
break ;
case ncsi_dev_state_probe_dp :
ndp - > pending_req_num = 1 ;
/* Deselect the active package */
nca . type = NCSI_PKT_CMD_DP ;
nca . package = ndp - > active_package - > id ;
2016-10-04 03:25:48 +03:00
nca . channel = NCSI_RESERVED_CHANNEL ;
2016-07-19 04:54:19 +03:00
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret )
goto error ;
/* Scan channels in next package */
nd - > state = ncsi_dev_state_probe_channel ;
break ;
default :
netdev_warn ( nd - > dev , " Wrong NCSI state 0x%0x in enumeration \n " ,
nd - > state ) ;
}
return ;
error :
ncsi_report_link ( ndp , true ) ;
}
static void ncsi_dev_work ( struct work_struct * work )
{
struct ncsi_dev_priv * ndp = container_of ( work ,
struct ncsi_dev_priv , work ) ;
struct ncsi_dev * nd = & ndp - > ndev ;
switch ( nd - > state & ncsi_dev_state_major ) {
case ncsi_dev_state_probe :
ncsi_probe_channel ( ndp ) ;
break ;
case ncsi_dev_state_suspend :
ncsi_suspend_channel ( ndp ) ;
break ;
case ncsi_dev_state_config :
ncsi_configure_channel ( ndp ) ;
break ;
default :
netdev_warn ( nd - > dev , " Wrong NCSI state 0x%x in workqueue \n " ,
nd - > state ) ;
}
}
int ncsi_process_next_channel ( struct ncsi_dev_priv * ndp )
{
struct ncsi_channel * nc ;
int old_state ;
unsigned long flags ;
spin_lock_irqsave ( & ndp - > lock , flags ) ;
nc = list_first_or_null_rcu ( & ndp - > channel_queue ,
struct ncsi_channel , link ) ;
2016-07-21 22:28:34 +03:00
if ( ! nc ) {
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
goto out ;
2016-07-19 04:54:19 +03:00
}
2016-07-21 22:28:34 +03:00
list_del_init ( & nc - > link ) ;
2016-07-19 04:54:19 +03:00
spin_unlock_irqrestore ( & ndp - > lock , flags ) ;
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
old_state = nc - > state ;
nc - > state = NCSI_CHANNEL_INVISIBLE ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
2016-07-19 04:54:19 +03:00
ndp - > active_channel = nc ;
2016-07-21 22:28:34 +03:00
ndp - > active_package = nc - > package ;
2016-07-19 04:54:19 +03:00
switch ( old_state ) {
case NCSI_CHANNEL_INACTIVE :
ndp - > ndev . state = ncsi_dev_state_config ;
ncsi_configure_channel ( ndp ) ;
break ;
case NCSI_CHANNEL_ACTIVE :
ndp - > ndev . state = ncsi_dev_state_suspend ;
ncsi_suspend_channel ( ndp ) ;
break ;
default :
netdev_err ( ndp - > ndev . dev , " Invalid state 0x%x on %d:%d \n " ,
2016-10-04 03:25:47 +03:00
old_state , nc - > package - > id , nc - > id ) ;
2016-07-19 04:54:19 +03:00
ncsi_report_link ( ndp , false ) ;
return - EINVAL ;
}
return 0 ;
2016-07-21 22:28:34 +03:00
out :
ndp - > active_channel = NULL ;
ndp - > active_package = NULL ;
if ( ndp - > flags & NCSI_DEV_RESHUFFLE ) {
ndp - > flags & = ~ NCSI_DEV_RESHUFFLE ;
return ncsi_choose_active_channel ( ndp ) ;
}
ncsi_report_link ( ndp , false ) ;
return - ENODEV ;
2016-07-19 04:54:19 +03:00
}
# if IS_ENABLED(CONFIG_IPV6)
static int ncsi_inet6addr_event ( struct notifier_block * this ,
unsigned long event , void * data )
{
struct inet6_ifaddr * ifa = data ;
struct net_device * dev = ifa - > idev - > dev ;
struct ncsi_dev * nd = ncsi_find_dev ( dev ) ;
struct ncsi_dev_priv * ndp = nd ? TO_NCSI_DEV_PRIV ( nd ) : NULL ;
struct ncsi_package * np ;
struct ncsi_channel * nc ;
struct ncsi_cmd_arg nca ;
bool action ;
int ret ;
if ( ! ndp | | ( ipv6_addr_type ( & ifa - > addr ) &
( IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK ) ) )
return NOTIFY_OK ;
switch ( event ) {
case NETDEV_UP :
action = ( + + ndp - > inet6_addr_num ) = = 1 ;
nca . type = NCSI_PKT_CMD_EGMF ;
break ;
case NETDEV_DOWN :
action = ( - - ndp - > inet6_addr_num = = 0 ) ;
nca . type = NCSI_PKT_CMD_DGMF ;
break ;
default :
return NOTIFY_OK ;
}
/* We might not have active channel or packages. The IPv6
* required multicast will be enabled when active channel
* or packages are chosen .
*/
np = ndp - > active_package ;
nc = ndp - > active_channel ;
if ( ! action | | ! np | | ! nc )
return NOTIFY_OK ;
/* We needn't enable or disable it if the function isn't supported */
if ( ! ( nc - > caps [ NCSI_CAP_GENERIC ] . cap & NCSI_CAP_GENERIC_MC ) )
return NOTIFY_OK ;
nca . ndp = ndp ;
2016-10-04 03:25:51 +03:00
nca . req_flags = 0 ;
2016-07-19 04:54:19 +03:00
nca . package = np - > id ;
nca . channel = nc - > id ;
nca . dwords [ 0 ] = nc - > caps [ NCSI_CAP_MC ] . cap ;
ret = ncsi_xmit_cmd ( & nca ) ;
if ( ret ) {
netdev_warn ( dev , " Fail to %s global multicast filter (%d) \n " ,
( event = = NETDEV_UP ) ? " enable " : " disable " , ret ) ;
return NOTIFY_DONE ;
}
return NOTIFY_OK ;
}
static struct notifier_block ncsi_inet6addr_notifier = {
. notifier_call = ncsi_inet6addr_event ,
} ;
# endif /* CONFIG_IPV6 */
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
struct ncsi_dev * ncsi_register_dev ( struct net_device * dev ,
void ( * handler ) ( struct ncsi_dev * ndev ) )
{
struct ncsi_dev_priv * ndp ;
struct ncsi_dev * nd ;
unsigned long flags ;
int i ;
/* Check if the device has been registered or not */
nd = ncsi_find_dev ( dev ) ;
if ( nd )
return nd ;
/* Create NCSI device */
ndp = kzalloc ( sizeof ( * ndp ) , GFP_ATOMIC ) ;
if ( ! ndp )
return NULL ;
nd = & ndp - > ndev ;
nd - > state = ncsi_dev_state_registered ;
nd - > dev = dev ;
nd - > handler = handler ;
2016-07-19 04:54:19 +03:00
ndp - > pending_req_num = 0 ;
INIT_LIST_HEAD ( & ndp - > channel_queue ) ;
INIT_WORK ( & ndp - > work , ncsi_dev_work ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
/* Initialize private NCSI device */
spin_lock_init ( & ndp - > lock ) ;
INIT_LIST_HEAD ( & ndp - > packages ) ;
2016-10-04 03:25:50 +03:00
ndp - > request_id = NCSI_REQ_START_IDX ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( ndp - > requests ) ; i + + ) {
ndp - > requests [ i ] . id = i ;
ndp - > requests [ i ] . ndp = ndp ;
setup_timer ( & ndp - > requests [ i ] . timer ,
ncsi_request_timeout ,
( unsigned long ) & ndp - > requests [ i ] ) ;
}
spin_lock_irqsave ( & ncsi_dev_lock , flags ) ;
2016-07-19 04:54:19 +03:00
# if IS_ENABLED(CONFIG_IPV6)
ndp - > inet6_addr_num = 0 ;
if ( list_empty ( & ncsi_dev_list ) )
register_inet6addr_notifier ( & ncsi_inet6addr_notifier ) ;
# endif
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
list_add_tail_rcu ( & ndp - > node , & ncsi_dev_list ) ;
spin_unlock_irqrestore ( & ncsi_dev_lock , flags ) ;
2016-07-19 04:54:19 +03:00
/* Register NCSI packet Rx handler */
ndp - > ptype . type = cpu_to_be16 ( ETH_P_NCSI ) ;
ndp - > ptype . func = ncsi_rcv_rsp ;
ndp - > ptype . dev = dev ;
dev_add_pack ( & ndp - > ptype ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
return nd ;
}
EXPORT_SYMBOL_GPL ( ncsi_register_dev ) ;
2016-07-19 04:54:19 +03:00
int ncsi_start_dev ( struct ncsi_dev * nd )
{
struct ncsi_dev_priv * ndp = TO_NCSI_DEV_PRIV ( nd ) ;
2016-10-04 03:25:53 +03:00
int ret ;
2016-07-19 04:54:19 +03:00
if ( nd - > state ! = ncsi_dev_state_registered & &
nd - > state ! = ncsi_dev_state_functional )
return - ENOTTY ;
if ( ! ( ndp - > flags & NCSI_DEV_PROBED ) ) {
nd - > state = ncsi_dev_state_probe ;
schedule_work ( & ndp - > work ) ;
return 0 ;
}
2016-10-04 03:25:53 +03:00
if ( ndp - > flags & NCSI_DEV_HWA )
ret = ncsi_enable_hwa ( ndp ) ;
else
ret = ncsi_choose_active_channel ( ndp ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( ncsi_start_dev ) ;
void ncsi_stop_dev ( struct ncsi_dev * nd )
{
struct ncsi_dev_priv * ndp = TO_NCSI_DEV_PRIV ( nd ) ;
struct ncsi_package * np ;
struct ncsi_channel * nc ;
bool chained ;
int old_state ;
unsigned long flags ;
/* Stop the channel monitor and reset channel's state */
2016-07-19 04:54:19 +03:00
NCSI_FOR_EACH_PACKAGE ( ndp , np ) {
NCSI_FOR_EACH_CHANNEL ( np , nc ) {
2016-10-04 03:25:53 +03:00
ncsi_stop_channel_monitor ( nc ) ;
2016-10-04 03:25:47 +03:00
spin_lock_irqsave ( & nc - > lock , flags ) ;
chained = ! list_empty ( & nc - > link ) ;
old_state = nc - > state ;
nc - > state = NCSI_CHANNEL_INACTIVE ;
spin_unlock_irqrestore ( & nc - > lock , flags ) ;
WARN_ON_ONCE ( chained | |
2016-07-19 04:54:19 +03:00
old_state = = NCSI_CHANNEL_INVISIBLE ) ;
}
}
2016-10-04 03:25:53 +03:00
ncsi_report_link ( ndp , true ) ;
2016-07-19 04:54:19 +03:00
}
2016-10-04 03:25:53 +03:00
EXPORT_SYMBOL_GPL ( ncsi_stop_dev ) ;
2016-07-19 04:54:19 +03:00
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
void ncsi_unregister_dev ( struct ncsi_dev * nd )
{
struct ncsi_dev_priv * ndp = TO_NCSI_DEV_PRIV ( nd ) ;
struct ncsi_package * np , * tmp ;
unsigned long flags ;
2016-07-19 04:54:19 +03:00
dev_remove_pack ( & ndp - > ptype ) ;
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
list_for_each_entry_safe ( np , tmp , & ndp - > packages , node )
ncsi_remove_package ( np ) ;
spin_lock_irqsave ( & ncsi_dev_lock , flags ) ;
list_del_rcu ( & ndp - > node ) ;
2016-07-19 04:54:19 +03:00
# if IS_ENABLED(CONFIG_IPV6)
if ( list_empty ( & ncsi_dev_list ) )
unregister_inet6addr_notifier ( & ncsi_inet6addr_notifier ) ;
# endif
net/ncsi: Resource management
NCSI spec (DSP0222) defines several objects: package, channel, mode,
filter, version and statistics etc. This introduces the data structs
to represent those objects and implement functions to manage them.
Also, this introduces CONFIG_NET_NCSI for the newly implemented NCSI
stack.
* The user (e.g. netdev driver) dereference NCSI device by
"struct ncsi_dev", which is embedded to "struct ncsi_dev_priv".
The later one is used by NCSI stack internally.
* Every NCSI device can have multiple packages simultaneously, up
to 8 packages. It's represented by "struct ncsi_package" and
identified by 3-bits ID.
* Every NCSI package can have multiple channels, up to 32. It's
represented by "struct ncsi_channel" and identified by 5-bits ID.
* Every NCSI channel has version, statistics, various modes and
filters. They are represented by "struct ncsi_channel_version",
"struct ncsi_channel_stats", "struct ncsi_channel_mode" and
"struct ncsi_channel_filter" separately.
* Apart from AEN (Asynchronous Event Notification), the NCSI stack
works in terms of command and response. This introduces "struct
ncsi_req" to represent a complete NCSI transaction made of NCSI
request and response.
link: https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.1.0.pdf
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-07-19 04:54:16 +03:00
spin_unlock_irqrestore ( & ncsi_dev_lock , flags ) ;
kfree ( ndp ) ;
}
EXPORT_SYMBOL_GPL ( ncsi_unregister_dev ) ;