2015-08-21 17:29:17 +09:00
/*
* FUJITSU Extended Socket Network Device driver
* Copyright ( c ) 2015 FUJITSU LIMITED
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , see < http : //www.gnu.org/licenses/>.
*
* The full GNU General Public License is included in this distribution in
* the file called " COPYING " .
*
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/nls.h>
# include <linux/platform_device.h>
2015-08-21 17:29:20 +09:00
# include <linux/netdevice.h>
2015-08-21 17:29:23 +09:00
# include <linux/interrupt.h>
2015-08-21 17:29:17 +09:00
# include "fjes.h"
2016-10-14 20:27:38 +09:00
# include "fjes_trace.h"
2015-08-21 17:29:17 +09:00
# define MAJ 1
2016-10-14 20:28:15 +09:00
# define MIN 2
2015-08-21 17:29:17 +09:00
# define DRV_VERSION __stringify(MAJ) "." __stringify(MIN)
# define DRV_NAME "fjes"
char fjes_driver_name [ ] = DRV_NAME ;
char fjes_driver_version [ ] = DRV_VERSION ;
static const char fjes_driver_string [ ] =
" FUJITSU Extended Socket Network Device Driver " ;
static const char fjes_copyright [ ] =
" Copyright (c) 2015 FUJITSU LIMITED " ;
MODULE_AUTHOR ( " Taku Izumi <izumi.taku@jp.fujitsu.com> " ) ;
MODULE_DESCRIPTION ( " FUJITSU Extended Socket Network Device Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_VERSION ) ;
2017-03-21 11:44:25 -04:00
# define ACPI_MOTHERBOARD_RESOURCE_HID "PNP0C02"
2015-08-21 17:29:23 +09:00
static int fjes_request_irq ( struct fjes_adapter * ) ;
static void fjes_free_irq ( struct fjes_adapter * ) ;
static int fjes_open ( struct net_device * ) ;
static int fjes_close ( struct net_device * ) ;
static int fjes_setup_resources ( struct fjes_adapter * ) ;
static void fjes_free_resources ( struct fjes_adapter * ) ;
2015-08-21 17:29:24 +09:00
static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * ) ;
2015-08-21 17:29:25 +09:00
static void fjes_raise_intr_rxdata_task ( struct work_struct * ) ;
2015-08-21 17:29:26 +09:00
static void fjes_tx_stall_task ( struct work_struct * ) ;
2015-08-21 17:29:33 +09:00
static void fjes_force_close_task ( struct work_struct * ) ;
2015-08-21 17:29:23 +09:00
static irqreturn_t fjes_intr ( int , void * ) ;
2017-01-06 19:12:52 -08:00
static void fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * ) ;
2015-08-21 17:29:29 +09:00
static int fjes_change_mtu ( struct net_device * , int ) ;
2015-08-21 17:29:31 +09:00
static int fjes_vlan_rx_add_vid ( struct net_device * , __be16 proto , u16 ) ;
static int fjes_vlan_rx_kill_vid ( struct net_device * , __be16 proto , u16 ) ;
2015-08-21 17:29:30 +09:00
static void fjes_tx_retry ( struct net_device * ) ;
2015-08-21 17:29:23 +09:00
2015-08-21 17:29:17 +09:00
static int fjes_acpi_add ( struct acpi_device * ) ;
static int fjes_acpi_remove ( struct acpi_device * ) ;
static acpi_status fjes_get_acpi_resource ( struct acpi_resource * , void * ) ;
static int fjes_probe ( struct platform_device * ) ;
static int fjes_remove ( struct platform_device * ) ;
2015-08-21 17:29:20 +09:00
static int fjes_sw_init ( struct fjes_adapter * ) ;
static void fjes_netdev_setup ( struct net_device * ) ;
2015-08-21 17:29:32 +09:00
static void fjes_irq_watch_task ( struct work_struct * ) ;
2015-08-21 17:29:34 +09:00
static void fjes_watch_unshare_task ( struct work_struct * ) ;
2015-08-21 17:29:27 +09:00
static void fjes_rx_irq ( struct fjes_adapter * , int ) ;
static int fjes_poll ( struct napi_struct * , int ) ;
2015-08-21 17:29:17 +09:00
static const struct acpi_device_id fjes_acpi_ids [ ] = {
2017-03-21 11:44:25 -04:00
{ ACPI_MOTHERBOARD_RESOURCE_HID , 0 } ,
2015-08-21 17:29:17 +09:00
{ " " , 0 } ,
} ;
MODULE_DEVICE_TABLE ( acpi , fjes_acpi_ids ) ;
static struct acpi_driver fjes_acpi_driver = {
. name = DRV_NAME ,
. class = DRV_NAME ,
. owner = THIS_MODULE ,
. ids = fjes_acpi_ids ,
. ops = {
. add = fjes_acpi_add ,
. remove = fjes_acpi_remove ,
} ,
} ;
static struct platform_driver fjes_driver = {
. driver = {
. name = DRV_NAME ,
} ,
. probe = fjes_probe ,
. remove = fjes_remove ,
} ;
static struct resource fjes_resource [ ] = {
{
. flags = IORESOURCE_MEM ,
. start = 0 ,
. end = 0 ,
} ,
{
. flags = IORESOURCE_IRQ ,
. start = 0 ,
. end = 0 ,
} ,
} ;
2017-03-21 11:44:25 -04:00
static bool is_extended_socket_device ( struct acpi_device * device )
2015-08-21 17:29:17 +09:00
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
char str_buf [ sizeof ( FJES_ACPI_SYMBOL ) + 1 ] ;
union acpi_object * str ;
acpi_status status ;
int result ;
status = acpi_evaluate_object ( device - > handle , " _STR " , NULL , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
2017-03-21 11:44:25 -04:00
return false ;
2015-08-21 17:29:17 +09:00
str = buffer . pointer ;
result = utf16s_to_utf8s ( ( wchar_t * ) str - > string . pointer ,
str - > string . length , UTF16_LITTLE_ENDIAN ,
str_buf , sizeof ( str_buf ) - 1 ) ;
str_buf [ result ] = 0 ;
if ( strncmp ( FJES_ACPI_SYMBOL , str_buf , strlen ( FJES_ACPI_SYMBOL ) ) ! = 0 ) {
kfree ( buffer . pointer ) ;
2017-03-21 11:44:25 -04:00
return false ;
2015-08-21 17:29:17 +09:00
}
kfree ( buffer . pointer ) ;
2017-03-21 11:44:25 -04:00
return true ;
}
2017-03-21 11:46:35 -04:00
static int acpi_check_extended_socket_status ( struct acpi_device * device )
{
unsigned long long sta ;
acpi_status status ;
status = acpi_evaluate_integer ( device - > handle , " _STA " , NULL , & sta ) ;
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
if ( ! ( ( sta & ACPI_STA_DEVICE_PRESENT ) & &
( sta & ACPI_STA_DEVICE_ENABLED ) & &
( sta & ACPI_STA_DEVICE_UI ) & &
( sta & ACPI_STA_DEVICE_FUNCTIONING ) ) )
return - ENODEV ;
return 0 ;
}
2017-03-21 11:44:25 -04:00
static int fjes_acpi_add ( struct acpi_device * device )
{
struct platform_device * plat_dev ;
acpi_status status ;
if ( ! is_extended_socket_device ( device ) )
return - ENODEV ;
2017-03-21 11:46:35 -04:00
if ( acpi_check_extended_socket_status ( device ) )
return - ENODEV ;
2015-08-21 17:29:17 +09:00
status = acpi_walk_resources ( device - > handle , METHOD_NAME__CRS ,
fjes_get_acpi_resource , fjes_resource ) ;
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
/* create platform_device */
plat_dev = platform_device_register_simple ( DRV_NAME , 0 , fjes_resource ,
ARRAY_SIZE ( fjes_resource ) ) ;
device - > driver_data = plat_dev ;
return 0 ;
}
static int fjes_acpi_remove ( struct acpi_device * device )
{
struct platform_device * plat_dev ;
plat_dev = ( struct platform_device * ) acpi_driver_data ( device ) ;
platform_device_unregister ( plat_dev ) ;
return 0 ;
}
static acpi_status
fjes_get_acpi_resource ( struct acpi_resource * acpi_res , void * data )
{
struct acpi_resource_address32 * addr ;
struct acpi_resource_irq * irq ;
struct resource * res = data ;
switch ( acpi_res - > type ) {
case ACPI_RESOURCE_TYPE_ADDRESS32 :
addr = & acpi_res - > data . address32 ;
res [ 0 ] . start = addr - > address . minimum ;
res [ 0 ] . end = addr - > address . minimum +
addr - > address . address_length - 1 ;
break ;
case ACPI_RESOURCE_TYPE_IRQ :
irq = & acpi_res - > data . irq ;
if ( irq - > interrupt_count ! = 1 )
return AE_ERROR ;
res [ 1 ] . start = irq - > interrupts [ 0 ] ;
res [ 1 ] . end = irq - > interrupts [ 0 ] ;
break ;
default :
break ;
}
return AE_OK ;
}
2015-08-21 17:29:23 +09:00
static int fjes_request_irq ( struct fjes_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
int result = - 1 ;
2015-08-21 17:29:32 +09:00
adapter - > interrupt_watch_enable = true ;
if ( ! delayed_work_pending ( & adapter - > interrupt_watch_task ) ) {
queue_delayed_work ( adapter - > control_wq ,
& adapter - > interrupt_watch_task ,
FJES_IRQ_WATCH_DELAY ) ;
}
2015-08-21 17:29:23 +09:00
if ( ! adapter - > irq_registered ) {
result = request_irq ( adapter - > hw . hw_res . irq , fjes_intr ,
IRQF_SHARED , netdev - > name , adapter ) ;
if ( result )
adapter - > irq_registered = false ;
else
adapter - > irq_registered = true ;
}
return result ;
}
static void fjes_free_irq ( struct fjes_adapter * adapter )
{
struct fjes_hw * hw = & adapter - > hw ;
2015-08-21 17:29:32 +09:00
adapter - > interrupt_watch_enable = false ;
cancel_delayed_work_sync ( & adapter - > interrupt_watch_task ) ;
2015-08-21 17:29:23 +09:00
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , true ) ;
if ( adapter - > irq_registered ) {
free_irq ( adapter - > hw . hw_res . irq , adapter ) ;
adapter - > irq_registered = false ;
}
}
2015-08-21 17:29:20 +09:00
static const struct net_device_ops fjes_netdev_ops = {
2015-08-21 17:29:23 +09:00
. ndo_open = fjes_open ,
. ndo_stop = fjes_close ,
2015-08-21 17:29:24 +09:00
. ndo_start_xmit = fjes_xmit_frame ,
2015-08-21 17:29:28 +09:00
. ndo_get_stats64 = fjes_get_stats64 ,
2015-08-21 17:29:29 +09:00
. ndo_change_mtu = fjes_change_mtu ,
2015-08-21 17:29:30 +09:00
. ndo_tx_timeout = fjes_tx_retry ,
2015-08-21 17:29:31 +09:00
. ndo_vlan_rx_add_vid = fjes_vlan_rx_add_vid ,
. ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid ,
2015-08-21 17:29:20 +09:00
} ;
2015-08-21 17:29:23 +09:00
/* fjes_open - Called when a network interface is made active */
static int fjes_open ( struct net_device * netdev )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
struct fjes_hw * hw = & adapter - > hw ;
int result ;
if ( adapter - > open_guard )
return - ENXIO ;
result = fjes_setup_resources ( adapter ) ;
if ( result )
goto err_setup_res ;
hw - > txrx_stop_req_bit = 0 ;
hw - > epstop_req_bit = 0 ;
2015-08-21 17:29:27 +09:00
napi_enable ( & adapter - > napi ) ;
2015-08-21 17:29:23 +09:00
fjes_hw_capture_interrupt_status ( hw ) ;
result = fjes_request_irq ( adapter ) ;
if ( result )
goto err_req_irq ;
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , false ) ;
netif_tx_start_all_queues ( netdev ) ;
netif_carrier_on ( netdev ) ;
return 0 ;
err_req_irq :
fjes_free_irq ( adapter ) ;
2015-08-21 17:29:27 +09:00
napi_disable ( & adapter - > napi ) ;
2015-08-21 17:29:23 +09:00
err_setup_res :
fjes_free_resources ( adapter ) ;
return result ;
}
/* fjes_close - Disables a network interface */
static int fjes_close ( struct net_device * netdev )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
struct fjes_hw * hw = & adapter - > hw ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:23 +09:00
int epidx ;
netif_tx_stop_all_queues ( netdev ) ;
netif_carrier_off ( netdev ) ;
fjes_hw_raise_epstop ( hw ) ;
2015-08-21 17:29:27 +09:00
napi_disable ( & adapter - > napi ) ;
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
2016-04-15 11:25:46 +09:00
if ( fjes_hw_get_partner_ep_status ( hw , epidx ) = =
EP_PARTNER_SHARED )
adapter - > hw . ep_shm_info [ epidx ]
. tx . info - > v1i . rx_status & =
~ FJES_RX_POLL_WORK ;
2015-08-21 17:29:23 +09:00
}
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
fjes_free_irq ( adapter ) ;
2015-08-21 17:29:32 +09:00
cancel_delayed_work_sync ( & adapter - > interrupt_watch_task ) ;
2015-08-21 17:29:34 +09:00
cancel_work_sync ( & adapter - > unshare_watch_task ) ;
adapter - > unshare_watch_bitmask = 0 ;
2015-08-21 17:29:25 +09:00
cancel_work_sync ( & adapter - > raise_intr_rxdata_task ) ;
2015-08-21 17:29:26 +09:00
cancel_work_sync ( & adapter - > tx_stall_task ) ;
2015-08-21 17:29:25 +09:00
2015-08-21 17:29:35 +09:00
cancel_work_sync ( & hw - > update_zone_task ) ;
2015-08-21 17:29:36 +09:00
cancel_work_sync ( & hw - > epstop_task ) ;
2015-08-21 17:29:35 +09:00
2015-08-21 17:29:23 +09:00
fjes_hw_wait_epstop ( hw ) ;
fjes_free_resources ( adapter ) ;
return 0 ;
}
static int fjes_setup_resources ( struct fjes_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
struct ep_share_mem_info * buf_pair ;
struct fjes_hw * hw = & adapter - > hw ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:23 +09:00
int result ;
int epidx ;
mutex_lock ( & hw - > hw_info . lock ) ;
result = fjes_hw_request_info ( hw ) ;
switch ( result ) {
case 0 :
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
hw - > ep_shm_info [ epidx ] . es_status =
hw - > hw_info . res_buf - > info . info [ epidx ] . es_status ;
hw - > ep_shm_info [ epidx ] . zone =
hw - > hw_info . res_buf - > info . info [ epidx ] . zone ;
}
break ;
default :
case - ENOMSG :
case - EBUSY :
adapter - > force_reset = true ;
mutex_unlock ( & hw - > hw_info . lock ) ;
return result ;
}
mutex_unlock ( & hw - > hw_info . lock ) ;
for ( epidx = 0 ; epidx < ( hw - > max_epid ) ; epidx + + ) {
if ( ( epidx ! = hw - > my_epid ) & &
( hw - > ep_shm_info [ epidx ] . es_status = =
FJES_ZONING_STATUS_ENABLE ) ) {
fjes_hw_raise_interrupt ( hw , epidx ,
REG_ICTL_MASK_INFO_UPDATE ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epidx ] . ep_stats
. send_intr_zoneupdate + = 1 ;
2015-08-21 17:29:23 +09:00
}
}
msleep ( FJES_OPEN_ZONE_UPDATE_WAIT * hw - > max_epid ) ;
for ( epidx = 0 ; epidx < ( hw - > max_epid ) ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
buf_pair = & hw - > ep_shm_info [ epidx ] ;
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
fjes_hw_setup_epbuf ( & buf_pair - > tx , netdev - > dev_addr ,
netdev - > mtu ) ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
if ( fjes_hw_epid_is_same_zone ( hw , epidx ) ) {
mutex_lock ( & hw - > hw_info . lock ) ;
result =
fjes_hw_register_buff_addr ( hw , epidx , buf_pair ) ;
mutex_unlock ( & hw - > hw_info . lock ) ;
switch ( result ) {
case 0 :
break ;
case - ENOMSG :
case - EBUSY :
default :
adapter - > force_reset = true ;
return result ;
}
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epidx ] . ep_stats
. com_regist_buf_exec + = 1 ;
2015-08-21 17:29:23 +09:00
}
}
return 0 ;
}
static void fjes_free_resources ( struct fjes_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
struct fjes_device_command_param param ;
struct ep_share_mem_info * buf_pair ;
struct fjes_hw * hw = & adapter - > hw ;
bool reset_flag = false ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:23 +09:00
int result ;
int epidx ;
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
mutex_lock ( & hw - > hw_info . lock ) ;
result = fjes_hw_unregister_buff_addr ( hw , epidx ) ;
mutex_unlock ( & hw - > hw_info . lock ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epidx ] . ep_stats . com_unregist_buf_exec + = 1 ;
2015-08-21 17:29:23 +09:00
if ( result )
reset_flag = true ;
buf_pair = & hw - > ep_shm_info [ epidx ] ;
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
fjes_hw_setup_epbuf ( & buf_pair - > tx ,
netdev - > dev_addr , netdev - > mtu ) ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:23 +09:00
clear_bit ( epidx , & hw - > txrx_stop_req_bit ) ;
}
if ( reset_flag | | adapter - > force_reset ) {
result = fjes_hw_reset ( hw ) ;
adapter - > force_reset = false ;
if ( result )
adapter - > open_guard = true ;
hw - > hw_info . buffer_share_bit = 0 ;
memset ( ( void * ) & param , 0 , sizeof ( param ) ) ;
param . req_len = hw - > hw_info . req_buf_size ;
param . req_start = __pa ( hw - > hw_info . req_buf ) ;
param . res_len = hw - > hw_info . res_buf_size ;
param . res_start = __pa ( hw - > hw_info . res_buf ) ;
param . share_start = __pa ( hw - > hw_info . share - > ep_status ) ;
fjes_hw_init_command_registers ( hw , & param ) ;
}
}
2015-08-21 17:29:26 +09:00
static void fjes_tx_stall_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( work ,
struct fjes_adapter , tx_stall_task ) ;
struct net_device * netdev = adapter - > netdev ;
struct fjes_hw * hw = & adapter - > hw ;
int all_queue_available , sendable ;
enum ep_partner_status pstatus ;
int max_epid , my_epid , epid ;
union ep_buffer_info * info ;
int i ;
if ( ( ( long ) jiffies -
2016-05-03 16:30:59 +02:00
dev_trans_start ( netdev ) ) > FJES_TX_TX_STALL_TIMEOUT ) {
2015-08-21 17:29:26 +09:00
netif_wake_queue ( netdev ) ;
return ;
}
my_epid = hw - > my_epid ;
max_epid = hw - > max_epid ;
for ( i = 0 ; i < 5 ; i + + ) {
all_queue_available = 1 ;
for ( epid = 0 ; epid < max_epid ; epid + + ) {
if ( my_epid = = epid )
continue ;
pstatus = fjes_hw_get_partner_ep_status ( hw , epid ) ;
sendable = ( pstatus = = EP_PARTNER_SHARED ) ;
if ( ! sendable )
continue ;
info = adapter - > hw . ep_shm_info [ epid ] . tx . info ;
2016-04-15 11:25:40 +09:00
if ( ! ( info - > v1i . rx_status & FJES_RX_MTU_CHANGING_DONE ) )
return ;
2015-08-21 17:29:26 +09:00
if ( EP_RING_FULL ( info - > v1i . head , info - > v1i . tail ,
info - > v1i . count_max ) ) {
all_queue_available = 0 ;
break ;
}
}
if ( all_queue_available ) {
netif_wake_queue ( netdev ) ;
return ;
}
}
usleep_range ( 50 , 100 ) ;
queue_work ( adapter - > txrx_wq , & adapter - > tx_stall_task ) ;
}
2015-08-21 17:29:33 +09:00
static void fjes_force_close_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( work ,
struct fjes_adapter , force_close_task ) ;
struct net_device * netdev = adapter - > netdev ;
rtnl_lock ( ) ;
dev_close ( netdev ) ;
rtnl_unlock ( ) ;
}
2015-08-21 17:29:25 +09:00
static void fjes_raise_intr_rxdata_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( work ,
struct fjes_adapter , raise_intr_rxdata_task ) ;
struct fjes_hw * hw = & adapter - > hw ;
enum ep_partner_status pstatus ;
int max_epid , my_epid , epid ;
my_epid = hw - > my_epid ;
max_epid = hw - > max_epid ;
for ( epid = 0 ; epid < max_epid ; epid + + )
hw - > ep_shm_info [ epid ] . tx_status_work = 0 ;
for ( epid = 0 ; epid < max_epid ; epid + + ) {
if ( epid = = my_epid )
continue ;
pstatus = fjes_hw_get_partner_ep_status ( hw , epid ) ;
if ( pstatus = = EP_PARTNER_SHARED ) {
hw - > ep_shm_info [ epid ] . tx_status_work =
hw - > ep_shm_info [ epid ] . tx . info - > v1i . tx_status ;
if ( hw - > ep_shm_info [ epid ] . tx_status_work = =
FJES_TX_DELAY_SEND_PENDING ) {
hw - > ep_shm_info [ epid ] . tx . info - > v1i . tx_status =
FJES_TX_DELAY_SEND_NONE ;
}
}
}
for ( epid = 0 ; epid < max_epid ; epid + + ) {
if ( epid = = my_epid )
continue ;
pstatus = fjes_hw_get_partner_ep_status ( hw , epid ) ;
if ( ( hw - > ep_shm_info [ epid ] . tx_status_work = =
FJES_TX_DELAY_SEND_PENDING ) & &
( pstatus = = EP_PARTNER_SHARED ) & &
2016-04-15 11:25:34 +09:00
! ( hw - > ep_shm_info [ epid ] . rx . info - > v1i . rx_status &
FJES_RX_POLL_WORK ) ) {
2015-08-21 17:29:25 +09:00
fjes_hw_raise_interrupt ( hw , epid ,
REG_ICTL_MASK_RX_DATA ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epid ] . ep_stats . send_intr_rx + = 1 ;
2015-08-21 17:29:25 +09:00
}
}
usleep_range ( 500 , 1000 ) ;
}
2015-08-21 17:29:24 +09:00
static int fjes_tx_send ( struct fjes_adapter * adapter , int dest ,
void * data , size_t len )
{
int retval ;
retval = fjes_hw_epbuf_tx_pkt_send ( & adapter - > hw . ep_shm_info [ dest ] . tx ,
data , len ) ;
if ( retval )
return retval ;
adapter - > hw . ep_shm_info [ dest ] . tx . info - > v1i . tx_status =
FJES_TX_DELAY_SEND_PENDING ;
2015-08-21 17:29:25 +09:00
if ( ! work_pending ( & adapter - > raise_intr_rxdata_task ) )
queue_work ( adapter - > txrx_wq ,
& adapter - > raise_intr_rxdata_task ) ;
2015-08-21 17:29:24 +09:00
retval = 0 ;
return retval ;
}
static netdev_tx_t
fjes_xmit_frame ( struct sk_buff * skb , struct net_device * netdev )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
struct fjes_hw * hw = & adapter - > hw ;
int max_epid , my_epid , dest_epid ;
enum ep_partner_status pstatus ;
struct netdev_queue * cur_queue ;
char shortpkt [ VLAN_ETH_HLEN ] ;
bool is_multi , vlan ;
struct ethhdr * eth ;
u16 queue_no = 0 ;
u16 vlan_id = 0 ;
netdev_tx_t ret ;
char * data ;
int len ;
ret = NETDEV_TX_OK ;
is_multi = false ;
cur_queue = netdev_get_tx_queue ( netdev , queue_no ) ;
eth = ( struct ethhdr * ) skb - > data ;
my_epid = hw - > my_epid ;
vlan = ( vlan_get_tag ( skb , & vlan_id ) = = 0 ) ? true : false ;
data = skb - > data ;
len = skb - > len ;
if ( is_multicast_ether_addr ( eth - > h_dest ) ) {
dest_epid = 0 ;
max_epid = hw - > max_epid ;
is_multi = true ;
} else if ( is_local_ether_addr ( eth - > h_dest ) ) {
dest_epid = eth - > h_dest [ ETH_ALEN - 1 ] ;
max_epid = dest_epid + 1 ;
if ( ( eth - > h_dest [ 0 ] = = 0x02 ) & &
( 0x00 = = ( eth - > h_dest [ 1 ] | eth - > h_dest [ 2 ] |
eth - > h_dest [ 3 ] | eth - > h_dest [ 4 ] ) ) & &
( dest_epid < hw - > max_epid ) ) {
;
} else {
dest_epid = 0 ;
max_epid = 0 ;
ret = NETDEV_TX_OK ;
adapter - > stats64 . tx_packets + = 1 ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_packets + = 1 ;
adapter - > stats64 . tx_bytes + = len ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_bytes + = len ;
}
} else {
dest_epid = 0 ;
max_epid = 0 ;
ret = NETDEV_TX_OK ;
adapter - > stats64 . tx_packets + = 1 ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_packets + = 1 ;
adapter - > stats64 . tx_bytes + = len ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_bytes + = len ;
}
for ( ; dest_epid < max_epid ; dest_epid + + ) {
if ( my_epid = = dest_epid )
continue ;
pstatus = fjes_hw_get_partner_ep_status ( hw , dest_epid ) ;
if ( pstatus ! = EP_PARTNER_SHARED ) {
2016-10-14 20:27:32 +09:00
if ( ! is_multi )
hw - > ep_shm_info [ dest_epid ] . ep_stats
. tx_dropped_not_shared + = 1 ;
2015-08-21 17:29:24 +09:00
ret = NETDEV_TX_OK ;
} else if ( ! fjes_hw_check_epbuf_version (
& adapter - > hw . ep_shm_info [ dest_epid ] . rx , 0 ) ) {
/* version is NOT 0 */
adapter - > stats64 . tx_carrier_errors + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats
2015-08-21 17:29:24 +09:00
. tx_carrier_errors + = 1 ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ dest_epid ] . ep_stats
. tx_dropped_ver_mismatch + = 1 ;
2015-08-21 17:29:24 +09:00
ret = NETDEV_TX_OK ;
} else if ( ! fjes_hw_check_mtu (
& adapter - > hw . ep_shm_info [ dest_epid ] . rx ,
netdev - > mtu ) ) {
adapter - > stats64 . tx_dropped + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats . tx_dropped + = 1 ;
2015-08-21 17:29:24 +09:00
adapter - > stats64 . tx_errors + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats . tx_errors + = 1 ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ dest_epid ] . ep_stats
. tx_dropped_buf_size_mismatch + = 1 ;
2015-08-21 17:29:24 +09:00
ret = NETDEV_TX_OK ;
} else if ( vlan & &
! fjes_hw_check_vlan_id (
& adapter - > hw . ep_shm_info [ dest_epid ] . rx ,
vlan_id ) ) {
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ dest_epid ] . ep_stats
. tx_dropped_vlanid_mismatch + = 1 ;
2015-08-21 17:29:24 +09:00
ret = NETDEV_TX_OK ;
} else {
if ( len < VLAN_ETH_HLEN ) {
memset ( shortpkt , 0 , VLAN_ETH_HLEN ) ;
memcpy ( shortpkt , skb - > data , skb - > len ) ;
len = VLAN_ETH_HLEN ;
data = shortpkt ;
}
if ( adapter - > tx_retry_count = = 0 ) {
adapter - > tx_start_jiffies = jiffies ;
adapter - > tx_retry_count = 1 ;
} else {
adapter - > tx_retry_count + + ;
}
if ( fjes_tx_send ( adapter , dest_epid , data , len ) ) {
if ( is_multi ) {
ret = NETDEV_TX_OK ;
} else if (
( ( long ) jiffies -
( long ) adapter - > tx_start_jiffies ) > =
FJES_TX_RETRY_TIMEOUT ) {
adapter - > stats64 . tx_fifo_errors + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats
2015-08-21 17:29:24 +09:00
. tx_fifo_errors + = 1 ;
adapter - > stats64 . tx_errors + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats
2015-08-21 17:29:24 +09:00
. tx_errors + = 1 ;
ret = NETDEV_TX_OK ;
} else {
2016-05-03 16:33:13 +02:00
netif_trans_update ( netdev ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ dest_epid ] . ep_stats
. tx_buffer_full + = 1 ;
2015-08-21 17:29:24 +09:00
netif_tx_stop_queue ( cur_queue ) ;
2015-08-21 17:29:26 +09:00
if ( ! work_pending ( & adapter - > tx_stall_task ) )
queue_work ( adapter - > txrx_wq ,
& adapter - > tx_stall_task ) ;
2015-08-21 17:29:24 +09:00
ret = NETDEV_TX_BUSY ;
}
} else {
if ( ! is_multi ) {
adapter - > stats64 . tx_packets + = 1 ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats
2015-08-21 17:29:24 +09:00
. tx_packets + = 1 ;
adapter - > stats64 . tx_bytes + = len ;
2016-04-15 11:25:27 +09:00
hw - > ep_shm_info [ dest_epid ] . net_stats
2015-08-21 17:29:24 +09:00
. tx_bytes + = len ;
}
adapter - > tx_retry_count = 0 ;
ret = NETDEV_TX_OK ;
}
}
}
if ( ret = = NETDEV_TX_OK ) {
dev_kfree_skb ( skb ) ;
if ( is_multi ) {
adapter - > stats64 . tx_packets + = 1 ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_packets + = 1 ;
adapter - > stats64 . tx_bytes + = 1 ;
hw - > ep_shm_info [ my_epid ] . net_stats . tx_bytes + = len ;
}
}
return ret ;
}
2015-08-21 17:29:30 +09:00
static void fjes_tx_retry ( struct net_device * netdev )
{
struct netdev_queue * queue = netdev_get_tx_queue ( netdev , 0 ) ;
netif_tx_wake_queue ( queue ) ;
}
2017-01-06 19:12:52 -08:00
static void
2015-08-21 17:29:28 +09:00
fjes_get_stats64 ( struct net_device * netdev , struct rtnl_link_stats64 * stats )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
memcpy ( stats , & adapter - > stats64 , sizeof ( struct rtnl_link_stats64 ) ) ;
}
2015-08-21 17:29:29 +09:00
static int fjes_change_mtu ( struct net_device * netdev , int new_mtu )
{
2016-04-15 11:25:40 +09:00
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
2015-08-21 17:29:29 +09:00
bool running = netif_running ( netdev ) ;
2016-04-15 11:25:40 +09:00
struct fjes_hw * hw = & adapter - > hw ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2016-04-15 11:25:40 +09:00
int ret = - EINVAL ;
int idx , epidx ;
2015-08-21 17:29:29 +09:00
for ( idx = 0 ; fjes_support_mtu [ idx ] ! = 0 ; idx + + ) {
if ( new_mtu < = fjes_support_mtu [ idx ] ) {
new_mtu = fjes_support_mtu [ idx ] ;
if ( new_mtu = = netdev - > mtu )
return 0 ;
2016-04-15 11:25:40 +09:00
ret = 0 ;
break ;
}
}
if ( ret )
return ret ;
2015-08-21 17:29:29 +09:00
2016-04-15 11:25:40 +09:00
if ( running ) {
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2016-04-15 11:25:40 +09:00
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
hw - > ep_shm_info [ epidx ] . tx . info - > v1i . rx_status & =
~ FJES_RX_MTU_CHANGING_DONE ;
}
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2016-04-15 11:25:40 +09:00
netif_tx_stop_all_queues ( netdev ) ;
netif_carrier_off ( netdev ) ;
cancel_work_sync ( & adapter - > tx_stall_task ) ;
napi_disable ( & adapter - > napi ) ;
2015-08-21 17:29:29 +09:00
2016-04-15 11:25:40 +09:00
msleep ( 1000 ) ;
2015-08-21 17:29:29 +09:00
2016-04-15 11:25:40 +09:00
netif_tx_stop_all_queues ( netdev ) ;
}
netdev - > mtu = new_mtu ;
if ( running ) {
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2016-04-15 11:25:40 +09:00
fjes_hw_setup_epbuf ( & hw - > ep_shm_info [ epidx ] . tx ,
netdev - > dev_addr ,
netdev - > mtu ) ;
hw - > ep_shm_info [ epidx ] . tx . info - > v1i . rx_status | =
FJES_RX_MTU_CHANGING_DONE ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:29 +09:00
}
2016-04-15 11:25:40 +09:00
netif_tx_wake_all_queues ( netdev ) ;
netif_carrier_on ( netdev ) ;
napi_enable ( & adapter - > napi ) ;
2016-04-15 11:25:46 +09:00
napi_schedule ( & adapter - > napi ) ;
2015-08-21 17:29:29 +09:00
}
2016-04-15 11:25:40 +09:00
return ret ;
2015-08-21 17:29:29 +09:00
}
2015-08-21 17:29:31 +09:00
static int fjes_vlan_rx_add_vid ( struct net_device * netdev ,
__be16 proto , u16 vid )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
bool ret = true ;
int epid ;
for ( epid = 0 ; epid < adapter - > hw . max_epid ; epid + + ) {
if ( epid = = adapter - > hw . my_epid )
continue ;
if ( ! fjes_hw_check_vlan_id (
& adapter - > hw . ep_shm_info [ epid ] . tx , vid ) )
ret = fjes_hw_set_vlan_id (
& adapter - > hw . ep_shm_info [ epid ] . tx , vid ) ;
}
return ret ? 0 : - ENOSPC ;
}
static int fjes_vlan_rx_kill_vid ( struct net_device * netdev ,
__be16 proto , u16 vid )
{
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
int epid ;
for ( epid = 0 ; epid < adapter - > hw . max_epid ; epid + + ) {
if ( epid = = adapter - > hw . my_epid )
continue ;
fjes_hw_del_vlan_id ( & adapter - > hw . ep_shm_info [ epid ] . tx , vid ) ;
}
return 0 ;
}
2015-08-21 17:29:37 +09:00
static void fjes_txrx_stop_req_irq ( struct fjes_adapter * adapter ,
int src_epid )
{
struct fjes_hw * hw = & adapter - > hw ;
enum ep_partner_status status ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:37 +09:00
status = fjes_hw_get_partner_ep_status ( hw , src_epid ) ;
2016-10-14 20:27:38 +09:00
trace_fjes_txrx_stop_req_irq_pre ( hw , src_epid , status ) ;
2015-08-21 17:29:37 +09:00
switch ( status ) {
case EP_PARTNER_UNSHARE :
case EP_PARTNER_COMPLETE :
default :
break ;
case EP_PARTNER_WAITING :
if ( src_epid < hw - > my_epid ) {
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:37 +09:00
hw - > ep_shm_info [ src_epid ] . tx . info - > v1i . rx_status | =
FJES_RX_STOP_REQ_DONE ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:37 +09:00
clear_bit ( src_epid , & hw - > txrx_stop_req_bit ) ;
set_bit ( src_epid , & adapter - > unshare_watch_bitmask ) ;
if ( ! work_pending ( & adapter - > unshare_watch_task ) )
queue_work ( adapter - > control_wq ,
& adapter - > unshare_watch_task ) ;
}
break ;
case EP_PARTNER_SHARED :
if ( hw - > ep_shm_info [ src_epid ] . rx . info - > v1i . rx_status &
FJES_RX_STOP_REQ_REQUEST ) {
set_bit ( src_epid , & hw - > epstop_req_bit ) ;
if ( ! work_pending ( & hw - > epstop_task ) )
queue_work ( adapter - > control_wq ,
& hw - > epstop_task ) ;
}
break ;
}
2016-10-14 20:27:38 +09:00
trace_fjes_txrx_stop_req_irq_post ( hw , src_epid ) ;
2015-08-21 17:29:37 +09:00
}
static void fjes_stop_req_irq ( struct fjes_adapter * adapter , int src_epid )
{
struct fjes_hw * hw = & adapter - > hw ;
enum ep_partner_status status ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:37 +09:00
set_bit ( src_epid , & hw - > hw_info . buffer_unshare_reserve_bit ) ;
status = fjes_hw_get_partner_ep_status ( hw , src_epid ) ;
2016-10-14 20:27:38 +09:00
trace_fjes_stop_req_irq_pre ( hw , src_epid , status ) ;
2015-08-21 17:29:37 +09:00
switch ( status ) {
case EP_PARTNER_WAITING :
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:37 +09:00
hw - > ep_shm_info [ src_epid ] . tx . info - > v1i . rx_status | =
FJES_RX_STOP_REQ_DONE ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:37 +09:00
clear_bit ( src_epid , & hw - > txrx_stop_req_bit ) ;
/* fall through */
case EP_PARTNER_UNSHARE :
case EP_PARTNER_COMPLETE :
default :
set_bit ( src_epid , & adapter - > unshare_watch_bitmask ) ;
if ( ! work_pending ( & adapter - > unshare_watch_task ) )
queue_work ( adapter - > control_wq ,
& adapter - > unshare_watch_task ) ;
break ;
case EP_PARTNER_SHARED :
set_bit ( src_epid , & hw - > epstop_req_bit ) ;
if ( ! work_pending ( & hw - > epstop_task ) )
queue_work ( adapter - > control_wq , & hw - > epstop_task ) ;
break ;
}
2016-10-14 20:27:38 +09:00
trace_fjes_stop_req_irq_post ( hw , src_epid ) ;
2015-08-21 17:29:37 +09:00
}
2015-08-21 17:29:35 +09:00
static void fjes_update_zone_irq ( struct fjes_adapter * adapter ,
int src_epid )
{
struct fjes_hw * hw = & adapter - > hw ;
if ( ! work_pending ( & hw - > update_zone_task ) )
queue_work ( adapter - > control_wq , & hw - > update_zone_task ) ;
}
2015-08-21 17:29:23 +09:00
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ;
struct fjes_hw * hw = & adapter - > hw ;
irqreturn_t ret ;
u32 icr ;
icr = fjes_hw_capture_interrupt_status ( hw ) ;
2015-08-21 17:29:27 +09:00
if ( icr & REG_IS_MASK_IS_ASSERT ) {
2016-10-14 20:27:32 +09:00
if ( icr & REG_ICTL_MASK_RX_DATA ) {
2015-08-21 17:29:27 +09:00
fjes_rx_irq ( adapter , icr & REG_IS_MASK_EPID ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ icr & REG_IS_MASK_EPID ] . ep_stats
. recv_intr_rx + = 1 ;
}
2015-08-21 17:29:27 +09:00
2016-10-14 20:27:32 +09:00
if ( icr & REG_ICTL_MASK_DEV_STOP_REQ ) {
2015-08-21 17:29:37 +09:00
fjes_stop_req_irq ( adapter , icr & REG_IS_MASK_EPID ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ icr & REG_IS_MASK_EPID ] . ep_stats
. recv_intr_stop + = 1 ;
}
2015-08-21 17:29:37 +09:00
2016-10-14 20:27:32 +09:00
if ( icr & REG_ICTL_MASK_TXRX_STOP_REQ ) {
2015-08-21 17:29:37 +09:00
fjes_txrx_stop_req_irq ( adapter , icr & REG_IS_MASK_EPID ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ icr & REG_IS_MASK_EPID ] . ep_stats
. recv_intr_unshare + = 1 ;
}
2015-08-21 17:29:37 +09:00
if ( icr & REG_ICTL_MASK_TXRX_STOP_DONE )
fjes_hw_set_irqmask ( hw ,
REG_ICTL_MASK_TXRX_STOP_DONE , true ) ;
2016-10-14 20:27:32 +09:00
if ( icr & REG_ICTL_MASK_INFO_UPDATE ) {
2015-08-21 17:29:35 +09:00
fjes_update_zone_irq ( adapter , icr & REG_IS_MASK_EPID ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ icr & REG_IS_MASK_EPID ] . ep_stats
. recv_intr_zoneupdate + = 1 ;
}
2015-08-21 17:29:35 +09:00
2015-08-21 17:29:23 +09:00
ret = IRQ_HANDLED ;
2015-08-21 17:29:27 +09:00
} else {
2015-08-21 17:29:23 +09:00
ret = IRQ_NONE ;
2015-08-21 17:29:27 +09:00
}
2015-08-21 17:29:23 +09:00
return ret ;
}
2015-08-21 17:29:27 +09:00
static int fjes_rxframe_search_exist ( struct fjes_adapter * adapter ,
int start_epid )
{
struct fjes_hw * hw = & adapter - > hw ;
enum ep_partner_status pstatus ;
int max_epid , cur_epid ;
int i ;
max_epid = hw - > max_epid ;
start_epid = ( start_epid + 1 + max_epid ) % max_epid ;
for ( i = 0 ; i < max_epid ; i + + ) {
cur_epid = ( start_epid + i ) % max_epid ;
if ( cur_epid = = hw - > my_epid )
continue ;
pstatus = fjes_hw_get_partner_ep_status ( hw , cur_epid ) ;
if ( pstatus = = EP_PARTNER_SHARED ) {
if ( ! fjes_hw_epbuf_rx_is_empty (
& hw - > ep_shm_info [ cur_epid ] . rx ) )
return cur_epid ;
}
}
return - 1 ;
}
static void * fjes_rxframe_get ( struct fjes_adapter * adapter , size_t * psize ,
int * cur_epid )
{
void * frame ;
* cur_epid = fjes_rxframe_search_exist ( adapter , * cur_epid ) ;
if ( * cur_epid < 0 )
return NULL ;
frame =
fjes_hw_epbuf_rx_curpkt_get_addr (
& adapter - > hw . ep_shm_info [ * cur_epid ] . rx , psize ) ;
return frame ;
}
static void fjes_rxframe_release ( struct fjes_adapter * adapter , int cur_epid )
{
fjes_hw_epbuf_rx_curpkt_drop ( & adapter - > hw . ep_shm_info [ cur_epid ] . rx ) ;
}
static void fjes_rx_irq ( struct fjes_adapter * adapter , int src_epid )
{
struct fjes_hw * hw = & adapter - > hw ;
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_RX_DATA , true ) ;
adapter - > unset_rx_last = true ;
napi_schedule ( & adapter - > napi ) ;
}
static int fjes_poll ( struct napi_struct * napi , int budget )
{
struct fjes_adapter * adapter =
container_of ( napi , struct fjes_adapter , napi ) ;
struct net_device * netdev = napi - > dev ;
struct fjes_hw * hw = & adapter - > hw ;
struct sk_buff * skb ;
int work_done = 0 ;
int cur_epid = 0 ;
int epidx ;
size_t frame_len ;
void * frame ;
2016-04-15 11:25:46 +09:00
spin_lock ( & hw - > rx_status_lock ) ;
2015-08-21 17:29:27 +09:00
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
2016-04-15 11:25:46 +09:00
if ( fjes_hw_get_partner_ep_status ( hw , epidx ) = =
EP_PARTNER_SHARED )
adapter - > hw . ep_shm_info [ epidx ]
. tx . info - > v1i . rx_status | = FJES_RX_POLL_WORK ;
2015-08-21 17:29:27 +09:00
}
2016-04-15 11:25:46 +09:00
spin_unlock ( & hw - > rx_status_lock ) ;
2015-08-21 17:29:27 +09:00
while ( work_done < budget ) {
prefetch ( & adapter - > hw ) ;
frame = fjes_rxframe_get ( adapter , & frame_len , & cur_epid ) ;
if ( frame ) {
skb = napi_alloc_skb ( napi , frame_len ) ;
if ( ! skb ) {
adapter - > stats64 . rx_dropped + = 1 ;
hw - > ep_shm_info [ cur_epid ] . net_stats
. rx_dropped + = 1 ;
adapter - > stats64 . rx_errors + = 1 ;
hw - > ep_shm_info [ cur_epid ] . net_stats
. rx_errors + = 1 ;
} else {
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 14:29:20 +02:00
skb_put_data ( skb , frame , frame_len ) ;
2015-08-21 17:29:27 +09:00
skb - > protocol = eth_type_trans ( skb , netdev ) ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
netif_receive_skb ( skb ) ;
work_done + + ;
adapter - > stats64 . rx_packets + = 1 ;
hw - > ep_shm_info [ cur_epid ] . net_stats
. rx_packets + = 1 ;
adapter - > stats64 . rx_bytes + = frame_len ;
hw - > ep_shm_info [ cur_epid ] . net_stats
. rx_bytes + = frame_len ;
if ( is_multicast_ether_addr (
( ( struct ethhdr * ) frame ) - > h_dest ) ) {
adapter - > stats64 . multicast + = 1 ;
hw - > ep_shm_info [ cur_epid ] . net_stats
. multicast + = 1 ;
}
}
fjes_rxframe_release ( adapter , cur_epid ) ;
adapter - > unset_rx_last = true ;
} else {
break ;
}
}
if ( work_done < budget ) {
2017-01-30 08:22:01 -08:00
napi_complete_done ( napi , work_done ) ;
2015-08-21 17:29:27 +09:00
if ( adapter - > unset_rx_last ) {
adapter - > rx_last_jiffies = jiffies ;
adapter - > unset_rx_last = false ;
}
if ( ( ( long ) jiffies - ( long ) adapter - > rx_last_jiffies ) < 3 ) {
napi_reschedule ( napi ) ;
} else {
2016-04-15 11:25:46 +09:00
spin_lock ( & hw - > rx_status_lock ) ;
2015-08-21 17:29:27 +09:00
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
2016-04-15 11:25:46 +09:00
if ( fjes_hw_get_partner_ep_status ( hw , epidx ) = =
EP_PARTNER_SHARED )
adapter - > hw . ep_shm_info [ epidx ] . tx
. info - > v1i . rx_status & =
2015-08-21 17:29:27 +09:00
~ FJES_RX_POLL_WORK ;
}
2016-04-15 11:25:46 +09:00
spin_unlock ( & hw - > rx_status_lock ) ;
2015-08-21 17:29:27 +09:00
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_RX_DATA , false ) ;
}
}
return work_done ;
}
2015-08-21 17:29:17 +09:00
/* fjes_probe - Device Initialization Routine */
static int fjes_probe ( struct platform_device * plat_dev )
{
2015-08-21 17:29:20 +09:00
struct fjes_adapter * adapter ;
struct net_device * netdev ;
struct resource * res ;
struct fjes_hw * hw ;
int err ;
err = - ENOMEM ;
netdev = alloc_netdev_mq ( sizeof ( struct fjes_adapter ) , " es%d " ,
NET_NAME_UNKNOWN , fjes_netdev_setup ,
FJES_MAX_QUEUES ) ;
if ( ! netdev )
goto err_out ;
SET_NETDEV_DEV ( netdev , & plat_dev - > dev ) ;
dev_set_drvdata ( & plat_dev - > dev , netdev ) ;
adapter = netdev_priv ( netdev ) ;
adapter - > netdev = netdev ;
adapter - > plat_dev = plat_dev ;
hw = & adapter - > hw ;
hw - > back = adapter ;
/* setup the private structure */
err = fjes_sw_init ( adapter ) ;
if ( err )
goto err_free_netdev ;
2015-08-21 17:29:33 +09:00
INIT_WORK ( & adapter - > force_close_task , fjes_force_close_task ) ;
2015-08-21 17:29:20 +09:00
adapter - > force_reset = false ;
adapter - > open_guard = false ;
2016-06-02 15:00:57 +05:30
adapter - > txrx_wq = alloc_workqueue ( DRV_NAME " /txrx " , WQ_MEM_RECLAIM , 0 ) ;
adapter - > control_wq = alloc_workqueue ( DRV_NAME " /control " ,
WQ_MEM_RECLAIM , 0 ) ;
2015-08-21 17:29:25 +09:00
2015-08-21 17:29:26 +09:00
INIT_WORK ( & adapter - > tx_stall_task , fjes_tx_stall_task ) ;
2015-08-21 17:29:25 +09:00
INIT_WORK ( & adapter - > raise_intr_rxdata_task ,
fjes_raise_intr_rxdata_task ) ;
2015-08-21 17:29:34 +09:00
INIT_WORK ( & adapter - > unshare_watch_task , fjes_watch_unshare_task ) ;
adapter - > unshare_watch_bitmask = 0 ;
2015-08-21 17:29:25 +09:00
2015-08-21 17:29:32 +09:00
INIT_DELAYED_WORK ( & adapter - > interrupt_watch_task , fjes_irq_watch_task ) ;
adapter - > interrupt_watch_enable = false ;
2015-08-21 17:29:20 +09:00
res = platform_get_resource ( plat_dev , IORESOURCE_MEM , 0 ) ;
hw - > hw_res . start = res - > start ;
2016-04-11 15:58:17 +05:30
hw - > hw_res . size = resource_size ( res ) ;
2015-08-21 17:29:20 +09:00
hw - > hw_res . irq = platform_get_irq ( plat_dev , 0 ) ;
err = fjes_hw_init ( & adapter - > hw ) ;
if ( err )
goto err_free_netdev ;
/* setup MAC address (02:00:00:00:00:[epid])*/
netdev - > dev_addr [ 0 ] = 2 ;
netdev - > dev_addr [ 1 ] = 0 ;
netdev - > dev_addr [ 2 ] = 0 ;
netdev - > dev_addr [ 3 ] = 0 ;
netdev - > dev_addr [ 4 ] = 0 ;
netdev - > dev_addr [ 5 ] = hw - > my_epid ; /* EPID */
err = register_netdev ( netdev ) ;
if ( err )
goto err_hw_exit ;
netif_carrier_off ( netdev ) ;
2016-10-14 20:28:07 +09:00
fjes_dbg_adapter_init ( adapter ) ;
2015-08-21 17:29:17 +09:00
return 0 ;
2015-08-21 17:29:20 +09:00
err_hw_exit :
fjes_hw_exit ( & adapter - > hw ) ;
err_free_netdev :
free_netdev ( netdev ) ;
err_out :
return err ;
2015-08-21 17:29:17 +09:00
}
/* fjes_remove - Device Removal Routine */
static int fjes_remove ( struct platform_device * plat_dev )
{
2015-08-21 17:29:20 +09:00
struct net_device * netdev = dev_get_drvdata ( & plat_dev - > dev ) ;
struct fjes_adapter * adapter = netdev_priv ( netdev ) ;
struct fjes_hw * hw = & adapter - > hw ;
2016-10-14 20:28:07 +09:00
fjes_dbg_adapter_exit ( adapter ) ;
2015-08-21 17:29:32 +09:00
cancel_delayed_work_sync ( & adapter - > interrupt_watch_task ) ;
2015-08-21 17:29:34 +09:00
cancel_work_sync ( & adapter - > unshare_watch_task ) ;
2015-08-21 17:29:25 +09:00
cancel_work_sync ( & adapter - > raise_intr_rxdata_task ) ;
2015-08-21 17:29:26 +09:00
cancel_work_sync ( & adapter - > tx_stall_task ) ;
2015-08-21 17:29:32 +09:00
if ( adapter - > control_wq )
destroy_workqueue ( adapter - > control_wq ) ;
2015-08-21 17:29:25 +09:00
if ( adapter - > txrx_wq )
destroy_workqueue ( adapter - > txrx_wq ) ;
2015-08-21 17:29:20 +09:00
unregister_netdev ( netdev ) ;
fjes_hw_exit ( hw ) ;
2015-08-21 17:29:27 +09:00
netif_napi_del ( & adapter - > napi ) ;
2015-08-21 17:29:20 +09:00
free_netdev ( netdev ) ;
2015-08-21 17:29:17 +09:00
return 0 ;
}
2015-08-21 17:29:20 +09:00
static int fjes_sw_init ( struct fjes_adapter * adapter )
{
2015-08-21 17:29:27 +09:00
struct net_device * netdev = adapter - > netdev ;
netif_napi_add ( netdev , & adapter - > napi , fjes_poll , 64 ) ;
2015-08-21 17:29:20 +09:00
return 0 ;
}
/* fjes_netdev_setup - netdevice initialization routine */
static void fjes_netdev_setup ( struct net_device * netdev )
{
ether_setup ( netdev ) ;
netdev - > watchdog_timeo = FJES_TX_RETRY_INTERVAL ;
netdev - > netdev_ops = & fjes_netdev_ops ;
2015-08-21 17:29:38 +09:00
fjes_set_ethtool_ops ( netdev ) ;
2016-04-15 11:25:40 +09:00
netdev - > mtu = fjes_support_mtu [ 3 ] ;
net: use core MTU range checking in misc drivers
firewire-net:
- set min/max_mtu
- remove fwnet_change_mtu
nes:
- set max_mtu
- clean up nes_netdev_change_mtu
xpnet:
- set min/max_mtu
- remove xpnet_dev_change_mtu
hippi:
- set min/max_mtu
- remove hippi_change_mtu
batman-adv:
- set max_mtu
- remove batadv_interface_change_mtu
- initialization is a little async, not 100% certain that max_mtu is set
in the optimal place, don't have hardware to test with
rionet:
- set min/max_mtu
- remove rionet_change_mtu
slip:
- set min/max_mtu
- streamline sl_change_mtu
um/net_kern:
- remove pointless ndo_change_mtu
hsi/clients/ssi_protocol:
- use core MTU range checking
- remove now redundant ssip_pn_set_mtu
ipoib:
- set a default max MTU value
- Note: ipoib's actual max MTU can vary, depending on if the device is in
connected mode or not, so we'll just set the max_mtu value to the max
possible, and let the ndo_change_mtu function continue to validate any new
MTU change requests with checks for CM or not. Note that ipoib has no
min_mtu set, and thus, the network core's mtu > 0 check is the only lower
bounds here.
mptlan:
- use net core MTU range checking
- remove now redundant mpt_lan_change_mtu
fddi:
- min_mtu = 21, max_mtu = 4470
- remove now redundant fddi_change_mtu (including export)
fjes:
- min_mtu = 8192, max_mtu = 65536
- The max_mtu value is actually one over IP_MAX_MTU here, but the idea is to
get past the core net MTU range checks so fjes_change_mtu can validate a
new MTU against what it supports (see fjes_support_mtu in fjes_hw.c)
hsr:
- min_mtu = 0 (calls ether_setup, max_mtu is 1500)
f_phonet:
- min_mtu = 6, max_mtu = 65541
u_ether:
- min_mtu = 14, max_mtu = 15412
phonet/pep-gprs:
- min_mtu = 576, max_mtu = 65530
- remove redundant gprs_set_mtu
CC: netdev@vger.kernel.org
CC: linux-rdma@vger.kernel.org
CC: Stefan Richter <stefanr@s5r6.in-berlin.de>
CC: Faisal Latif <faisal.latif@intel.com>
CC: linux-rdma@vger.kernel.org
CC: Cliff Whickman <cpw@sgi.com>
CC: Robin Holt <robinmholt@gmail.com>
CC: Jes Sorensen <jes@trained-monkey.org>
CC: Marek Lindner <mareklindner@neomailbox.ch>
CC: Simon Wunderlich <sw@simonwunderlich.de>
CC: Antonio Quartulli <a@unstable.cc>
CC: Sathya Prakash <sathya.prakash@broadcom.com>
CC: Chaitra P B <chaitra.basappa@broadcom.com>
CC: Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
CC: MPT-FusionLinux.pdl@broadcom.com
CC: Sebastian Reichel <sre@kernel.org>
CC: Felipe Balbi <balbi@kernel.org>
CC: Arvid Brodin <arvid.brodin@alten.se>
CC: Remi Denis-Courmont <courmisch@gmail.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2016-10-20 13:55:22 -04:00
netdev - > min_mtu = fjes_support_mtu [ 0 ] ;
netdev - > max_mtu = fjes_support_mtu [ 3 ] ;
2017-03-15 13:47:50 +09:00
netdev - > features | = NETIF_F_HW_VLAN_CTAG_FILTER ;
2015-08-21 17:29:20 +09:00
}
2015-08-21 17:29:32 +09:00
static void fjes_irq_watch_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( to_delayed_work ( work ) ,
struct fjes_adapter , interrupt_watch_task ) ;
local_irq_disable ( ) ;
fjes_intr ( adapter - > hw . hw_res . irq , adapter ) ;
local_irq_enable ( ) ;
if ( fjes_rxframe_search_exist ( adapter , 0 ) > = 0 )
napi_schedule ( & adapter - > napi ) ;
if ( adapter - > interrupt_watch_enable ) {
if ( ! delayed_work_pending ( & adapter - > interrupt_watch_task ) )
queue_delayed_work ( adapter - > control_wq ,
& adapter - > interrupt_watch_task ,
FJES_IRQ_WATCH_DELAY ) ;
}
}
2015-08-21 17:29:34 +09:00
static void fjes_watch_unshare_task ( struct work_struct * work )
{
struct fjes_adapter * adapter =
container_of ( work , struct fjes_adapter , unshare_watch_task ) ;
struct net_device * netdev = adapter - > netdev ;
struct fjes_hw * hw = & adapter - > hw ;
int unshare_watch , unshare_reserve ;
int max_epid , my_epid , epidx ;
int stop_req , stop_req_done ;
ulong unshare_watch_bitmask ;
2016-04-15 11:25:46 +09:00
unsigned long flags ;
2015-08-21 17:29:34 +09:00
int wait_time = 0 ;
int is_shared ;
int ret ;
my_epid = hw - > my_epid ;
max_epid = hw - > max_epid ;
unshare_watch_bitmask = adapter - > unshare_watch_bitmask ;
adapter - > unshare_watch_bitmask = 0 ;
while ( ( unshare_watch_bitmask | | hw - > txrx_stop_req_bit ) & &
( wait_time < 3000 ) ) {
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
is_shared = fjes_hw_epid_is_shared ( hw - > hw_info . share ,
epidx ) ;
stop_req = test_bit ( epidx , & hw - > txrx_stop_req_bit ) ;
stop_req_done = hw - > ep_shm_info [ epidx ] . rx . info - > v1i . rx_status &
FJES_RX_STOP_REQ_DONE ;
unshare_watch = test_bit ( epidx , & unshare_watch_bitmask ) ;
unshare_reserve = test_bit ( epidx ,
& hw - > hw_info . buffer_unshare_reserve_bit ) ;
if ( ( ! stop_req | |
( is_shared & & ( ! is_shared | | ! stop_req_done ) ) ) & &
( is_shared | | ! unshare_watch | | ! unshare_reserve ) )
continue ;
mutex_lock ( & hw - > hw_info . lock ) ;
ret = fjes_hw_unregister_buff_addr ( hw , epidx ) ;
switch ( ret ) {
case 0 :
break ;
case - ENOMSG :
case - EBUSY :
default :
if ( ! work_pending (
& adapter - > force_close_task ) ) {
adapter - > force_reset = true ;
schedule_work (
& adapter - > force_close_task ) ;
}
break ;
}
mutex_unlock ( & hw - > hw_info . lock ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epidx ] . ep_stats
. com_unregist_buf_exec + = 1 ;
2015-08-21 17:29:34 +09:00
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:34 +09:00
fjes_hw_setup_epbuf ( & hw - > ep_shm_info [ epidx ] . tx ,
netdev - > dev_addr , netdev - > mtu ) ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:34 +09:00
clear_bit ( epidx , & hw - > txrx_stop_req_bit ) ;
clear_bit ( epidx , & unshare_watch_bitmask ) ;
clear_bit ( epidx ,
& hw - > hw_info . buffer_unshare_reserve_bit ) ;
}
msleep ( 100 ) ;
wait_time + = 100 ;
}
if ( hw - > hw_info . buffer_unshare_reserve_bit ) {
for ( epidx = 0 ; epidx < hw - > max_epid ; epidx + + ) {
if ( epidx = = hw - > my_epid )
continue ;
if ( test_bit ( epidx ,
& hw - > hw_info . buffer_unshare_reserve_bit ) ) {
mutex_lock ( & hw - > hw_info . lock ) ;
ret = fjes_hw_unregister_buff_addr ( hw , epidx ) ;
switch ( ret ) {
case 0 :
break ;
case - ENOMSG :
case - EBUSY :
default :
if ( ! work_pending (
& adapter - > force_close_task ) ) {
adapter - > force_reset = true ;
schedule_work (
& adapter - > force_close_task ) ;
}
break ;
}
mutex_unlock ( & hw - > hw_info . lock ) ;
2016-10-14 20:27:32 +09:00
hw - > ep_shm_info [ epidx ] . ep_stats
. com_unregist_buf_exec + = 1 ;
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:34 +09:00
fjes_hw_setup_epbuf (
& hw - > ep_shm_info [ epidx ] . tx ,
netdev - > dev_addr , netdev - > mtu ) ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock ,
flags ) ;
2015-08-21 17:29:34 +09:00
clear_bit ( epidx , & hw - > txrx_stop_req_bit ) ;
clear_bit ( epidx , & unshare_watch_bitmask ) ;
clear_bit ( epidx , & hw - > hw_info . buffer_unshare_reserve_bit ) ;
}
if ( test_bit ( epidx , & unshare_watch_bitmask ) ) {
2016-04-15 11:25:46 +09:00
spin_lock_irqsave ( & hw - > rx_status_lock , flags ) ;
2015-08-21 17:29:34 +09:00
hw - > ep_shm_info [ epidx ] . tx . info - > v1i . rx_status & =
~ FJES_RX_STOP_REQ_DONE ;
2016-04-15 11:25:46 +09:00
spin_unlock_irqrestore ( & hw - > rx_status_lock ,
flags ) ;
2015-08-21 17:29:34 +09:00
}
}
}
}
2017-03-21 11:44:25 -04:00
static acpi_status
acpi_find_extended_socket_device ( acpi_handle obj_handle , u32 level ,
void * context , void * * return_value )
{
struct acpi_device * device ;
bool * found = context ;
int result ;
result = acpi_bus_get_device ( obj_handle , & device ) ;
if ( result )
return AE_OK ;
if ( strcmp ( acpi_device_hid ( device ) , ACPI_MOTHERBOARD_RESOURCE_HID ) )
return AE_OK ;
if ( ! is_extended_socket_device ( device ) )
return AE_OK ;
2017-03-21 11:46:35 -04:00
if ( acpi_check_extended_socket_status ( device ) )
return AE_OK ;
2017-03-21 11:44:25 -04:00
* found = true ;
return AE_CTRL_TERMINATE ;
}
2015-08-21 17:29:17 +09:00
/* fjes_init_module - Driver Registration Routine */
static int __init fjes_init_module ( void )
{
2017-03-21 11:44:25 -04:00
bool found = false ;
2015-08-21 17:29:17 +09:00
int result ;
2017-03-21 11:44:25 -04:00
acpi_walk_namespace ( ACPI_TYPE_DEVICE , ACPI_ROOT_OBJECT , ACPI_UINT32_MAX ,
acpi_find_extended_socket_device , NULL , & found ,
NULL ) ;
if ( ! found )
return - ENODEV ;
2015-08-21 17:29:17 +09:00
pr_info ( " %s - version %s - %s \n " ,
fjes_driver_string , fjes_driver_version , fjes_copyright ) ;
2016-10-14 20:28:07 +09:00
fjes_dbg_init ( ) ;
2015-08-21 17:29:17 +09:00
result = platform_driver_register ( & fjes_driver ) ;
2016-10-14 20:28:07 +09:00
if ( result < 0 ) {
fjes_dbg_exit ( ) ;
2015-08-21 17:29:17 +09:00
return result ;
2016-10-14 20:28:07 +09:00
}
2015-08-21 17:29:17 +09:00
result = acpi_bus_register_driver ( & fjes_acpi_driver ) ;
if ( result < 0 )
goto fail_acpi_driver ;
return 0 ;
fail_acpi_driver :
platform_driver_unregister ( & fjes_driver ) ;
2016-10-14 20:28:07 +09:00
fjes_dbg_exit ( ) ;
2015-08-21 17:29:17 +09:00
return result ;
}
module_init ( fjes_init_module ) ;
/* fjes_exit_module - Driver Exit Cleanup Routine */
static void __exit fjes_exit_module ( void )
{
acpi_bus_unregister_driver ( & fjes_acpi_driver ) ;
platform_driver_unregister ( & fjes_driver ) ;
2016-10-14 20:28:07 +09:00
fjes_dbg_exit ( ) ;
2015-08-21 17:29:17 +09:00
}
module_exit ( fjes_exit_module ) ;