2017-11-07 16:58:41 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-01-21 05:24:15 +03:00
/*
* Greybus " AP " USB driver for " ES2 " controller chips
*
2015-03-27 05:25:06 +03:00
* Copyright 2014 - 2015 Google Inc .
* Copyright 2014 - 2015 Linaro Ltd .
2015-01-21 05:24:15 +03:00
*/
2015-03-27 13:38:07 +03:00
# include <linux/kthread.h>
2015-01-21 05:24:15 +03:00
# include <linux/sizes.h>
# include <linux/usb.h>
2015-03-27 13:38:07 +03:00
# include <linux/kfifo.h>
# include <linux/debugfs.h>
2016-07-07 15:41:00 +03:00
# include <linux/list.h>
2019-08-25 08:54:27 +03:00
# include <linux/greybus.h>
2015-04-07 12:27:20 +03:00
# include <asm/unaligned.h>
2015-01-21 05:24:15 +03:00
2016-08-10 13:58:41 +03:00
# include "arpc.h"
2019-08-25 08:54:29 +03:00
# include "greybus_trace.h"
2016-05-11 11:18:01 +03:00
2016-08-03 15:09:34 +03:00
2016-08-03 15:09:35 +03:00
/* Default timeout for USB vendor requests. */
# define ES2_USB_CTRL_TIMEOUT 500
2016-08-03 15:09:34 +03:00
/* Default timeout for ARPC CPort requests */
# define ES2_ARPC_CPORT_TIMEOUT 500
2016-05-11 11:18:01 +03:00
/* Fixed CPort numbers */
# define ES2_CPORT_CDSI0 16
# define ES2_CPORT_CDSI1 17
2015-10-28 06:18:37 +03:00
/* Memory sizes for the buffers sent to/from the ES2 controller */
# define ES2_GBUF_MSG_SIZE_MAX 2048
2015-01-21 05:24:15 +03:00
2016-07-07 15:41:00 +03:00
/* Memory sizes for the ARPC buffers */
2016-07-07 15:41:00 +03:00
# define ARPC_OUT_SIZE_MAX U16_MAX
2016-07-07 15:41:00 +03:00
# define ARPC_IN_SIZE_MAX 128
2015-01-21 05:24:15 +03:00
static const struct usb_device_id id_table [ ] = {
2015-10-23 02:40:41 +03:00
{ USB_DEVICE ( 0x18d1 , 0x1eaf ) } ,
2015-01-21 05:24:15 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2015-03-27 13:38:07 +03:00
# define APB1_LOG_SIZE SZ_16K
2015-01-21 05:24:15 +03:00
/*
* Number of CPort IN urbs in flight at any point in time .
* Adjust if we are having stalls in the USB buffer due to not enough urbs in
* flight .
*/
# define NUM_CPORT_IN_URB 4
/* Number of CPort OUT urbs in flight at any point in time.
* Adjust if we get messages saying we are out of urbs in the system log .
*/
2016-08-17 14:21:51 +03:00
# define NUM_CPORT_OUT_URB 8
2015-01-21 05:24:15 +03:00
2016-07-07 15:41:00 +03:00
/*
* Number of ARPC in urbs in flight at any point in time .
*/
# define NUM_ARPC_IN_URB 2
2015-06-15 19:08:12 +03:00
/*
* @ endpoint : bulk in endpoint for CPort data
* @ urb : array of urbs for the CPort in messages
* @ buffer : array of buffers for the @ cport_in_urb urbs
*/
2015-10-28 06:18:37 +03:00
struct es2_cport_in {
2015-06-15 19:08:12 +03:00
__u8 endpoint ;
struct urb * urb [ NUM_CPORT_IN_URB ] ;
u8 * buffer [ NUM_CPORT_IN_URB ] ;
} ;
2015-01-21 05:24:15 +03:00
/**
2021-04-15 08:43:38 +03:00
* struct es2_ap_dev - ES2 USB Bridge to AP structure
2015-01-21 05:24:15 +03:00
* @ usb_dev : pointer to the USB device we are .
* @ usb_intf : pointer to the USB interface we are bound to .
2015-11-03 20:03:23 +03:00
* @ hd : pointer to our gb_host_device structure
2021-04-15 08:43:38 +03:00
*
2015-06-15 19:08:12 +03:00
* @ cport_in : endpoint , urbs and buffer for cport in messages
2021-12-12 06:16:57 +03:00
* @ cport_out_endpoint : endpoint for cport out messages
2015-01-21 05:24:15 +03:00
* @ cport_out_urb : array of urbs for the CPort out messages
* @ cport_out_urb_busy : array of flags to see if the @ cport_out_urb is busy or
* not .
2015-07-01 13:37:21 +03:00
* @ cport_out_urb_cancelled : array of flags indicating whether the
* corresponding @ cport_out_urb is being cancelled
2015-01-21 05:24:15 +03:00
* @ cport_out_urb_lock : locks the @ cport_out_urb_busy " list "
2021-04-15 08:43:38 +03:00
* @ cdsi1_in_use : true if cport CDSI1 is in use
2015-10-28 06:18:41 +03:00
* @ apb_log_task : task pointer for logging thread
* @ apb_log_dentry : file system entry for the log file interface
* @ apb_log_enable_dentry : file system entry for enabling logging
* @ apb_log_fifo : kernel FIFO to carry logged data
2016-07-07 15:41:00 +03:00
* @ arpc_urb : array of urbs for the ARPC in messages
* @ arpc_buffer : array of buffers for the @ arpc_urb urbs
* @ arpc_endpoint_in : bulk in endpoint for APBridgeA RPC
2016-07-07 15:41:00 +03:00
* @ arpc_id_cycle : gives an unique id to ARPC
* @ arpc_lock : locks ARPC list
* @ arpcs : list of in progress ARPCs
2015-01-21 05:24:15 +03:00
*/
2015-10-28 06:18:37 +03:00
struct es2_ap_dev {
2015-01-21 05:24:15 +03:00
struct usb_device * usb_dev ;
struct usb_interface * usb_intf ;
2015-11-03 20:03:23 +03:00
struct gb_host_device * hd ;
2015-01-21 05:24:15 +03:00
2016-08-17 17:37:39 +03:00
struct es2_cport_in cport_in ;
2016-08-17 17:27:49 +03:00
__u8 cport_out_endpoint ;
2015-01-21 05:24:15 +03:00
struct urb * cport_out_urb [ NUM_CPORT_OUT_URB ] ;
bool cport_out_urb_busy [ NUM_CPORT_OUT_URB ] ;
2015-07-01 13:37:21 +03:00
bool cport_out_urb_cancelled [ NUM_CPORT_OUT_URB ] ;
2015-01-21 05:24:15 +03:00
spinlock_t cport_out_urb_lock ;
2015-06-15 19:08:14 +03:00
2016-05-11 11:18:04 +03:00
bool cdsi1_in_use ;
2015-10-28 06:18:41 +03:00
struct task_struct * apb_log_task ;
struct dentry * apb_log_dentry ;
struct dentry * apb_log_enable_dentry ;
DECLARE_KFIFO ( apb_log_fifo , char , APB1_LOG_SIZE ) ;
2016-07-07 15:41:00 +03:00
__u8 arpc_endpoint_in ;
struct urb * arpc_urb [ NUM_ARPC_IN_URB ] ;
u8 * arpc_buffer [ NUM_ARPC_IN_URB ] ;
2016-07-07 15:41:00 +03:00
int arpc_id_cycle ;
spinlock_t arpc_lock ;
struct list_head arpcs ;
2015-06-15 19:08:14 +03:00
} ;
2016-07-07 15:41:00 +03:00
struct arpc {
struct list_head list ;
struct arpc_request_message * req ;
struct arpc_response_message * resp ;
struct completion response_received ;
bool active ;
} ;
2015-11-03 20:03:23 +03:00
static inline struct es2_ap_dev * hd_to_es2 ( struct gb_host_device * hd )
2015-01-21 05:24:15 +03:00
{
2015-10-28 06:18:37 +03:00
return ( struct es2_ap_dev * ) & hd - > hd_priv ;
2015-01-21 05:24:15 +03:00
}
static void cport_out_callback ( struct urb * urb ) ;
2015-10-28 06:18:37 +03:00
static void usb_log_enable ( struct es2_ap_dev * es2 ) ;
static void usb_log_disable ( struct es2_ap_dev * es2 ) ;
2016-07-07 15:41:00 +03:00
static int arpc_sync ( struct es2_ap_dev * es2 , u8 type , void * payload ,
size_t size , int * result , unsigned int timeout ) ;
2015-01-21 05:24:15 +03:00
2015-12-23 05:21:51 +03:00
static int output_sync ( struct es2_ap_dev * es2 , void * req , u16 size , u8 cmd )
2015-12-18 22:23:24 +03:00
{
struct usb_device * udev = es2 - > usb_dev ;
2015-12-23 05:21:51 +03:00
u8 * data ;
2015-12-18 22:23:24 +03:00
int retval ;
2016-10-16 11:49:48 +03:00
data = kmemdup ( req , size , GFP_KERNEL ) ;
2015-12-23 05:21:51 +03:00
if ( ! data )
2015-12-22 04:00:37 +03:00
return - ENOMEM ;
2015-12-18 22:23:24 +03:00
retval = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2015-12-23 05:21:51 +03:00
cmd ,
2015-12-18 22:23:24 +03:00
USB_DIR_OUT | USB_TYPE_VENDOR |
2015-12-23 05:21:51 +03:00
USB_RECIP_INTERFACE ,
2016-08-03 15:09:35 +03:00
0 , 0 , data , size , ES2_USB_CTRL_TIMEOUT ) ;
2015-12-22 04:00:37 +03:00
if ( retval < 0 )
2015-12-23 05:21:51 +03:00
dev_err ( & udev - > dev , " %s: return error %d \n " , __func__ , retval ) ;
else
retval = 0 ;
2015-12-18 22:23:24 +03:00
2015-12-23 05:21:51 +03:00
kfree ( data ) ;
2015-12-22 04:00:37 +03:00
return retval ;
2015-12-18 22:23:24 +03:00
}
2015-12-23 05:21:51 +03:00
static void ap_urb_complete ( struct urb * urb )
{
struct usb_ctrlrequest * dr = urb - > context ;
kfree ( dr ) ;
usb_free_urb ( urb ) ;
}
static int output_async ( struct es2_ap_dev * es2 , void * req , u16 size , u8 cmd )
{
struct usb_device * udev = es2 - > usb_dev ;
struct urb * urb ;
struct usb_ctrlrequest * dr ;
u8 * buf ;
int retval ;
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
if ( ! urb )
return - ENOMEM ;
dr = kmalloc ( sizeof ( * dr ) + size , GFP_ATOMIC ) ;
if ( ! dr ) {
usb_free_urb ( urb ) ;
return - ENOMEM ;
}
buf = ( u8 * ) dr + sizeof ( * dr ) ;
memcpy ( buf , req , size ) ;
dr - > bRequest = cmd ;
dr - > bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE ;
dr - > wValue = 0 ;
dr - > wIndex = 0 ;
dr - > wLength = cpu_to_le16 ( size ) ;
usb_fill_control_urb ( urb , udev , usb_sndctrlpipe ( udev , 0 ) ,
( unsigned char * ) dr , buf , size ,
ap_urb_complete , dr ) ;
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( retval ) {
usb_free_urb ( urb ) ;
kfree ( dr ) ;
}
return retval ;
}
static int output ( struct gb_host_device * hd , void * req , u16 size , u8 cmd ,
2018-11-25 19:58:15 +03:00
bool async )
2015-12-23 05:21:51 +03:00
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
if ( async )
return output_async ( es2 , req , size , cmd ) ;
return output_sync ( es2 , req , size , cmd ) ;
}
2015-12-18 22:23:24 +03:00
2015-11-04 20:55:14 +03:00
static int es2_cport_in_enable ( struct es2_ap_dev * es2 ,
2018-11-25 19:58:15 +03:00
struct es2_cport_in * cport_in )
2015-11-04 20:55:14 +03:00
{
struct urb * urb ;
int ret ;
int i ;
for ( i = 0 ; i < NUM_CPORT_IN_URB ; + + i ) {
urb = cport_in - > urb [ i ] ;
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret ) {
dev_err ( & es2 - > usb_dev - > dev ,
2018-11-25 19:58:15 +03:00
" failed to submit in-urb: %d \n " , ret ) ;
2015-11-04 20:55:14 +03:00
goto err_kill_urbs ;
}
}
return 0 ;
err_kill_urbs :
for ( - - i ; i > = 0 ; - - i ) {
urb = cport_in - > urb [ i ] ;
usb_kill_urb ( urb ) ;
}
return ret ;
}
2015-11-04 20:55:16 +03:00
static void es2_cport_in_disable ( struct es2_ap_dev * es2 ,
2018-11-25 19:58:15 +03:00
struct es2_cport_in * cport_in )
2015-11-04 20:55:16 +03:00
{
struct urb * urb ;
int i ;
for ( i = 0 ; i < NUM_CPORT_IN_URB ; + + i ) {
urb = cport_in - > urb [ i ] ;
usb_kill_urb ( urb ) ;
}
}
2016-07-07 15:41:00 +03:00
static int es2_arpc_in_enable ( struct es2_ap_dev * es2 )
{
struct urb * urb ;
int ret ;
int i ;
for ( i = 0 ; i < NUM_ARPC_IN_URB ; + + i ) {
urb = es2 - > arpc_urb [ i ] ;
ret = usb_submit_urb ( urb , GFP_KERNEL ) ;
if ( ret ) {
dev_err ( & es2 - > usb_dev - > dev ,
" failed to submit arpc in-urb: %d \n " , ret ) ;
goto err_kill_urbs ;
}
}
return 0 ;
err_kill_urbs :
for ( - - i ; i > = 0 ; - - i ) {
urb = es2 - > arpc_urb [ i ] ;
usb_kill_urb ( urb ) ;
}
return ret ;
}
static void es2_arpc_in_disable ( struct es2_ap_dev * es2 )
{
struct urb * urb ;
int i ;
for ( i = 0 ; i < NUM_ARPC_IN_URB ; + + i ) {
urb = es2 - > arpc_urb [ i ] ;
usb_kill_urb ( urb ) ;
}
}
2015-10-28 06:18:37 +03:00
static struct urb * next_free_urb ( struct es2_ap_dev * es2 , gfp_t gfp_mask )
2015-01-21 05:24:15 +03:00
{
struct urb * urb = NULL ;
unsigned long flags ;
int i ;
2015-10-28 06:18:37 +03:00
spin_lock_irqsave ( & es2 - > cport_out_urb_lock , flags ) ;
2015-01-21 05:24:15 +03:00
/* Look in our pool of allocated urbs first, as that's the "fastest" */
for ( i = 0 ; i < NUM_CPORT_OUT_URB ; + + i ) {
2018-11-09 16:54:57 +03:00
if ( ! es2 - > cport_out_urb_busy [ i ] & &
! es2 - > cport_out_urb_cancelled [ i ] ) {
2015-10-28 06:18:37 +03:00
es2 - > cport_out_urb_busy [ i ] = true ;
urb = es2 - > cport_out_urb [ i ] ;
2015-01-21 05:24:15 +03:00
break ;
}
}
2015-10-28 06:18:37 +03:00
spin_unlock_irqrestore ( & es2 - > cport_out_urb_lock , flags ) ;
2015-01-21 05:24:15 +03:00
if ( urb )
return urb ;
/*
* Crap , pool is empty , complain to the syslog and go allocate one
* dynamically as we have to succeed .
*/
2015-12-15 17:51:48 +03:00
dev_dbg ( & es2 - > usb_dev - > dev ,
2015-01-21 05:24:15 +03:00
" No free CPort OUT urbs, having to dynamically allocate one! \n " ) ;
return usb_alloc_urb ( 0 , gfp_mask ) ;
}
2015-10-28 06:18:37 +03:00
static void free_urb ( struct es2_ap_dev * es2 , struct urb * urb )
2015-01-21 05:24:15 +03:00
{
unsigned long flags ;
int i ;
/*
* See if this was an urb in our pool , if so mark it " free " , otherwise
* we need to free it ourselves .
*/
2015-10-28 06:18:37 +03:00
spin_lock_irqsave ( & es2 - > cport_out_urb_lock , flags ) ;
2015-01-21 05:24:15 +03:00
for ( i = 0 ; i < NUM_CPORT_OUT_URB ; + + i ) {
2015-10-28 06:18:37 +03:00
if ( urb = = es2 - > cport_out_urb [ i ] ) {
es2 - > cport_out_urb_busy [ i ] = false ;
2015-01-21 05:24:15 +03:00
urb = NULL ;
break ;
}
}
2015-10-28 06:18:37 +03:00
spin_unlock_irqrestore ( & es2 - > cport_out_urb_lock , flags ) ;
2015-01-21 05:24:15 +03:00
/* If urb is not NULL, then we need to free this urb */
usb_free_urb ( urb ) ;
}
2015-06-13 19:02:08 +03:00
/*
* We ( ab ) use the operation - message header pad bytes to transfer the
* cport id in order to minimise overhead .
*/
static void
gb_message_cport_pack ( struct gb_operation_msg_hdr * header , u16 cport_id )
{
2015-06-13 19:02:11 +03:00
header - > pad [ 0 ] = cport_id ;
2015-06-13 19:02:08 +03:00
}
/* Clear the pad bytes used for the CPort id */
static void gb_message_cport_clear ( struct gb_operation_msg_hdr * header )
{
2015-06-13 19:02:11 +03:00
header - > pad [ 0 ] = 0 ;
2015-06-13 19:02:08 +03:00
}
/* Extract the CPort id packed into the header, and clear it */
static u16 gb_message_cport_unpack ( struct gb_operation_msg_hdr * header )
{
2015-06-13 19:02:11 +03:00
u16 cport_id = header - > pad [ 0 ] ;
2015-06-13 19:02:08 +03:00
gb_message_cport_clear ( header ) ;
return cport_id ;
}
2015-01-21 05:24:15 +03:00
/*
2015-07-01 13:37:21 +03:00
* Returns zero if the message was successfully queued , or a negative errno
* otherwise .
2015-01-21 05:24:15 +03:00
*/
2015-11-03 20:03:23 +03:00
static int message_send ( struct gb_host_device * hd , u16 cport_id ,
2015-04-07 12:27:16 +03:00
struct gb_message * message , gfp_t gfp_mask )
2015-01-21 05:24:15 +03:00
{
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct usb_device * udev = es2 - > usb_dev ;
2015-04-07 12:27:16 +03:00
size_t buffer_size ;
2015-01-21 05:24:15 +03:00
int retval ;
struct urb * urb ;
2015-07-01 13:37:21 +03:00
unsigned long flags ;
2015-01-21 05:24:15 +03:00
/*
* The data actually transferred will include an indication
* of where the data should be sent . Do one last check of
* the target CPort id before filling it in .
*/
2015-09-02 16:50:35 +03:00
if ( ! cport_id_valid ( hd , cport_id ) ) {
2015-12-07 17:05:38 +03:00
dev_err ( & udev - > dev , " invalid cport %u \n " , cport_id ) ;
2015-07-01 13:37:21 +03:00
return - EINVAL ;
2015-01-21 05:24:15 +03:00
}
/* Find a free urb */
2015-10-28 06:18:37 +03:00
urb = next_free_urb ( es2 , gfp_mask ) ;
2015-01-21 05:24:15 +03:00
if ( ! urb )
2015-07-01 13:37:21 +03:00
return - ENOMEM ;
2015-10-28 06:18:37 +03:00
spin_lock_irqsave ( & es2 - > cport_out_urb_lock , flags ) ;
2015-07-01 13:37:21 +03:00
message - > hcpriv = urb ;
2015-10-28 06:18:37 +03:00
spin_unlock_irqrestore ( & es2 - > cport_out_urb_lock , flags ) ;
2015-01-21 05:24:15 +03:00
2015-06-13 19:02:08 +03:00
/* Pack the cport id into the message header */
gb_message_cport_pack ( message - > header , cport_id ) ;
2015-04-07 12:27:20 +03:00
2015-06-13 19:02:07 +03:00
buffer_size = sizeof ( * message - > header ) + message - > payload_size ;
2015-04-07 12:27:20 +03:00
2015-01-21 05:24:15 +03:00
usb_fill_bulk_urb ( urb , udev ,
2015-06-15 19:08:13 +03:00
usb_sndbulkpipe ( udev ,
2016-08-17 17:27:49 +03:00
es2 - > cport_out_endpoint ) ,
2015-06-13 19:02:07 +03:00
message - > buffer , buffer_size ,
2015-04-07 12:27:16 +03:00
cport_out_callback , message ) ;
2015-08-31 10:00:16 +03:00
urb - > transfer_flags | = URB_ZERO_PACKET ;
2016-06-03 23:55:38 +03:00
trace_gb_message_submit ( message ) ;
2015-01-21 05:24:15 +03:00
retval = usb_submit_urb ( urb , gfp_mask ) ;
if ( retval ) {
2016-06-23 20:52:15 +03:00
dev_err ( & udev - > dev , " failed to submit out-urb: %d \n " , retval ) ;
2015-07-01 13:37:21 +03:00
2015-10-28 06:18:37 +03:00
spin_lock_irqsave ( & es2 - > cport_out_urb_lock , flags ) ;
2015-07-01 13:37:21 +03:00
message - > hcpriv = NULL ;
2015-10-28 06:18:37 +03:00
spin_unlock_irqrestore ( & es2 - > cport_out_urb_lock , flags ) ;
2015-07-01 13:37:21 +03:00
2015-10-28 06:18:37 +03:00
free_urb ( es2 , urb ) ;
2015-06-13 19:02:08 +03:00
gb_message_cport_clear ( message - > header ) ;
2015-07-01 13:37:21 +03:00
return retval ;
2015-01-21 05:24:15 +03:00
}
2015-07-01 13:37:21 +03:00
return 0 ;
2015-01-21 05:24:15 +03:00
}
/*
2015-07-01 13:37:21 +03:00
* Can not be called in atomic context .
2015-01-21 05:24:15 +03:00
*/
2015-07-01 13:37:21 +03:00
static void message_cancel ( struct gb_message * message )
2015-01-21 05:24:15 +03:00
{
2015-11-03 20:03:23 +03:00
struct gb_host_device * hd = message - > operation - > connection - > hd ;
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
2015-07-01 13:37:21 +03:00
struct urb * urb ;
int i ;
2015-01-21 05:24:15 +03:00
2015-07-01 13:37:21 +03:00
might_sleep ( ) ;
2016-06-27 21:07:11 +03:00
spin_lock_irq ( & es2 - > cport_out_urb_lock ) ;
2015-07-01 13:37:21 +03:00
urb = message - > hcpriv ;
/* Prevent dynamically allocated urb from being deallocated. */
usb_get_urb ( urb ) ;
/* Prevent pre-allocated urb from being reused. */
for ( i = 0 ; i < NUM_CPORT_OUT_URB ; + + i ) {
2015-10-28 06:18:37 +03:00
if ( urb = = es2 - > cport_out_urb [ i ] ) {
es2 - > cport_out_urb_cancelled [ i ] = true ;
2015-07-01 13:37:21 +03:00
break ;
}
}
2016-06-27 21:07:11 +03:00
spin_unlock_irq ( & es2 - > cport_out_urb_lock ) ;
2015-07-01 13:37:21 +03:00
usb_kill_urb ( urb ) ;
if ( i < NUM_CPORT_OUT_URB ) {
2016-06-27 21:07:11 +03:00
spin_lock_irq ( & es2 - > cport_out_urb_lock ) ;
2015-10-28 06:18:37 +03:00
es2 - > cport_out_urb_cancelled [ i ] = false ;
2016-06-27 21:07:11 +03:00
spin_unlock_irq ( & es2 - > cport_out_urb_lock ) ;
2015-07-01 13:37:21 +03:00
}
usb_free_urb ( urb ) ;
2015-01-21 05:24:15 +03:00
}
2016-05-11 11:18:04 +03:00
static int es2_cport_allocate ( struct gb_host_device * hd , int cport_id ,
2018-11-25 19:58:15 +03:00
unsigned long flags )
2016-05-11 11:18:04 +03:00
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct ida * id_map = & hd - > cport_id_map ;
int ida_start , ida_end ;
switch ( cport_id ) {
case ES2_CPORT_CDSI0 :
case ES2_CPORT_CDSI1 :
dev_err ( & hd - > dev , " cport %d not available \n " , cport_id ) ;
return - EBUSY ;
}
if ( flags & GB_CONNECTION_FLAG_OFFLOADED & &
2018-11-25 19:58:15 +03:00
flags & GB_CONNECTION_FLAG_CDSI1 ) {
2016-05-11 11:18:04 +03:00
if ( es2 - > cdsi1_in_use ) {
dev_err ( & hd - > dev , " CDSI1 already in use \n " ) ;
return - EBUSY ;
}
es2 - > cdsi1_in_use = true ;
return ES2_CPORT_CDSI1 ;
}
if ( cport_id < 0 ) {
ida_start = 0 ;
ida_end = hd - > num_cports ;
} else if ( cport_id < hd - > num_cports ) {
ida_start = cport_id ;
ida_end = cport_id + 1 ;
} else {
dev_err ( & hd - > dev , " cport %d not available \n " , cport_id ) ;
return - EINVAL ;
}
return ida_simple_get ( id_map , ida_start , ida_end , GFP_KERNEL ) ;
}
static void es2_cport_release ( struct gb_host_device * hd , u16 cport_id )
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
switch ( cport_id ) {
case ES2_CPORT_CDSI1 :
es2 - > cdsi1_in_use = false ;
return ;
}
ida_simple_remove ( & hd - > cport_id_map , cport_id ) ;
}
2016-06-22 12:42:05 +03:00
static int cport_enable ( struct gb_host_device * hd , u16 cport_id ,
unsigned long flags )
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct usb_device * udev = es2 - > usb_dev ;
struct gb_apb_request_cport_flags * req ;
2016-07-18 16:59:36 +03:00
u32 connection_flags ;
2016-06-22 12:42:05 +03:00
int ret ;
req = kzalloc ( sizeof ( * req ) , GFP_KERNEL ) ;
if ( ! req )
return - ENOMEM ;
2016-07-18 16:59:36 +03:00
connection_flags = 0 ;
2016-06-22 12:42:05 +03:00
if ( flags & GB_CONNECTION_FLAG_CONTROL )
2016-07-18 16:59:36 +03:00
connection_flags | = GB_APB_CPORT_FLAG_CONTROL ;
2016-06-22 12:42:05 +03:00
if ( flags & GB_CONNECTION_FLAG_HIGH_PRIO )
2016-07-18 16:59:36 +03:00
connection_flags | = GB_APB_CPORT_FLAG_HIGH_PRIO ;
req - > flags = cpu_to_le32 ( connection_flags ) ;
2016-06-22 12:42:05 +03:00
dev_dbg ( & hd - > dev , " %s - cport = %u, flags = %02x \n " , __func__ ,
2018-11-25 19:58:15 +03:00
cport_id , connection_flags ) ;
2016-06-22 12:42:05 +03:00
ret = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2018-11-25 19:58:15 +03:00
GB_APB_REQUEST_CPORT_FLAGS ,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE , cport_id , 0 ,
req , sizeof ( * req ) , ES2_USB_CTRL_TIMEOUT ) ;
2021-01-18 17:46:29 +03:00
if ( ret < 0 ) {
2016-06-22 12:42:05 +03:00
dev_err ( & udev - > dev , " failed to set cport flags for port %d \n " ,
2018-11-25 19:58:15 +03:00
cport_id ) ;
2016-06-22 12:42:05 +03:00
goto out ;
}
ret = 0 ;
out :
kfree ( req ) ;
return ret ;
}
2016-08-10 13:58:42 +03:00
static int es2_cport_connected ( struct gb_host_device * hd , u16 cport_id )
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct device * dev = & es2 - > usb_dev - > dev ;
struct arpc_cport_connected_req req ;
int ret ;
req . cport_id = cpu_to_le16 ( cport_id ) ;
ret = arpc_sync ( es2 , ARPC_TYPE_CPORT_CONNECTED , & req , sizeof ( req ) ,
NULL , ES2_ARPC_CPORT_TIMEOUT ) ;
if ( ret ) {
dev_err ( dev , " failed to set connected state for cport %u: %d \n " ,
2018-11-25 19:58:15 +03:00
cport_id , ret ) ;
2016-08-10 13:58:42 +03:00
return ret ;
}
return 0 ;
}
2016-08-26 13:55:47 +03:00
static int es2_cport_flush ( struct gb_host_device * hd , u16 cport_id )
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct device * dev = & es2 - > usb_dev - > dev ;
struct arpc_cport_flush_req req ;
int ret ;
req . cport_id = cpu_to_le16 ( cport_id ) ;
ret = arpc_sync ( es2 , ARPC_TYPE_CPORT_FLUSH , & req , sizeof ( req ) ,
NULL , ES2_ARPC_CPORT_TIMEOUT ) ;
if ( ret ) {
dev_err ( dev , " failed to flush cport %u: %d \n " , cport_id , ret ) ;
return ret ;
}
return 0 ;
}
2016-08-26 13:55:48 +03:00
static int es2_cport_shutdown ( struct gb_host_device * hd , u16 cport_id ,
2018-11-25 19:58:15 +03:00
u8 phase , unsigned int timeout )
2016-08-26 13:55:48 +03:00
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct device * dev = & es2 - > usb_dev - > dev ;
struct arpc_cport_shutdown_req req ;
int result ;
int ret ;
if ( timeout > U16_MAX )
return - EINVAL ;
req . cport_id = cpu_to_le16 ( cport_id ) ;
req . timeout = cpu_to_le16 ( timeout ) ;
req . phase = phase ;
ret = arpc_sync ( es2 , ARPC_TYPE_CPORT_SHUTDOWN , & req , sizeof ( req ) ,
& result , ES2_ARPC_CPORT_TIMEOUT + timeout ) ;
if ( ret ) {
dev_err ( dev , " failed to send shutdown over cport %u: %d (%d) \n " ,
2018-11-25 19:58:15 +03:00
cport_id , ret , result ) ;
2016-08-26 13:55:48 +03:00
return ret ;
}
return 0 ;
}
2016-08-10 13:58:43 +03:00
static int es2_cport_quiesce ( struct gb_host_device * hd , u16 cport_id ,
2018-11-25 19:58:15 +03:00
size_t peer_space , unsigned int timeout )
2016-08-10 13:58:43 +03:00
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct device * dev = & es2 - > usb_dev - > dev ;
struct arpc_cport_quiesce_req req ;
int result ;
int ret ;
if ( peer_space > U16_MAX )
return - EINVAL ;
if ( timeout > U16_MAX )
return - EINVAL ;
req . cport_id = cpu_to_le16 ( cport_id ) ;
req . peer_space = cpu_to_le16 ( peer_space ) ;
req . timeout = cpu_to_le16 ( timeout ) ;
ret = arpc_sync ( es2 , ARPC_TYPE_CPORT_QUIESCE , & req , sizeof ( req ) ,
& result , ES2_ARPC_CPORT_TIMEOUT + timeout ) ;
if ( ret ) {
dev_err ( dev , " failed to quiesce cport %u: %d (%d) \n " ,
2018-11-25 19:58:15 +03:00
cport_id , ret , result ) ;
2016-08-10 13:58:43 +03:00
return ret ;
}
return 0 ;
}
2016-08-10 13:58:44 +03:00
static int es2_cport_clear ( struct gb_host_device * hd , u16 cport_id )
{
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct device * dev = & es2 - > usb_dev - > dev ;
struct arpc_cport_clear_req req ;
int ret ;
req . cport_id = cpu_to_le16 ( cport_id ) ;
ret = arpc_sync ( es2 , ARPC_TYPE_CPORT_CLEAR , & req , sizeof ( req ) ,
NULL , ES2_ARPC_CPORT_TIMEOUT ) ;
if ( ret ) {
dev_err ( dev , " failed to clear cport %u: %d \n " , cport_id , ret ) ;
return ret ;
}
return 0 ;
}
2015-11-03 20:03:23 +03:00
static int latency_tag_enable ( struct gb_host_device * hd , u16 cport_id )
2015-10-15 18:10:41 +03:00
{
int retval ;
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct usb_device * udev = es2 - > usb_dev ;
2015-10-15 18:10:41 +03:00
retval = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2015-12-31 22:14:33 +03:00
GB_APB_REQUEST_LATENCY_TAG_EN ,
2015-10-15 18:10:41 +03:00
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE , cport_id , 0 , NULL ,
2016-08-03 15:09:35 +03:00
0 , ES2_USB_CTRL_TIMEOUT ) ;
2015-10-15 18:10:41 +03:00
if ( retval < 0 )
dev_err ( & udev - > dev , " Cannot enable latency tag for cport %d \n " ,
cport_id ) ;
return retval ;
}
2015-11-03 20:03:23 +03:00
static int latency_tag_disable ( struct gb_host_device * hd , u16 cport_id )
2015-10-15 18:10:41 +03:00
{
int retval ;
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
struct usb_device * udev = es2 - > usb_dev ;
2015-10-15 18:10:41 +03:00
retval = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2015-12-31 22:14:33 +03:00
GB_APB_REQUEST_LATENCY_TAG_DIS ,
2015-10-15 18:10:41 +03:00
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE , cport_id , 0 , NULL ,
2016-08-03 15:09:35 +03:00
0 , ES2_USB_CTRL_TIMEOUT ) ;
2015-10-15 18:10:41 +03:00
if ( retval < 0 )
dev_err ( & udev - > dev , " Cannot disable latency tag for cport %d \n " ,
cport_id ) ;
return retval ;
}
2015-11-03 20:03:24 +03:00
static struct gb_hd_driver es2_driver = {
2016-05-15 21:37:48 +03:00
. hd_priv_size = sizeof ( struct es2_ap_dev ) ,
. message_send = message_send ,
. message_cancel = message_cancel ,
. cport_allocate = es2_cport_allocate ,
. cport_release = es2_cport_release ,
2016-06-22 12:42:05 +03:00
. cport_enable = cport_enable ,
2016-08-10 13:58:42 +03:00
. cport_connected = es2_cport_connected ,
2016-08-26 13:55:47 +03:00
. cport_flush = es2_cport_flush ,
2016-08-26 13:55:48 +03:00
. cport_shutdown = es2_cport_shutdown ,
2016-08-10 13:58:43 +03:00
. cport_quiesce = es2_cport_quiesce ,
2016-08-10 13:58:44 +03:00
. cport_clear = es2_cport_clear ,
2016-05-15 21:37:48 +03:00
. latency_tag_enable = latency_tag_enable ,
. latency_tag_disable = latency_tag_disable ,
. output = output ,
2015-01-21 05:24:15 +03:00
} ;
/* Common function to report consistent warnings based on URB status */
static int check_urb_status ( struct urb * urb )
{
struct device * dev = & urb - > dev - > dev ;
int status = urb - > status ;
switch ( status ) {
case 0 :
return 0 ;
case - EOVERFLOW :
dev_err ( dev , " %s: overflow actual length is %d \n " ,
__func__ , urb - > actual_length ) ;
2020-07-27 21:32:58 +03:00
fallthrough ;
2015-01-21 05:24:15 +03:00
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
case - EILSEQ :
case - EPROTO :
/* device is gone, stop sending */
return status ;
}
dev_err ( dev , " %s: unknown status %d \n " , __func__ , status ) ;
return - EAGAIN ;
}
2015-11-04 20:55:20 +03:00
static void es2_destroy ( struct es2_ap_dev * es2 )
2015-01-21 05:24:15 +03:00
{
struct usb_device * udev ;
2016-08-17 17:44:11 +03:00
struct urb * urb ;
2015-01-21 05:24:15 +03:00
int i ;
2015-11-04 20:55:18 +03:00
debugfs_remove ( es2 - > apb_log_enable_dentry ) ;
2015-10-28 06:18:37 +03:00
usb_log_disable ( es2 ) ;
2015-03-27 13:38:07 +03:00
2015-01-21 05:24:15 +03:00
/* Tear down everything! */
for ( i = 0 ; i < NUM_CPORT_OUT_URB ; + + i ) {
2016-08-17 17:44:11 +03:00
urb = es2 - > cport_out_urb [ i ] ;
2015-01-21 05:24:15 +03:00
usb_kill_urb ( urb ) ;
usb_free_urb ( urb ) ;
2015-10-28 06:18:37 +03:00
es2 - > cport_out_urb [ i ] = NULL ;
es2 - > cport_out_urb_busy [ i ] = false ; /* just to be anal */
2015-01-21 05:24:15 +03:00
}
2016-07-07 15:41:00 +03:00
for ( i = 0 ; i < NUM_ARPC_IN_URB ; + + i ) {
2016-08-17 17:44:11 +03:00
usb_free_urb ( es2 - > arpc_urb [ i ] ) ;
2016-07-07 15:41:00 +03:00
kfree ( es2 - > arpc_buffer [ i ] ) ;
es2 - > arpc_buffer [ i ] = NULL ;
}
2016-08-17 17:37:39 +03:00
for ( i = 0 ; i < NUM_CPORT_IN_URB ; + + i ) {
usb_free_urb ( es2 - > cport_in . urb [ i ] ) ;
kfree ( es2 - > cport_in . buffer [ i ] ) ;
es2 - > cport_in . buffer [ i ] = NULL ;
2015-01-21 05:24:15 +03:00
}
2016-05-27 08:19:24 +03:00
/* release reserved CDSI0 and CDSI1 cports */
gb_hd_cport_release_reserved ( es2 - > hd , ES2_CPORT_CDSI1 ) ;
gb_hd_cport_release_reserved ( es2 - > hd , ES2_CPORT_CDSI0 ) ;
2015-10-28 06:18:37 +03:00
udev = es2 - > usb_dev ;
2015-11-04 20:55:22 +03:00
gb_hd_put ( es2 - > hd ) ;
2015-01-21 05:24:15 +03:00
usb_put_dev ( udev ) ;
}
static void cport_in_callback ( struct urb * urb )
{
2015-11-03 20:03:23 +03:00
struct gb_host_device * hd = urb - > context ;
2015-01-21 05:24:15 +03:00
struct device * dev = & urb - > dev - > dev ;
2015-04-07 12:27:20 +03:00
struct gb_operation_msg_hdr * header ;
2015-01-21 05:24:15 +03:00
int status = check_urb_status ( urb ) ;
int retval ;
u16 cport_id ;
if ( status ) {
if ( ( status = = - EAGAIN ) | | ( status = = - EPROTO ) )
goto exit ;
2016-04-21 09:01:15 +03:00
/* The urb is being unlinked */
if ( status = = - ENOENT | | status = = - ESHUTDOWN )
return ;
2015-01-21 05:24:15 +03:00
dev_err ( dev , " urb cport in error %d (dropped) \n " , status ) ;
return ;
}
2015-04-07 12:27:20 +03:00
if ( urb - > actual_length < sizeof ( * header ) ) {
2015-10-13 20:10:20 +03:00
dev_err ( dev , " short message received \n " ) ;
2015-01-21 05:24:15 +03:00
goto exit ;
}
2015-06-13 19:02:08 +03:00
/* Extract the CPort id, which is packed in the message header */
2015-04-07 12:27:20 +03:00
header = urb - > transfer_buffer ;
2015-06-13 19:02:08 +03:00
cport_id = gb_message_cport_unpack ( header ) ;
2015-01-21 05:24:15 +03:00
2015-09-23 04:06:39 +03:00
if ( cport_id_valid ( hd , cport_id ) ) {
2015-06-13 19:02:07 +03:00
greybus_data_rcvd ( hd , cport_id , urb - > transfer_buffer ,
2018-11-25 19:58:15 +03:00
urb - > actual_length ) ;
2015-09-23 04:06:39 +03:00
} else {
2015-12-07 17:05:38 +03:00
dev_err ( dev , " invalid cport id %u received \n " , cport_id ) ;
2015-09-23 04:06:39 +03:00
}
2015-01-21 05:24:15 +03:00
exit :
/* put our urb back in the request pool */
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( retval )
2015-10-13 20:10:20 +03:00
dev_err ( dev , " failed to resubmit in-urb: %d \n " , retval ) ;
2015-01-21 05:24:15 +03:00
}
static void cport_out_callback ( struct urb * urb )
{
2015-04-07 12:27:16 +03:00
struct gb_message * message = urb - > context ;
2015-11-03 20:03:23 +03:00
struct gb_host_device * hd = message - > operation - > connection - > hd ;
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = hd_to_es2 ( hd ) ;
2015-01-21 05:24:15 +03:00
int status = check_urb_status ( urb ) ;
2015-07-01 13:37:21 +03:00
unsigned long flags ;
2015-01-21 05:24:15 +03:00
2015-06-13 19:02:08 +03:00
gb_message_cport_clear ( message - > header ) ;
2015-04-07 12:27:20 +03:00
2015-10-28 06:18:37 +03:00
spin_lock_irqsave ( & es2 - > cport_out_urb_lock , flags ) ;
2015-09-27 00:37:59 +03:00
message - > hcpriv = NULL ;
2015-10-28 06:18:37 +03:00
spin_unlock_irqrestore ( & es2 - > cport_out_urb_lock , flags ) ;
2015-09-27 00:37:59 +03:00
2015-01-21 05:24:15 +03:00
/*
2015-04-07 12:27:16 +03:00
* Tell the submitter that the message send ( attempt ) is
* complete , and report the status .
2015-01-21 05:24:15 +03:00
*/
2015-04-07 12:27:16 +03:00
greybus_message_sent ( hd , message , status ) ;
2015-10-28 06:18:37 +03:00
free_urb ( es2 , urb ) ;
2015-01-21 05:24:15 +03:00
}
2016-07-07 15:41:00 +03:00
static struct arpc * arpc_alloc ( void * payload , u16 size , u8 type )
{
struct arpc * rpc ;
if ( size + sizeof ( * rpc - > req ) > ARPC_OUT_SIZE_MAX )
return NULL ;
rpc = kzalloc ( sizeof ( * rpc ) , GFP_KERNEL ) ;
if ( ! rpc )
return NULL ;
INIT_LIST_HEAD ( & rpc - > list ) ;
rpc - > req = kzalloc ( sizeof ( * rpc - > req ) + size , GFP_KERNEL ) ;
if ( ! rpc - > req )
goto err_free_rpc ;
rpc - > resp = kzalloc ( sizeof ( * rpc - > resp ) , GFP_KERNEL ) ;
2016-07-27 17:37:20 +03:00
if ( ! rpc - > resp )
2016-07-07 15:41:00 +03:00
goto err_free_req ;
rpc - > req - > type = type ;
2016-10-19 15:44:25 +03:00
rpc - > req - > size = cpu_to_le16 ( sizeof ( * rpc - > req ) + size ) ;
2016-07-07 15:41:00 +03:00
memcpy ( rpc - > req - > data , payload , size ) ;
init_completion ( & rpc - > response_received ) ;
return rpc ;
err_free_req :
kfree ( rpc - > req ) ;
err_free_rpc :
kfree ( rpc ) ;
return NULL ;
}
static void arpc_free ( struct arpc * rpc )
{
kfree ( rpc - > req ) ;
kfree ( rpc - > resp ) ;
kfree ( rpc ) ;
}
2016-07-14 20:55:00 +03:00
static struct arpc * arpc_find ( struct es2_ap_dev * es2 , __le16 id )
2016-07-07 15:41:00 +03:00
{
struct arpc * rpc ;
list_for_each_entry ( rpc , & es2 - > arpcs , list ) {
2016-07-14 20:55:00 +03:00
if ( rpc - > req - > id = = id )
2016-07-07 15:41:00 +03:00
return rpc ;
}
return NULL ;
}
static void arpc_add ( struct es2_ap_dev * es2 , struct arpc * rpc )
{
rpc - > active = true ;
2016-07-14 20:18:00 +03:00
rpc - > req - > id = cpu_to_le16 ( es2 - > arpc_id_cycle + + ) ;
2016-07-27 17:37:22 +03:00
list_add_tail ( & rpc - > list , & es2 - > arpcs ) ;
2016-07-07 15:41:00 +03:00
}
static void arpc_del ( struct es2_ap_dev * es2 , struct arpc * rpc )
{
if ( rpc - > active ) {
rpc - > active = false ;
list_del ( & rpc - > list ) ;
}
}
static int arpc_send ( struct es2_ap_dev * es2 , struct arpc * rpc , int timeout )
{
struct usb_device * udev = es2 - > usb_dev ;
int retval ;
retval = usb_control_msg ( udev , usb_sndctrlpipe ( udev , 0 ) ,
2016-08-10 13:58:40 +03:00
GB_APB_REQUEST_ARPC_RUN ,
2016-07-07 15:41:00 +03:00
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE ,
0 , 0 ,
2016-07-14 20:18:00 +03:00
rpc - > req , le16_to_cpu ( rpc - > req - > size ) ,
2016-08-03 15:09:35 +03:00
ES2_USB_CTRL_TIMEOUT ) ;
2021-01-18 17:46:29 +03:00
if ( retval < 0 ) {
2016-07-07 15:41:00 +03:00
dev_err ( & udev - > dev ,
" failed to send ARPC request %d: %d \n " ,
rpc - > req - > type , retval ) ;
return retval ;
}
return 0 ;
}
static int arpc_sync ( struct es2_ap_dev * es2 , u8 type , void * payload ,
size_t size , int * result , unsigned int timeout )
{
struct arpc * rpc ;
unsigned long flags ;
int retval ;
2016-08-03 15:09:33 +03:00
if ( result )
* result = 0 ;
2016-08-03 15:09:32 +03:00
2016-07-07 15:41:00 +03:00
rpc = arpc_alloc ( payload , size , type ) ;
if ( ! rpc )
return - ENOMEM ;
spin_lock_irqsave ( & es2 - > arpc_lock , flags ) ;
arpc_add ( es2 , rpc ) ;
spin_unlock_irqrestore ( & es2 - > arpc_lock , flags ) ;
retval = arpc_send ( es2 , rpc , timeout ) ;
if ( retval )
goto out_arpc_del ;
retval = wait_for_completion_interruptible_timeout (
& rpc - > response_received ,
msecs_to_jiffies ( timeout ) ) ;
if ( retval < = 0 ) {
if ( ! retval )
retval = - ETIMEDOUT ;
goto out_arpc_del ;
}
2016-08-03 15:09:32 +03:00
if ( rpc - > resp - > result ) {
2016-07-07 15:41:00 +03:00
retval = - EREMOTEIO ;
2016-08-03 15:09:33 +03:00
if ( result )
* result = rpc - > resp - > result ;
2016-08-03 15:09:32 +03:00
} else {
2016-07-13 17:34:00 +03:00
retval = 0 ;
2016-08-03 15:09:32 +03:00
}
2016-07-07 15:41:00 +03:00
out_arpc_del :
spin_lock_irqsave ( & es2 - > arpc_lock , flags ) ;
arpc_del ( es2 , rpc ) ;
spin_unlock_irqrestore ( & es2 - > arpc_lock , flags ) ;
arpc_free ( rpc ) ;
if ( retval < 0 & & retval ! = - EREMOTEIO ) {
dev_err ( & es2 - > usb_dev - > dev ,
" failed to execute ARPC: %d \n " , retval ) ;
}
return retval ;
}
2016-07-07 15:41:00 +03:00
static void arpc_in_callback ( struct urb * urb )
{
2016-07-07 15:41:00 +03:00
struct es2_ap_dev * es2 = urb - > context ;
2016-07-07 15:41:00 +03:00
struct device * dev = & urb - > dev - > dev ;
int status = check_urb_status ( urb ) ;
2016-07-07 15:41:00 +03:00
struct arpc * rpc ;
struct arpc_response_message * resp ;
unsigned long flags ;
2016-07-07 15:41:00 +03:00
int retval ;
if ( status ) {
if ( ( status = = - EAGAIN ) | | ( status = = - EPROTO ) )
goto exit ;
/* The urb is being unlinked */
if ( status = = - ENOENT | | status = = - ESHUTDOWN )
return ;
dev_err ( dev , " arpc in-urb error %d (dropped) \n " , status ) ;
return ;
}
2016-07-07 15:41:00 +03:00
if ( urb - > actual_length < sizeof ( * resp ) ) {
dev_err ( dev , " short aprc response received \n " ) ;
goto exit ;
}
resp = urb - > transfer_buffer ;
spin_lock_irqsave ( & es2 - > arpc_lock , flags ) ;
2016-07-14 20:55:00 +03:00
rpc = arpc_find ( es2 , resp - > id ) ;
2016-07-07 15:41:00 +03:00
if ( ! rpc ) {
2016-07-27 17:37:21 +03:00
dev_err ( dev , " invalid arpc response id received: %u \n " ,
le16_to_cpu ( resp - > id ) ) ;
2016-07-07 15:41:00 +03:00
spin_unlock_irqrestore ( & es2 - > arpc_lock , flags ) ;
goto exit ;
}
arpc_del ( es2 , rpc ) ;
memcpy ( rpc - > resp , resp , sizeof ( * resp ) ) ;
complete ( & rpc - > response_received ) ;
spin_unlock_irqrestore ( & es2 - > arpc_lock , flags ) ;
2016-07-07 15:41:00 +03:00
exit :
/* put our urb back in the request pool */
retval = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( retval )
dev_err ( dev , " failed to resubmit arpc in-urb: %d \n " , retval ) ;
}
2015-04-07 12:27:12 +03:00
# define APB1_LOG_MSG_SIZE 64
2015-10-28 06:18:41 +03:00
static void apb_log_get ( struct es2_ap_dev * es2 , char * buf )
2015-03-27 13:38:07 +03:00
{
int retval ;
do {
2015-10-28 06:18:37 +03:00
retval = usb_control_msg ( es2 - > usb_dev ,
2018-11-25 19:58:15 +03:00
usb_rcvctrlpipe ( es2 - > usb_dev , 0 ) ,
GB_APB_REQUEST_LOG ,
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE ,
0x00 , 0x00 ,
buf ,
APB1_LOG_MSG_SIZE ,
ES2_USB_CTRL_TIMEOUT ) ;
2015-03-27 13:38:07 +03:00
if ( retval > 0 )
2015-10-28 06:18:41 +03:00
kfifo_in ( & es2 - > apb_log_fifo , buf , retval ) ;
2015-03-27 13:38:07 +03:00
} while ( retval > 0 ) ;
}
2015-10-28 06:18:41 +03:00
static int apb_log_poll ( void * data )
2015-03-27 13:38:07 +03:00
{
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 = data ;
2015-04-07 12:27:12 +03:00
char * buf ;
buf = kmalloc ( APB1_LOG_MSG_SIZE , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
2015-03-27 13:38:07 +03:00
while ( ! kthread_should_stop ( ) ) {
msleep ( 1000 ) ;
2015-10-28 06:18:41 +03:00
apb_log_get ( es2 , buf ) ;
2015-03-27 13:38:07 +03:00
}
2015-04-07 12:27:12 +03:00
kfree ( buf ) ;
2015-03-27 13:38:07 +03:00
return 0 ;
}
2015-10-28 06:18:41 +03:00
static ssize_t apb_log_read ( struct file * f , char __user * buf ,
2018-11-25 19:58:15 +03:00
size_t count , loff_t * ppos )
2015-03-27 13:38:07 +03:00
{
2016-12-05 02:24:56 +03:00
struct es2_ap_dev * es2 = file_inode ( f ) - > i_private ;
2015-03-27 13:38:07 +03:00
ssize_t ret ;
size_t copied ;
char * tmp_buf ;
if ( count > APB1_LOG_SIZE )
count = APB1_LOG_SIZE ;
tmp_buf = kmalloc ( count , GFP_KERNEL ) ;
if ( ! tmp_buf )
return - ENOMEM ;
2015-10-28 06:18:41 +03:00
copied = kfifo_out ( & es2 - > apb_log_fifo , tmp_buf , count ) ;
2015-03-27 13:38:07 +03:00
ret = simple_read_from_buffer ( buf , count , ppos , tmp_buf , copied ) ;
kfree ( tmp_buf ) ;
return ret ;
}
2015-10-28 06:18:41 +03:00
static const struct file_operations apb_log_fops = {
. read = apb_log_read ,
2015-03-27 13:38:07 +03:00
} ;
2015-10-28 06:18:37 +03:00
static void usb_log_enable ( struct es2_ap_dev * es2 )
2015-03-27 13:38:07 +03:00
{
2015-10-28 06:18:41 +03:00
if ( ! IS_ERR_OR_NULL ( es2 - > apb_log_task ) )
2015-03-27 13:38:07 +03:00
return ;
/* get log from APB1 */
2015-10-28 06:18:41 +03:00
es2 - > apb_log_task = kthread_run ( apb_log_poll , es2 , " apb_log " ) ;
if ( IS_ERR ( es2 - > apb_log_task ) )
2015-03-27 13:38:07 +03:00
return ;
2015-10-28 06:18:41 +03:00
/* XXX We will need to rename this per APB */
2017-02-09 19:30:12 +03:00
es2 - > apb_log_dentry = debugfs_create_file ( " apb_log " , 0444 ,
2018-11-25 19:58:15 +03:00
gb_debugfs_get ( ) , es2 ,
& apb_log_fops ) ;
2015-03-27 13:38:07 +03:00
}
2015-10-28 06:18:37 +03:00
static void usb_log_disable ( struct es2_ap_dev * es2 )
2015-03-27 13:38:07 +03:00
{
2015-10-28 06:18:41 +03:00
if ( IS_ERR_OR_NULL ( es2 - > apb_log_task ) )
2015-03-27 13:38:07 +03:00
return ;
2015-10-28 06:18:41 +03:00
debugfs_remove ( es2 - > apb_log_dentry ) ;
es2 - > apb_log_dentry = NULL ;
2015-03-27 13:38:07 +03:00
2015-10-28 06:18:41 +03:00
kthread_stop ( es2 - > apb_log_task ) ;
es2 - > apb_log_task = NULL ;
2015-03-27 13:38:07 +03:00
}
2015-10-28 06:18:41 +03:00
static ssize_t apb_log_enable_read ( struct file * f , char __user * buf ,
2018-11-25 19:58:15 +03:00
size_t count , loff_t * ppos )
2015-03-27 13:38:07 +03:00
{
2016-12-05 02:24:56 +03:00
struct es2_ap_dev * es2 = file_inode ( f ) - > i_private ;
2015-10-28 06:18:41 +03:00
int enable = ! IS_ERR_OR_NULL ( es2 - > apb_log_task ) ;
2015-10-28 06:18:37 +03:00
char tmp_buf [ 3 ] ;
2015-03-27 13:38:07 +03:00
sprintf ( tmp_buf , " %d \n " , enable ) ;
2021-03-26 18:22:54 +03:00
return simple_read_from_buffer ( buf , count , ppos , tmp_buf , 2 ) ;
2015-03-27 13:38:07 +03:00
}
2015-10-28 06:18:41 +03:00
static ssize_t apb_log_enable_write ( struct file * f , const char __user * buf ,
2018-11-25 19:58:15 +03:00
size_t count , loff_t * ppos )
2015-03-27 13:38:07 +03:00
{
int enable ;
ssize_t retval ;
2016-12-05 02:24:56 +03:00
struct es2_ap_dev * es2 = file_inode ( f ) - > i_private ;
2015-03-27 13:38:07 +03:00
retval = kstrtoint_from_user ( buf , count , 10 , & enable ) ;
if ( retval )
return retval ;
if ( enable )
2015-10-28 06:18:37 +03:00
usb_log_enable ( es2 ) ;
2015-03-27 13:38:07 +03:00
else
2015-10-28 06:18:37 +03:00
usb_log_disable ( es2 ) ;
2015-03-27 13:38:07 +03:00
return count ;
}
2015-10-28 06:18:41 +03:00
static const struct file_operations apb_log_enable_fops = {
. read = apb_log_enable_read ,
. write = apb_log_enable_write ,
2015-03-27 13:38:07 +03:00
} ;
2015-10-28 06:18:41 +03:00
static int apb_get_cport_count ( struct usb_device * udev )
2015-09-02 16:50:37 +03:00
{
int retval ;
__le16 * cport_count ;
2016-02-17 21:30:40 +03:00
cport_count = kzalloc ( sizeof ( * cport_count ) , GFP_KERNEL ) ;
2015-09-02 16:50:37 +03:00
if ( ! cport_count )
return - ENOMEM ;
retval = usb_control_msg ( udev , usb_rcvctrlpipe ( udev , 0 ) ,
2015-12-31 22:14:33 +03:00
GB_APB_REQUEST_CPORT_COUNT ,
2015-09-02 16:50:37 +03:00
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE , 0 , 0 , cport_count ,
2016-08-03 15:09:35 +03:00
sizeof ( * cport_count ) , ES2_USB_CTRL_TIMEOUT ) ;
2016-02-17 21:30:40 +03:00
if ( retval ! = sizeof ( * cport_count ) ) {
2015-09-02 16:50:37 +03:00
dev_err ( & udev - > dev , " Cannot retrieve CPort count: %d \n " ,
retval ) ;
2016-02-17 21:30:40 +03:00
if ( retval > = 0 )
retval = - EIO ;
2015-09-02 16:50:37 +03:00
goto out ;
}
retval = le16_to_cpu ( * cport_count ) ;
/* We need to fit a CPort ID in one byte of a message header */
if ( retval > U8_MAX ) {
retval = U8_MAX ;
dev_warn ( & udev - > dev , " Limiting number of CPorts to U8_MAX \n " ) ;
}
out :
kfree ( cport_count ) ;
return retval ;
}
2015-01-21 05:24:15 +03:00
/*
2015-11-02 13:56:57 +03:00
* The ES2 USB Bridge device has 15 endpoints
* 1 Control - usual USB stuff + AP - > APBridgeA messages
* 7 Bulk IN - CPort data in
* 7 Bulk OUT - CPort data out
2015-01-21 05:24:15 +03:00
*/
static int ap_probe ( struct usb_interface * interface ,
const struct usb_device_id * id )
{
2015-10-28 06:18:37 +03:00
struct es2_ap_dev * es2 ;
2015-11-03 20:03:23 +03:00
struct gb_host_device * hd ;
2015-01-21 05:24:15 +03:00
struct usb_device * udev ;
struct usb_host_interface * iface_desc ;
struct usb_endpoint_descriptor * endpoint ;
2016-08-17 18:11:04 +03:00
__u8 ep_addr ;
2016-05-11 11:18:00 +03:00
int retval ;
2015-01-21 05:24:15 +03:00
int i ;
2015-09-02 16:50:37 +03:00
int num_cports ;
2016-08-17 17:27:49 +03:00
bool bulk_out_found = false ;
2016-08-17 17:37:39 +03:00
bool bulk_in_found = false ;
bool arpc_in_found = false ;
2015-06-13 19:02:11 +03:00
2015-01-21 05:24:15 +03:00
udev = usb_get_dev ( interface_to_usbdev ( interface ) ) ;
2015-10-28 06:18:41 +03:00
num_cports = apb_get_cport_count ( udev ) ;
2015-09-02 16:50:37 +03:00
if ( num_cports < 0 ) {
usb_put_dev ( udev ) ;
dev_err ( & udev - > dev , " Cannot retrieve CPort count: %d \n " ,
num_cports ) ;
return num_cports ;
}
2015-11-03 20:03:25 +03:00
hd = gb_hd_create ( & es2_driver , & udev - > dev , ES2_GBUF_MSG_SIZE_MAX ,
2018-11-25 19:58:15 +03:00
num_cports ) ;
2015-05-22 17:52:45 +03:00
if ( IS_ERR ( hd ) ) {
2015-01-21 05:24:15 +03:00
usb_put_dev ( udev ) ;
2015-05-22 17:52:45 +03:00
return PTR_ERR ( hd ) ;
2015-01-21 05:24:15 +03:00
}
2015-10-28 06:18:37 +03:00
es2 = hd_to_es2 ( hd ) ;
es2 - > hd = hd ;
es2 - > usb_intf = interface ;
es2 - > usb_dev = udev ;
spin_lock_init ( & es2 - > cport_out_urb_lock ) ;
2015-10-28 06:18:41 +03:00
INIT_KFIFO ( es2 - > apb_log_fifo ) ;
2015-10-28 06:18:37 +03:00
usb_set_intfdata ( interface , es2 ) ;
2015-01-21 05:24:15 +03:00
2016-05-11 11:18:01 +03:00
/*
* Reserve the CDSI0 and CDSI1 CPorts so they won ' t be allocated
* dynamically .
*/
retval = gb_hd_cport_reserve ( hd , ES2_CPORT_CDSI0 ) ;
if ( retval )
goto error ;
retval = gb_hd_cport_reserve ( hd , ES2_CPORT_CDSI1 ) ;
if ( retval )
goto error ;
2015-11-02 13:56:57 +03:00
/* find all bulk endpoints */
2015-01-21 05:24:15 +03:00
iface_desc = interface - > cur_altsetting ;
for ( i = 0 ; i < iface_desc - > desc . bNumEndpoints ; + + i ) {
endpoint = & iface_desc - > endpoint [ i ] . desc ;
2016-08-17 18:11:04 +03:00
ep_addr = endpoint - > bEndpointAddress ;
2015-01-21 05:24:15 +03:00
2015-07-25 03:09:48 +03:00
if ( usb_endpoint_is_bulk_in ( endpoint ) ) {
2016-08-17 17:37:39 +03:00
if ( ! bulk_in_found ) {
2016-08-17 18:11:04 +03:00
es2 - > cport_in . endpoint = ep_addr ;
2016-08-17 17:37:39 +03:00
bulk_in_found = true ;
} else if ( ! arpc_in_found ) {
2016-08-17 18:11:04 +03:00
es2 - > arpc_endpoint_in = ep_addr ;
2016-08-17 17:37:39 +03:00
arpc_in_found = true ;
2016-08-17 18:11:04 +03:00
} else {
dev_warn ( & udev - > dev ,
" Unused bulk IN endpoint found: 0x%02x \n " ,
ep_addr ) ;
2016-08-17 17:37:39 +03:00
}
2016-08-17 18:11:04 +03:00
continue ;
2015-01-21 05:24:15 +03:00
}
2016-08-17 18:11:04 +03:00
if ( usb_endpoint_is_bulk_out ( endpoint ) ) {
if ( ! bulk_out_found ) {
es2 - > cport_out_endpoint = ep_addr ;
bulk_out_found = true ;
} else {
dev_warn ( & udev - > dev ,
" Unused bulk OUT endpoint found: 0x%02x \n " ,
ep_addr ) ;
}
continue ;
}
dev_warn ( & udev - > dev ,
" Unknown endpoint type found, address 0x%02x \n " ,
ep_addr ) ;
2015-01-21 05:24:15 +03:00
}
2016-08-17 17:37:39 +03:00
if ( ! bulk_in_found | | ! arpc_in_found | | ! bulk_out_found ) {
2015-01-21 05:24:15 +03:00
dev_err ( & udev - > dev , " Not enough endpoints found in device, aborting! \n " ) ;
2016-05-11 11:18:00 +03:00
retval = - ENODEV ;
2015-01-21 05:24:15 +03:00
goto error ;
}
2015-11-04 20:55:14 +03:00
/* Allocate buffers for our cport in messages */
2016-08-17 17:37:39 +03:00
for ( i = 0 ; i < NUM_CPORT_IN_URB ; + + i ) {
struct urb * urb ;
u8 * buffer ;
2015-06-15 19:08:13 +03:00
2016-08-17 17:37:39 +03:00
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! urb ) {
retval = - ENOMEM ;
goto error ;
}
es2 - > cport_in . urb [ i ] = urb ;
2016-08-17 16:43:32 +03:00
2016-08-17 17:37:39 +03:00
buffer = kmalloc ( ES2_GBUF_MSG_SIZE_MAX , GFP_KERNEL ) ;
if ( ! buffer ) {
retval = - ENOMEM ;
goto error ;
}
2015-06-15 19:08:13 +03:00
2016-08-17 17:37:39 +03:00
usb_fill_bulk_urb ( urb , udev ,
usb_rcvbulkpipe ( udev , es2 - > cport_in . endpoint ) ,
buffer , ES2_GBUF_MSG_SIZE_MAX ,
cport_in_callback , hd ) ;
2016-08-17 16:43:32 +03:00
2016-08-17 17:37:39 +03:00
es2 - > cport_in . buffer [ i ] = buffer ;
2015-01-21 05:24:15 +03:00
}
2016-07-07 15:41:00 +03:00
/* Allocate buffers for ARPC in messages */
for ( i = 0 ; i < NUM_ARPC_IN_URB ; + + i ) {
struct urb * urb ;
u8 * buffer ;
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! urb ) {
retval = - ENOMEM ;
goto error ;
}
2016-08-17 16:43:32 +03:00
es2 - > arpc_urb [ i ] = urb ;
2016-07-07 15:41:00 +03:00
buffer = kmalloc ( ARPC_IN_SIZE_MAX , GFP_KERNEL ) ;
if ( ! buffer ) {
retval = - ENOMEM ;
goto error ;
}
usb_fill_bulk_urb ( urb , udev ,
usb_rcvbulkpipe ( udev ,
es2 - > arpc_endpoint_in ) ,
buffer , ARPC_IN_SIZE_MAX ,
arpc_in_callback , es2 ) ;
es2 - > arpc_buffer [ i ] = buffer ;
}
2015-01-21 05:24:15 +03:00
/* Allocate urbs for our CPort OUT messages */
for ( i = 0 ; i < NUM_CPORT_OUT_URB ; + + i ) {
struct urb * urb ;
urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2016-05-11 11:18:00 +03:00
if ( ! urb ) {
retval = - ENOMEM ;
2015-01-21 05:24:15 +03:00
goto error ;
2016-05-11 11:18:00 +03:00
}
2015-01-21 05:24:15 +03:00
2015-10-28 06:18:37 +03:00
es2 - > cport_out_urb [ i ] = urb ;
es2 - > cport_out_urb_busy [ i ] = false ; /* just to be anal */
2015-01-21 05:24:15 +03:00
}
2015-10-28 06:18:41 +03:00
/* XXX We will need to rename this per APB */
es2 - > apb_log_enable_dentry = debugfs_create_file ( " apb_log_enable " ,
2018-11-25 19:58:15 +03:00
0644 ,
gb_debugfs_get ( ) , es2 ,
& apb_log_enable_fops ) ;
2015-11-04 20:55:14 +03:00
2016-07-07 15:41:00 +03:00
INIT_LIST_HEAD ( & es2 - > arpcs ) ;
spin_lock_init ( & es2 - > arpc_lock ) ;
2016-10-19 16:17:53 +03:00
retval = es2_arpc_in_enable ( es2 ) ;
if ( retval )
2016-07-07 15:41:00 +03:00
goto error ;
2015-11-04 20:55:22 +03:00
retval = gb_hd_add ( hd ) ;
if ( retval )
2016-07-07 15:41:00 +03:00
goto err_disable_arpc_in ;
2015-11-04 20:55:22 +03:00
2016-08-17 17:37:39 +03:00
retval = es2_cport_in_enable ( es2 , & es2 - > cport_in ) ;
if ( retval )
goto err_hd_del ;
2015-11-04 20:55:14 +03:00
2015-01-21 05:24:15 +03:00
return 0 ;
2015-11-04 20:55:20 +03:00
2016-08-17 17:37:39 +03:00
err_hd_del :
2015-11-04 20:55:22 +03:00
gb_hd_del ( hd ) ;
2016-07-07 15:41:00 +03:00
err_disable_arpc_in :
es2_arpc_in_disable ( es2 ) ;
2015-01-21 05:24:15 +03:00
error :
2015-11-04 20:55:20 +03:00
es2_destroy ( es2 ) ;
2015-01-21 05:24:15 +03:00
return retval ;
}
2016-04-21 09:01:16 +03:00
static void ap_disconnect ( struct usb_interface * interface )
{
struct es2_ap_dev * es2 = usb_get_intfdata ( interface ) ;
gb_hd_del ( es2 - > hd ) ;
2016-08-17 17:37:39 +03:00
es2_cport_in_disable ( es2 , & es2 - > cport_in ) ;
2016-07-07 15:41:00 +03:00
es2_arpc_in_disable ( es2 ) ;
2016-04-21 09:01:16 +03:00
es2_destroy ( es2 ) ;
}
2015-10-28 06:18:37 +03:00
static struct usb_driver es2_ap_driver = {
2015-05-05 19:04:22 +03:00
. name = " es2_ap_driver " ,
2015-01-21 05:24:15 +03:00
. probe = ap_probe ,
. disconnect = ap_disconnect ,
. id_table = id_table ,
2016-04-21 09:01:13 +03:00
. soft_unbind = 1 ,
2015-01-21 05:24:15 +03:00
} ;
2015-10-28 06:18:37 +03:00
module_usb_driver ( es2_ap_driver ) ;
2015-01-21 05:24:15 +03:00
2015-04-13 20:51:33 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2015-01-21 05:24:15 +03:00
MODULE_AUTHOR ( " Greg Kroah-Hartman <gregkh@linuxfoundation.org> " ) ;