[PATCH v2 00/22] FUJITSU Extended Socket network device driver
STALE4052d
Revision v2 of 5 in this series.
34 messages,
4 authors,
2015-07-13 · open the first message on its own page
This patchsets adds FUJITSU Extended Socket network device driver.
Extended Socket network device is a shared memory based high-speed network
interface between Extended Partitions of PRIMEQUEST 2000 E2 series.
You can get some information about Extended Partition and Extended
Socket by referring the following manual.
http://globalsp.ts.fujitsu.com/dmsp/Publications/public/CA92344-0537.pdf
3.2.1 Extended Partitioning
3.2.2 Extended Socket
v1 -> v2:
- Location change
drivers/platform/x86 => driver/net
- Fix most of style problem
- Follow v1 feedback
Taku Izumi (22):
fjes: Introduce FUJITSU Extended Socket Network Device driver
fjes: Hardware initialization routine
fjes: Hardware cleanup routine
fjes: platform_driver's .probe and .remove routine
fjes: ES information acquisition routine
fjes: buffer address regist/unregistration routine
fjes: net_device_ops.ndo_open and .ndo_stop
fjes: net_device_ops.ndo_start_xmit
fjes: raise_intr_rxdata_task
fjes: tx_stall_task
fjes: NAPI polling function
fjes: net_device_ops.ndo_get_stats64
fjes: net_device_ops.ndo_change_mtu
fjes: net_device_ops.ndo_tx_timeout
fjes: net_device_ops.ndo_vlan_rx_add/kill_vid
fjes: interrupt_watch_task
fjes: force_close_task
fjes: unshare_watch_task
fjes: update_zone_task
fjes: epstop_task
fjes: handle receive cancellation request interrupt
fjes: ethtool support
drivers/net/Kconfig | 7 +
drivers/net/Makefile | 2 +
drivers/net/fjes/Makefile | 31 +
drivers/net/fjes/fjes.h | 77 +++
drivers/net/fjes/fjes_ethtool.c | 135 ++++
drivers/net/fjes/fjes_hw.c | 1122 +++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 333 ++++++++++
drivers/net/fjes/fjes_main.c | 1397 +++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 142 ++++
9 files changed, 3246 insertions(+)
create mode 100644 drivers/net/fjes/Makefile
create mode 100644 drivers/net/fjes/fjes.h
create mode 100644 drivers/net/fjes/fjes_ethtool.c
create mode 100644 drivers/net/fjes/fjes_hw.c
create mode 100644 drivers/net/fjes/fjes_hw.h
create mode 100644 drivers/net/fjes/fjes_main.c
create mode 100644 drivers/net/fjes/fjes_regs.h
--
1.8.3.1
This patch adds the basic code of FUJITSU Extended Socket
Network Device driver.
When "PNP0C02" is found in ACPI DSDT, it evaluates "_STR"
to check if "PNP0C02" is for Extended Socket device driver
and retrieves ACPI resource information. Then creates
platform_device.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/Kconfig | 7 ++
drivers/net/Makefile | 2 +
drivers/net/fjes/Makefile | 31 +++++++
drivers/net/fjes/fjes.h | 33 +++++++
drivers/net/fjes/fjes_main.c | 216 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 289 insertions(+)
create mode 100644 drivers/net/fjes/Makefile
create mode 100644 drivers/net/fjes/fjes.h
create mode 100644 drivers/net/fjes/fjes_main.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index df51d60..57afbb6 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig @@ -379,6 +379,13 @@ config VMXNET3
To compile this driver as a module, choose M here: the
module will be called vmxnet3.
+ config FUJITSU_ES
+ tristate "FUJITSU Extended Socket Network Device driver"
+ depends on ACPI
+ help
+ This driver provides support for Extended Socket network device
+ on Extended Partitioning of FUJITSU PRIMEQUEST 2000 E2 series.
+
source "drivers/net/hyperv/Kconfig"
endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e25fdd7..4cbc7a4 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile @@ -66,3 +66,5 @@ obj-$(CONFIG_USB_NET_DRIVERS) += usb/
obj-$(CONFIG_HYPERV_NET) += hyperv/
obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o
+
+ obj-$(CONFIG_FUJITSU_ES) += fjes/diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile
new file mode 100644
index 0000000..98e59cb
--- /dev/null
+++ b/drivers/net/fjes/Makefile @@ -0,0 +1,31 @@
+ ################################################################################
+ #
+ # 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".
+ #
+ ################################################################################
+
+
+ #
+ # Makefile for the FUJITSU Extended Socket network device driver
+ #
+
+ obj-$(CONFIG_FUJITSU_ES) += fjes.o
+
+ fjes-objs := fjes_main.o
+ diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
new file mode 100644
index 0000000..4622da1
--- /dev/null
+++ b/drivers/net/fjes/fjes.h @@ -0,0 +1,33 @@
+ /*
+ * 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" .
+ *
+ */
+
+ #ifndef FJES_H_
+ #define FJES_H_
+
+ #include <linux/acpi.h>
+
+ #define FJES_ACPI_SYMBOL "Extended Socket"
+
+ extern char fjes_driver_name [];
+ extern char fjes_driver_version [];
+ extern u32 fjes_support_mtu [];
+
+ #endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
new file mode 100644
index 0000000..d20d515
--- /dev/null
+++ b/drivers/net/fjes/fjes_main.c @@ -0,0 +1,216 @@
+ /*
+ * 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>
+
+ #include "fjes.h"
+
+ #define MAJ 1
+ #define MIN 0
+ #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 );
+
+ 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 * );
+
+ static const struct acpi_device_id fjes_acpi_ids [] = {
+ { "PNP0C02" , 0 },
+ { "" , 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 ,
+ . owner = THIS_MODULE ,
+ },
+ . 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 ,
+ },
+ };
+
+ static int fjes_acpi_add ( struct acpi_device * device )
+ {
+ acpi_status status ;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL };
+ union acpi_object * str ;
+ char str_buf [ sizeof ( FJES_ACPI_SYMBOL ) + 1 ];
+ int result ;
+ struct platform_device * plat_dev ;
+
+ status = acpi_evaluate_object ( device -> handle , "_STR" , NULL , & buffer );
+ if ( ACPI_FAILURE ( status ))
+ return - ENODEV ;
+
+ 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 );
+ return - ENODEV ;
+ }
+ kfree ( buffer . pointer );
+
+ 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 resource * res = data ;
+ struct acpi_resource_address32 * addr ;
+ struct acpi_resource_irq * irq ;
+
+ 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 ;
+ }
+
+ /* fjes_probe - Device Initialization Routine */
+ static int fjes_probe ( struct platform_device * plat_dev )
+ {
+ return 0 ;
+ }
+
+ /* fjes_remove - Device Removal Routine */
+ static int fjes_remove ( struct platform_device * plat_dev )
+ {
+ return 0 ;
+ }
+
+ /* fjes_init_module - Driver Registration Routine */
+ static int __init fjes_init_module ( void )
+ {
+ int result ;
+
+ pr_info ( "%s - version %s - %s \n " ,
+ fjes_driver_string , fjes_driver_version , fjes_copyright );
+
+ result = platform_driver_register ( & fjes_driver );
+ if ( result < 0 )
+ return result ;
+
+ 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 );
+ 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 );
+ }
+
+ module_exit ( fjes_exit_module );
+ --
1.8.3.1
This patch adds hardware cleanup routine to be
invoked at driver's .remove routine.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 1 +
2 files changed, 67 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 68ef4d3..13e1da0e 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -56,6 +56,12 @@ static u8 *fjes_hw_iomap(struct fjes_hw *hw)
return base ;
}
+ static void fjes_hw_iounmap ( struct fjes_hw * hw )
+ {
+ iounmap ( hw -> base );
+ release_mem_region ( hw -> hw_res . start , hw -> hw_res . size );
+ }
+
int fjes_hw_reset ( struct fjes_hw * hw )
{
int timeout ; @@ -109,6 +115,12 @@ static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw)
return 0 ;
}
+ static void fjes_hw_free_shared_status_region ( struct fjes_hw * hw )
+ {
+ kfree ( hw -> hw_info . share );
+ hw -> hw_info . share = NULL ;
+ }
+
static int fjes_hw_alloc_epbuf ( struct epbuf_handler * epbh )
{
void * mem ; @@ -126,6 +138,18 @@ static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh)
return 0 ;
}
+ static void fjes_hw_free_epbuf ( struct epbuf_handler * epbh )
+ {
+ if ( epbh -> buffer )
+ vfree ( epbh -> buffer );
+
+ epbh -> buffer = NULL ;
+ epbh -> size = 0 ;
+
+ epbh -> info = NULL ;
+ epbh -> ring = NULL ;
+ }
+
void fjes_hw_setup_epbuf ( struct epbuf_handler * epbh , u8 * mac_addr , u32 mtu )
{
union ep_buffer_info * info = epbh -> info ; @@ -259,6 +283,32 @@ static int fjes_hw_setup(struct fjes_hw *hw)
return 0 ;
}
+ static void fjes_hw_cleanup ( struct fjes_hw * hw )
+ {
+ int epidx ;
+
+ if ( ! hw -> ep_shm_info )
+ return ;
+
+ fjes_hw_free_shared_status_region ( hw );
+
+ kfree ( hw -> hw_info . req_buf );
+ hw -> hw_info . req_buf = NULL ;
+
+ kfree ( hw -> hw_info . res_buf );
+ hw -> hw_info . res_buf = NULL ;
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+ fjes_hw_free_epbuf ( & hw -> ep_shm_info [ epidx ]. tx );
+ fjes_hw_free_epbuf ( & hw -> ep_shm_info [ epidx ]. rx );
+ }
+
+ kfree ( hw -> ep_shm_info );
+ hw -> ep_shm_info = NULL ;
+ }
+
int fjes_hw_init ( struct fjes_hw * hw )
{
int ret ; @@ -286,6 +336,22 @@ int fjes_hw_init(struct fjes_hw *hw)
return ret ;
}
+ void fjes_hw_exit ( struct fjes_hw * hw )
+ {
+ int ret ;
+
+ if ( hw -> base ) {
+ ret = fjes_hw_reset ( hw );
+ if ( ret )
+ pr_err ( "%s: reset error" , __func__ );
+
+ fjes_hw_iounmap ( hw );
+ hw -> base = NULL ;
+ }
+
+ fjes_hw_cleanup ( hw );
+ }
+
void fjes_hw_set_irqmask ( struct fjes_hw * hw ,
enum REG_ICTL_MASK intr_mask , bool mask )
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 6c53f8b..b586fe5 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -240,6 +240,7 @@ struct fjes_hw {
};
int fjes_hw_init ( struct fjes_hw * );
+ void fjes_hw_exit ( struct fjes_hw * );
int fjes_hw_reset ( struct fjes_hw * );
void fjes_hw_init_command_registers ( struct fjes_hw * , --
1.8.3.1
This patch implements platform_driver's .probe and .remove
routine, and also adds board specific private data structure.
This driver registers net_device at platform_driver's .probe
routine and unregisters net_device at its .remove routine.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 25 ++++++++++++
drivers/net/fjes/fjes_main.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 120 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 15ded96..54bc189 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -24,7 +24,32 @@
#include <linux/acpi.h>
+ #include "fjes_hw.h"
+
#define FJES_ACPI_SYMBOL "Extended Socket"
+ #define FJES_MAX_QUEUES 1
+ #define FJES_TX_RETRY_INTERVAL (20 * HZ)
+
+ /* board specific private data structure */
+ struct fjes_adapter {
+ struct net_device * netdev ;
+ struct platform_device * plat_dev ;
+
+ struct napi_struct napi ;
+ struct rtnl_link_stats64 stats64 ;
+
+ unsigned int tx_retry_count ;
+ unsigned long tx_start_jiffies ;
+ unsigned long rx_last_jiffies ;
+ bool unset_rx_last ;
+
+ bool force_reset ;
+ bool open_guard ;
+
+ bool irq_registered ;
+
+ struct fjes_hw hw ;
+ };
extern char fjes_driver_name [];
extern char fjes_driver_version []; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index d20d515..8b8bcb8 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -23,6 +23,7 @@
#include <linux/types.h>
#include <linux/nls.h>
#include <linux/platform_device.h>
+ #include <linux/netdevice.h>
#include "fjes.h"
@@ -49,6 +50,9 @@ 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 * );
+ static int fjes_sw_init ( struct fjes_adapter * );
+ static void fjes_netdev_setup ( struct net_device * );
+
static const struct acpi_device_id fjes_acpi_ids [] = {
{ "PNP0C02" , 0 },
{ "" , 0 }, @@ -168,18 +172,109 @@ fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK ;
}
+ static const struct net_device_ops fjes_netdev_ops = {
+ };
+
/* fjes_probe - Device Initialization Routine */
static int fjes_probe ( struct platform_device * plat_dev )
{
+ struct net_device * netdev ;
+ struct fjes_adapter * adapter ;
+ struct fjes_hw * hw ;
+ struct resource * res ;
+ 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_alloc_netdev ;
+
+ 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_sw_init ;
+
+ adapter -> force_reset = false ;
+ adapter -> open_guard = false ;
+
+ res = platform_get_resource ( plat_dev , IORESOURCE_MEM , 0 );
+ hw -> hw_res . start = res -> start ;
+ hw -> hw_res . size = res -> end - res -> start + 1 ;
+ hw -> hw_res . irq = platform_get_irq ( plat_dev , 0 );
+ err = fjes_hw_init ( & adapter -> hw );
+ if ( err )
+ goto err_hw_init ;
+
+ /* 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_register ;
+
+ netif_carrier_off ( netdev );
+
return 0 ;
+
+ err_register :
+ fjes_hw_exit ( & adapter -> hw );
+ err_hw_init :
+ err_sw_init :
+ free_netdev ( netdev );
+ err_alloc_netdev :
+ return err ;
}
/* fjes_remove - Device Removal Routine */
static int fjes_remove ( struct platform_device * plat_dev )
{
+ struct net_device * netdev = dev_get_drvdata ( & plat_dev -> dev );
+ struct fjes_adapter * adapter = netdev_priv ( netdev );
+ struct fjes_hw * hw = & adapter -> hw ;
+
+ unregister_netdev ( netdev );
+
+ fjes_hw_exit ( hw );
+
+ free_netdev ( netdev );
+
return 0 ;
}
+ static int fjes_sw_init ( struct fjes_adapter * adapter )
+ {
+ 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 ;
+ netdev -> mtu = fjes_support_mtu [ 0 ];
+ netdev -> flags |= IFF_BROADCAST ;
+ netdev -> features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER ;
+ }
+
/* fjes_init_module - Driver Registration Routine */
static int __init fjes_init_module ( void )
{ --
1.8.3.1
This patch adds ES information acquisition routine.
ES information can be retrieved issuing information
request command. ES information includes which
receiver is same zone.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 101 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 24 ++++++++++
drivers/net/fjes/fjes_regs.h | 23 ++++++++++
3 files changed, 148 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 13e1da0e..1ffa62e 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -352,6 +352,107 @@ void fjes_hw_exit(struct fjes_hw *hw)
fjes_hw_cleanup ( hw );
}
+ static enum fjes_dev_command_response_e
+ fjes_hw_issue_request_command ( struct fjes_hw * hw ,
+ enum fjes_dev_command_request_type type )
+ {
+ union REG_CR cr ;
+ union REG_CS cs ;
+ enum fjes_dev_command_response_e ret = FJES_CMD_STATUS_UNKNOWN ;
+ int timeout ;
+
+ cr . reg = 0 ;
+ cr . bits . req_start = 1 ;
+ cr . bits . req_code = type ;
+ wr32 ( XSCT_CR , cr . reg );
+ cr . reg = rd32 ( XSCT_CR );
+
+ if ( cr . bits . error == 0 ) {
+ timeout = FJES_COMMAND_REQ_TIMEOUT * 1000 ;
+ cs . reg = rd32 ( XSCT_CS );
+
+ while (( cs . bits . complete != 1 ) && timeout > 0 ) {
+ msleep ( 1000 );
+ cs . reg = rd32 ( XSCT_CS );
+ timeout -= 1000 ;
+ }
+
+ if ( cs . bits . complete == 1 )
+ ret = FJES_CMD_STATUS_NORMAL ;
+ else if ( timeout <= 0 )
+ ret = FJES_CMD_STATUS_TIMEOUT ;
+
+ } else {
+ switch ( cr . bits . err_info ) {
+ case FJES_CMD_REQ_ERR_INFO_PARAM :
+ ret = FJES_CMD_STATUS_ERROR_PARAM ;
+ break ;
+ case FJES_CMD_REQ_ERR_INFO_STATUS :
+ ret = FJES_CMD_STATUS_ERROR_STATUS ;
+ break ;
+ default :
+ ret = FJES_CMD_STATUS_UNKNOWN ;
+ break ;
+ }
+ }
+
+ return ret ;
+ }
+
+ int fjes_hw_request_info ( struct fjes_hw * hw )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ enum fjes_dev_command_response_e ret ;
+ int result ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> info . length = FJES_DEV_COMMAND_INFO_REQ_LEN ;
+
+ res_buf -> info . length = 0 ;
+ res_buf -> info . code = 0 ;
+
+ ret = fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_INFO );
+
+ result = 0 ;
+
+ if ( FJES_DEV_COMMAND_INFO_RES_LEN (( * hw -> hw_info . max_epid )) !=
+ res_buf -> info . length ) {
+ result = - ENOMSG ;
+ } else if ( ret == FJES_CMD_STATUS_NORMAL ) {
+ switch ( res_buf -> info . code ) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL :
+ result = 0 ;
+ break ;
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ } else {
+ switch ( ret ) {
+ case FJES_CMD_STATUS_UNKNOWN :
+ result = - EPERM ;
+ break ;
+ case FJES_CMD_STATUS_TIMEOUT :
+ result = - EBUSY ;
+ break ;
+ case FJES_CMD_STATUS_ERROR_PARAM :
+ result = - EPERM ;
+ break ;
+ case FJES_CMD_STATUS_ERROR_STATUS :
+ result = - EPERM ;
+ break ;
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ }
+
+ return result ;
+ }
+
void fjes_hw_set_irqmask ( struct fjes_hw * hw ,
enum REG_ICTL_MASK intr_mask , bool mask )
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index b586fe5..2ee166a 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -33,6 +33,12 @@ struct fjes_hw;
#define EP_BUFFER_INFO_SIZE 4096
#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
+ #define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
+
+ #define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
+ #define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002)
+
+ #define FJES_CMD_REQ_RES_CODE_NORMAL (0)
#define EP_BUFFER_SIZE \
((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \ @@ -49,6 +55,7 @@ struct fjes_hw;
(( size ) - sizeof ( struct esmem_frame ) - \
( ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN ))
+ #define FJES_DEV_COMMAND_INFO_REQ_LEN (4)
#define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
#define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE ))) @@ -123,6 +130,13 @@ union fjes_device_command_res {
} stop_trace ;
};
+ /* request command type */
+ enum fjes_dev_command_request_type {
+ FJES_CMD_REQ_INFO = 0x0001 ,
+ FJES_CMD_REQ_SHARE_BUFFER = 0x0002 ,
+ FJES_CMD_REQ_UNSHARE_BUFFER = 0x0004 ,
+ };
+
/* parameter for command control */
struct fjes_device_command_param {
u32 req_len ; @@ -132,6 +146,15 @@ struct fjes_device_command_param {
phys_addr_t share_start ;
};
+ /* error code for command control */
+ enum fjes_dev_command_response_e {
+ FJES_CMD_STATUS_UNKNOWN ,
+ FJES_CMD_STATUS_NORMAL ,
+ FJES_CMD_STATUS_TIMEOUT ,
+ FJES_CMD_STATUS_ERROR_PARAM ,
+ FJES_CMD_STATUS_ERROR_STATUS ,
+ };
+
/* EP buffer information */
union ep_buffer_info {
u8 raw [ EP_BUFFER_INFO_SIZE ]; @@ -242,6 +265,7 @@ struct fjes_hw {
int fjes_hw_init ( struct fjes_hw * );
void fjes_hw_exit ( struct fjes_hw * );
int fjes_hw_reset ( struct fjes_hw * );
+ int fjes_hw_request_info ( struct fjes_hw * );
void fjes_hw_init_command_registers ( struct fjes_hw * ,
struct fjes_device_command_param * ); diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h
index 4d0e071..cc975a0 100644
--- a/drivers/net/fjes/fjes_regs.h
+++ b/drivers/net/fjes/fjes_regs.h @@ -35,6 +35,8 @@
#define XSCT_DCTL 0x0010 /* Device Control */
/* Command Control registers */
+ #define XSCT_CR 0x0020 /* Command request */
+ #define XSCT_CS 0x0024 /* Command status */
#define XSCT_SHSTSAL 0x0028 /* Share status address Low */
#define XSCT_SHSTSAH 0x002C /* Share status address High */
@@ -78,6 +80,27 @@ union REG_DCTL {
__le32 reg ;
};
+ /* Command Control registers */
+ union REG_CR {
+ struct {
+ __le32 req_code : 16 ;
+ __le32 err_info : 14 ;
+ __le32 error : 1 ;
+ __le32 req_start : 1 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ union REG_CS {
+ struct {
+ __le32 req_code : 16 ;
+ __le32 rsv0 : 14 ;
+ __le32 busy : 1 ;
+ __le32 complete : 1 ;
+ } bits ;
+ __le32 reg ;
+ };
+
enum REG_ICTL_MASK {
REG_ICTL_MASK_INFO_UPDATE = 1 << 20 ,
REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19 , --
1.8.3.1
This patch adds buffer address regist/unregistration routine.
This function is mainly invoked when network device's
activation (open) and deactivation (close)
in order to retist/unregist shared buffer address.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 9 ++-
2 files changed, 195 insertions(+), 1 deletion(-)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 1ffa62e..4451e70 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -453,6 +453,193 @@ int fjes_hw_request_info(struct fjes_hw *hw)
return result ;
}
+ int fjes_hw_register_buff_addr ( struct fjes_hw * hw , int dest_epid ,
+ struct ep_share_mem_info * buf_pair )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ enum fjes_dev_command_response_e ret ;
+ int i , idx ;
+ int page_count ;
+ void * addr ;
+ int timeout ;
+ int result ;
+
+ if ( test_bit ( dest_epid , & hw -> hw_info . buffer_share_bit ))
+ return 0 ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> share_buffer . length =
+ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( buf_pair -> tx . size ,
+ buf_pair -> rx . size );
+ req_buf -> share_buffer . epid = dest_epid ;
+
+ idx = 0 ;
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> tx . size ;
+ page_count = buf_pair -> tx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> tx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> rx . size ;
+ page_count = buf_pair -> rx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> rx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+
+ res_buf -> share_buffer . length = 0 ;
+ res_buf -> share_buffer . code = 0 ;
+
+ ret = fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_SHARE_BUFFER );
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000 ;
+ while (( ret == FJES_CMD_STATUS_NORMAL ) &&
+ ( res_buf -> share_buffer . length ==
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN ) &&
+ ( res_buf -> share_buffer . code == FJES_CMD_REQ_RES_CODE_BUSY ) &&
+ ( timeout > 0 )) {
+ msleep ( 200 + hw -> my_epid * 20 );
+ timeout -= ( 200 + hw -> my_epid * 20 );
+
+ res_buf -> share_buffer . length = 0 ;
+ res_buf -> share_buffer . code = 0 ;
+
+ ret =
+ fjes_hw_issue_request_command ( hw ,
+ FJES_CMD_REQ_SHARE_BUFFER );
+ }
+
+ result = 0 ;
+
+ if ( res_buf -> share_buffer . length !=
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN )
+ result = - ENOMSG ;
+ else if ( ret == FJES_CMD_STATUS_NORMAL ) {
+ switch ( res_buf -> share_buffer . code ) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL :
+ result = 0 ;
+ set_bit ( dest_epid , & hw -> hw_info . buffer_share_bit );
+ break ;
+ case FJES_CMD_REQ_RES_CODE_BUSY :
+ result = - EBUSY ;
+ break ;
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ } else {
+ switch ( ret ) {
+ case FJES_CMD_STATUS_UNKNOWN :
+ result = - EPERM ;
+ break ;
+ case FJES_CMD_STATUS_TIMEOUT :
+ result = - EBUSY ;
+ break ;
+ case FJES_CMD_STATUS_ERROR_PARAM :
+ case FJES_CMD_STATUS_ERROR_STATUS :
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ }
+
+ return result ;
+ }
+
+ int fjes_hw_unregister_buff_addr ( struct fjes_hw * hw , int dest_epid )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ struct fjes_device_shared_info * share = hw -> hw_info . share ;
+ enum fjes_dev_command_response_e ret ;
+ int result ;
+ int timeout ;
+
+ if ( ! hw -> base )
+ return - EPERM ;
+
+ if ( ! req_buf || ! res_buf || ! share )
+ return - EPERM ;
+
+ if ( ! test_bit ( dest_epid , & hw -> hw_info . buffer_share_bit ))
+ return 0 ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> unshare_buffer . length =
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN ;
+ req_buf -> unshare_buffer . epid = dest_epid ;
+
+ res_buf -> unshare_buffer . length = 0 ;
+ res_buf -> unshare_buffer . code = 0 ;
+
+ ret = fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_UNSHARE_BUFFER );
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000 ;
+ while (( ret == FJES_CMD_STATUS_NORMAL ) &&
+ ( res_buf -> unshare_buffer . length ==
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN ) &&
+ ( res_buf -> unshare_buffer . code ==
+ FJES_CMD_REQ_RES_CODE_BUSY ) &&
+ ( timeout > 0 )) {
+ msleep ( 200 + hw -> my_epid * 20 );
+ timeout -= ( 200 + hw -> my_epid * 20 );
+
+ res_buf -> unshare_buffer . length = 0 ;
+ res_buf -> unshare_buffer . code = 0 ;
+
+ ret =
+ fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_UNSHARE_BUFFER );
+ }
+
+ result = 0 ;
+
+ if ( res_buf -> unshare_buffer . length !=
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN ) {
+ result = - ENOMSG ;
+ } else if ( ret == FJES_CMD_STATUS_NORMAL ) {
+ switch ( res_buf -> unshare_buffer . code ) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL :
+ result = 0 ;
+ clear_bit ( dest_epid , & hw -> hw_info . buffer_share_bit );
+ break ;
+ case FJES_CMD_REQ_RES_CODE_BUSY :
+ result = - EBUSY ;
+ break ;
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ } else {
+ switch ( ret ) {
+ case FJES_CMD_STATUS_UNKNOWN :
+ result = - EPERM ;
+ break ;
+ case FJES_CMD_STATUS_TIMEOUT :
+ result = - EBUSY ;
+ break ;
+ case FJES_CMD_STATUS_ERROR_PARAM :
+ case FJES_CMD_STATUS_ERROR_STATUS :
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ }
+
+ return result ;
+ }
+
void fjes_hw_set_irqmask ( struct fjes_hw * hw ,
enum REG_ICTL_MASK intr_mask , bool mask )
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 2ee166a..d1321e8 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -34,11 +34,13 @@ struct fjes_hw;
#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
+ #define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */
#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002)
#define FJES_CMD_REQ_RES_CODE_NORMAL (0)
+ #define FJES_CMD_REQ_RES_CODE_BUSY (1)
#define EP_BUFFER_SIZE \
((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \ @@ -59,6 +61,9 @@ struct fjes_hw;
#define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
#define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE )))
+ #define FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN (8)
#define FJES_DEV_REQ_BUF_SIZE(maxep) \
FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( EP_BUFFER_SIZE , EP_BUFFER_SIZE ) @@ -266,7 +271,9 @@ int fjes_hw_init(struct fjes_hw *);
void fjes_hw_exit ( struct fjes_hw * );
int fjes_hw_reset ( struct fjes_hw * );
int fjes_hw_request_info ( struct fjes_hw * );
-
+ int fjes_hw_register_buff_addr ( struct fjes_hw * , int ,
+ struct ep_share_mem_info * );
+ int fjes_hw_unregister_buff_addr ( struct fjes_hw * , int );
void fjes_hw_init_command_registers ( struct fjes_hw * ,
struct fjes_device_command_param * );
void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 ); --
1.8.3.1
This patch adds tx_stall_task.
When receiver's buffer is full, sender stops
its tx queue. This task is used to monitor
receiver's status and when receiver's buffer
is avairable, it resumes tx queue.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 2 ++
drivers/net/fjes/fjes_main.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 8e9899e..b04ea9d 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -30,6 +30,7 @@
#define FJES_MAX_QUEUES 1
#define FJES_TX_RETRY_INTERVAL (20 * HZ)
#define FJES_TX_RETRY_TIMEOUT (100)
+ #define FJES_TX_TX_STALL_TIMEOUT (FJES_TX_RETRY_INTERVAL / 2)
#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
/* board specific private data structure */ @@ -52,6 +53,7 @@ struct fjes_adapter {
struct workqueue_struct * txrx_wq ;
+ struct work_struct tx_stall_task ;
struct work_struct raise_intr_rxdata_task ;
struct fjes_hw hw ; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 735aa5e..f4c2445 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -53,6 +53,7 @@ static int fjes_setup_resources(struct fjes_adapter *);
static void fjes_free_resources ( struct fjes_adapter * );
static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
static void fjes_raise_intr_rxdata_task ( struct work_struct * );
+ static void fjes_tx_stall_task ( struct work_struct * );
static irqreturn_t fjes_intr ( int , void * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -281,6 +282,7 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
+ cancel_work_sync ( & adapter -> tx_stall_task );
fjes_hw_wait_epstop ( hw );
@@ -410,6 +412,61 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
}
}
+ static void fjes_tx_stall_task ( struct work_struct * work )
+ {
+ struct fjes_adapter * adapter = container_of ( work ,
+ struct fjes_adapter , tx_stall_task );
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+ enum ep_partner_status pstatus ;
+ int epid ;
+ int max_epid , my_epid ;
+ union ep_buffer_info * info ;
+ int all_queue_available ;
+ int i ;
+ int sendable ;
+
+ if ((( long ) jiffies -
+ ( long )( netdev -> trans_start )) > FJES_TX_TX_STALL_TIMEOUT ) {
+ 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 ;
+
+ 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 );
+ }
+
static void fjes_raise_intr_rxdata_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( work , @@ -606,6 +663,10 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
netdev -> trans_start = jiffies ;
netif_tx_stop_queue ( cur_queue );
+ if ( ! work_pending ( & adapter -> tx_stall_task ))
+ queue_work ( adapter -> txrx_wq ,
+ & adapter -> tx_stall_task );
+
ret = NETDEV_TX_BUSY ;
}
} else { @@ -690,6 +751,7 @@ static int fjes_probe(struct platform_device *plat_dev)
adapter -> txrx_wq = create_workqueue ( DRV_NAME "/txrx" );
+ INIT_WORK ( & adapter -> tx_stall_task , fjes_tx_stall_task );
INIT_WORK ( & adapter -> raise_intr_rxdata_task ,
fjes_raise_intr_rxdata_task );
@@ -734,6 +796,7 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_hw * hw = & adapter -> hw ;
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
+ cancel_work_sync ( & adapter -> tx_stall_task );
if ( adapter -> txrx_wq )
destroy_workqueue ( adapter -> txrx_wq );
--
1.8.3.1
This patch adds net_device_ops.ndo_get_stats64 callback.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_main.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 2e7b382..0aa289d 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -55,6 +55,8 @@ static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *);
static void fjes_raise_intr_rxdata_task ( struct work_struct * );
static void fjes_tx_stall_task ( struct work_struct * );
static irqreturn_t fjes_intr ( int , void * );
+ static struct rtnl_link_stats64 *
+ fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * );
static int fjes_acpi_add ( struct acpi_device * );
static int fjes_acpi_remove ( struct acpi_device * ); @@ -222,6 +224,7 @@ static const struct net_device_ops fjes_netdev_ops = {
. ndo_open = fjes_open ,
. ndo_stop = fjes_close ,
. ndo_start_xmit = fjes_xmit_frame ,
+ . ndo_get_stats64 = fjes_get_stats64 ,
};
/* fjes_open - Called when a network interface is made active */ @@ -706,6 +709,16 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return ret ;
}
+ static struct rtnl_link_stats64 *
+ 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 ));
+
+ return stats ;
+ }
+
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ; --
1.8.3.1
This patch adds net_device_ops.ndo_tx_timeout callback.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_main.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 47e5b2f..e2e69e0 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -58,6 +58,7 @@ static irqreturn_t fjes_intr(int, void*);
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * );
static int fjes_change_mtu ( struct net_device * , int );
+ static void fjes_tx_retry ( struct net_device * );
static int fjes_acpi_add ( struct acpi_device * );
static int fjes_acpi_remove ( struct acpi_device * ); @@ -227,6 +228,7 @@ static const struct net_device_ops fjes_netdev_ops = {
. ndo_start_xmit = fjes_xmit_frame ,
. ndo_get_stats64 = fjes_get_stats64 ,
. ndo_change_mtu = fjes_change_mtu ,
+ . ndo_tx_timeout = fjes_tx_retry ,
};
/* fjes_open - Called when a network interface is made active */ @@ -711,6 +713,13 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return ret ;
}
+ static void fjes_tx_retry ( struct net_device * netdev )
+ {
+ struct netdev_queue * queue = netdev_get_tx_queue ( netdev , 0 );
+
+ netif_tx_wake_queue ( queue );
+ }
+
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * netdev , struct rtnl_link_stats64 * stats )
{ --
1.8.3.1
This patch adds net_device_ops.ndo_vlan_rx_add_vid and
net_device_ops.ndo_vlan_rx_kill_vid callback.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 27 +++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 2 ++
drivers/net/fjes/fjes_main.c | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 5e3f847..8363e22 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -827,6 +827,33 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)
return ret ;
}
+ bool fjes_hw_set_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ ) {
+ if ( info -> v1i . vlan_id [ i ] == 0 ) {
+ info -> v1i . vlan_id [ i ] = vlan_id ;
+ return true ;
+ }
+ }
+ return false ;
+ }
+
+ void fjes_hw_del_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+
+ if ( 0 != vlan_id ) {
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ ) {
+ if ( vlan_id == info -> v1i . vlan_id [ i ])
+ info -> v1i . vlan_id [ i ] = 0 ;
+ }
+ }
+ }
+
bool fjes_hw_epbuf_rx_is_empty ( struct epbuf_handler * epbh )
{
union ep_buffer_info * info = epbh -> info ; diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index ea30aeb..afad03e 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -321,6 +321,8 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int);
bool fjes_hw_check_epbuf_version ( struct epbuf_handler * , u32 );
bool fjes_hw_check_mtu ( struct epbuf_handler * , u32 );
bool fjes_hw_check_vlan_id ( struct epbuf_handler * , u16 );
+ bool fjes_hw_set_vlan_id ( struct epbuf_handler * , u16 );
+ void fjes_hw_del_vlan_id ( struct epbuf_handler * , u16 );
bool fjes_hw_epbuf_rx_is_empty ( struct epbuf_handler * );
void * fjes_hw_epbuf_rx_curpkt_get_addr ( struct epbuf_handler * , size_t * );
void fjes_hw_epbuf_rx_curpkt_drop ( struct epbuf_handler * ); diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index e2e69e0..bb4c8e4 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -58,6 +58,8 @@ static irqreturn_t fjes_intr(int, void*);
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * );
static int fjes_change_mtu ( struct net_device * , int );
+ 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 );
static void fjes_tx_retry ( struct net_device * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -229,6 +231,8 @@ static const struct net_device_ops fjes_netdev_ops = {
. ndo_get_stats64 = fjes_get_stats64 ,
. ndo_change_mtu = fjes_change_mtu ,
. ndo_tx_timeout = fjes_tx_retry ,
+ . ndo_vlan_rx_add_vid = fjes_vlan_rx_add_vid ,
+ . ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid ,
};
/* fjes_open - Called when a network interface is made active */ @@ -757,6 +761,42 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
return - EINVAL ;
}
+ 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 ;
+ }
+
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ; --
1.8.3.1
This patch adds interrupt_watch_task.
This task is used to prevent delay of interrupts.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 5 +++++
drivers/net/fjes/fjes_main.c | 40 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index b04ea9d..1743dbb 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -32,6 +32,7 @@
#define FJES_TX_RETRY_TIMEOUT (100)
#define FJES_TX_TX_STALL_TIMEOUT (FJES_TX_RETRY_INTERVAL / 2)
#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
+ #define FJES_IRQ_WATCH_DELAY (HZ)
/* board specific private data structure */
struct fjes_adapter { @@ -52,10 +53,14 @@ struct fjes_adapter {
bool irq_registered ;
struct workqueue_struct * txrx_wq ;
+ struct workqueue_struct * control_wq ;
struct work_struct tx_stall_task ;
struct work_struct raise_intr_rxdata_task ;
+ struct delayed_work interrupt_watch_task ;
+ bool interrupt_watch_enable ;
+
struct fjes_hw hw ;
};
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index bb4c8e4..5c93c4e 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -71,7 +71,7 @@ static int fjes_remove(struct platform_device *);
static int fjes_sw_init ( struct fjes_adapter * );
static void fjes_netdev_setup ( struct net_device * );
-
+ static void fjes_irq_watch_task ( struct work_struct * );
static void fjes_rx_irq ( struct fjes_adapter * , int );
static int fjes_poll ( struct napi_struct * , int );
@@ -199,6 +199,13 @@ static int fjes_request_irq(struct fjes_adapter *adapter)
struct net_device * netdev = adapter -> netdev ;
int result = -1 ;
+ 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 );
+ }
+
if ( ! adapter -> irq_registered ) {
result =
request_irq ( adapter -> hw . hw_res . irq , fjes_intr , @@ -216,6 +223,9 @@ static void fjes_free_irq(struct fjes_adapter *adapter)
{
struct fjes_hw * hw = & adapter -> hw ;
+ adapter -> interrupt_watch_enable = false ;
+ cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
+
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , true );
if ( adapter -> irq_registered ) { @@ -300,6 +310,7 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
+ cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
@@ -1003,11 +1014,15 @@ static int fjes_probe(struct platform_device *plat_dev)
adapter -> open_guard = false ;
adapter -> txrx_wq = create_workqueue ( DRV_NAME "/txrx" );
+ adapter -> control_wq = create_workqueue ( DRV_NAME "/control" );
INIT_WORK ( & adapter -> tx_stall_task , fjes_tx_stall_task );
INIT_WORK ( & adapter -> raise_intr_rxdata_task ,
fjes_raise_intr_rxdata_task );
+ INIT_DELAYED_WORK ( & adapter -> interrupt_watch_task , fjes_irq_watch_task );
+ adapter -> interrupt_watch_enable = false ;
+
res = platform_get_resource ( plat_dev , IORESOURCE_MEM , 0 );
hw -> hw_res . start = res -> start ;
hw -> hw_res . size = res -> end - res -> start + 1 ; @@ -1048,8 +1063,11 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_adapter * adapter = netdev_priv ( netdev );
struct fjes_hw * hw = & adapter -> hw ;
+ cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
+ if ( adapter -> control_wq )
+ destroy_workqueue ( adapter -> control_wq );
if ( adapter -> txrx_wq )
destroy_workqueue ( adapter -> txrx_wq );
@@ -1085,6 +1103,26 @@ static void fjes_netdev_setup(struct net_device *netdev)
netdev -> features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER ;
}
+ 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 );
+ }
+ }
+
/* fjes_init_module - Driver Registration Routine */
static int __init fjes_init_module ( void )
{ --
1.8.3.1
This patch adds unshare_watch_task.
Shared buffer's status can be changed into unshared.
This task is used to monitor shared buffer's status.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 3 +
drivers/net/fjes/fjes_main.c | 130 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index d31d4c3..57feee8 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -59,6 +59,9 @@ struct fjes_adapter {
struct work_struct tx_stall_task ;
struct work_struct raise_intr_rxdata_task ;
+ struct work_struct unshare_watch_task ;
+ unsigned long unshare_watch_bitmask ;
+
struct delayed_work interrupt_watch_task ;
bool interrupt_watch_enable ;
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 1ddb9d3..69a238c 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -73,6 +73,7 @@ static int fjes_remove(struct platform_device *);
static int fjes_sw_init ( struct fjes_adapter * );
static void fjes_netdev_setup ( struct net_device * );
static void fjes_irq_watch_task ( struct work_struct * );
+ static void fjes_watch_unshare_task ( struct work_struct * );
static void fjes_rx_irq ( struct fjes_adapter * , int );
static int fjes_poll ( struct napi_struct * , int );
@@ -312,6 +313,8 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
+ cancel_work_sync ( & adapter -> unshare_watch_task );
+ adapter -> unshare_watch_bitmask = 0 ;
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
@@ -1032,6 +1035,8 @@ static int fjes_probe(struct platform_device *plat_dev)
INIT_WORK ( & adapter -> tx_stall_task , fjes_tx_stall_task );
INIT_WORK ( & adapter -> raise_intr_rxdata_task ,
fjes_raise_intr_rxdata_task );
+ INIT_WORK ( & adapter -> unshare_watch_task , fjes_watch_unshare_task );
+ adapter -> unshare_watch_bitmask = 0 ;
INIT_DELAYED_WORK ( & adapter -> interrupt_watch_task , fjes_irq_watch_task );
adapter -> interrupt_watch_enable = false ; @@ -1077,6 +1082,7 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_hw * hw = & adapter -> hw ;
cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
+ cancel_work_sync ( & adapter -> unshare_watch_task );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
if ( adapter -> control_wq ) @@ -1136,6 +1142,130 @@ static void fjes_irq_watch_task(struct work_struct *work)
}
}
+ static void fjes_watch_unshare_task ( struct work_struct * work )
+ {
+ struct fjes_adapter * adapter =
+ container_of ( work , struct fjes_adapter , unshare_watch_task );
+
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+ int epidx ;
+ int max_epid , my_epid ;
+ unsigned long unshare_watch_bitmask ;
+ int wait_time = 0 ;
+ int is_shared ;
+ int stop_req , stop_req_done ;
+ int unshare_watch , unshare_reserve ;
+ 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 );
+
+ fjes_hw_setup_epbuf ( & hw -> ep_shm_info [ epidx ]. tx ,
+ netdev -> dev_addr , netdev -> mtu );
+
+ 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 );
+
+ fjes_hw_setup_epbuf (
+ & hw -> ep_shm_info [ epidx ]. tx ,
+ netdev -> dev_addr , netdev -> mtu );
+
+ 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 )) {
+ hw -> ep_shm_info [ epidx ]. tx . info -> v1i . rx_status &=
+ ~ FJES_RX_STOP_REQ_DONE ;
+ }
+ }
+ }
+ }
+
/* fjes_init_module - Driver Registration Routine */
static int __init fjes_init_module ( void )
{ --
1.8.3.1
This patch adds update_zone_task.
Zoning information can be changed by user.
This task is used to monitor if zoning information is
changed or not.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 171 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 1 +
drivers/net/fjes/fjes_main.c | 14 ++++
3 files changed, 186 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 8363e22..8756d3e 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -22,6 +22,8 @@
#include "fjes_hw.h"
#include "fjes.h"
+ static void fjes_hw_update_zone_task ( struct work_struct * );
+
/* supported MTU list */
const u32 fjes_support_mtu [] = {
FJES_MTU_DEFINE ( 8 * 1024 ), @@ -323,6 +325,8 @@ int fjes_hw_init(struct fjes_hw *hw)
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , true );
+ INIT_WORK ( & hw -> update_zone_task , fjes_hw_update_zone_task );
+
mutex_init ( & hw -> hw_info . lock );
hw -> max_epid = fjes_hw_get_max_epid ( hw ); @@ -350,6 +354,8 @@ void fjes_hw_exit(struct fjes_hw *hw)
}
fjes_hw_cleanup ( hw );
+
+ cancel_work_sync ( & hw -> update_zone_task );
}
static enum fjes_dev_command_response_e @@ -919,3 +925,168 @@ int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh,
return 0 ;
}
+ static void fjes_hw_update_zone_task ( struct work_struct * work )
+ {
+ struct fjes_hw * hw = container_of ( work ,
+ struct fjes_hw , update_zone_task );
+ struct fjes_adapter * adapter = ( struct fjes_adapter * ) hw -> back ;
+ struct net_device * netdev = adapter -> netdev ;
+ int ret ;
+ int epidx ;
+ enum ep_partner_status pstatus ;
+ unsigned long share_bit = 0 ;
+ unsigned long unshare_bit = 0 ;
+ unsigned long irq_bit = 0 ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ struct my_s { u8 es_status ; u8 zone ; } * info =
+ ( struct my_s * ) & res_buf -> info . info ;
+
+ mutex_lock ( & hw -> hw_info . lock );
+
+ ret = fjes_hw_request_info ( hw );
+ switch ( ret ) {
+ case - ENOMSG :
+ case - EBUSY :
+ default :
+ if ( ! work_pending ( & adapter -> force_close_task )) {
+ adapter -> force_reset = true ;
+ schedule_work ( & adapter -> force_close_task );
+ }
+ break ;
+
+ case 0 :
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid ) {
+ hw -> ep_shm_info [ epidx ]. es_status =
+ info [ epidx ]. es_status ;
+ hw -> ep_shm_info [ epidx ]. zone =
+ info [ epidx ]. zone ;
+ continue ;
+ }
+
+ pstatus = fjes_hw_get_partner_ep_status ( hw , epidx );
+ switch ( pstatus ) {
+ case EP_PARTNER_UNSHARE :
+ default :
+ if (( info [ epidx ]. zone !=
+ FJES_ZONING_ZONE_TYPE_NONE ) &&
+ ( info [ epidx ]. es_status ==
+ FJES_ZONING_STATUS_ENABLE ) &&
+ ( info [ epidx ]. zone ==
+ info [ hw -> my_epid ]. zone ))
+ set_bit ( epidx , & share_bit );
+ else
+ set_bit ( epidx , & unshare_bit );
+ break ;
+
+ case EP_PARTNER_COMPLETE :
+ case EP_PARTNER_WAITING :
+ if (( info [ epidx ]. zone ==
+ FJES_ZONING_ZONE_TYPE_NONE ) ||
+ ( info [ epidx ]. es_status !=
+ FJES_ZONING_STATUS_ENABLE ) ||
+ ( info [ epidx ]. zone !=
+ info [ hw -> my_epid ]. zone )) {
+ set_bit ( epidx ,
+ & adapter -> unshare_watch_bitmask );
+ set_bit ( epidx ,
+ & hw -> hw_info . buffer_unshare_reserve_bit );
+ }
+ break ;
+
+ case EP_PARTNER_SHARED :
+ if (( info [ epidx ]. zone ==
+ FJES_ZONING_ZONE_TYPE_NONE ) ||
+ ( info [ epidx ]. es_status !=
+ FJES_ZONING_STATUS_ENABLE ) ||
+ ( info [ epidx ]. zone !=
+ info [ hw -> my_epid ]. zone ))
+ set_bit ( epidx , & irq_bit );
+ break ;
+ }
+ }
+
+ hw -> ep_shm_info [ epidx ]. es_status = info [ epidx ]. es_status ;
+ hw -> ep_shm_info [ epidx ]. zone = info [ epidx ]. zone ;
+
+ break ;
+ }
+
+ mutex_unlock ( & hw -> hw_info . lock );
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+
+ if ( test_bit ( epidx , & share_bit )) {
+ fjes_hw_setup_epbuf ( & hw -> ep_shm_info [ epidx ]. tx ,
+ netdev -> dev_addr , netdev -> mtu );
+
+ mutex_lock ( & hw -> hw_info . lock );
+
+ ret = fjes_hw_register_buff_addr (
+ hw , epidx , & hw -> ep_shm_info [ 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 );
+ }
+
+ if ( test_bit ( epidx , & unshare_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 );
+
+ if ( ret == 0 )
+ fjes_hw_setup_epbuf (
+ & hw -> ep_shm_info [ epidx ]. tx ,
+ netdev -> dev_addr , netdev -> mtu );
+ }
+
+ if ( test_bit ( epidx , & irq_bit )) {
+ fjes_hw_raise_interrupt ( hw , epidx ,
+ REG_ICTL_MASK_TXRX_STOP_REQ );
+
+ set_bit ( epidx , & hw -> txrx_stop_req_bit );
+ hw -> ep_shm_info [ epidx ]. tx .
+ info -> v1i . rx_status |=
+ FJES_RX_STOP_REQ_REQUEST ;
+ set_bit ( epidx , & hw -> hw_info . buffer_unshare_reserve_bit );
+ }
+ }
+
+ if ( irq_bit || adapter -> unshare_watch_bitmask ) {
+ if ( ! work_pending ( & adapter -> unshare_watch_task ))
+ queue_work ( adapter -> control_wq ,
+ & adapter -> unshare_watch_task );
+ }
+ }
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index afad03e..d80b8c8 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -281,6 +281,7 @@ struct fjes_hw {
unsigned long txrx_stop_req_bit ;
unsigned long epstop_req_bit ;
+ struct work_struct update_zone_task ;
int my_epid ;
int max_epid ; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 69a238c..b37e909 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -318,6 +318,8 @@ static int fjes_close(struct net_device *netdev)
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
+ cancel_work_sync ( & hw -> update_zone_task );
+
fjes_hw_wait_epstop ( hw );
fjes_free_resources ( adapter ); @@ -823,6 +825,15 @@ static int fjes_vlan_rx_kill_vid(struct net_device *netdev,
return 0 ;
}
+ 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 );
+ }
+
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ; @@ -836,6 +847,9 @@ static irqreturn_t fjes_intr(int irq, void *data)
if ( icr & REG_ICTL_MASK_RX_DATA )
fjes_rx_irq ( adapter , icr & REG_IS_MASK_EPID );
+ if ( icr & REG_ICTL_MASK_INFO_UPDATE )
+ fjes_update_zone_irq ( adapter , icr & REG_IS_MASK_EPID );
+
ret = IRQ_HANDLED ;
} else {
ret = IRQ_NONE ; --
1.8.3.1
This patch adds implementation for ethtool support.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/Makefile | 2 +-
drivers/net/fjes/fjes.h | 2 +
drivers/net/fjes/fjes_ethtool.c | 135 ++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_main.c | 1 +
4 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/fjes/fjes_ethtool.c
diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile
index a67f65d8..8ca4de0 100644
--- a/drivers/net/fjes/Makefile
+++ b/drivers/net/fjes/Makefile @@ -27,5 +27,5 @@
obj-$(CONFIG_FUJITSU_ES) += fjes.o
- fjes-objs := fjes_main.o fjes_hw.o
+ fjes-objs := fjes_main.o fjes_hw.o fjes_ethtool.o
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 57feee8..a592fe2 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -72,4 +72,6 @@ extern char fjes_driver_name[];
extern char fjes_driver_version [];
extern const u32 fjes_support_mtu [];
+ void fjes_set_ethtool_ops ( struct net_device * );
+
#endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_ethtool.c b/drivers/net/fjes/fjes_ethtool.c
new file mode 100644
index 0000000..c69be42
--- /dev/null
+++ b/drivers/net/fjes/fjes_ethtool.c @@ -0,0 +1,135 @@
+ /*
+ * 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" .
+ *
+ */
+
+ /* ethtool support for fjes */
+
+ #include <linux/vmalloc.h>
+ #include <linux/netdevice.h>
+ #include <linux/ethtool.h>
+ #include <linux/platform_device.h>
+
+ #include "fjes.h"
+
+ struct fjes_stats {
+ char stat_string [ ETH_GSTRING_LEN ];
+ int sizeof_stat ;
+ int stat_offset ;
+ };
+
+ #define FJES_STAT(name, stat) { \
+ . stat_string = name , \
+ . sizeof_stat = FIELD_SIZEOF ( struct fjes_adapter , stat ), \
+ . stat_offset = offsetof ( struct fjes_adapter , stat ) \
+ }
+
+ static const struct fjes_stats fjes_gstrings_stats [] = {
+ FJES_STAT ( "rx_packets" , stats64 . rx_packets ),
+ FJES_STAT ( "tx_packets" , stats64 . tx_packets ),
+ FJES_STAT ( "rx_bytes" , stats64 . rx_bytes ),
+ FJES_STAT ( "tx_bytes" , stats64 . rx_bytes ),
+ FJES_STAT ( "rx_dropped" , stats64 . rx_dropped ),
+ FJES_STAT ( "tx_dropped" , stats64 . tx_dropped ),
+ };
+
+ static void fjes_get_ethtool_stats ( struct net_device * netdev ,
+ struct ethtool_stats * stats , u64 * data )
+ {
+ struct fjes_adapter * adapter = netdev_priv ( netdev );
+ int i ;
+ char * p ;
+
+ for ( i = 0 ; i < ARRAY_SIZE ( fjes_gstrings_stats ); i ++ ) {
+ p = ( char * ) adapter + fjes_gstrings_stats [ i ]. stat_offset ;
+ data [ i ] = ( fjes_gstrings_stats [ i ]. sizeof_stat == sizeof ( u64 ))
+ ? * ( u64 * ) p : * ( u32 * ) p ;
+ }
+ }
+
+ static void fjes_get_strings ( struct net_device * netdev ,
+ u32 stringset , u8 * data )
+ {
+ u8 * p = data ;
+ int i ;
+
+ switch ( stringset ) {
+ case ETH_SS_STATS :
+ for ( i = 0 ; i < ARRAY_SIZE ( fjes_gstrings_stats ); i ++ ) {
+ memcpy ( p , fjes_gstrings_stats [ i ]. stat_string ,
+ ETH_GSTRING_LEN );
+ p += ETH_GSTRING_LEN ;
+ }
+ break ;
+ }
+ }
+
+ static int fjes_get_sset_count ( struct net_device * netdev , int sset )
+ {
+ switch ( sset ) {
+ case ETH_SS_STATS :
+ return ARRAY_SIZE ( fjes_gstrings_stats );
+ default :
+ return - EOPNOTSUPP ;
+ }
+ }
+
+ static void fjes_get_drvinfo ( struct net_device * netdev ,
+ struct ethtool_drvinfo * drvinfo )
+ {
+ struct fjes_adapter * adapter = netdev_priv ( netdev );
+ struct platform_device * plat_dev = adapter -> plat_dev ;
+
+ strlcpy ( drvinfo -> driver , fjes_driver_name , sizeof ( drvinfo -> driver ));
+ strlcpy ( drvinfo -> version , fjes_driver_version ,
+ sizeof ( drvinfo -> version ));
+
+ strlcpy ( drvinfo -> fw_version , "none" , sizeof ( drvinfo -> fw_version ));
+ snprintf ( drvinfo -> bus_info , sizeof ( drvinfo -> bus_info ),
+ "platform:%s" , plat_dev -> name );
+ drvinfo -> regdump_len = 0 ;
+ drvinfo -> eedump_len = 0 ;
+ }
+
+ static int fjes_get_settings ( struct net_device * netdev ,
+ struct ethtool_cmd * ecmd )
+ {
+ ecmd -> supported = 0 ;
+ ecmd -> advertising = 0 ;
+ ecmd -> duplex = DUPLEX_FULL ;
+ ecmd -> autoneg = AUTONEG_DISABLE ;
+ ecmd -> transceiver = XCVR_DUMMY1 ;
+ ecmd -> port = PORT_NONE ;
+ ethtool_cmd_speed_set ( ecmd , 20000 ); /* 20Gb/s */
+
+ return 0 ;
+ }
+
+ static const struct ethtool_ops fjes_ethtool_ops = {
+ . get_settings = fjes_get_settings ,
+ . get_drvinfo = fjes_get_drvinfo ,
+ . get_ethtool_stats = fjes_get_ethtool_stats ,
+ . get_strings = fjes_get_strings ,
+ . get_sset_count = fjes_get_sset_count ,
+ };
+
+ void fjes_set_ethtool_ops ( struct net_device * netdev )
+ {
+ netdev -> ethtool_ops = & fjes_ethtool_ops ;
+ } diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 1db1a7d..f61ce3b 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -1211,6 +1211,7 @@ static void fjes_netdev_setup(struct net_device *netdev)
netdev -> watchdog_timeo = FJES_TX_RETRY_INTERVAL ;
netdev -> netdev_ops = & fjes_netdev_ops ;
+ fjes_set_ethtool_ops ( netdev );
netdev -> mtu = fjes_support_mtu [ 0 ];
netdev -> flags |= IFF_BROADCAST ;
netdev -> features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER ; --
1.8.3.1
This patch adds hardware initialization routine to be
invoked at driver's .probe routine.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/Makefile | 2 +-
drivers/net/fjes/fjes.h | 2 +-
drivers/net/fjes/fjes_hw.c | 297 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 250 ++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 102 +++++++++++++++
5 files changed, 651 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/fjes/fjes_hw.c
create mode 100644 drivers/net/fjes/fjes_hw.h
create mode 100644 drivers/net/fjes/fjes_regs.h
diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile
index 98e59cb..a67f65d8 100644
--- a/drivers/net/fjes/Makefile
+++ b/drivers/net/fjes/Makefile @@ -27,5 +27,5 @@
obj-$(CONFIG_FUJITSU_ES) += fjes.o
- fjes-objs := fjes_main.o
+ fjes-objs := fjes_main.o fjes_hw.o
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 4622da1..15ded96 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -28,6 +28,6 @@
extern char fjes_driver_name [];
extern char fjes_driver_version [];
- extern u32 fjes_support_mtu [];
+ extern const u32 fjes_support_mtu [];
#endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
new file mode 100644
index 0000000..68ef4d3
--- /dev/null
+++ b/drivers/net/fjes/fjes_hw.c @@ -0,0 +1,297 @@
+ /*
+ * 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 "fjes_hw.h"
+ #include "fjes.h"
+
+ /* supported MTU list */
+ const u32 fjes_support_mtu [] = {
+ FJES_MTU_DEFINE ( 8 * 1024 ),
+ FJES_MTU_DEFINE ( 16 * 1024 ),
+ FJES_MTU_DEFINE ( 32 * 1024 ),
+ FJES_MTU_DEFINE ( 64 * 1024 ),
+ 0
+ };
+
+ u32 fjes_hw_rd32 ( struct fjes_hw * hw , u32 reg )
+ {
+ u8 * base = hw -> base ;
+ u32 value = 0 ;
+
+ value = readl ( & base [ reg ]);
+
+ return value ;
+ }
+
+ static u8 * fjes_hw_iomap ( struct fjes_hw * hw )
+ {
+ u8 * base ;
+
+ if ( ! request_mem_region ( hw -> hw_res . start , hw -> hw_res . size ,
+ fjes_driver_name )) {
+ pr_err ( "request_mem_region failed \n " );
+ return NULL ;
+ }
+
+ base = ( u8 * ) ioremap_nocache ( hw -> hw_res . start , hw -> hw_res . size );
+
+ return base ;
+ }
+
+ int fjes_hw_reset ( struct fjes_hw * hw )
+ {
+ int timeout ;
+ union REG_DCTL dctl ;
+
+ dctl . reg = 0 ;
+ dctl . bits . reset = 1 ;
+ wr32 ( XSCT_DCTL , dctl . reg );
+
+ timeout = FJES_DEVICE_RESET_TIMEOUT * 1000 ;
+ dctl . reg = rd32 ( XSCT_DCTL );
+ while (( dctl . bits . reset == 1 ) && ( timeout > 0 )) {
+ msleep ( 1000 );
+ dctl . reg = rd32 ( XSCT_DCTL );
+ timeout -= 1000 ;
+ }
+
+ return timeout > 0 ? 0 : - EIO ;
+ }
+
+ static int fjes_hw_get_max_epid ( struct fjes_hw * hw )
+ {
+ union REG_MAX_EP info ;
+
+ info . reg = rd32 ( XSCT_MAX_EP );
+
+ return info . bits . maxep ;
+ }
+
+ static int fjes_hw_get_my_epid ( struct fjes_hw * hw )
+ {
+ union REG_OWNER_EPID info ;
+
+ info . reg = rd32 ( XSCT_OWNER_EPID );
+
+ return info . bits . epid ;
+ }
+
+ static int fjes_hw_alloc_shared_status_region ( struct fjes_hw * hw )
+ {
+ size_t size ;
+
+ size = sizeof ( struct fjes_device_shared_info ) +
+ ( sizeof ( u8 ) * hw -> max_epid );
+ hw -> hw_info . share = kzalloc ( size , GFP_KERNEL );
+ if ( ! hw -> hw_info . share )
+ return - ENOMEM ;
+
+ hw -> hw_info . share -> epnum = hw -> max_epid ;
+
+ return 0 ;
+ }
+
+ static int fjes_hw_alloc_epbuf ( struct epbuf_handler * epbh )
+ {
+ void * mem ;
+
+ mem = vzalloc ( EP_BUFFER_SIZE );
+ if ( ! mem )
+ return - ENOMEM ;
+
+ epbh -> buffer = mem ;
+ epbh -> size = EP_BUFFER_SIZE ;
+
+ epbh -> info = ( union ep_buffer_info * ) mem ;
+ epbh -> ring = ( u8 * )( mem + sizeof ( union ep_buffer_info ));
+
+ return 0 ;
+ }
+
+ void fjes_hw_setup_epbuf ( struct epbuf_handler * epbh , u8 * mac_addr , u32 mtu )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+ u16 vlan_id [ EP_BUFFER_SUPPORT_VLAN_MAX ];
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ )
+ vlan_id [ i ] = info -> v1i . vlan_id [ i ];
+
+ memset ( info , 0 , sizeof ( union ep_buffer_info ));
+
+ info -> v1i . version = 0 ; /* version 0 */
+
+ for ( i = 0 ; i < ETH_ALEN ; i ++ )
+ info -> v1i . mac_addr [ i ] = mac_addr [ i ];
+
+ info -> v1i . head = 0 ;
+ info -> v1i . tail = 1 ;
+
+ info -> v1i . info_size = sizeof ( union ep_buffer_info );
+ info -> v1i . buffer_size = epbh -> size - info -> v1i . info_size ;
+
+ info -> v1i . frame_max = FJES_MTU_TO_FRAME_SIZE ( mtu );
+ info -> v1i . count_max =
+ EP_RING_NUM ( info -> v1i . buffer_size , info -> v1i . frame_max );
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ )
+ info -> v1i . vlan_id [ i ] = vlan_id [ i ];
+ }
+
+ void
+ fjes_hw_init_command_registers ( struct fjes_hw * hw ,
+ struct fjes_device_command_param * param )
+ {
+ /* Request Buffer length */
+ wr32 ( XSCT_REQBL , ( __le32 )( param -> req_len ));
+ /* Response Buffer Length */
+ wr32 ( XSCT_RESPBL , ( __le32 )( param -> res_len ));
+
+ /* Request Buffer Address */
+ wr32 ( XSCT_REQBAL ,
+ ( __le32 )( param -> req_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_REQBAH ,
+ ( __le32 )(( param -> req_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+
+ /* Response Buffer Address */
+ wr32 ( XSCT_RESPBAL ,
+ ( __le32 )( param -> res_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_RESPBAH ,
+ ( __le32 )(( param -> res_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+
+ /* Share status address */
+ wr32 ( XSCT_SHSTSAL ,
+ ( __le32 )( param -> share_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_SHSTSAH ,
+ ( __le32 )(( param -> share_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+ }
+
+ static int fjes_hw_setup ( struct fjes_hw * hw )
+ {
+ int epidx ;
+ void * buf ;
+ struct ep_share_mem_info * buf_pair ;
+ size_t mem_size ;
+ int result ;
+ u8 mac [ ETH_ALEN ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+ struct fjes_device_command_param param ;
+
+ hw -> hw_info . max_epid = & hw -> max_epid ;
+ hw -> hw_info . my_epid = & hw -> my_epid ;
+
+ buf =
+ kcalloc ( hw -> max_epid ,
+ sizeof ( struct ep_share_mem_info ), GFP_KERNEL );
+ if ( ! buf )
+ return - ENOMEM ;
+
+ hw -> ep_shm_info = ( struct ep_share_mem_info * ) buf ;
+
+ mem_size = FJES_DEV_REQ_BUF_SIZE ( hw -> max_epid );
+ hw -> hw_info . req_buf = kzalloc ( mem_size , GFP_KERNEL );
+ if ( ! ( hw -> hw_info . req_buf ))
+ return - ENOMEM ;
+
+ hw -> hw_info . req_buf_size = mem_size ;
+
+ mem_size = FJES_DEV_RES_BUF_SIZE ( hw -> max_epid );
+ hw -> hw_info . res_buf = kzalloc ( mem_size , GFP_KERNEL );
+ if ( ! ( hw -> hw_info . res_buf ))
+ return - ENOMEM ;
+
+ hw -> hw_info . res_buf_size = mem_size ;
+
+ result = fjes_hw_alloc_shared_status_region ( hw );
+ if ( result )
+ return result ;
+
+ hw -> hw_info . buffer_share_bit = 0 ;
+ hw -> hw_info . buffer_unshare_reserve_bit = 0 ;
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx != hw -> my_epid ) {
+ buf_pair = & hw -> ep_shm_info [ epidx ];
+
+ result = fjes_hw_alloc_epbuf ( & buf_pair -> tx );
+ if ( result )
+ return result ;
+
+ result = fjes_hw_alloc_epbuf ( & buf_pair -> rx );
+ if ( result )
+ return result ;
+
+ fjes_hw_setup_epbuf ( & buf_pair -> tx , mac ,
+ fjes_support_mtu [ 0 ]);
+ fjes_hw_setup_epbuf ( & buf_pair -> rx , mac ,
+ fjes_support_mtu [ 0 ]);
+ }
+ }
+
+ memset ( & 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 );
+
+ return 0 ;
+ }
+
+ int fjes_hw_init ( struct fjes_hw * hw )
+ {
+ int ret ;
+
+ hw -> base = fjes_hw_iomap ( hw );
+ if ( ! hw -> base )
+ return - EIO ;
+
+ ret = fjes_hw_reset ( hw );
+ if ( ret )
+ return ret ;
+
+ fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , true );
+
+ mutex_init ( & hw -> hw_info . lock );
+
+ hw -> max_epid = fjes_hw_get_max_epid ( hw );
+ hw -> my_epid = fjes_hw_get_my_epid ( hw );
+
+ if (( hw -> max_epid == 0 ) || ( hw -> my_epid >= hw -> max_epid ))
+ return - ENXIO ;
+
+ ret = fjes_hw_setup ( hw );
+
+ return ret ;
+ }
+
+ void fjes_hw_set_irqmask ( struct fjes_hw * hw ,
+ enum REG_ICTL_MASK intr_mask , bool mask )
+ {
+ if ( mask )
+ wr32 ( XSCT_IMS , intr_mask );
+ else
+ wr32 ( XSCT_IMC , intr_mask );
+ }
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
new file mode 100644
index 0000000..6c53f8b
--- /dev/null
+++ b/drivers/net/fjes/fjes_hw.h @@ -0,0 +1,250 @@
+ /*
+ * 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" .
+ *
+ */
+
+ #ifndef FJES_HW_H_
+ #define FJES_HW_H_
+
+ #include <linux/netdevice.h>
+ #include <linux/if_vlan.h>
+
+ #include "fjes_regs.h"
+
+ struct fjes_hw ;
+
+ #define EP_BUFFER_SUPPORT_VLAN_MAX 4
+ #define EP_BUFFER_INFO_SIZE 4096
+
+ #define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
+
+ #define EP_BUFFER_SIZE \
+ ((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \
+ / EP_BUFFER_INFO_SIZE ) * EP_BUFFER_INFO_SIZE )
+
+ #define EP_RING_NUM(buffer_size, frame_size) \
+ ( u32 )(( buffer_size ) / ( frame_size ))
+
+ #define FJES_MTU_TO_BUFFER_SIZE(mtu) \
+ ( ETH_HLEN + VLAN_HLEN + ( mtu ) + ETH_FCS_LEN )
+ #define FJES_MTU_TO_FRAME_SIZE(mtu) \
+ ( sizeof ( struct esmem_frame ) + FJES_MTU_TO_BUFFER_SIZE ( mtu ))
+ #define FJES_MTU_DEFINE(size) \
+ (( size ) - sizeof ( struct esmem_frame ) - \
+ ( ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN ))
+
+ #define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
+ #define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
+ ( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE )))
+
+ #define FJES_DEV_REQ_BUF_SIZE(maxep) \
+ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( EP_BUFFER_SIZE , EP_BUFFER_SIZE )
+ #define FJES_DEV_RES_BUF_SIZE(maxep) \
+ FJES_DEV_COMMAND_INFO_RES_LEN ( maxep )
+
+ /* Frame & MTU */
+ struct esmem_frame {
+ __le32 frame_size ;
+ u8 frame_data [];
+ };
+
+ /* shared status region */
+ struct fjes_device_shared_info {
+ int epnum ;
+ u8 ep_status [];
+ };
+
+ /* structures for command control request data*/
+ union fjes_device_command_req {
+ struct {
+ __le32 length ;
+ } info ;
+ struct {
+ __le32 length ;
+ __le32 epid ;
+ __le64 buffer [];
+ } share_buffer ;
+ struct {
+ __le32 length ;
+ __le32 epid ;
+ } unshare_buffer ;
+ struct {
+ __le32 length ;
+ __le32 mode ;
+ __le64 buffer_len ;
+ __le64 buffer [];
+ } start_trace ;
+ struct {
+ __le32 length ;
+ } stop_trace ;
+ };
+
+ /* structures for command control response data */
+ union fjes_device_command_res {
+ struct {
+ __le32 length ;
+ __le32 code ;
+ struct {
+ u8 es_status ;
+ u8 zone ;
+ } info [];
+ } info ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } share_buffer ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } unshare_buffer ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } start_trace ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } stop_trace ;
+ };
+
+ /* parameter for command control */
+ struct fjes_device_command_param {
+ u32 req_len ;
+ phys_addr_t req_start ;
+ u32 res_len ;
+ phys_addr_t res_start ;
+ phys_addr_t share_start ;
+ };
+
+ /* EP buffer information */
+ union ep_buffer_info {
+ u8 raw [ EP_BUFFER_INFO_SIZE ];
+
+ struct _ep_buffer_info_common_t {
+ u32 version ;
+ } common ;
+
+ struct _ep_buffer_info_v1_t {
+ u32 version ;
+ u32 info_size ;
+
+ u32 buffer_size ;
+ u16 count_max ;
+
+ u16 _rsv_1 ;
+
+ u32 frame_max ;
+ u8 mac_addr [ ETH_ALEN ];
+
+ u16 _rsv_2 ;
+ u32 _rsv_3 ;
+
+ u16 tx_status ;
+ u16 rx_status ;
+
+ u32 head ;
+ u32 tail ;
+
+ u16 vlan_id [ EP_BUFFER_SUPPORT_VLAN_MAX ];
+
+ } v1i ;
+
+ };
+
+ /* buffer pair for Extended Partition */
+ struct ep_share_mem_info {
+ struct epbuf_handler {
+ void * buffer ;
+ size_t size ;
+ union ep_buffer_info * info ;
+ u8 * ring ;
+ } tx , rx ;
+
+ struct rtnl_link_stats64 net_stats ;
+
+ u16 tx_status_work ;
+
+ u8 es_status ;
+ u8 zone ;
+ };
+
+ struct es_device_trace {
+ u32 record_num ;
+ u32 current_record ;
+ u32 status_flag ;
+ u32 _rsv ;
+
+ struct {
+ u16 epid ;
+ u16 dir_offset ;
+ u32 data ;
+ u64 tsc ;
+ } record [];
+ };
+
+ struct fjes_hw_info {
+ struct fjes_device_shared_info * share ;
+ union fjes_device_command_req * req_buf ;
+ u64 req_buf_size ;
+ union fjes_device_command_res * res_buf ;
+ u64 res_buf_size ;
+
+ int * my_epid ;
+ int * max_epid ;
+
+ struct es_device_trace * trace ;
+ u64 trace_size ;
+
+ struct mutex lock ; /* buffer lock*/
+
+ unsigned long buffer_share_bit ;
+ unsigned long buffer_unshare_reserve_bit ;
+ };
+
+ struct fjes_hw {
+ void * back ;
+
+ unsigned long txrx_stop_req_bit ;
+ unsigned long epstop_req_bit ;
+
+ int my_epid ;
+ int max_epid ;
+
+ struct ep_share_mem_info * ep_shm_info ;
+
+ struct fjes_hw_resource {
+ u64 start ;
+ u64 size ;
+ int irq ;
+ } hw_res ;
+
+ u8 * base ;
+
+ struct fjes_hw_info hw_info ;
+ };
+
+ int fjes_hw_init ( struct fjes_hw * );
+ int fjes_hw_reset ( struct fjes_hw * );
+
+ void fjes_hw_init_command_registers ( struct fjes_hw * ,
+ struct fjes_device_command_param * );
+ void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 );
+ void fjes_hw_set_irqmask ( struct fjes_hw * , enum REG_ICTL_MASK , bool );
+
+ #endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h
new file mode 100644
index 0000000..4d0e071
--- /dev/null
+++ b/drivers/net/fjes/fjes_regs.h @@ -0,0 +1,102 @@
+ /*
+ * 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" .
+ *
+ */
+
+ #ifndef FJES_REGS_H_
+ #define FJES_REGS_H_
+
+ #include <linux/bitops.h>
+
+ #define XSCT_DEVICE_REGISTER_SIZE 0x1000
+
+ /* register offset */
+ /* Information registers */
+ #define XSCT_OWNER_EPID 0x0000 /* Owner EPID */
+ #define XSCT_MAX_EP 0x0004 /* Maximum EP */
+
+ /* Device Control registers */
+ #define XSCT_DCTL 0x0010 /* Device Control */
+
+ /* Command Control registers */
+ #define XSCT_SHSTSAL 0x0028 /* Share status address Low */
+ #define XSCT_SHSTSAH 0x002C /* Share status address High */
+
+ #define XSCT_REQBL 0x0034 /* Request Buffer length */
+ #define XSCT_REQBAL 0x0038 /* Request Buffer Address Low */
+ #define XSCT_REQBAH 0x003C /* Request Buffer Address High */
+
+ #define XSCT_RESPBL 0x0044 /* Response Buffer Length */
+ #define XSCT_RESPBAL 0x0048 /* Response Buffer Address Low */
+ #define XSCT_RESPBAH 0x004C /* Response Buffer Address High */
+
+ /* Interrupt Control registers */
+ #define XSCT_IMS 0x0084 /* Interrupt mask set */
+ #define XSCT_IMC 0x0088 /* Interrupt mask clear */
+
+ /* register structure */
+ /* Information registers */
+ union REG_OWNER_EPID {
+ struct {
+ __le32 epid : 16 ;
+ __le32 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ union REG_MAX_EP {
+ struct {
+ __le32 maxep : 16 ;
+ __le32 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ /* Device Control registers */
+ union REG_DCTL {
+ struct {
+ __le32 reset : 1 ;
+ __le32 rsv0 : 15 ;
+ __le32 rsv1 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ enum REG_ICTL_MASK {
+ REG_ICTL_MASK_INFO_UPDATE = 1 << 20 ,
+ REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19 ,
+ REG_ICTL_MASK_TXRX_STOP_REQ = 1 << 18 ,
+ REG_ICTL_MASK_TXRX_STOP_DONE = 1 << 17 ,
+ REG_ICTL_MASK_RX_DATA = 1 << 16 ,
+ REG_ICTL_MASK_ALL = GENMASK ( 20 , 16 ),
+ };
+
+ struct fjes_hw ;
+
+ u32 fjes_hw_rd32 ( struct fjes_hw * hw , u32 reg );
+
+ #define wr32(reg, val) \
+ do { \
+ u8 * base = hw -> base ; \
+ writel (( val ), & base [( reg )]); \
+ } while ( 0 )
+
+ #define rd32(reg) (fjes_hw_rd32(hw, reg))
+
+ #endif /* FJES_REGS_H_ */ --
1.8.3.1
This patch adds net_device_ops.ndo_open and .ndo_stop
callback. These function is called when network device
activation and deactivation.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 1 +
drivers/net/fjes/fjes_hw.c | 144 +++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 30 ++++++
drivers/net/fjes/fjes_main.c | 247 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 17 +++
5 files changed, 439 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 54bc189..f182ed3 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -29,6 +29,7 @@
#define FJES_ACPI_SYMBOL "Extended Socket"
#define FJES_MAX_QUEUES 1
#define FJES_TX_RETRY_INTERVAL (20 * HZ)
+ #define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
/* board specific private data structure */
struct fjes_adapter { diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 4451e70..a17cb96 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -640,6 +640,25 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)
return result ;
}
+ int fjes_hw_raise_interrupt ( struct fjes_hw * hw , int dest_epid ,
+ enum REG_ICTL_MASK mask )
+ {
+ u32 ig = mask | dest_epid ;
+
+ wr32 ( XSCT_IG , cpu_to_le32 ( ig ));
+
+ return 0 ;
+ }
+
+ u32 fjes_hw_capture_interrupt_status ( struct fjes_hw * hw )
+ {
+ u32 cur_is ;
+
+ cur_is = rd32 ( XSCT_IS );
+
+ return cur_is ;
+ }
+
void fjes_hw_set_irqmask ( struct fjes_hw * hw ,
enum REG_ICTL_MASK intr_mask , bool mask )
{ @@ -649,3 +668,128 @@ void fjes_hw_set_irqmask(struct fjes_hw *hw,
wr32 ( XSCT_IMC , intr_mask );
}
+ bool fjes_hw_epid_is_same_zone ( struct fjes_hw * hw , int epid )
+ {
+ if ( epid >= hw -> max_epid )
+ return false ;
+
+ if (( hw -> ep_shm_info [ epid ]. es_status !=
+ FJES_ZONING_STATUS_ENABLE ) ||
+ ( hw -> ep_shm_info [ hw -> my_epid ]. zone ==
+ FJES_ZONING_ZONE_TYPE_NONE ))
+ return false ;
+ else
+ return ( hw -> ep_shm_info [ epid ]. zone ==
+ hw -> ep_shm_info [ hw -> my_epid ]. zone );
+ }
+
+ int fjes_hw_epid_is_shared ( struct fjes_device_shared_info * share ,
+ int dest_epid )
+ {
+ int value = false ;
+
+ if ( dest_epid < share -> epnum )
+ value = share -> ep_status [ dest_epid ];
+
+ return value ;
+ }
+
+ static bool fjes_hw_epid_is_stop_requested ( struct fjes_hw * hw , int src_epid )
+ {
+ return test_bit ( src_epid , & hw -> txrx_stop_req_bit );
+ }
+
+ static bool fjes_hw_epid_is_stop_process_done ( struct fjes_hw * hw , int src_epid )
+ {
+ return ( hw -> ep_shm_info [ src_epid ]. tx . info -> v1i . rx_status &
+ FJES_RX_STOP_REQ_DONE );
+ }
+
+ enum ep_partner_status
+ fjes_hw_get_partner_ep_status ( struct fjes_hw * hw , int epid )
+ {
+ enum ep_partner_status status ;
+
+ if ( fjes_hw_epid_is_shared ( hw -> hw_info . share , epid )) {
+ if ( fjes_hw_epid_is_stop_requested ( hw , epid )) {
+ status = EP_PARTNER_WAITING ;
+ } else {
+ if ( fjes_hw_epid_is_stop_process_done ( hw , epid ))
+ status = EP_PARTNER_COMPLETE ;
+ else
+ status = EP_PARTNER_SHARED ;
+ }
+ } else {
+ status = EP_PARTNER_UNSHARE ;
+ }
+
+ return status ;
+ }
+
+ void fjes_hw_raise_epstop ( struct fjes_hw * hw )
+ {
+ int epidx ;
+ enum ep_partner_status status ;
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+
+ status = fjes_hw_get_partner_ep_status ( hw , epidx );
+ switch ( status ) {
+ case EP_PARTNER_SHARED :
+ fjes_hw_raise_interrupt ( hw , epidx ,
+ REG_ICTL_MASK_TXRX_STOP_REQ );
+ break ;
+ default :
+ break ;
+ }
+
+ set_bit ( epidx , & hw -> hw_info . buffer_unshare_reserve_bit );
+ set_bit ( epidx , & hw -> txrx_stop_req_bit );
+
+ hw -> ep_shm_info [ epidx ]. tx . info -> v1i . rx_status |=
+ FJES_RX_STOP_REQ_REQUEST ;
+ }
+ }
+
+ int fjes_hw_wait_epstop ( struct fjes_hw * hw )
+ {
+ int epidx ;
+ int wait_time = 0 ;
+ enum ep_partner_status status ;
+ union ep_buffer_info * info ;
+
+ while ( hw -> hw_info . buffer_unshare_reserve_bit &&
+ ( wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000 )) {
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+ status =
+ fjes_hw_epid_is_shared ( hw -> hw_info . share , epidx );
+ info = hw -> ep_shm_info [ epidx ]. rx . info ;
+ if (( ! status ||
+ ( info -> v1i . rx_status &
+ FJES_RX_STOP_REQ_DONE )) &&
+ test_bit ( epidx ,
+ & hw -> hw_info . buffer_unshare_reserve_bit )) {
+ clear_bit ( epidx ,
+ & hw -> hw_info . buffer_unshare_reserve_bit );
+ }
+ }
+
+ msleep ( 100 );
+ wait_time += 100 ;
+ }
+
+ 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 ))
+ clear_bit ( epidx ,
+ & hw -> hw_info . buffer_unshare_reserve_bit );
+ }
+
+ return ( wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000 )
+ ? 0 : - EBUSY ;
+ } diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index d1321e8..823d802 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -35,6 +35,7 @@ struct fjes_hw;
#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
#define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */
+ #define FJES_COMMAND_EPSTOP_WAIT_TIMEOUT (1) /* sec */
#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002) @@ -42,6 +43,17 @@ struct fjes_hw;
#define FJES_CMD_REQ_RES_CODE_NORMAL (0)
#define FJES_CMD_REQ_RES_CODE_BUSY (1)
+ #define FJES_ZONING_STATUS_DISABLE (0x00)
+ #define FJES_ZONING_STATUS_ENABLE (0x01)
+ #define FJES_ZONING_STATUS_INVALID (0xFF)
+
+ #define FJES_ZONING_ZONE_TYPE_NONE (0xFF)
+
+ #define FJES_RX_STOP_REQ_NONE (0x0)
+ #define FJES_RX_STOP_REQ_DONE (0x1)
+ #define FJES_RX_STOP_REQ_REQUEST (0x2)
+ #define FJES_RX_POLL_WORK (0x4)
+
#define EP_BUFFER_SIZE \
((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \
/ EP_BUFFER_INFO_SIZE ) * EP_BUFFER_INFO_SIZE ) @@ -76,6 +88,15 @@ struct esmem_frame {
u8 frame_data [];
};
+ /* EP partner status */
+ enum ep_partner_status {
+ EP_PARTNER_UNSHARE ,
+ EP_PARTNER_SHARED ,
+ EP_PARTNER_WAITING ,
+ EP_PARTNER_COMPLETE ,
+ EP_PARTNER_STATUS_MAX ,
+ };
+
/* shared status region */
struct fjes_device_shared_info {
int epnum ; @@ -277,6 +298,15 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *, int);
void fjes_hw_init_command_registers ( struct fjes_hw * ,
struct fjes_device_command_param * );
void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 );
+ int fjes_hw_raise_interrupt ( struct fjes_hw * , int , enum REG_ICTL_MASK );
void fjes_hw_set_irqmask ( struct fjes_hw * , enum REG_ICTL_MASK , bool );
+ u32 fjes_hw_capture_interrupt_status ( struct fjes_hw * );
+ void fjes_hw_raise_epstop ( struct fjes_hw * );
+ int fjes_hw_wait_epstop ( struct fjes_hw * );
+ enum ep_partner_status
+ fjes_hw_get_partner_ep_status ( struct fjes_hw * , int );
+
+ bool fjes_hw_epid_is_same_zone ( struct fjes_hw * , int );
+ int fjes_hw_epid_is_shared ( struct fjes_device_shared_info * , int );
#endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 8b8bcb8..832439b 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -24,6 +24,7 @@
#include <linux/nls.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h>
+ #include <linux/interrupt.h>
#include "fjes.h"
@@ -43,6 +44,15 @@ MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver");
MODULE_LICENSE ( "GPL" );
MODULE_VERSION ( DRV_VERSION );
+ 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 * );
+ static irqreturn_t fjes_intr ( int , void * );
+
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 * ); @@ -172,9 +182,246 @@ fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
return AE_OK ;
}
+ static int fjes_request_irq ( struct fjes_adapter * adapter )
+ {
+ struct net_device * netdev = adapter -> netdev ;
+ int result = -1 ;
+
+ 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 ;
+
+ 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 ;
+ }
+ }
+
static const struct net_device_ops fjes_netdev_ops = {
+ . ndo_open = fjes_open ,
+ . ndo_stop = fjes_close ,
};
+ /* fjes_open - Called when a network interface is made active */
+ static int fjes_open ( struct net_device * netdev )
+ {
+ int result ;
+ struct fjes_adapter * adapter = netdev_priv ( netdev );
+ struct fjes_hw * hw = & adapter -> hw ;
+
+ 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 ;
+
+ 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 );
+
+ 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 ;
+ int epidx ;
+
+ netif_tx_stop_all_queues ( netdev );
+ netif_carrier_off ( netdev );
+
+ fjes_hw_raise_epstop ( hw );
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+
+ adapter -> hw . ep_shm_info [ epidx ]. tx . info -> v1i . rx_status &=
+ ~ FJES_RX_POLL_WORK ;
+ }
+
+ fjes_free_irq ( adapter );
+
+ fjes_hw_wait_epstop ( hw );
+
+ fjes_free_resources ( adapter );
+
+ return 0 ;
+ }
+
+ static int fjes_setup_resources ( struct fjes_adapter * adapter )
+ {
+ int epidx ;
+ struct ep_share_mem_info * buf_pair ;
+ int result ;
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+
+ 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 );
+ }
+ }
+
+ 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 ];
+
+ fjes_hw_setup_epbuf ( & buf_pair -> tx , netdev -> dev_addr ,
+ netdev -> mtu );
+
+ 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 ;
+ }
+ }
+ }
+
+ return 0 ;
+ }
+
+ static void fjes_free_resources ( struct fjes_adapter * adapter )
+ {
+ int epidx ;
+ struct ep_share_mem_info * buf_pair ;
+ int result ;
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+ struct fjes_device_command_param param ;
+ bool reset_flag = false ;
+
+ 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 );
+
+ if ( result )
+ reset_flag = true ;
+
+ buf_pair = & hw -> ep_shm_info [ epidx ];
+
+ fjes_hw_setup_epbuf ( & buf_pair -> tx ,
+ netdev -> dev_addr , netdev -> mtu );
+
+ 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 );
+ }
+ }
+
+ 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 );
+
+ if ( icr & REG_IS_MASK_IS_ASSERT )
+ ret = IRQ_HANDLED ;
+ else
+ ret = IRQ_NONE ;
+
+ return ret ;
+ }
+
/* fjes_probe - Device Initialization Routine */
static int fjes_probe ( struct platform_device * plat_dev )
{ diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h
index cc975a0..029c924 100644
--- a/drivers/net/fjes/fjes_regs.h
+++ b/drivers/net/fjes/fjes_regs.h @@ -49,8 +49,11 @@
#define XSCT_RESPBAH 0x004C /* Response Buffer Address High */
/* Interrupt Control registers */
+ #define XSCT_IS 0x0080 /* Interrupt status */
#define XSCT_IMS 0x0084 /* Interrupt mask set */
#define XSCT_IMC 0x0088 /* Interrupt mask clear */
+ #define XSCT_IG 0x008C /* Interrupt generator */
+ #define XSCT_ICTL 0x0090 /* Interrupt control */
/* register structure */
/* Information registers */ @@ -101,6 +104,15 @@ union REG_CS {
__le32 reg ;
};
+ /* Interrupt Control registers */
+ union REG_ICTL {
+ struct {
+ __le32 automak : 1 ;
+ __le32 rsv0 : 31 ;
+ } bits ;
+ __le32 reg ;
+ };
+
enum REG_ICTL_MASK {
REG_ICTL_MASK_INFO_UPDATE = 1 << 20 ,
REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19 , @@ -110,6 +122,11 @@ enum REG_ICTL_MASK {
REG_ICTL_MASK_ALL = GENMASK ( 20 , 16 ),
};
+ enum REG_IS_MASK {
+ REG_IS_MASK_IS_ASSERT = 1 << 31 ,
+ REG_IS_MASK_EPID = GENMASK ( 15 , 0 ),
+ };
+
struct fjes_hw ;
u32 fjes_hw_rd32 ( struct fjes_hw * hw , u32 reg ); --
1.8.3.1
This patch adds net_device_ops.ndo_start_xmit callback,
which is called when sending packets.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 1 +
drivers/net/fjes/fjes_hw.c | 58 ++++++++++++++
drivers/net/fjes/fjes_hw.h | 12 +++
drivers/net/fjes/fjes_main.c | 177 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 248 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index f182ed3..7af4304 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -29,6 +29,7 @@
#define FJES_ACPI_SYMBOL "Extended Socket"
#define FJES_MAX_QUEUES 1
#define FJES_TX_RETRY_INTERVAL (20 * HZ)
+ #define FJES_TX_RETRY_TIMEOUT (100)
#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
/* board specific private data structure */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index a17cb96..b2e7509 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -793,3 +793,61 @@ int fjes_hw_wait_epstop(struct fjes_hw *hw)
return ( wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000 )
? 0 : - EBUSY ;
}
+
+ bool fjes_hw_check_epbuf_version ( struct epbuf_handler * epbh , u32 version )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ return ( info -> common . version == version );
+ }
+
+ bool fjes_hw_check_mtu ( struct epbuf_handler * epbh , u32 mtu )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ return ( info -> v1i . frame_max == FJES_MTU_TO_FRAME_SIZE ( mtu ));
+ }
+
+ bool fjes_hw_check_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+ bool ret = false ;
+
+ if ( vlan_id == 0 ) {
+ ret = true ;
+ } else {
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ ) {
+ if ( vlan_id == info -> v1i . vlan_id [ i ]) {
+ ret = true ;
+ break ;
+ }
+ }
+ }
+ return ret ;
+ }
+
+ int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * epbh ,
+ void * frame , size_t size )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ struct esmem_frame * ring_frame ;
+
+ if ( EP_RING_FULL ( info -> v1i . head , info -> v1i . tail , info -> v1i . count_max ))
+ return - ENOBUFS ;
+
+ ring_frame =
+ ( struct esmem_frame * ) & ( epbh ->
+ ring [ EP_RING_INDEX
+ ( info -> v1i . tail - 1 ,
+ info -> v1i . count_max ) *
+ info -> v1i . frame_max ]);
+
+ ring_frame -> frame_size = size ;
+ memcpy (( void * )( ring_frame -> frame_data ), ( void * ) frame , size );
+
+ EP_RING_INDEX_INC ( epbh -> info -> v1i . tail , info -> v1i . count_max );
+
+ return 0 ;
+ }
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 823d802..95b9732 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -49,6 +49,9 @@ struct fjes_hw;
#define FJES_ZONING_ZONE_TYPE_NONE (0xFF)
+ #define FJES_TX_DELAY_SEND_NONE (0)
+ #define FJES_TX_DELAY_SEND_PENDING (1)
+
#define FJES_RX_STOP_REQ_NONE (0x0)
#define FJES_RX_STOP_REQ_DONE (0x1)
#define FJES_RX_STOP_REQ_REQUEST (0x2) @@ -60,6 +63,11 @@ struct fjes_hw;
#define EP_RING_NUM(buffer_size, frame_size) \
( u32 )(( buffer_size ) / ( frame_size ))
+ #define EP_RING_INDEX(_num, _max) (((_num) + (_max)) % (_max))
+ #define EP_RING_INDEX_INC(_num, _max) \
+ (( _num ) = EP_RING_INDEX (( _num ) + 1 , ( _max )))
+ #define EP_RING_FULL(_head, _tail, _max) \
+ ( 0 == EP_RING_INDEX ((( _tail ) - ( _head )), ( _max )))
#define FJES_MTU_TO_BUFFER_SIZE(mtu) \
( ETH_HLEN + VLAN_HLEN + ( mtu ) + ETH_FCS_LEN ) @@ -308,5 +316,9 @@ enum ep_partner_status
bool fjes_hw_epid_is_same_zone ( struct fjes_hw * , int );
int fjes_hw_epid_is_shared ( struct fjes_device_shared_info * , int );
+ bool fjes_hw_check_epbuf_version ( struct epbuf_handler * , u32 );
+ bool fjes_hw_check_mtu ( struct epbuf_handler * , u32 );
+ bool fjes_hw_check_vlan_id ( struct epbuf_handler * , u16 );
+ int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * , void * , size_t );
#endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 832439b..f2ef286 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -51,6 +51,7 @@ 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 * );
+ static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
static irqreturn_t fjes_intr ( int , void * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -215,6 +216,7 @@ static void fjes_free_irq(struct fjes_adapter *adapter)
static const struct net_device_ops fjes_netdev_ops = {
. ndo_open = fjes_open ,
. ndo_stop = fjes_close ,
+ . ndo_start_xmit = fjes_xmit_frame ,
};
/* fjes_open - Called when a network interface is made active */ @@ -405,6 +407,181 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
}
}
+ 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 ;
+
+ 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 ;
+ enum ep_partner_status pstatus ;
+
+ int len ;
+ char * data , shortpkt [ VLAN_ETH_HLEN ];
+
+ u16 queue_no = 0 ;
+ struct netdev_queue * cur_queue = netdev_get_tx_queue ( netdev , queue_no );
+ netdev_tx_t ret = NETDEV_TX_OK ;
+ struct ethhdr * eth ;
+ int dest_epid ;
+
+ int max_epid , my_epid ;
+ u16 vlan_id = 0 ;
+ bool vlan = false ;
+ bool is_multi = false ;
+
+ 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 ) {
+ 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 ;
+ hw -> ep_shm_info [ my_epid ]. net_stats
+ . tx_carrier_errors += 1 ;
+
+ 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 ;
+ hw -> ep_shm_info [ my_epid ]. net_stats . tx_dropped += 1 ;
+ adapter -> stats64 . tx_errors += 1 ;
+ hw -> ep_shm_info [ my_epid ]. net_stats . tx_errors += 1 ;
+
+ ret = NETDEV_TX_OK ;
+ } else if ( vlan &&
+ ! fjes_hw_check_vlan_id (
+ & adapter -> hw . ep_shm_info [ dest_epid ]. rx ,
+ vlan_id )) {
+ 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 ;
+ hw -> ep_shm_info [ my_epid ]. net_stats
+ . tx_fifo_errors += 1 ;
+ adapter -> stats64 . tx_errors += 1 ;
+ hw -> ep_shm_info [ my_epid ]. net_stats
+ . tx_errors += 1 ;
+
+ ret = NETDEV_TX_OK ;
+ } else {
+ netdev -> trans_start = jiffies ;
+ netif_tx_stop_queue ( cur_queue );
+
+ ret = NETDEV_TX_BUSY ;
+ }
+ } else {
+ if ( ! is_multi ) {
+ 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 ;
+ }
+
+ 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 ;
+ }
+
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ; --
1.8.3.1
This patch add raise_intr_rxdata_task.
Extended Socket Network Device is shared memory
based, so someone's transmission denotes other's
reception. In order to notify receivers, sender
has to raise interruption of receivers.
raise_intr_rxdata_task does this work.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 4 +++
drivers/net/fjes/fjes_main.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 7af4304..8e9899e 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -50,6 +50,10 @@ struct fjes_adapter {
bool irq_registered ;
+ struct workqueue_struct * txrx_wq ;
+
+ struct work_struct raise_intr_rxdata_task ;
+
struct fjes_hw hw ;
};
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index f2ef286..735aa5e 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -52,6 +52,7 @@ static int fjes_close(struct net_device *);
static int fjes_setup_resources ( struct fjes_adapter * );
static void fjes_free_resources ( struct fjes_adapter * );
static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
+ static void fjes_raise_intr_rxdata_task ( struct work_struct * );
static irqreturn_t fjes_intr ( int , void * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -279,6 +280,8 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
+ cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
+
fjes_hw_wait_epstop ( hw );
fjes_free_resources ( adapter ); @@ -407,6 +410,55 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
}
}
+ 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 ;
+ int epid ;
+ int max_epid , my_epid ;
+ enum ep_partner_status pstatus ;
+
+ 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 ) &&
+ ! ( hw -> ep_shm_info [ epid ]. rx . info -> v1i . rx_status )) {
+ fjes_hw_raise_interrupt ( hw , epid ,
+ REG_ICTL_MASK_RX_DATA );
+ }
+ }
+
+ usleep_range ( 500 , 1000 );
+ }
+
static int fjes_tx_send ( struct fjes_adapter * adapter , int dest ,
void * data , size_t len )
{ @@ -420,6 +472,9 @@ static int fjes_tx_send(struct fjes_adapter *adapter, int dest,
adapter -> hw . ep_shm_info [ dest ]. tx . info -> v1i . tx_status =
FJES_TX_DELAY_SEND_PENDING ;
+ if ( ! work_pending ( & adapter -> raise_intr_rxdata_task ))
+ queue_work ( adapter -> txrx_wq ,
+ & adapter -> raise_intr_rxdata_task );
retval = 0 ;
return retval ; @@ -633,6 +688,11 @@ static int fjes_probe(struct platform_device *plat_dev)
adapter -> force_reset = false ;
adapter -> open_guard = false ;
+ adapter -> txrx_wq = create_workqueue ( DRV_NAME "/txrx" );
+
+ INIT_WORK ( & adapter -> raise_intr_rxdata_task ,
+ fjes_raise_intr_rxdata_task );
+
res = platform_get_resource ( plat_dev , IORESOURCE_MEM , 0 );
hw -> hw_res . start = res -> start ;
hw -> hw_res . size = res -> end - res -> start + 1 ; @@ -673,6 +733,10 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_adapter * adapter = netdev_priv ( netdev );
struct fjes_hw * hw = & adapter -> hw ;
+ cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
+ if ( adapter -> txrx_wq )
+ destroy_workqueue ( adapter -> txrx_wq );
+
unregister_netdev ( netdev );
fjes_hw_exit ( hw ); --
1.8.3.1
This patch adds NAPI polling function and receive related work.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 41 +++++++++++
drivers/net/fjes/fjes_hw.h | 5 ++
drivers/net/fjes/fjes_main.c | 172 ++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 216 insertions(+), 2 deletions(-)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index b2e7509..5e3f847 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -827,6 +827,47 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)
return ret ;
}
+ bool fjes_hw_epbuf_rx_is_empty ( struct epbuf_handler * epbh )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ if ( info -> v1i . count_max == 0 )
+ return true ;
+
+ return EP_RING_EMPTY ( info -> v1i . head , info -> v1i . tail ,
+ info -> v1i . count_max );
+ }
+
+ void * fjes_hw_epbuf_rx_curpkt_get_addr ( struct epbuf_handler * epbh ,
+ size_t * psize )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ struct esmem_frame * ring_frame ;
+ void * frame ;
+
+ ring_frame =
+ ( struct esmem_frame * )
+ & ( epbh -> ring [ EP_RING_INDEX ( info -> v1i . head ,
+ info -> v1i . count_max ) *
+ info -> v1i . frame_max ]);
+
+ * psize = ( size_t ) ring_frame -> frame_size ;
+
+ frame = ring_frame -> frame_data ;
+
+ return frame ;
+ }
+
+ void fjes_hw_epbuf_rx_curpkt_drop ( struct epbuf_handler * epbh )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ if ( fjes_hw_epbuf_rx_is_empty ( epbh ))
+ return ;
+
+ EP_RING_INDEX_INC ( epbh -> info -> v1i . head , info -> v1i . count_max );
+ }
+
int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * epbh ,
void * frame , size_t size )
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 95b9732..ea30aeb 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -68,6 +68,8 @@ struct fjes_hw;
(( _num ) = EP_RING_INDEX (( _num ) + 1 , ( _max )))
#define EP_RING_FULL(_head, _tail, _max) \
( 0 == EP_RING_INDEX ((( _tail ) - ( _head )), ( _max )))
+ #define EP_RING_EMPTY(_head, _tail, _max) \
+ ( 1 == EP_RING_INDEX ((( _tail ) - ( _head )), ( _max )))
#define FJES_MTU_TO_BUFFER_SIZE(mtu) \
( ETH_HLEN + VLAN_HLEN + ( mtu ) + ETH_FCS_LEN ) @@ -319,6 +321,9 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int);
bool fjes_hw_check_epbuf_version ( struct epbuf_handler * , u32 );
bool fjes_hw_check_mtu ( struct epbuf_handler * , u32 );
bool fjes_hw_check_vlan_id ( struct epbuf_handler * , u16 );
+ bool fjes_hw_epbuf_rx_is_empty ( struct epbuf_handler * );
+ void * fjes_hw_epbuf_rx_curpkt_get_addr ( struct epbuf_handler * , size_t * );
+ void fjes_hw_epbuf_rx_curpkt_drop ( struct epbuf_handler * );
int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * , void * , size_t );
#endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index f4c2445..2e7b382 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -66,6 +66,9 @@ static int fjes_remove(struct platform_device *);
static int fjes_sw_init ( struct fjes_adapter * );
static void fjes_netdev_setup ( struct net_device * );
+ static void fjes_rx_irq ( struct fjes_adapter * , int );
+ static int fjes_poll ( struct napi_struct * , int );
+
static const struct acpi_device_id fjes_acpi_ids [] = {
{ "PNP0C02" , 0 },
{ "" , 0 }, @@ -238,6 +241,8 @@ static int fjes_open(struct net_device *netdev)
hw -> txrx_stop_req_bit = 0 ;
hw -> epstop_req_bit = 0 ;
+ napi_enable ( & adapter -> napi );
+
fjes_hw_capture_interrupt_status ( hw );
result = fjes_request_irq ( adapter ); @@ -253,6 +258,7 @@ static int fjes_open(struct net_device *netdev)
err_req_irq :
fjes_free_irq ( adapter );
+ napi_disable ( & adapter -> napi );
err_setup_res :
fjes_free_resources ( adapter ); @@ -271,6 +277,8 @@ static int fjes_close(struct net_device *netdev)
fjes_hw_raise_epstop ( hw );
+ napi_disable ( & adapter -> napi );
+
for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
if ( epidx == hw -> my_epid )
continue ; @@ -707,14 +715,168 @@ static irqreturn_t fjes_intr(int irq, void *data)
icr = fjes_hw_capture_interrupt_status ( hw );
- if ( icr & REG_IS_MASK_IS_ASSERT )
+ if ( icr & REG_IS_MASK_IS_ASSERT ) {
+ if ( icr & REG_ICTL_MASK_RX_DATA )
+ fjes_rx_irq ( adapter , icr & REG_IS_MASK_EPID );
+
ret = IRQ_HANDLED ;
- else
+ } else {
ret = IRQ_NONE ;
+ }
return ret ;
}
+ static int fjes_rxframe_search_exist ( struct fjes_adapter * adapter ,
+ int start_epid )
+ {
+ struct fjes_hw * hw = & adapter -> hw ;
+ int cur_epid ;
+ int max_epid ;
+ int i ;
+ enum ep_partner_status pstatus ;
+
+ 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 fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = napi -> dev ;
+ int work_done = 0 ;
+ struct sk_buff * skb ;
+ void * frame ;
+ size_t frame_len ;
+ int cur_epid = 0 ;
+ int epidx = 0 ;
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+
+ adapter -> hw . ep_shm_info [ epidx ]. tx . info -> v1i . rx_status |=
+ FJES_RX_POLL_WORK ;
+ }
+
+ 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 {
+ memcpy ( skb_put ( skb , frame_len ),
+ frame , frame_len );
+ 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 ) {
+ napi_complete ( napi );
+
+ 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 {
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) {
+ if ( epidx == hw -> my_epid )
+ continue ;
+ adapter -> hw . ep_shm_info [ epidx ]
+ . tx . info -> v1i . rx_status &=
+ ~ FJES_RX_POLL_WORK ;
+ }
+
+ fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_RX_DATA , false );
+ }
+ }
+
+ return work_done ;
+ }
+
/* fjes_probe - Device Initialization Routine */
static int fjes_probe ( struct platform_device * plat_dev )
{ @@ -804,6 +966,8 @@ static int fjes_remove(struct platform_device *plat_dev)
fjes_hw_exit ( hw );
+ netif_napi_del ( & adapter -> napi );
+
free_netdev ( netdev );
return 0 ; @@ -811,6 +975,10 @@ static int fjes_remove(struct platform_device *plat_dev)
static int fjes_sw_init ( struct fjes_adapter * adapter )
{
+ struct net_device * netdev = adapter -> netdev ;
+
+ netif_napi_add ( netdev , & adapter -> napi , fjes_poll , 64 );
+
return 0 ;
}
--
1.8.3.1
This patch adds net_device_ops.ndo_change_mtu.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_main.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 0aa289d..47e5b2f 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -57,6 +57,7 @@ static void fjes_tx_stall_task(struct work_struct *);
static irqreturn_t fjes_intr ( int , void * );
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * );
+ static int fjes_change_mtu ( struct net_device * , int );
static int fjes_acpi_add ( struct acpi_device * );
static int fjes_acpi_remove ( struct acpi_device * ); @@ -225,6 +226,7 @@ static const struct net_device_ops fjes_netdev_ops = {
. ndo_stop = fjes_close ,
. ndo_start_xmit = fjes_xmit_frame ,
. ndo_get_stats64 = fjes_get_stats64 ,
+ . ndo_change_mtu = fjes_change_mtu ,
};
/* fjes_open - Called when a network interface is made active */ @@ -719,6 +721,33 @@ fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
return stats ;
}
+ static int fjes_change_mtu ( struct net_device * netdev , int new_mtu )
+ {
+ int idx ;
+ bool running = netif_running ( netdev );
+ int ret = 0 ;
+
+ 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 ;
+
+ if ( running )
+ fjes_close ( netdev );
+
+ netdev -> mtu = new_mtu ;
+
+ if ( running )
+ ret = fjes_open ( netdev );
+
+ return ret ;
+ }
+ }
+
+ return - EINVAL ;
+ }
+
static irqreturn_t fjes_intr ( int irq , void * data )
{
struct fjes_adapter * adapter = data ; --
1.8.3.1
This patch adds force_close_task.
This task is used to close network device forcibly.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 1 +
drivers/net/fjes/fjes_main.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 1743dbb..d31d4c3 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -47,6 +47,7 @@ struct fjes_adapter {
unsigned long rx_last_jiffies ;
bool unset_rx_last ;
+ struct work_struct force_close_task ;
bool force_reset ;
bool open_guard ;
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 5c93c4e..1ddb9d3 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -54,6 +54,7 @@ static void fjes_free_resources(struct fjes_adapter *);
static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
static void fjes_raise_intr_rxdata_task ( struct work_struct * );
static void fjes_tx_stall_task ( struct work_struct * );
+ static void fjes_force_close_task ( struct work_struct * );
static irqreturn_t fjes_intr ( int , void * );
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * ); @@ -497,6 +498,17 @@ static void fjes_tx_stall_task(struct work_struct *work)
queue_work ( adapter -> txrx_wq , & adapter -> tx_stall_task );
}
+ 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 ();
+ }
+
static void fjes_raise_intr_rxdata_task ( struct work_struct * work )
{
struct fjes_adapter * adapter = container_of ( work , @@ -1010,6 +1022,7 @@ static int fjes_probe(struct platform_device *plat_dev)
if ( err )
goto err_sw_init ;
+ INIT_WORK ( & adapter -> force_close_task , fjes_force_close_task );
adapter -> force_reset = false ;
adapter -> open_guard = false ;
--
1.8.3.1
This patch adds epstop_task.
This task is used to process other receiver's
cancellation request.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 30 ++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 1 +
drivers/net/fjes/fjes_main.c | 1 +
3 files changed, 32 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 8756d3e..1c66218 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -23,6 +23,7 @@
#include "fjes.h"
static void fjes_hw_update_zone_task ( struct work_struct * );
+ static void fjes_hw_epstop_task ( struct work_struct * );
/* supported MTU list */
const u32 fjes_support_mtu [] = { @@ -326,6 +327,7 @@ int fjes_hw_init(struct fjes_hw *hw)
fjes_hw_set_irqmask ( hw , REG_ICTL_MASK_ALL , true );
INIT_WORK ( & hw -> update_zone_task , fjes_hw_update_zone_task );
+ INIT_WORK ( & hw -> epstop_task , fjes_hw_epstop_task );
mutex_init ( & hw -> hw_info . lock );
@@ -356,6 +358,7 @@ void fjes_hw_exit(struct fjes_hw *hw)
fjes_hw_cleanup ( hw );
cancel_work_sync ( & hw -> update_zone_task );
+ cancel_work_sync ( & hw -> epstop_task );
}
static enum fjes_dev_command_response_e @@ -1090,3 +1093,30 @@ static void fjes_hw_update_zone_task(struct work_struct *work)
}
}
+ static void fjes_hw_epstop_task ( struct work_struct * work )
+ {
+ struct fjes_hw * hw = container_of ( work , struct fjes_hw , epstop_task );
+ struct fjes_adapter * adapter = ( struct fjes_adapter * ) hw -> back ;
+ int epid_bit ;
+ unsigned long remain_bit ;
+
+ while (( remain_bit = hw -> epstop_req_bit )) {
+ for ( epid_bit = 0 ; remain_bit ; remain_bit >>= 1 , epid_bit ++ ) {
+ if ( remain_bit & 1 ) {
+ hw -> ep_shm_info [ epid_bit ].
+ tx . info -> v1i . rx_status |=
+ FJES_RX_STOP_REQ_DONE ;
+
+ clear_bit ( epid_bit , & hw -> epstop_req_bit );
+ set_bit ( epid_bit ,
+ & adapter -> unshare_watch_bitmask );
+
+ if ( ! work_pending ( & adapter -> unshare_watch_task ))
+ queue_work (
+ adapter -> control_wq ,
+ & adapter -> unshare_watch_task );
+ }
+ }
+ }
+ }
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index d80b8c8..4ef15ad 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -282,6 +282,7 @@ struct fjes_hw {
unsigned long txrx_stop_req_bit ;
unsigned long epstop_req_bit ;
struct work_struct update_zone_task ;
+ struct work_struct epstop_task ;
int my_epid ;
int max_epid ; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index b37e909..df4a292 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -319,6 +319,7 @@ static int fjes_close(struct net_device *netdev)
cancel_work_sync ( & adapter -> tx_stall_task );
cancel_work_sync ( & hw -> update_zone_task );
+ cancel_work_sync ( & hw -> epstop_task );
fjes_hw_wait_epstop ( hw );
--
1.8.3.1
This patch adds implementation of handling IRQ
of other receiver's receive cancellation request.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_main.c | 79 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index df4a292..1db1a7d 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -826,6 +826,75 @@ static int fjes_vlan_rx_kill_vid(struct net_device *netdev,
return 0 ;
}
+ 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 ;
+
+ status = fjes_hw_get_partner_ep_status ( hw , src_epid );
+ switch ( status ) {
+ case EP_PARTNER_UNSHARE :
+ default :
+ break ;
+ case EP_PARTNER_COMPLETE :
+ break ;
+ case EP_PARTNER_WAITING :
+ if ( src_epid < hw -> my_epid ) {
+ hw -> ep_shm_info [ src_epid ]. tx . info -> v1i . rx_status |=
+ FJES_RX_STOP_REQ_DONE ;
+
+ 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 ;
+ }
+ }
+
+ static void fjes_stop_req_irq ( struct fjes_adapter * adapter , int src_epid )
+ {
+ struct fjes_hw * hw = & adapter -> hw ;
+ enum ep_partner_status status ;
+
+ set_bit ( src_epid , & hw -> hw_info . buffer_unshare_reserve_bit );
+
+ status = fjes_hw_get_partner_ep_status ( hw , src_epid );
+ switch ( status ) {
+ case EP_PARTNER_WAITING :
+ hw -> ep_shm_info [ src_epid ]. tx . info -> v1i . rx_status |=
+ FJES_RX_STOP_REQ_DONE ;
+ 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 ;
+ }
+ }
+
static void fjes_update_zone_irq ( struct fjes_adapter * adapter ,
int src_epid )
{ @@ -848,6 +917,16 @@ static irqreturn_t fjes_intr(int irq, void *data)
if ( icr & REG_ICTL_MASK_RX_DATA )
fjes_rx_irq ( adapter , icr & REG_IS_MASK_EPID );
+ if ( icr & REG_ICTL_MASK_DEV_STOP_REQ )
+ fjes_stop_req_irq ( adapter , icr & REG_IS_MASK_EPID );
+
+ if ( icr & REG_ICTL_MASK_TXRX_STOP_REQ )
+ fjes_txrx_stop_req_irq ( adapter , icr & REG_IS_MASK_EPID );
+
+ if ( icr & REG_ICTL_MASK_TXRX_STOP_DONE )
+ fjes_hw_set_irqmask ( hw ,
+ REG_ICTL_MASK_TXRX_STOP_DONE , true );
+
if ( icr & REG_ICTL_MASK_INFO_UPDATE )
fjes_update_zone_irq ( adapter , icr & REG_IS_MASK_EPID );
--
1.8.3.1
On Wed, 2015-06-24 at 11:55 +0900, Taku Izumi wrote: This patch adds the basic code of FUJITSU Extended Socket
Network Device driver.
trivial notes:
quoted hunk diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c [] +static int fjes_acpi_add(struct acpi_device *device)
+{ [] + result =
+ utf16s_to_utf8s((wchar_t *)str->string.pointer,
+ str->string.length, UTF16_LITTLE_ENDIAN,
+ str_buf, sizeof(str_buf) - 1);
I dislike this style as it's not normally used in the kernel.
Most would use another tab indent on the utf16s_to_utf8s line
if the line didn't fit, but this would is more common:
result = utf16s_to_utf8s((wchar_t *)str->string.pointer,
str->string.length, UTF16_LITTLE_ENDIAN,
str_buf, sizeof(str_buf) - 1);
+ /* create platform_device */
+ plat_dev =
+ platform_device_register_simple(DRV_NAME, 0, fjes_resource,
+ ARRAY_SIZE(fjes_resource));
plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
ARRAY_SIZE(fjes_resource));
etc...
+static acpi_status
+fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
+{
+ struct resource *res = data;
+ struct acpi_resource_address32 *addr;
+ struct acpi_resource_irq *irq;
+
+ 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;
+}
Is this function used in this compilation?
If not, it's odd to add code that isn't used.
Is it better to make the 2nd argument a
struct resource * rather than a void * ?
On Wed, 24 Jun 2015 11:52:31 +0900
Taku Izumi [off-list ref] wrote:
This patchsets adds FUJITSU Extended Socket network device driver.
Extended Socket network device is a shared memory based high-speed network
interface between Extended Partitions of PRIMEQUEST 2000 E2 series.
You can get some information about Extended Partition and Extended
Socket by referring the following manual.
http://globalsp.ts.fujitsu.com/dmsp/Publications/public/CA92344-0537.pdf
3.2.1 Extended Partitioning
3.2.2 Extended Socket
v1 -> v2:
- Location change
drivers/platform/x86 => driver/net
Could/should this driver be placed under driver/net/ethernet/fujitsu ??
You are using Ethernet addresses but they are kind of special, always
02:00:00:00:00:xx which is hard-coded... maybe I misunderstand the
code/hw and it is not Ethernet?
[...] drivers/net/fjes/Makefile | 31 +
drivers/net/fjes/fjes.h | 77 +++
drivers/net/fjes/fjes_ethtool.c | 135 ++++
drivers/net/fjes/fjes_hw.c | 1122 +++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 333 ++++++++++
drivers/net/fjes/fjes_main.c | 1397 +++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 142 ++++
9 files changed, 3246 insertions(+)
create mode 100644 drivers/net/fjes/Makefile
create mode 100644 drivers/net/fjes/fjes.h
create mode 100644 drivers/net/fjes/fjes_ethtool.c
create mode 100644 drivers/net/fjes/fjes_hw.c
create mode 100644 drivers/net/fjes/fjes_hw.h
create mode 100644 drivers/net/fjes/fjes_main.c
create mode 100644 drivers/net/fjes/fjes_regs.h
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
Thanks for your help.
-----Original Message-----
From: platform-driver-x86-owner@vger.kernel.org [mailto:platform-driver-x86-owner@vger.kernel.org] On Behalf Of Joe
Perches
Sent: Wednesday, June 24, 2015 3:51 PM
To: Izumi, Taku/泉 拓
Cc: netdev@vger.kernel.org; davem@davemloft.net; platform-driver-x86@vger.kernel.org; dvhart@infradead.org;
rkhan@redhat.com; alexander.h.duyck@redhat.com; linux-acpi@vger.kernel.org; sergei.shtylyov@cogentembedded.com;
stephen@networkplumber.org; yasu.isimatu@gmail.com
Subject: Re: [PATCH v2 01/22] fjes: Introduce FUJITSU Extended Socket Network Device driver
On Wed, 2015-06-24 at 11:55 +0900, Taku Izumi wrote: quoted This patch adds the basic code of FUJITSU Extended Socket
Network Device driver.
trivial notes:
quoted diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c [] quoted +static int fjes_acpi_add(struct acpi_device *device)
+{ [] quoted + result =
+ utf16s_to_utf8s((wchar_t *)str->string.pointer,
+ str->string.length, UTF16_LITTLE_ENDIAN,
+ str_buf, sizeof(str_buf) - 1);
I dislike this style as it's not normally used in the kernel.
Most would use another tab indent on the utf16s_to_utf8s line
if the line didn't fit, but this would is more common:
To tell the truth, I dislike this style too.... OK, I'll fix.
I reformatted to fix " CHECK: Alignment should match open parenthesis"
style issue.
I thought the following style is easy to exceed 80 columns, I opted
the above style.
result = utf16s_to_utf8s((wchar_t *)str->string.pointer,
str->string.length, UTF16_LITTLE_ENDIAN,
str_buf, sizeof(str_buf) - 1); quoted
+ /* create platform_device */
+ plat_dev =
+ platform_device_register_simple(DRV_NAME, 0, fjes_resource,
+ ARRAY_SIZE(fjes_resource));
plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource,
ARRAY_SIZE(fjes_resource));
etc...
quoted +static acpi_status
+fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
+{
+ struct resource *res = data;
+ struct acpi_resource_address32 *addr;
+ struct acpi_resource_irq *irq;
+
+ 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;
+}
Is this function used in this compilation?
If not, it's odd to add code that isn't used.
Is it better to make the 2nd argument a
struct resource * rather than a void * ?
This function is used as a callback function of "acpi_walk_resources".
Its signature is
acpi_status(*acpi_walk_resource_callback) (struct acpi_resource * resource, void *context);
Sincerely,
Taku Izumi
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Thanks for your comment.
-----Original Message-----
From: platform-driver-x86-owner@vger.kernel.org [mailto:platform-driver-x86-owner@vger.kernel.org] On Behalf Of Jesper
Dangaard Brouer
Sent: Wednesday, June 24, 2015 10:41 PM
To: Izumi, Taku/泉 拓
Cc: brouer@redhat.com; netdev@vger.kernel.org; platform-driver-x86@vger.kernel.org; dvhart@infradead.org;
rkhan@redhat.com; alexander.h.duyck@redhat.com; linux-acpi@vger.kernel.org; joe@perches.com; yasu.isimatu@gmail.com
Subject: Re: [PATCH v2 00/22] FUJITSU Extended Socket network device driver
On Wed, 24 Jun 2015 11:52:31 +0900
Taku Izumi [off-list ref] wrote:
quoted This patchsets adds FUJITSU Extended Socket network device driver.
Extended Socket network device is a shared memory based high-speed network
interface between Extended Partitions of PRIMEQUEST 2000 E2 series.
You can get some information about Extended Partition and Extended
Socket by referring the following manual.
http://globalsp.ts.fujitsu.com/dmsp/Publications/public/CA92344-0537.pdf
3.2.1 Extended Partitioning
3.2.2 Extended Socket
v1 -> v2:
- Location change
drivers/platform/x86 => driver/net
Could/should this driver be placed under driver/net/ethernet/fujitsu ??
You are using Ethernet addresses but they are kind of special, always
02:00:00:00:00:xx which is hard-coded... maybe I misunderstand the
code/hw and it is not Ethernet?
"Extended Socket network device" doesn't necessitate real (physical) Ethernet card.
There's no Ethernet card, so I'm not quite sure I can put this code
under driver/net/ethernet.
I thought this driver is analogous with "vmxnet3" or "hyperv", so I put at driver/net.
If it's no problem to put it under driver/net/ethernet, I'm ready to migrate it.
Sincerely,
Taku Izumi
[...] quoted drivers/net/fjes/Makefile | 31 +
drivers/net/fjes/fjes.h | 77 +++
drivers/net/fjes/fjes_ethtool.c | 135 ++++
drivers/net/fjes/fjes_hw.c | 1122 +++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 333 ++++++++++
drivers/net/fjes/fjes_main.c | 1397 +++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 142 ++++
9 files changed, 3246 insertions(+)
create mode 100644 drivers/net/fjes/Makefile
create mode 100644 drivers/net/fjes/fjes.h
create mode 100644 drivers/net/fjes/fjes_ethtool.c
create mode 100644 drivers/net/fjes/fjes_hw.c
create mode 100644 drivers/net/fjes/fjes_hw.h
create mode 100644 drivers/net/fjes/fjes_main.c
create mode 100644 drivers/net/fjes/fjes_regs.h
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, 24 Jun 2015 11:55:38 +0900
Taku Izumi [off-list ref] wrote:
This patch adds buffer address regist/unregistration routine.
This function is mainly invoked when network device's
activation (open) and deactivation (close) in order to retist/unregist shared buffer address. register/unregister
quoted hunk
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 9 ++-
2 files changed, 195 insertions(+), 1 deletion(-)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 1ffa62e..4451e70 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -453,6 +453,193 @@ int fjes_hw_request_info(struct fjes_hw *hw)
return result ;
}
+ int fjes_hw_register_buff_addr ( struct fjes_hw * hw , int dest_epid ,
+ struct ep_share_mem_info * buf_pair )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ enum fjes_dev_command_response_e ret ;
+ int i , idx ;
+ int page_count ;
+ void * addr ;
+ int timeout ;
+ int result ;
+
+ if ( test_bit ( dest_epid , & hw -> hw_info . buffer_share_bit ))
+ return 0 ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> share_buffer . length =
+ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( buf_pair -> tx . size ,
+ buf_pair -> rx . size );
+ req_buf -> share_buffer . epid = dest_epid ;
+
+ idx = 0 ;
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> tx . size ;
+ page_count = buf_pair -> tx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> tx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> rx . size ;
+ page_count = buf_pair -> rx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> rx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+
+ res_buf -> share_buffer . length = 0 ;
+ res_buf -> share_buffer . code = 0 ;
+
+ ret = fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_SHARE_BUFFER );
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000 ;
+ while (( ret == FJES_CMD_STATUS_NORMAL ) &&
+ ( res_buf -> share_buffer . length ==
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN ) &&
+ ( res_buf -> share_buffer . code == FJES_CMD_REQ_RES_CODE_BUSY ) &&
+ ( timeout > 0 )) {
+ msleep ( 200 + hw -> my_epid * 20 );
+ timeout -= ( 200 + hw -> my_epid * 20 );
+
+ res_buf -> share_buffer . length = 0 ;
+ res_buf -> share_buffer . code = 0 ;
+
+ ret =
+ fjes_hw_issue_request_command ( hw ,
+ FJES_CMD_REQ_SHARE_BUFFER );
+ }
+
+ result = 0 ;
+
+ if ( res_buf -> share_buffer . length !=
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN )
+ result = - ENOMSG ;
+ else if ( ret == FJES_CMD_STATUS_NORMAL ) {
+ switch ( res_buf -> share_buffer . code ) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL :
+ result = 0 ;
+ set_bit ( dest_epid , & hw -> hw_info . buffer_share_bit );
+ break ;
+ case FJES_CMD_REQ_RES_CODE_BUSY :
+ result = - EBUSY ;
+ break ;
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ } else {
+ switch ( ret ) {
+ case FJES_CMD_STATUS_UNKNOWN :
+ result = - EPERM ;
+ break ;
+ case FJES_CMD_STATUS_TIMEOUT :
+ result = - EBUSY ;
+ break ;
+ case FJES_CMD_STATUS_ERROR_PARAM :
+ case FJES_CMD_STATUS_ERROR_STATUS :
+ default :
+ result = - EPERM ;
+ break ;
+ }
+ }
+
+ return result ;
+ }
+
+ int fjes_hw_unregister_buff_addr ( struct fjes_hw * hw , int dest_epid )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ struct fjes_device_shared_info * share = hw -> hw_info . share ;
+ enum fjes_dev_command_response_e ret ;
+ int result ;
+ int timeout ;
+
+ if ( ! hw -> base )
+ return - EPERM ;
+
+ if ( ! req_buf || ! res_buf || ! share )
+ return - EPERM ;
+
+ if ( ! test_bit ( dest_epid , & hw -> hw_info . buffer_share_bit ))
+ return 0 ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> unshare_buffer . length =
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN ;
+ req_buf -> unshare_buffer . epid = dest_epid ;
+
+ res_buf -> unshare_buffer . length = 0 ;
+ res_buf -> unshare_buffer . code = 0 ;
+
+ ret = fjes_hw_issue_request_command ( hw , FJES_CMD_REQ_UNSHARE_BUFFER );
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000 ;
+ while (( ret == FJES_CMD_STATUS_NORMAL ) &&
+ ( res_buf -> unshare_buffer . length ==
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN ) &&
+ ( res_buf -> unshare_buffer . code ==
+ FJES_CMD_REQ_RES_CODE_BUSY ) &&
+ ( timeout > 0 )) {
+ msleep ( 200 + hw -> my_epid * 20 ); + timeout -= (200 + hw->my_epid * 20); There is a extra indent.
quoted hunk +
+ res_buf->unshare_buffer.length = 0;
+ res_buf->unshare_buffer.code = 0;
+
+ ret =
+ fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER);
+ }
+
+ result = 0;
+
+ if (res_buf->unshare_buffer.length !=
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) {
+ result = -ENOMSG;
+ } else if (ret == FJES_CMD_STATUS_NORMAL) {
+ switch (res_buf->unshare_buffer.code) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL:
+ result = 0;
+ clear_bit(dest_epid, &hw->hw_info.buffer_share_bit);
+ break;
+ case FJES_CMD_REQ_RES_CODE_BUSY:
+ result = -EBUSY;
+ break;
+ default:
+ result = -EPERM;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case FJES_CMD_STATUS_UNKNOWN:
+ result = -EPERM;
+ break;
+ case FJES_CMD_STATUS_TIMEOUT:
+ result = -EBUSY;
+ break;
+ case FJES_CMD_STATUS_ERROR_PARAM:
+ case FJES_CMD_STATUS_ERROR_STATUS:
+ default:
+ result = -EPERM;
+ break;
+ }
+ }
+
+ return result;
+}
+
void fjes_hw_set_irqmask(struct fjes_hw *hw,
enum REG_ICTL_MASK intr_mask, bool mask)
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 2ee166a..d1321e8 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -34,11 +34,13 @@ struct fjes_hw;
#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
+ #define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */
#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002)
#define FJES_CMD_REQ_RES_CODE_NORMAL (0)
+ #define FJES_CMD_REQ_RES_CODE_BUSY (1)
#define EP_BUFFER_SIZE \
((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \ @@ -59,6 +61,9 @@ struct fjes_hw;
#define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
#define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE )))
+ #define FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN (8)
#define FJES_DEV_REQ_BUF_SIZE(maxep) \
FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( EP_BUFFER_SIZE , EP_BUFFER_SIZE ) @@ -266,7 +271,9 @@ int fjes_hw_init(struct fjes_hw *);
void fjes_hw_exit ( struct fjes_hw * );
int fjes_hw_reset ( struct fjes_hw * );
int fjes_hw_request_info ( struct fjes_hw * );
-
+ int fjes_hw_register_buff_addr ( struct fjes_hw * , int ,
+ struct ep_share_mem_info * );
+ int fjes_hw_unregister_buff_addr ( struct fjes_hw * , int );
void fjes_hw_init_command_registers ( struct fjes_hw * ,
struct fjes_device_command_param * );
void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 ); --
1.8.3.1
On Wed, 24 Jun 2015 11:55:34 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds hardware initialization routine to be
invoked at driver's .probe routine.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/Makefile | 2 +-
drivers/net/fjes/fjes.h | 2 +-
drivers/net/fjes/fjes_hw.c | 297 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 250 ++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_regs.h | 102 +++++++++++++++
5 files changed, 651 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/fjes/fjes_hw.c
create mode 100644 drivers/net/fjes/fjes_hw.h
create mode 100644 drivers/net/fjes/fjes_regs.h
diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile
index 98e59cb..a67f65d8 100644
--- a/drivers/net/fjes/Makefile
+++ b/drivers/net/fjes/Makefile @@ -27,5 +27,5 @@
obj-$(CONFIG_FUJITSU_ES) += fjes.o
- fjes-objs := fjes_main.o
+ fjes-objs := fjes_main.o fjes_hw.o
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 4622da1..15ded96 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -28,6 +28,6 @@
extern char fjes_driver_name [];
extern char fjes_driver_version [];
- extern u32 fjes_support_mtu [];
+ extern const u32 fjes_support_mtu [];
#endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
new file mode 100644
index 0000000..68ef4d3
--- /dev/null
+++ b/drivers/net/fjes/fjes_hw.c @@ -0,0 +1,297 @@
+ /*
+ * 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 "fjes_hw.h"
+ #include "fjes.h"
+
+ /* supported MTU list */
+ const u32 fjes_support_mtu [] = {
+ FJES_MTU_DEFINE ( 8 * 1024 ),
+ FJES_MTU_DEFINE ( 16 * 1024 ),
+ FJES_MTU_DEFINE ( 32 * 1024 ),
+ FJES_MTU_DEFINE ( 64 * 1024 ),
+ 0
+ };
+
+ u32 fjes_hw_rd32 ( struct fjes_hw * hw , u32 reg )
+ {
+ u8 * base = hw -> base ;
+ u32 value = 0 ;
+
+ value = readl ( & base [ reg ]);
+
+ return value ;
+ }
+
+ static u8 * fjes_hw_iomap ( struct fjes_hw * hw )
+ {
+ u8 * base ;
+
+ if ( ! request_mem_region ( hw -> hw_res . start , hw -> hw_res . size ,
+ fjes_driver_name )) {
+ pr_err ( "request_mem_region failed \n " );
+ return NULL ;
+ }
+
+ base = ( u8 * ) ioremap_nocache ( hw -> hw_res . start , hw -> hw_res . size );
+
+ return base ;
+ }
+
+ int fjes_hw_reset ( struct fjes_hw * hw )
+ {
+ int timeout ;
+ union REG_DCTL dctl ;
+
+ dctl . reg = 0 ;
+ dctl . bits . reset = 1 ;
+ wr32 ( XSCT_DCTL , dctl . reg );
+
+ timeout = FJES_DEVICE_RESET_TIMEOUT * 1000 ;
+ dctl . reg = rd32 ( XSCT_DCTL );
+ while (( dctl . bits . reset == 1 ) && ( timeout > 0 )) {
+ msleep ( 1000 );
+ dctl . reg = rd32 ( XSCT_DCTL );
+ timeout -= 1000 ;
+ }
+
+ return timeout > 0 ? 0 : - EIO ;
+ }
+
+ static int fjes_hw_get_max_epid ( struct fjes_hw * hw )
+ {
+ union REG_MAX_EP info ;
+
+ info . reg = rd32 ( XSCT_MAX_EP );
+
+ return info . bits . maxep ;
+ }
+
+ static int fjes_hw_get_my_epid ( struct fjes_hw * hw )
+ {
+ union REG_OWNER_EPID info ;
+
+ info . reg = rd32 ( XSCT_OWNER_EPID );
+
+ return info . bits . epid ;
+ }
+
+ static int fjes_hw_alloc_shared_status_region ( struct fjes_hw * hw )
+ {
+ size_t size ;
+
+ size = sizeof ( struct fjes_device_shared_info ) +
+ ( sizeof ( u8 ) * hw -> max_epid );
+ hw -> hw_info . share = kzalloc ( size , GFP_KERNEL );
+ if ( ! hw -> hw_info . share )
+ return - ENOMEM ;
+
+ hw -> hw_info . share -> epnum = hw -> max_epid ;
+
+ return 0 ;
+ }
+
+ static int fjes_hw_alloc_epbuf ( struct epbuf_handler * epbh )
+ {
+ void * mem ;
+
+ mem = vzalloc ( EP_BUFFER_SIZE );
+ if ( ! mem )
+ return - ENOMEM ;
+
+ epbh -> buffer = mem ;
+ epbh -> size = EP_BUFFER_SIZE ;
+
+ epbh -> info = ( union ep_buffer_info * ) mem ;
+ epbh -> ring = ( u8 * )( mem + sizeof ( union ep_buffer_info ));
+
+ return 0 ;
+ }
+
+ void fjes_hw_setup_epbuf ( struct epbuf_handler * epbh , u8 * mac_addr , u32 mtu )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+ u16 vlan_id [ EP_BUFFER_SUPPORT_VLAN_MAX ];
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ )
+ vlan_id [ i ] = info -> v1i . vlan_id [ i ];
+
+ memset ( info , 0 , sizeof ( union ep_buffer_info ));
+
+ info -> v1i . version = 0 ; /* version 0 */
+
+ for ( i = 0 ; i < ETH_ALEN ; i ++ )
+ info -> v1i . mac_addr [ i ] = mac_addr [ i ];
+
+ info -> v1i . head = 0 ;
+ info -> v1i . tail = 1 ;
+
+ info -> v1i . info_size = sizeof ( union ep_buffer_info );
+ info -> v1i . buffer_size = epbh -> size - info -> v1i . info_size ;
+
+ info -> v1i . frame_max = FJES_MTU_TO_FRAME_SIZE ( mtu );
+ info -> v1i . count_max =
+ EP_RING_NUM ( info -> v1i . buffer_size , info -> v1i . frame_max );
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ )
+ info -> v1i . vlan_id [ i ] = vlan_id [ i ];
+ }
+
+ void
+ fjes_hw_init_command_registers ( struct fjes_hw * hw ,
+ struct fjes_device_command_param * param )
+ {
+ /* Request Buffer length */
+ wr32 ( XSCT_REQBL , ( __le32 )( param -> req_len ));
+ /* Response Buffer Length */
+ wr32 ( XSCT_RESPBL , ( __le32 )( param -> res_len ));
+
+ /* Request Buffer Address */
+ wr32 ( XSCT_REQBAL ,
+ ( __le32 )( param -> req_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_REQBAH ,
+ ( __le32 )(( param -> req_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+
+ /* Response Buffer Address */
+ wr32 ( XSCT_RESPBAL ,
+ ( __le32 )( param -> res_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_RESPBAH ,
+ ( __le32 )(( param -> res_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+
+ /* Share status address */
+ wr32 ( XSCT_SHSTSAL ,
+ ( __le32 )( param -> share_start & GENMASK_ULL ( 31 , 0 )));
+ wr32 ( XSCT_SHSTSAH ,
+ ( __le32 )(( param -> share_start & GENMASK_ULL ( 63 , 32 )) >> 32 ));
+ }
+
+ static int fjes_hw_setup ( struct fjes_hw * hw )
+ {
+ int epidx ;
+ void * buf ;
+ struct ep_share_mem_info * buf_pair ;
+ size_t mem_size ;
+ int result ;
+ u8 mac [ ETH_ALEN ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+ struct fjes_device_command_param param ;
+
+ hw -> hw_info . max_epid = & hw -> max_epid ;
+ hw -> hw_info . my_epid = & hw -> my_epid ;
+
+ buf =
+ kcalloc ( hw -> max_epid ,
+ sizeof ( struct ep_share_mem_info ), GFP_KERNEL );
+ if ( ! buf )
+ return - ENOMEM ;
+
+ hw -> ep_shm_info = ( struct ep_share_mem_info * ) buf ;
+
+ mem_size = FJES_DEV_REQ_BUF_SIZE ( hw -> max_epid );
+ hw -> hw_info . req_buf = kzalloc ( mem_size , GFP_KERNEL );
+ if ( ! ( hw -> hw_info . req_buf ))
+ return - ENOMEM ;
+
+ hw -> hw_info . req_buf_size = mem_size ;
+
+ mem_size = FJES_DEV_RES_BUF_SIZE ( hw -> max_epid );
+ hw -> hw_info . res_buf = kzalloc ( mem_size , GFP_KERNEL );
+ if ( ! ( hw -> hw_info . res_buf ))
+ return - ENOMEM ;
+
+ hw -> hw_info . res_buf_size = mem_size ;
+
+ result = fjes_hw_alloc_shared_status_region ( hw );
+ if ( result )
+ return result ;
+
+ hw -> hw_info . buffer_share_bit = 0 ;
+ hw -> hw_info . buffer_unshare_reserve_bit = 0 ;
+
+ for ( epidx = 0 ; epidx < hw -> max_epid ; epidx ++ ) { + if (epidx != hw->my_epid) {
How about use the following condition so that you can delete a indent.
if (epidx == hw->my_epid)
continue;
Thanks,
Yasuaki Ishimatsu
quoted hunk + buf_pair = &hw->ep_shm_info[epidx];
+
+ result = fjes_hw_alloc_epbuf(&buf_pair->tx);
+ if (result)
+ return result;
+
+ result = fjes_hw_alloc_epbuf(&buf_pair->rx);
+ if (result)
+ return result;
+
+ fjes_hw_setup_epbuf(&buf_pair->tx, mac,
+ fjes_support_mtu[0]);
+ fjes_hw_setup_epbuf(&buf_pair->rx, mac,
+ fjes_support_mtu[0]);
+ }
+ }
+
+ memset(¶m, 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, ¶m);
+
+ return 0;
+}
+
+int fjes_hw_init(struct fjes_hw *hw)
+{
+ int ret;
+
+ hw->base = fjes_hw_iomap(hw);
+ if (!hw->base)
+ return -EIO;
+
+ ret = fjes_hw_reset(hw);
+ if (ret)
+ return ret;
+
+ fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);
+
+ mutex_init(&hw->hw_info.lock);
+
+ hw->max_epid = fjes_hw_get_max_epid(hw);
+ hw->my_epid = fjes_hw_get_my_epid(hw);
+
+ if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid))
+ return -ENXIO;
+
+ ret = fjes_hw_setup(hw);
+
+ return ret;
+}
+
+void fjes_hw_set_irqmask(struct fjes_hw *hw,
+ enum REG_ICTL_MASK intr_mask, bool mask)
+{
+ if (mask)
+ wr32(XSCT_IMS, intr_mask);
+ else
+ wr32(XSCT_IMC, intr_mask);
+}
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
new file mode 100644
index 0000000..6c53f8b
--- /dev/null
+++ b/drivers/net/fjes/fjes_hw.h @@ -0,0 +1,250 @@
+ /*
+ * 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" .
+ *
+ */
+
+ #ifndef FJES_HW_H_
+ #define FJES_HW_H_
+
+ #include <linux/netdevice.h>
+ #include <linux/if_vlan.h>
+
+ #include "fjes_regs.h"
+
+ struct fjes_hw ;
+
+ #define EP_BUFFER_SUPPORT_VLAN_MAX 4
+ #define EP_BUFFER_INFO_SIZE 4096
+
+ #define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
+
+ #define EP_BUFFER_SIZE \
+ ((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \
+ / EP_BUFFER_INFO_SIZE ) * EP_BUFFER_INFO_SIZE )
+
+ #define EP_RING_NUM(buffer_size, frame_size) \
+ ( u32 )(( buffer_size ) / ( frame_size ))
+
+ #define FJES_MTU_TO_BUFFER_SIZE(mtu) \
+ ( ETH_HLEN + VLAN_HLEN + ( mtu ) + ETH_FCS_LEN )
+ #define FJES_MTU_TO_FRAME_SIZE(mtu) \
+ ( sizeof ( struct esmem_frame ) + FJES_MTU_TO_BUFFER_SIZE ( mtu ))
+ #define FJES_MTU_DEFINE(size) \
+ (( size ) - sizeof ( struct esmem_frame ) - \
+ ( ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN ))
+
+ #define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
+ #define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
+ ( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE )))
+
+ #define FJES_DEV_REQ_BUF_SIZE(maxep) \
+ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( EP_BUFFER_SIZE , EP_BUFFER_SIZE )
+ #define FJES_DEV_RES_BUF_SIZE(maxep) \
+ FJES_DEV_COMMAND_INFO_RES_LEN ( maxep )
+
+ /* Frame & MTU */
+ struct esmem_frame {
+ __le32 frame_size ;
+ u8 frame_data [];
+ };
+
+ /* shared status region */
+ struct fjes_device_shared_info {
+ int epnum ;
+ u8 ep_status [];
+ };
+
+ /* structures for command control request data*/
+ union fjes_device_command_req {
+ struct {
+ __le32 length ;
+ } info ;
+ struct {
+ __le32 length ;
+ __le32 epid ;
+ __le64 buffer [];
+ } share_buffer ;
+ struct {
+ __le32 length ;
+ __le32 epid ;
+ } unshare_buffer ;
+ struct {
+ __le32 length ;
+ __le32 mode ;
+ __le64 buffer_len ;
+ __le64 buffer [];
+ } start_trace ;
+ struct {
+ __le32 length ;
+ } stop_trace ;
+ };
+
+ /* structures for command control response data */
+ union fjes_device_command_res {
+ struct {
+ __le32 length ;
+ __le32 code ;
+ struct {
+ u8 es_status ;
+ u8 zone ;
+ } info [];
+ } info ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } share_buffer ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } unshare_buffer ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } start_trace ;
+ struct {
+ __le32 length ;
+ __le32 code ;
+ } stop_trace ;
+ };
+
+ /* parameter for command control */
+ struct fjes_device_command_param {
+ u32 req_len ;
+ phys_addr_t req_start ;
+ u32 res_len ;
+ phys_addr_t res_start ;
+ phys_addr_t share_start ;
+ };
+
+ /* EP buffer information */
+ union ep_buffer_info {
+ u8 raw [ EP_BUFFER_INFO_SIZE ];
+
+ struct _ep_buffer_info_common_t {
+ u32 version ;
+ } common ;
+
+ struct _ep_buffer_info_v1_t {
+ u32 version ;
+ u32 info_size ;
+
+ u32 buffer_size ;
+ u16 count_max ;
+
+ u16 _rsv_1 ;
+
+ u32 frame_max ;
+ u8 mac_addr [ ETH_ALEN ];
+
+ u16 _rsv_2 ;
+ u32 _rsv_3 ;
+
+ u16 tx_status ;
+ u16 rx_status ;
+
+ u32 head ;
+ u32 tail ;
+
+ u16 vlan_id [ EP_BUFFER_SUPPORT_VLAN_MAX ];
+
+ } v1i ;
+
+ };
+
+ /* buffer pair for Extended Partition */
+ struct ep_share_mem_info {
+ struct epbuf_handler {
+ void * buffer ;
+ size_t size ;
+ union ep_buffer_info * info ;
+ u8 * ring ;
+ } tx , rx ;
+
+ struct rtnl_link_stats64 net_stats ;
+
+ u16 tx_status_work ;
+
+ u8 es_status ;
+ u8 zone ;
+ };
+
+ struct es_device_trace {
+ u32 record_num ;
+ u32 current_record ;
+ u32 status_flag ;
+ u32 _rsv ;
+
+ struct {
+ u16 epid ;
+ u16 dir_offset ;
+ u32 data ;
+ u64 tsc ;
+ } record [];
+ };
+
+ struct fjes_hw_info {
+ struct fjes_device_shared_info * share ;
+ union fjes_device_command_req * req_buf ;
+ u64 req_buf_size ;
+ union fjes_device_command_res * res_buf ;
+ u64 res_buf_size ;
+
+ int * my_epid ;
+ int * max_epid ;
+
+ struct es_device_trace * trace ;
+ u64 trace_size ;
+
+ struct mutex lock ; /* buffer lock*/
+
+ unsigned long buffer_share_bit ;
+ unsigned long buffer_unshare_reserve_bit ;
+ };
+
+ struct fjes_hw {
+ void * back ;
+
+ unsigned long txrx_stop_req_bit ;
+ unsigned long epstop_req_bit ;
+
+ int my_epid ;
+ int max_epid ;
+
+ struct ep_share_mem_info * ep_shm_info ;
+
+ struct fjes_hw_resource {
+ u64 start ;
+ u64 size ;
+ int irq ;
+ } hw_res ;
+
+ u8 * base ;
+
+ struct fjes_hw_info hw_info ;
+ };
+
+ int fjes_hw_init ( struct fjes_hw * );
+ int fjes_hw_reset ( struct fjes_hw * );
+
+ void fjes_hw_init_command_registers ( struct fjes_hw * ,
+ struct fjes_device_command_param * );
+ void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 );
+ void fjes_hw_set_irqmask ( struct fjes_hw * , enum REG_ICTL_MASK , bool );
+
+ #endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h
new file mode 100644
index 0000000..4d0e071
--- /dev/null
+++ b/drivers/net/fjes/fjes_regs.h @@ -0,0 +1,102 @@
+ /*
+ * 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" .
+ *
+ */
+
+ #ifndef FJES_REGS_H_
+ #define FJES_REGS_H_
+
+ #include <linux/bitops.h>
+
+ #define XSCT_DEVICE_REGISTER_SIZE 0x1000
+
+ /* register offset */
+ /* Information registers */
+ #define XSCT_OWNER_EPID 0x0000 /* Owner EPID */
+ #define XSCT_MAX_EP 0x0004 /* Maximum EP */
+
+ /* Device Control registers */
+ #define XSCT_DCTL 0x0010 /* Device Control */
+
+ /* Command Control registers */
+ #define XSCT_SHSTSAL 0x0028 /* Share status address Low */
+ #define XSCT_SHSTSAH 0x002C /* Share status address High */
+
+ #define XSCT_REQBL 0x0034 /* Request Buffer length */
+ #define XSCT_REQBAL 0x0038 /* Request Buffer Address Low */
+ #define XSCT_REQBAH 0x003C /* Request Buffer Address High */
+
+ #define XSCT_RESPBL 0x0044 /* Response Buffer Length */
+ #define XSCT_RESPBAL 0x0048 /* Response Buffer Address Low */
+ #define XSCT_RESPBAH 0x004C /* Response Buffer Address High */
+
+ /* Interrupt Control registers */
+ #define XSCT_IMS 0x0084 /* Interrupt mask set */
+ #define XSCT_IMC 0x0088 /* Interrupt mask clear */
+
+ /* register structure */
+ /* Information registers */
+ union REG_OWNER_EPID {
+ struct {
+ __le32 epid : 16 ;
+ __le32 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ union REG_MAX_EP {
+ struct {
+ __le32 maxep : 16 ;
+ __le32 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ /* Device Control registers */
+ union REG_DCTL {
+ struct {
+ __le32 reset : 1 ;
+ __le32 rsv0 : 15 ;
+ __le32 rsv1 : 16 ;
+ } bits ;
+ __le32 reg ;
+ };
+
+ enum REG_ICTL_MASK {
+ REG_ICTL_MASK_INFO_UPDATE = 1 << 20 ,
+ REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19 ,
+ REG_ICTL_MASK_TXRX_STOP_REQ = 1 << 18 ,
+ REG_ICTL_MASK_TXRX_STOP_DONE = 1 << 17 ,
+ REG_ICTL_MASK_RX_DATA = 1 << 16 ,
+ REG_ICTL_MASK_ALL = GENMASK ( 20 , 16 ),
+ };
+
+ struct fjes_hw ;
+
+ u32 fjes_hw_rd32 ( struct fjes_hw * hw , u32 reg );
+
+ #define wr32(reg, val) \
+ do { \
+ u8 * base = hw -> base ; \
+ writel (( val ), & base [( reg )]); \
+ } while ( 0 )
+
+ #define rd32(reg) (fjes_hw_rd32(hw, reg))
+
+ #endif /* FJES_REGS_H_ */ --
1.8.3.1
On Wed, 24 Jun 2015 11:55:38 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds buffer address regist/unregistration routine.
This function is mainly invoked when network device's
activation (open) and deactivation (close)
in order to retist/unregist shared buffer address.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 187 +++++++++++++++++++++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 9 ++-
2 files changed, 195 insertions(+), 1 deletion(-)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 1ffa62e..4451e70 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -453,6 +453,193 @@ int fjes_hw_request_info(struct fjes_hw *hw)
return result ;
}
+ int fjes_hw_register_buff_addr ( struct fjes_hw * hw , int dest_epid ,
+ struct ep_share_mem_info * buf_pair )
+ {
+ union fjes_device_command_req * req_buf = hw -> hw_info . req_buf ;
+ union fjes_device_command_res * res_buf = hw -> hw_info . res_buf ;
+ enum fjes_dev_command_response_e ret ;
+ int i , idx ;
+ int page_count ;
+ void * addr ;
+ int timeout ;
+ int result ;
+
+ if ( test_bit ( dest_epid , & hw -> hw_info . buffer_share_bit ))
+ return 0 ;
+
+ memset ( req_buf , 0 , hw -> hw_info . req_buf_size );
+ memset ( res_buf , 0 , hw -> hw_info . res_buf_size );
+
+ req_buf -> share_buffer . length =
+ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( buf_pair -> tx . size ,
+ buf_pair -> rx . size );
+ req_buf -> share_buffer . epid = dest_epid ;
+
+ idx = 0 ;
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> tx . size ;
+ page_count = buf_pair -> tx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> tx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+
+ req_buf -> share_buffer . buffer [ idx ++ ] = buf_pair -> rx . size ;
+ page_count = buf_pair -> rx . size / EP_BUFFER_INFO_SIZE ;
+ for ( i = 0 ; i < page_count ; i ++ ) {
+ addr = (( u8 * )( buf_pair -> rx . buffer )) +
+ ( i * EP_BUFFER_INFO_SIZE );
+ req_buf -> share_buffer . buffer [ idx ++ ] =
+ ( __le64 )( page_to_phys ( vmalloc_to_page ( addr )) +
+ offset_in_page ( addr ));
+ }
+ + res_buf->share_buffer.length = 0;
+ res_buf->share_buffer.code = 0;
+
+ ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_SHARE_BUFFER);
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000;
+ while ((ret == FJES_CMD_STATUS_NORMAL) &&
+ (res_buf->share_buffer.length ==
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN) &&
+ (res_buf->share_buffer.code == FJES_CMD_REQ_RES_CODE_BUSY) &&
+ (timeout > 0)) {
+ msleep(200 + hw->my_epid * 20);
+ timeout -= (200 + hw->my_epid * 20);
+
+ res_buf->share_buffer.length = 0;
+ res_buf->share_buffer.code = 0;
+
+ ret =
+ fjes_hw_issue_request_command(hw,
+ FJES_CMD_REQ_SHARE_BUFFER);
+ }
+
+ result = 0;
+
+ if (res_buf->share_buffer.length !=
+ FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN)
+ result = -ENOMSG;
+ else if (ret == FJES_CMD_STATUS_NORMAL) {
+ switch (res_buf->share_buffer.code) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL:
+ result = 0;
+ set_bit(dest_epid, &hw->hw_info.buffer_share_bit);
+ break;
+ case FJES_CMD_REQ_RES_CODE_BUSY:
+ result = -EBUSY;
+ break;
+ default:
+ result = -EPERM;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case FJES_CMD_STATUS_UNKNOWN:
+ result = -EPERM;
+ break;
+ case FJES_CMD_STATUS_TIMEOUT:
+ result = -EBUSY;
+ break;
+ case FJES_CMD_STATUS_ERROR_PARAM:
+ case FJES_CMD_STATUS_ERROR_STATUS:
+ default:
+ result = -EPERM;
+ break;
+ }
+ }
+
+ return result;
fjes_hw_unregister_buff_addr() has same implemetation.
How about preparing new function to unify them?
Thanks,
Yasuaki Ishimatsu
quoted hunk +}
+
+int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)
+{
+ union fjes_device_command_req *req_buf = hw->hw_info.req_buf;
+ union fjes_device_command_res *res_buf = hw->hw_info.res_buf;
+ struct fjes_device_shared_info *share = hw->hw_info.share;
+ enum fjes_dev_command_response_e ret;
+ int result;
+ int timeout;
+
+ if (!hw->base)
+ return -EPERM;
+
+ if (!req_buf || !res_buf || !share)
+ return -EPERM;
+
+ if (!test_bit(dest_epid, &hw->hw_info.buffer_share_bit))
+ return 0;
+
+ memset(req_buf, 0, hw->hw_info.req_buf_size);
+ memset(res_buf, 0, hw->hw_info.res_buf_size);
+
+ req_buf->unshare_buffer.length =
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN;
+ req_buf->unshare_buffer.epid = dest_epid;
+
+ res_buf->unshare_buffer.length = 0;
+ res_buf->unshare_buffer.code = 0;
+
+ ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER);
+
+ timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000;
+ while ((ret == FJES_CMD_STATUS_NORMAL) &&
+ (res_buf->unshare_buffer.length ==
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) &&
+ (res_buf->unshare_buffer.code ==
+ FJES_CMD_REQ_RES_CODE_BUSY) &&
+ (timeout > 0)) {
+ msleep(200 + hw->my_epid * 20);
+ timeout -= (200 + hw->my_epid * 20);
+
+ res_buf->unshare_buffer.length = 0;
+ res_buf->unshare_buffer.code = 0;
+
+ ret =
+ fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER);
+ }
+
+ result = 0;
+
+ if (res_buf->unshare_buffer.length !=
+ FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) {
+ result = -ENOMSG;
+ } else if (ret == FJES_CMD_STATUS_NORMAL) {
+ switch (res_buf->unshare_buffer.code) {
+ case FJES_CMD_REQ_RES_CODE_NORMAL:
+ result = 0;
+ clear_bit(dest_epid, &hw->hw_info.buffer_share_bit);
+ break;
+ case FJES_CMD_REQ_RES_CODE_BUSY:
+ result = -EBUSY;
+ break;
+ default:
+ result = -EPERM;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case FJES_CMD_STATUS_UNKNOWN:
+ result = -EPERM;
+ break;
+ case FJES_CMD_STATUS_TIMEOUT:
+ result = -EBUSY;
+ break;
+ case FJES_CMD_STATUS_ERROR_PARAM:
+ case FJES_CMD_STATUS_ERROR_STATUS:
+ default:
+ result = -EPERM;
+ break;
+ }
+ }
+
+ return result;
+}
+
void fjes_hw_set_irqmask(struct fjes_hw *hw,
enum REG_ICTL_MASK intr_mask, bool mask)
{ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 2ee166a..d1321e8 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -34,11 +34,13 @@ struct fjes_hw;
#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
+ #define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */
#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002)
#define FJES_CMD_REQ_RES_CODE_NORMAL (0)
+ #define FJES_CMD_REQ_RES_CODE_BUSY (1)
#define EP_BUFFER_SIZE \
((( sizeof ( union ep_buffer_info ) + ( 128 * ( 64 * 1024 ))) \ @@ -59,6 +61,9 @@ struct fjes_hw;
#define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum))
#define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \
( 24 + ( 8 * (( txb ) / EP_BUFFER_INFO_SIZE + ( rxb ) / EP_BUFFER_INFO_SIZE )))
+ #define FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN (8)
+ #define FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN (8)
#define FJES_DEV_REQ_BUF_SIZE(maxep) \
FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN ( EP_BUFFER_SIZE , EP_BUFFER_SIZE ) @@ -266,7 +271,9 @@ int fjes_hw_init(struct fjes_hw *);
void fjes_hw_exit ( struct fjes_hw * );
int fjes_hw_reset ( struct fjes_hw * );
int fjes_hw_request_info ( struct fjes_hw * );
-
+ int fjes_hw_register_buff_addr ( struct fjes_hw * , int ,
+ struct ep_share_mem_info * );
+ int fjes_hw_unregister_buff_addr ( struct fjes_hw * , int );
void fjes_hw_init_command_registers ( struct fjes_hw * ,
struct fjes_device_command_param * );
void fjes_hw_setup_epbuf ( struct epbuf_handler * , u8 * , u32 ); --
1.8.3.1
Hi Izumi-san,
On Wed, 24 Jun 2015 11:55:40 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds net_device_ops.ndo_start_xmit callback,
which is called when sending packets.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 1 +
drivers/net/fjes/fjes_hw.c | 58 ++++++++++++++
drivers/net/fjes/fjes_hw.h | 12 +++
drivers/net/fjes/fjes_main.c | 177 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 248 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index f182ed3..7af4304 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -29,6 +29,7 @@
#define FJES_ACPI_SYMBOL "Extended Socket"
#define FJES_MAX_QUEUES 1
#define FJES_TX_RETRY_INTERVAL (20 * HZ)
+ #define FJES_TX_RETRY_TIMEOUT (100)
#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
/* board specific private data structure */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index a17cb96..b2e7509 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -793,3 +793,61 @@ int fjes_hw_wait_epstop(struct fjes_hw *hw)
return ( wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000 )
? 0 : - EBUSY ;
}
+
+ bool fjes_hw_check_epbuf_version ( struct epbuf_handler * epbh , u32 version )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ return ( info -> common . version == version );
+ }
+
+ bool fjes_hw_check_mtu ( struct epbuf_handler * epbh , u32 mtu )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+
+ return ( info -> v1i . frame_max == FJES_MTU_TO_FRAME_SIZE ( mtu ));
+ }
+
+ bool fjes_hw_check_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+ bool ret = false ;
+
+ if ( vlan_id == 0 ) {
+ ret = true ;
+ } else {
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ ) {
+ if ( vlan_id == info -> v1i . vlan_id [ i ]) {
+ ret = true ;
+ break ;
+ }
+ }
+ }
+ return ret ;
+ }
+
+ int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * epbh ,
+ void * frame , size_t size )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ struct esmem_frame * ring_frame ;
+
+ if ( EP_RING_FULL ( info -> v1i . head , info -> v1i . tail , info -> v1i . count_max ))
+ return - ENOBUFS ;
+
+ ring_frame =
+ ( struct esmem_frame * ) & ( epbh ->
+ ring [ EP_RING_INDEX
+ ( info -> v1i . tail - 1 ,
+ info -> v1i . count_max ) *
+ info -> v1i . frame_max ]);
+
+ ring_frame -> frame_size = size ;
+ memcpy (( void * )( ring_frame -> frame_data ), ( void * ) frame , size );
+
+ EP_RING_INDEX_INC ( epbh -> info -> v1i . tail , info -> v1i . count_max );
+
+ return 0 ;
+ }
+ diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 823d802..95b9732 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -49,6 +49,9 @@ struct fjes_hw;
#define FJES_ZONING_ZONE_TYPE_NONE (0xFF)
+ #define FJES_TX_DELAY_SEND_NONE (0)
+ #define FJES_TX_DELAY_SEND_PENDING (1)
+
#define FJES_RX_STOP_REQ_NONE (0x0)
#define FJES_RX_STOP_REQ_DONE (0x1)
#define FJES_RX_STOP_REQ_REQUEST (0x2) @@ -60,6 +63,11 @@ struct fjes_hw;
#define EP_RING_NUM(buffer_size, frame_size) \
( u32 )(( buffer_size ) / ( frame_size ))
+ #define EP_RING_INDEX(_num, _max) (((_num) + (_max)) % (_max))
+ #define EP_RING_INDEX_INC(_num, _max) \
+ (( _num ) = EP_RING_INDEX (( _num ) + 1 , ( _max )))
+ #define EP_RING_FULL(_head, _tail, _max) \
+ ( 0 == EP_RING_INDEX ((( _tail ) - ( _head )), ( _max )))
#define FJES_MTU_TO_BUFFER_SIZE(mtu) \
( ETH_HLEN + VLAN_HLEN + ( mtu ) + ETH_FCS_LEN ) @@ -308,5 +316,9 @@ enum ep_partner_status
bool fjes_hw_epid_is_same_zone ( struct fjes_hw * , int );
int fjes_hw_epid_is_shared ( struct fjes_device_shared_info * , int );
+ bool fjes_hw_check_epbuf_version ( struct epbuf_handler * , u32 );
+ bool fjes_hw_check_mtu ( struct epbuf_handler * , u32 );
+ bool fjes_hw_check_vlan_id ( struct epbuf_handler * , u16 );
+ int fjes_hw_epbuf_tx_pkt_send ( struct epbuf_handler * , void * , size_t );
#endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 832439b..f2ef286 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -51,6 +51,7 @@ 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 * );
+ static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
static irqreturn_t fjes_intr ( int , void * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -215,6 +216,7 @@ static void fjes_free_irq(struct fjes_adapter *adapter)
static const struct net_device_ops fjes_netdev_ops = {
. ndo_open = fjes_open ,
. ndo_stop = fjes_close ,
+ . ndo_start_xmit = fjes_xmit_frame ,
};
/* fjes_open - Called when a network interface is made active */ @@ -405,6 +407,181 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
}
}
+ 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 ;
+
+ 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 ;
+ enum ep_partner_status pstatus ;
+
+ int len ;
+ char * data , shortpkt [ VLAN_ETH_HLEN ];
+
+ u16 queue_no = 0 ;
+ struct netdev_queue * cur_queue = netdev_get_tx_queue ( netdev , queue_no );
+ netdev_tx_t ret = NETDEV_TX_OK ;
+ struct ethhdr * eth ;
+ int dest_epid ;
+
+ int max_epid , my_epid ;
+ u16 vlan_id = 0 ;
+ bool vlan = false ;
+ bool is_multi = false ;
+
+ 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;
There are same codes in the fjes_xmit_frame().
How about create a new function to unify them?
+ }
+ } 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) {
+ 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;
+ hw->ep_shm_info[my_epid].net_stats
+ .tx_carrier_errors += 1;
+
+ 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;
+ hw->ep_shm_info[my_epid].net_stats.tx_dropped += 1;
+ adapter->stats64.tx_errors += 1;
+ hw->ep_shm_info[my_epid].net_stats.tx_errors += 1;
There are same codes in the fjes_xmit_frame().
How about create a new function to unify them?
+
+ ret = NETDEV_TX_OK;
+ } else if (vlan &&
+ !fjes_hw_check_vlan_id(
+ &adapter->hw.ep_shm_info[dest_epid].rx,
+ vlan_id)) {
+ 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;
+ hw->ep_shm_info[my_epid].net_stats
+ .tx_fifo_errors += 1;
+ adapter->stats64.tx_errors += 1;
+ hw->ep_shm_info[my_epid].net_stats
+ .tx_errors += 1;
+
+ ret = NETDEV_TX_OK;
+ } else {
+ netdev->trans_start = jiffies;
+ netif_tx_stop_queue(cur_queue);
+ + ret = NETDEV_TX_BUSY;
Even if ret set NETDEV_TX_BUSY, it may be changed to NETDEV_TX_OK
in the for loop. Is it OK?
+ }
+ } else {
+ if (!is_multi) {
+ 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;
+ }
+
+ 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; adapter->stats64.tx_bytes +=len?
Thanks,
Yasuaki Ishimatsu
+ hw->ep_shm_info[my_epid].net_stats.tx_bytes += len;
+ }
+ }
+
+ return ret;
+}
+
static irqreturn_t fjes_intr(int irq, void *data)
{
struct fjes_adapter *adapter = data;
--
1.8.3.1
Hi Izum-san,
On Wed, 24 Jun 2015 11:55:42 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds tx_stall_task.
When receiver's buffer is full, sender stops
its tx queue. This task is used to monitor
receiver's status and when receiver's buffer
is avairable, it resumes tx queue.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 2 ++
drivers/net/fjes/fjes_main.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 8e9899e..b04ea9d 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -30,6 +30,7 @@
#define FJES_MAX_QUEUES 1
#define FJES_TX_RETRY_INTERVAL (20 * HZ)
#define FJES_TX_RETRY_TIMEOUT (100)
+ #define FJES_TX_TX_STALL_TIMEOUT (FJES_TX_RETRY_INTERVAL / 2)
#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
/* board specific private data structure */ @@ -52,6 +53,7 @@ struct fjes_adapter {
struct workqueue_struct * txrx_wq ;
+ struct work_struct tx_stall_task ;
struct work_struct raise_intr_rxdata_task ;
struct fjes_hw hw ; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 735aa5e..f4c2445 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -53,6 +53,7 @@ static int fjes_setup_resources(struct fjes_adapter *);
static void fjes_free_resources ( struct fjes_adapter * );
static netdev_tx_t fjes_xmit_frame ( struct sk_buff * , struct net_device * );
static void fjes_raise_intr_rxdata_task ( struct work_struct * );
+ static void fjes_tx_stall_task ( struct work_struct * );
static irqreturn_t fjes_intr ( int , void * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -281,6 +282,7 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
+ cancel_work_sync ( & adapter -> tx_stall_task );
fjes_hw_wait_epstop ( hw );
@@ -410,6 +412,61 @@ static void fjes_free_resources(struct fjes_adapter *adapter)
}
}
+ static void fjes_tx_stall_task ( struct work_struct * work )
+ {
+ struct fjes_adapter * adapter = container_of ( work ,
+ struct fjes_adapter , tx_stall_task );
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+ enum ep_partner_status pstatus ;
+ int epid ;
+ int max_epid , my_epid ;
+ union ep_buffer_info * info ;
+ int all_queue_available ;
+ int i ;
+ int sendable ;
+
+ if ((( long ) jiffies -
+ ( long )( netdev -> trans_start )) > FJES_TX_TX_STALL_TIMEOUT ) {
+ netif_wake_queue ( netdev );
+ return ;
+ }
+
+ my_epid = hw -> my_epid ;
+ max_epid = hw -> max_epid ;
+ + for (i = 0; i < 5; i++) {
Why do you loop 5 times?
Thanks,
Yasuaki Ishimatsu
quoted hunk + 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;
+
+ 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);
+}
+
static void fjes_raise_intr_rxdata_task(struct work_struct *work)
{
struct fjes_adapter *adapter = container_of(work, @@ -606,6 +663,10 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
netif_tx_stop_queue(cur_queue);
+ if (!work_pending(&adapter->tx_stall_task))
+ queue_work(adapter->txrx_wq,
+ &adapter->tx_stall_task);
+
ret = NETDEV_TX_BUSY;
}
} else { @@ -690,6 +751,7 @@ static int fjes_probe(struct platform_device *plat_dev)
adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx");
+ INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task);
INIT_WORK(&adapter->raise_intr_rxdata_task,
fjes_raise_intr_rxdata_task);
@@ -734,6 +796,7 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_hw *hw = &adapter->hw;
cancel_work_sync(&adapter->raise_intr_rxdata_task);
+ cancel_work_sync(&adapter->tx_stall_task);
if (adapter->txrx_wq)
destroy_workqueue(adapter->txrx_wq);
--
1.8.3.1
Hi Izumi-san,
On Wed, 24 Jun 2015 11:55:47 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds net_device_ops.ndo_vlan_rx_add_vid and
net_device_ops.ndo_vlan_rx_kill_vid callback.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes_hw.c | 27 +++++++++++++++++++++++++++
drivers/net/fjes/fjes_hw.h | 2 ++
drivers/net/fjes/fjes_main.c | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 5e3f847..8363e22 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c @@ -827,6 +827,33 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id)
return ret ;
}
+ bool fjes_hw_set_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+
+ for ( i = 0 ; i < EP_BUFFER_SUPPORT_VLAN_MAX ; i ++ ) {
+ if ( info -> v1i . vlan_id [ i ] == 0 ) {
+ info -> v1i . vlan_id [ i ] = vlan_id ;
+ return true ;
+ }
+ }
+ return false ;
+ }
+
+ void fjes_hw_del_vlan_id ( struct epbuf_handler * epbh , u16 vlan_id )
+ {
+ union ep_buffer_info * info = epbh -> info ;
+ int i ;
+ + if (0 != vlan_id) {
How about using the following if statement so than you can delete
indent?
if (vlan_id == 0)
return;
quoted hunk + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) {
+ if (vlan_id == info->v1i.vlan_id[i])
+ info->v1i.vlan_id[i] = 0;
+ }
+ }
+}
+
bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *epbh)
{
union ep_buffer_info *info = epbh->info; diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index ea30aeb..afad03e 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h @@ -321,6 +321,8 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int);
bool fjes_hw_check_epbuf_version ( struct epbuf_handler * , u32 );
bool fjes_hw_check_mtu ( struct epbuf_handler * , u32 );
bool fjes_hw_check_vlan_id ( struct epbuf_handler * , u16 );
+ bool fjes_hw_set_vlan_id ( struct epbuf_handler * , u16 );
+ void fjes_hw_del_vlan_id ( struct epbuf_handler * , u16 );
bool fjes_hw_epbuf_rx_is_empty ( struct epbuf_handler * );
void * fjes_hw_epbuf_rx_curpkt_get_addr ( struct epbuf_handler * , size_t * );
void fjes_hw_epbuf_rx_curpkt_drop ( struct epbuf_handler * ); diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index e2e69e0..bb4c8e4 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -58,6 +58,8 @@ static irqreturn_t fjes_intr(int, void*);
static struct rtnl_link_stats64 *
fjes_get_stats64 ( struct net_device * , struct rtnl_link_stats64 * );
static int fjes_change_mtu ( struct net_device * , int );
+ 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 );
static void fjes_tx_retry ( struct net_device * );
static int fjes_acpi_add ( struct acpi_device * ); @@ -229,6 +231,8 @@ static const struct net_device_ops fjes_netdev_ops = {
. ndo_get_stats64 = fjes_get_stats64 ,
. ndo_change_mtu = fjes_change_mtu ,
. ndo_tx_timeout = fjes_tx_retry ,
+ . ndo_vlan_rx_add_vid = fjes_vlan_rx_add_vid ,
+ . ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid ,
};
/* fjes_open - Called when a network interface is made active */ @@ -757,6 +761,42 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu)
return - EINVAL ;
}
+ 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)
The function always returns 0. So how about defining the function
as void?
Thanks,
Ysauaki Ishimatsu
+{
+ 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;
+}
+
static irqreturn_t fjes_intr(int irq, void *data)
{
struct fjes_adapter *adapter = data;
--
1.8.3.1
Hi Izumi-san,
On Wed, 24 Jun 2015 11:55:50 +0900
Taku Izumi [off-list ref] wrote:
quoted hunk This patch adds unshare_watch_task.
Shared buffer's status can be changed into unshared.
This task is used to monitor shared buffer's status.
Signed-off-by: Taku Izumi <redacted>
---
drivers/net/fjes/fjes.h | 3 +
drivers/net/fjes/fjes_main.c | 130 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index d31d4c3..57feee8 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h @@ -59,6 +59,9 @@ struct fjes_adapter {
struct work_struct tx_stall_task ;
struct work_struct raise_intr_rxdata_task ;
+ struct work_struct unshare_watch_task ;
+ unsigned long unshare_watch_bitmask ;
+
struct delayed_work interrupt_watch_task ;
bool interrupt_watch_enable ;
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 1ddb9d3..69a238c 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c @@ -73,6 +73,7 @@ static int fjes_remove(struct platform_device *);
static int fjes_sw_init ( struct fjes_adapter * );
static void fjes_netdev_setup ( struct net_device * );
static void fjes_irq_watch_task ( struct work_struct * );
+ static void fjes_watch_unshare_task ( struct work_struct * );
static void fjes_rx_irq ( struct fjes_adapter * , int );
static int fjes_poll ( struct napi_struct * , int );
@@ -312,6 +313,8 @@ static int fjes_close(struct net_device *netdev)
fjes_free_irq ( adapter );
cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
+ cancel_work_sync ( & adapter -> unshare_watch_task );
+ adapter -> unshare_watch_bitmask = 0 ;
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
@@ -1032,6 +1035,8 @@ static int fjes_probe(struct platform_device *plat_dev)
INIT_WORK ( & adapter -> tx_stall_task , fjes_tx_stall_task );
INIT_WORK ( & adapter -> raise_intr_rxdata_task ,
fjes_raise_intr_rxdata_task );
+ INIT_WORK ( & adapter -> unshare_watch_task , fjes_watch_unshare_task );
+ adapter -> unshare_watch_bitmask = 0 ;
INIT_DELAYED_WORK ( & adapter -> interrupt_watch_task , fjes_irq_watch_task );
adapter -> interrupt_watch_enable = false ; @@ -1077,6 +1082,7 @@ static int fjes_remove(struct platform_device *plat_dev)
struct fjes_hw * hw = & adapter -> hw ;
cancel_delayed_work_sync ( & adapter -> interrupt_watch_task );
+ cancel_work_sync ( & adapter -> unshare_watch_task );
cancel_work_sync ( & adapter -> raise_intr_rxdata_task );
cancel_work_sync ( & adapter -> tx_stall_task );
if ( adapter -> control_wq ) @@ -1136,6 +1142,130 @@ static void fjes_irq_watch_task(struct work_struct *work)
}
}
+ static void fjes_watch_unshare_task ( struct work_struct * work )
+ {
+ struct fjes_adapter * adapter =
+ container_of ( work , struct fjes_adapter , unshare_watch_task );
+
+ struct fjes_hw * hw = & adapter -> hw ;
+ struct net_device * netdev = adapter -> netdev ;
+ int epidx ;
+ int max_epid , my_epid ;
+ unsigned long unshare_watch_bitmask ;
+ int wait_time = 0 ;
+ int is_shared ;
+ int stop_req , stop_req_done ;
+ int unshare_watch , unshare_reserve ;
+ 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);
+
+ fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx,
+ netdev->dev_addr, netdev->mtu);
+
+ clear_bit(epidx, &hw->txrx_stop_req_bit);
+ clear_bit(epidx, &unshare_watch_bitmask);
+ clear_bit(epidx,
+ &hw->hw_info.buffer_unshare_reserve_bit);
How about creating a new function? There are the same codes below.
Thanks,
Yasuaki Ishimatsu
+ }
+
+ 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);
+
+ fjes_hw_setup_epbuf(
+ &hw->ep_shm_info[epidx].tx,
+ netdev->dev_addr, netdev->mtu);
+
+ 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)) {
+ hw->ep_shm_info[epidx].tx.info->v1i.rx_status &=
+ ~FJES_RX_STOP_REQ_DONE;
+ }
+ }
+ }
+}
+
/* fjes_init_module - Driver Registration Routine */
static int __init fjes_init_module(void)
{
--
1.8.3.1