2017-11-14 18:38:02 +01:00
// SPDX-License-Identifier: GPL-2.0
2008-07-17 17:16:48 +02:00
/*
* qdio queue initialization
*
2012-07-20 11:15:04 +02:00
* Copyright IBM Corp . 2008
2008-07-17 17:16:48 +02:00
* Author ( s ) : Jan Glauber < jang @ linux . vnet . ibm . com >
*/
# include <linux/kernel.h>
# include <linux/slab.h>
2011-07-30 09:25:15 +02:00
# include <linux/export.h>
2020-02-10 10:48:11 +01:00
# include <linux/io.h>
2008-07-17 17:16:48 +02:00
# include <asm/qdio.h>
# include "cio.h"
# include "css.h"
# include "device.h"
# include "ioasm.h"
# include "chsc.h"
# include "qdio.h"
# include "qdio_debug.h"
2014-06-27 16:56:18 +02:00
# define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
2008-07-17 17:16:48 +02:00
static struct kmem_cache * qdio_q_cache ;
2011-08-08 01:33:55 +00:00
static struct kmem_cache * qdio_aob_cache ;
2011-12-27 11:27:10 +01:00
struct qaob * qdio_allocate_aob ( void )
2011-08-08 01:33:55 +00:00
{
2011-12-27 11:27:10 +01:00
return kmem_cache_zalloc ( qdio_aob_cache , GFP_ATOMIC ) ;
2011-08-08 01:33:55 +00:00
}
void qdio_release_aob ( struct qaob * aob )
{
kmem_cache_free ( qdio_aob_cache , aob ) ;
}
EXPORT_SYMBOL_GPL ( qdio_release_aob ) ;
2008-07-17 17:16:48 +02:00
2014-06-27 16:56:18 +02:00
/**
* qdio_free_buffers ( ) - free qdio buffers
* @ buf : array of pointers to qdio buffers
* @ count : number of qdio buffers to free
*/
void qdio_free_buffers ( struct qdio_buffer * * buf , unsigned int count )
{
int pos ;
for ( pos = 0 ; pos < count ; pos + = QBUFF_PER_PAGE )
free_page ( ( unsigned long ) buf [ pos ] ) ;
}
EXPORT_SYMBOL_GPL ( qdio_free_buffers ) ;
/**
* qdio_alloc_buffers ( ) - allocate qdio buffers
* @ buf : array of pointers to qdio buffers
* @ count : number of qdio buffers to allocate
*/
int qdio_alloc_buffers ( struct qdio_buffer * * buf , unsigned int count )
{
int pos ;
for ( pos = 0 ; pos < count ; pos + = QBUFF_PER_PAGE ) {
buf [ pos ] = ( void * ) get_zeroed_page ( GFP_KERNEL ) ;
if ( ! buf [ pos ] ) {
qdio_free_buffers ( buf , count ) ;
return - ENOMEM ;
}
}
for ( pos = 0 ; pos < count ; pos + + )
if ( pos % QBUFF_PER_PAGE )
buf [ pos ] = buf [ pos - 1 ] + 1 ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( qdio_alloc_buffers ) ;
/**
* qdio_reset_buffers ( ) - reset qdio buffers
* @ buf : array of pointers to qdio buffers
* @ count : number of qdio buffers that will be zeroed
*/
void qdio_reset_buffers ( struct qdio_buffer * * buf , unsigned int count )
{
int pos ;
for ( pos = 0 ; pos < count ; pos + + )
memset ( buf [ pos ] , 0 , sizeof ( struct qdio_buffer ) ) ;
}
EXPORT_SYMBOL_GPL ( qdio_reset_buffers ) ;
2008-07-17 17:16:48 +02:00
/*
* qebsm is only available under 64 bit but the adapter sets the feature
* flag anyway , so we manually override it .
*/
static inline int qebsm_possible ( void )
{
return css_general_characteristics . qebsm ;
}
/*
* qib_param_field : pointer to 128 bytes or NULL , if no param field
* nr_input_qs : pointer to nr_queues * 128 words of data or NULL
*/
static void set_impl_params ( struct qdio_irq * irq_ptr ,
unsigned int qib_param_field_format ,
unsigned char * qib_param_field ,
unsigned long * input_slib_elements ,
unsigned long * output_slib_elements )
{
struct qdio_q * q ;
int i , j ;
if ( ! irq_ptr )
return ;
irq_ptr - > qib . pfmt = qib_param_field_format ;
if ( qib_param_field )
memcpy ( irq_ptr - > qib . parm , qib_param_field ,
2019-09-20 10:17:09 +02:00
sizeof ( irq_ptr - > qib . parm ) ) ;
2008-07-17 17:16:48 +02:00
if ( ! input_slib_elements )
goto output ;
for_each_input_queue ( irq_ptr , q , i ) {
for ( j = 0 ; j < QDIO_MAX_BUFFERS_PER_Q ; j + + )
q - > slib - > slibe [ j ] . parms =
input_slib_elements [ i * QDIO_MAX_BUFFERS_PER_Q + j ] ;
}
output :
if ( ! output_slib_elements )
return ;
for_each_output_queue ( irq_ptr , q , i ) {
for ( j = 0 ; j < QDIO_MAX_BUFFERS_PER_Q ; j + + )
q - > slib - > slibe [ j ] . parms =
output_slib_elements [ i * QDIO_MAX_BUFFERS_PER_Q + j ] ;
}
}
2020-04-02 23:30:41 +02:00
static void __qdio_free_queues ( struct qdio_q * * queues , unsigned int count )
{
struct qdio_q * q ;
unsigned int i ;
for ( i = 0 ; i < count ; i + + ) {
q = queues [ i ] ;
free_page ( ( unsigned long ) q - > slib ) ;
kmem_cache_free ( qdio_q_cache , q ) ;
}
}
2020-04-02 23:48:00 +02:00
void qdio_free_queues ( struct qdio_irq * irq_ptr )
{
__qdio_free_queues ( irq_ptr - > input_qs , irq_ptr - > max_input_qs ) ;
irq_ptr - > max_input_qs = 0 ;
__qdio_free_queues ( irq_ptr - > output_qs , irq_ptr - > max_output_qs ) ;
irq_ptr - > max_output_qs = 0 ;
}
2008-07-17 17:16:48 +02:00
static int __qdio_allocate_qs ( struct qdio_q * * irq_ptr_qs , int nr_queues )
{
struct qdio_q * q ;
int i ;
for ( i = 0 ; i < nr_queues ; i + + ) {
2018-05-02 08:48:43 +02:00
q = kmem_cache_zalloc ( qdio_q_cache , GFP_KERNEL ) ;
2020-04-02 23:30:41 +02:00
if ( ! q ) {
__qdio_free_queues ( irq_ptr_qs , i ) ;
2008-07-17 17:16:48 +02:00
return - ENOMEM ;
2020-04-02 23:30:41 +02:00
}
2008-07-17 17:16:48 +02:00
q - > slib = ( struct slib * ) __get_free_page ( GFP_KERNEL ) ;
if ( ! q - > slib ) {
kmem_cache_free ( qdio_q_cache , q ) ;
2020-04-02 23:30:41 +02:00
__qdio_free_queues ( irq_ptr_qs , i ) ;
2008-07-17 17:16:48 +02:00
return - ENOMEM ;
}
irq_ptr_qs [ i ] = q ;
}
return 0 ;
}
int qdio_allocate_qs ( struct qdio_irq * irq_ptr , int nr_input_qs , int nr_output_qs )
{
int rc ;
rc = __qdio_allocate_qs ( irq_ptr - > input_qs , nr_input_qs ) ;
if ( rc )
return rc ;
2020-04-02 23:30:41 +02:00
2008-07-17 17:16:48 +02:00
rc = __qdio_allocate_qs ( irq_ptr - > output_qs , nr_output_qs ) ;
2020-04-02 23:48:00 +02:00
if ( rc ) {
2020-04-02 23:30:41 +02:00
__qdio_free_queues ( irq_ptr - > input_qs , nr_input_qs ) ;
2020-04-02 23:48:00 +02:00
return rc ;
}
2020-04-02 23:30:41 +02:00
2020-04-02 23:48:00 +02:00
irq_ptr - > max_input_qs = nr_input_qs ;
irq_ptr - > max_output_qs = nr_output_qs ;
return 0 ;
2008-07-17 17:16:48 +02:00
}
static void setup_queues_misc ( struct qdio_q * q , struct qdio_irq * irq_ptr ,
qdio_handler_t * handler , int i )
{
2010-05-17 10:00:16 +02:00
struct slib * slib = q - > slib ;
2008-07-17 17:16:48 +02:00
2010-05-17 10:00:16 +02:00
/* queue must be cleared for qdio_establish */
memset ( q , 0 , sizeof ( * q ) ) ;
memset ( slib , 0 , PAGE_SIZE ) ;
q - > slib = slib ;
2008-07-17 17:16:48 +02:00
q - > irq_ptr = irq_ptr ;
q - > mask = 1 < < ( 31 - i ) ;
q - > nr = i ;
q - > handler = handler ;
}
static void setup_storage_lists ( struct qdio_q * q , struct qdio_irq * irq_ptr ,
2019-01-28 16:11:13 +01:00
struct qdio_buffer * * sbals_array , int i )
2008-07-17 17:16:48 +02:00
{
struct qdio_q * prev ;
int j ;
2008-12-25 13:38:46 +01:00
DBF_HEX ( & q , sizeof ( void * ) ) ;
2008-07-17 17:16:48 +02:00
q - > sl = ( struct sl * ) ( ( char * ) q - > slib + PAGE_SIZE / 2 ) ;
/* fill in sbal */
2012-10-24 12:38:35 +02:00
for ( j = 0 ; j < QDIO_MAX_BUFFERS_PER_Q ; j + + )
2008-07-17 17:16:48 +02:00
q - > sbal [ j ] = * sbals_array + + ;
/* fill in slib */
if ( i > 0 ) {
prev = ( q - > is_input_q ) ? irq_ptr - > input_qs [ i - 1 ]
: irq_ptr - > output_qs [ i - 1 ] ;
prev - > slib - > nsliba = ( unsigned long ) q - > slib ;
}
q - > slib - > sla = ( unsigned long ) q - > sl ;
q - > slib - > slsba = ( unsigned long ) & q - > slsb . val [ 0 ] ;
/* fill in sl */
for ( j = 0 ; j < QDIO_MAX_BUFFERS_PER_Q ; j + + )
2020-02-10 10:48:11 +01:00
q - > sl - > element [ j ] . sbal = virt_to_phys ( q - > sbal [ j ] ) ;
2008-07-17 17:16:48 +02:00
}
static void setup_queues ( struct qdio_irq * irq_ptr ,
struct qdio_initialize * qdio_init )
{
struct qdio_q * q ;
2011-08-08 01:33:55 +00:00
struct qdio_outbuf_state * output_sbal_state_array =
qdio_init - > output_sbal_state_array ;
2008-07-17 17:16:48 +02:00
int i ;
for_each_input_queue ( irq_ptr , q , i ) {
2011-08-08 01:33:55 +00:00
DBF_EVENT ( " inq:%1d " , i ) ;
2008-07-17 17:16:48 +02:00
setup_queues_misc ( q , irq_ptr , qdio_init - > input_handler , i ) ;
q - > is_input_q = 1 ;
2011-08-08 01:33:55 +00:00
2020-03-20 14:00:00 +01:00
setup_storage_lists ( q , irq_ptr ,
qdio_init - > input_sbal_addr_array [ i ] , i ) ;
2008-07-17 17:16:48 +02:00
2011-08-08 01:33:55 +00:00
if ( is_thinint_irq ( irq_ptr ) ) {
2008-07-17 17:16:48 +02:00
tasklet_init ( & q - > tasklet , tiqdio_inbound_processing ,
( unsigned long ) q ) ;
2011-08-08 01:33:55 +00:00
} else {
2008-07-17 17:16:48 +02:00
tasklet_init ( & q - > tasklet , qdio_inbound_processing ,
( unsigned long ) q ) ;
2011-08-08 01:33:55 +00:00
}
2008-07-17 17:16:48 +02:00
}
for_each_output_queue ( irq_ptr , q , i ) {
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " outq:%1d " , i ) ;
2008-07-17 17:16:48 +02:00
setup_queues_misc ( q , irq_ptr , qdio_init - > output_handler , i ) ;
2011-08-08 01:33:55 +00:00
q - > u . out . sbal_state = output_sbal_state_array ;
output_sbal_state_array + = QDIO_MAX_BUFFERS_PER_Q ;
2008-07-17 17:16:48 +02:00
q - > is_input_q = 0 ;
2020-03-20 14:00:00 +01:00
setup_storage_lists ( q , irq_ptr ,
qdio_init - > output_sbal_addr_array [ i ] , i ) ;
2008-07-17 17:16:48 +02:00
tasklet_init ( & q - > tasklet , qdio_outbound_processing ,
( unsigned long ) q ) ;
2017-10-04 17:54:35 -07:00
timer_setup ( & q - > u . out . timer , qdio_outbound_timer , 0 ) ;
2008-07-17 17:16:48 +02:00
}
}
static void process_ac_flags ( struct qdio_irq * irq_ptr , unsigned char qdioac )
{
if ( qdioac & AC1_SIGA_INPUT_NEEDED )
irq_ptr - > siga_flag . input = 1 ;
if ( qdioac & AC1_SIGA_OUTPUT_NEEDED )
irq_ptr - > siga_flag . output = 1 ;
if ( qdioac & AC1_SIGA_SYNC_NEEDED )
irq_ptr - > siga_flag . sync = 1 ;
2011-01-05 12:47:54 +01:00
if ( ! ( qdioac & AC1_AUTOMATIC_SYNC_ON_THININT ) )
irq_ptr - > siga_flag . sync_after_ai = 1 ;
if ( ! ( qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI ) )
irq_ptr - > siga_flag . sync_out_after_pci = 1 ;
2008-07-17 17:16:48 +02:00
}
static void check_and_setup_qebsm ( struct qdio_irq * irq_ptr ,
unsigned char qdioac , unsigned long token )
{
if ( ! ( irq_ptr - > qib . rflags & QIB_RFLAGS_ENABLE_QEBSM ) )
goto no_qebsm ;
if ( ! ( qdioac & AC1_SC_QEBSM_AVAILABLE ) | |
( ! ( qdioac & AC1_SC_QEBSM_ENABLED ) ) )
goto no_qebsm ;
irq_ptr - > sch_token = token ;
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " V=V:1 " ) ;
DBF_EVENT ( " %8lx " , irq_ptr - > sch_token ) ;
2008-07-17 17:16:48 +02:00
return ;
no_qebsm :
irq_ptr - > sch_token = 0 ;
irq_ptr - > qib . rflags & = ~ QIB_RFLAGS_ENABLE_QEBSM ;
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " noV=V " ) ;
2008-07-17 17:16:48 +02:00
}
2008-12-25 13:38:43 +01:00
/*
* If there is a qdio_irq we use the chsc_page and store the information
* in the qdio_irq , otherwise we copy it to the specified structure .
*/
int qdio_setup_get_ssqd ( struct qdio_irq * irq_ptr ,
struct subchannel_id * schid ,
struct qdio_ssqd_desc * data )
2008-07-17 17:16:48 +02:00
{
struct chsc_ssqd_area * ssqd ;
int rc ;
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " getssqd:%4x " , schid - > sch_no ) ;
2013-06-05 18:58:35 +02:00
if ( ! irq_ptr ) {
2008-12-25 13:38:43 +01:00
ssqd = ( struct chsc_ssqd_area * ) __get_free_page ( GFP_KERNEL ) ;
2013-06-05 18:58:35 +02:00
if ( ! ssqd )
return - ENOMEM ;
} else {
ssqd = ( struct chsc_ssqd_area * ) irq_ptr - > chsc_page ;
}
rc = chsc_ssqd ( * schid , ssqd ) ;
2008-07-17 17:16:48 +02:00
if ( rc )
2013-06-05 18:58:35 +02:00
goto out ;
2008-07-17 17:16:48 +02:00
if ( ! ( ssqd - > qdio_ssqd . flags & CHSC_FLAG_QDIO_CAPABILITY ) | |
! ( ssqd - > qdio_ssqd . flags & CHSC_FLAG_VALIDITY ) | |
2008-12-25 13:38:43 +01:00
( ssqd - > qdio_ssqd . sch ! = schid - > sch_no ) )
2013-06-05 18:58:35 +02:00
rc = - EINVAL ;
if ( ! rc )
memcpy ( data , & ssqd - > qdio_ssqd , sizeof ( * data ) ) ;
out :
if ( ! irq_ptr )
2008-12-25 13:38:43 +01:00
free_page ( ( unsigned long ) ssqd ) ;
2013-06-05 18:58:35 +02:00
return rc ;
2008-07-17 17:16:48 +02:00
}
void qdio_setup_ssqd_info ( struct qdio_irq * irq_ptr )
{
unsigned char qdioac ;
int rc ;
2013-06-05 18:58:35 +02:00
rc = qdio_setup_get_ssqd ( irq_ptr , & irq_ptr - > schid , & irq_ptr - > ssqd_desc ) ;
2008-07-17 17:16:48 +02:00
if ( rc ) {
2008-12-25 13:38:46 +01:00
DBF_ERROR ( " %4x ssqd ERR " , irq_ptr - > schid . sch_no ) ;
DBF_ERROR ( " rc:%x " , rc ) ;
2008-07-17 17:16:48 +02:00
/* all flags set, worst case */
qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED |
AC1_SIGA_SYNC_NEEDED ;
} else
qdioac = irq_ptr - > ssqd_desc . qdioac1 ;
check_and_setup_qebsm ( irq_ptr , qdioac , irq_ptr - > ssqd_desc . sch_token ) ;
process_ac_flags ( irq_ptr , qdioac ) ;
2012-03-23 11:13:04 +01:00
DBF_EVENT ( " ac 1:%2x 2:%4x " , qdioac , irq_ptr - > ssqd_desc . qdioac2 ) ;
DBF_EVENT ( " 3:%4x qib:%4x " , irq_ptr - > ssqd_desc . qdioac3 , irq_ptr - > qib . ac ) ;
2008-07-17 17:16:48 +02:00
}
2020-04-02 23:48:00 +02:00
void qdio_free_async_data ( struct qdio_irq * irq_ptr )
2008-07-17 17:16:48 +02:00
{
struct qdio_q * q ;
int i ;
2020-04-02 23:48:00 +02:00
for ( i = 0 ; i < irq_ptr - > max_output_qs ; i + + ) {
2008-07-17 17:16:48 +02:00
q = irq_ptr - > output_qs [ i ] ;
2020-04-02 23:48:00 +02:00
if ( q - > u . out . use_cq ) {
unsigned int n ;
for ( n = 0 ; n < QDIO_MAX_BUFFERS_PER_Q ; n + + ) {
struct qaob * aob = q - > u . out . aobs [ n ] ;
2011-08-08 01:33:55 +00:00
2020-04-02 23:48:00 +02:00
if ( aob ) {
qdio_release_aob ( aob ) ;
q - > u . out . aobs [ n ] = NULL ;
}
2011-08-08 01:33:55 +00:00
}
2020-04-02 23:48:00 +02:00
qdio_disable_async_operation ( & q - > u . out ) ;
2008-07-17 17:16:48 +02:00
}
}
}
static void __qdio_allocate_fill_qdr ( struct qdio_irq * irq_ptr ,
struct qdio_q * * irq_ptr_qs ,
int i , int nr )
{
irq_ptr - > qdr - > qdf0 [ i + nr ] . sliba =
( unsigned long ) irq_ptr_qs [ i ] - > slib ;
irq_ptr - > qdr - > qdf0 [ i + nr ] . sla =
( unsigned long ) irq_ptr_qs [ i ] - > sl ;
irq_ptr - > qdr - > qdf0 [ i + nr ] . slsba =
( unsigned long ) & irq_ptr_qs [ i ] - > slsb . val [ 0 ] ;
2010-02-26 22:37:30 +01:00
irq_ptr - > qdr - > qdf0 [ i + nr ] . akey = PAGE_DEFAULT_KEY > > 4 ;
irq_ptr - > qdr - > qdf0 [ i + nr ] . bkey = PAGE_DEFAULT_KEY > > 4 ;
irq_ptr - > qdr - > qdf0 [ i + nr ] . ckey = PAGE_DEFAULT_KEY > > 4 ;
irq_ptr - > qdr - > qdf0 [ i + nr ] . dkey = PAGE_DEFAULT_KEY > > 4 ;
2008-07-17 17:16:48 +02:00
}
static void setup_qdr ( struct qdio_irq * irq_ptr ,
struct qdio_initialize * qdio_init )
{
int i ;
irq_ptr - > qdr - > qfmt = qdio_init - > q_format ;
2011-08-15 14:40:31 +02:00
irq_ptr - > qdr - > ac = qdio_init - > qdr_ac ;
2008-07-17 17:16:48 +02:00
irq_ptr - > qdr - > iqdcnt = qdio_init - > no_input_qs ;
irq_ptr - > qdr - > oqdcnt = qdio_init - > no_output_qs ;
irq_ptr - > qdr - > iqdsz = sizeof ( struct qdesfmt0 ) / 4 ; /* size in words */
irq_ptr - > qdr - > oqdsz = sizeof ( struct qdesfmt0 ) / 4 ;
irq_ptr - > qdr - > qiba = ( unsigned long ) & irq_ptr - > qib ;
2010-02-26 22:37:30 +01:00
irq_ptr - > qdr - > qkey = PAGE_DEFAULT_KEY > > 4 ;
2008-07-17 17:16:48 +02:00
for ( i = 0 ; i < qdio_init - > no_input_qs ; i + + )
__qdio_allocate_fill_qdr ( irq_ptr , irq_ptr - > input_qs , i , 0 ) ;
for ( i = 0 ; i < qdio_init - > no_output_qs ; i + + )
__qdio_allocate_fill_qdr ( irq_ptr , irq_ptr - > output_qs , i ,
qdio_init - > no_input_qs ) ;
}
static void setup_qib ( struct qdio_irq * irq_ptr ,
struct qdio_initialize * init_data )
{
if ( qebsm_possible ( ) )
irq_ptr - > qib . rflags | = QIB_RFLAGS_ENABLE_QEBSM ;
2010-07-16 15:37:41 +02:00
irq_ptr - > qib . rflags | = init_data - > qib_rflags ;
2008-07-17 17:16:48 +02:00
irq_ptr - > qib . qfmt = init_data - > q_format ;
if ( init_data - > no_input_qs )
irq_ptr - > qib . isliba =
( unsigned long ) ( irq_ptr - > input_qs [ 0 ] - > slib ) ;
if ( init_data - > no_output_qs )
irq_ptr - > qib . osliba =
( unsigned long ) ( irq_ptr - > output_qs [ 0 ] - > slib ) ;
memcpy ( irq_ptr - > qib . ebcnam , init_data - > adapter_name , 8 ) ;
}
2020-02-10 14:58:07 +01:00
int qdio_setup_irq ( struct qdio_irq * irq_ptr , struct qdio_initialize * init_data )
2008-07-17 17:16:48 +02:00
{
2020-03-20 14:00:00 +01:00
struct ccw_device * cdev = irq_ptr - > cdev ;
2008-07-17 17:16:48 +02:00
struct ciw * ciw ;
2010-02-26 22:37:37 +01:00
memset ( & irq_ptr - > qib , 0 , sizeof ( irq_ptr - > qib ) ) ;
memset ( & irq_ptr - > siga_flag , 0 , sizeof ( irq_ptr - > siga_flag ) ) ;
memset ( & irq_ptr - > ccw , 0 , sizeof ( irq_ptr - > ccw ) ) ;
memset ( & irq_ptr - > ssqd_desc , 0 , sizeof ( irq_ptr - > ssqd_desc ) ) ;
memset ( & irq_ptr - > perf_stat , 0 , sizeof ( irq_ptr - > perf_stat ) ) ;
2020-02-21 10:54:41 +01:00
irq_ptr - > debugfs_dev = NULL ;
2020-02-19 11:19:15 +01:00
irq_ptr - > sch_token = irq_ptr - > perf_stat_enabled = 0 ;
irq_ptr - > state = QDIO_IRQ_STATE_INACTIVE ;
2010-02-26 22:37:37 +01:00
2008-07-17 17:16:48 +02:00
/* wipes qib.ac, required by ar7063 */
memset ( irq_ptr - > qdr , 0 , sizeof ( struct qdr ) ) ;
irq_ptr - > int_parm = init_data - > int_parm ;
irq_ptr - > nr_input_qs = init_data - > no_input_qs ;
irq_ptr - > nr_output_qs = init_data - > no_output_qs ;
2019-08-23 11:48:48 +02:00
irq_ptr - > scan_threshold = init_data - > scan_threshold ;
2020-02-10 14:56:41 +01:00
ccw_device_get_schid ( cdev , & irq_ptr - > schid ) ;
2008-07-17 17:16:48 +02:00
setup_queues ( irq_ptr , init_data ) ;
2020-03-25 10:35:00 +01:00
if ( init_data - > irq_poll ) {
irq_ptr - > irq_poll = init_data - > irq_poll ;
set_bit ( QDIO_IRQ_DISABLED , & irq_ptr - > poll_state ) ;
} else {
irq_ptr - > irq_poll = NULL ;
}
2008-07-17 17:16:48 +02:00
setup_qib ( irq_ptr , init_data ) ;
set_impl_params ( irq_ptr , init_data - > qib_param_field_format ,
init_data - > qib_param_field ,
init_data - > input_slib_elements ,
init_data - > output_slib_elements ) ;
/* fill input and output descriptors */
setup_qdr ( irq_ptr , init_data ) ;
/* qdr, qib, sls, slsbs, slibs, sbales are filled now */
2020-04-09 10:55:16 +02:00
/* set our IRQ handler */
spin_lock_irq ( get_ccwdev_lock ( cdev ) ) ;
irq_ptr - > orig_handler = cdev - > handler ;
cdev - > handler = qdio_int_handler ;
spin_unlock_irq ( get_ccwdev_lock ( cdev ) ) ;
2008-07-17 17:16:48 +02:00
/* get qdio commands */
2020-02-10 14:56:41 +01:00
ciw = ccw_device_get_ciw ( cdev , CIW_TYPE_EQUEUE ) ;
2008-07-17 17:16:48 +02:00
if ( ! ciw ) {
2008-12-25 13:38:46 +01:00
DBF_ERROR ( " %4x NO EQ " , irq_ptr - > schid . sch_no ) ;
2018-05-02 08:28:34 +02:00
return - EINVAL ;
2008-07-17 17:16:48 +02:00
}
irq_ptr - > equeue = * ciw ;
2020-02-10 14:56:41 +01:00
ciw = ccw_device_get_ciw ( cdev , CIW_TYPE_AQUEUE ) ;
2008-07-17 17:16:48 +02:00
if ( ! ciw ) {
2008-12-25 13:38:46 +01:00
DBF_ERROR ( " %4x NO AQ " , irq_ptr - > schid . sch_no ) ;
2018-05-02 08:28:34 +02:00
return - EINVAL ;
2008-07-17 17:16:48 +02:00
}
irq_ptr - > aqueue = * ciw ;
2020-04-09 10:55:16 +02:00
return 0 ;
}
void qdio_shutdown_irq ( struct qdio_irq * irq )
{
struct ccw_device * cdev = irq - > cdev ;
/* restore IRQ handler */
2020-02-10 14:56:41 +01:00
spin_lock_irq ( get_ccwdev_lock ( cdev ) ) ;
2020-04-09 10:55:16 +02:00
cdev - > handler = irq - > orig_handler ;
cdev - > private - > intparm = 0 ;
2020-02-10 14:56:41 +01:00
spin_unlock_irq ( get_ccwdev_lock ( cdev ) ) ;
2008-07-17 17:16:48 +02:00
}
2020-03-20 14:00:00 +01:00
void qdio_print_subchannel_info ( struct qdio_irq * irq_ptr )
2008-07-17 17:16:48 +02:00
{
char s [ 80 ] ;
2008-12-25 13:38:46 +01:00
snprintf ( s , 80 , " qdio: %s %s on SC %x using "
2012-12-06 13:30:26 +01:00
" AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s \n " ,
2020-03-20 14:00:00 +01:00
dev_name ( & irq_ptr - > cdev - > dev ) ,
2008-12-25 13:38:46 +01:00
( irq_ptr - > qib . qfmt = = QDIO_QETH_QFMT ) ? " OSA " :
( ( irq_ptr - > qib . qfmt = = QDIO_ZFCP_QFMT ) ? " ZFCP " : " HS " ) ,
irq_ptr - > schid . sch_no ,
is_thinint_irq ( irq_ptr ) ,
( irq_ptr - > sch_token ) ? 1 : 0 ,
2018-10-30 08:19:54 +01:00
pci_out_supported ( irq_ptr ) ? 1 : 0 ,
2008-12-25 13:38:46 +01:00
css_general_characteristics . aif_tdd ,
( irq_ptr - > siga_flag . input ) ? " R " : " " ,
( irq_ptr - > siga_flag . output ) ? " W " : " " ,
( irq_ptr - > siga_flag . sync ) ? " S " : " " ,
2011-01-05 12:47:54 +01:00
( irq_ptr - > siga_flag . sync_after_ai ) ? " A " : " " ,
( irq_ptr - > siga_flag . sync_out_after_pci ) ? " P " : " " ) ;
2008-10-03 21:55:00 +02:00
printk ( KERN_INFO " %s " , s ) ;
2008-07-17 17:16:48 +02:00
}
2011-08-08 01:33:55 +00:00
int qdio_enable_async_operation ( struct qdio_output_q * outq )
{
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:03:40 -07:00
outq - > aobs = kcalloc ( QDIO_MAX_BUFFERS_PER_Q , sizeof ( struct qaob * ) ,
2020-02-05 09:41:42 +01:00
GFP_KERNEL ) ;
2011-08-08 01:33:55 +00:00
if ( ! outq - > aobs ) {
outq - > use_cq = 0 ;
return - ENOMEM ;
}
outq - > use_cq = 1 ;
return 0 ;
}
void qdio_disable_async_operation ( struct qdio_output_q * q )
{
kfree ( q - > aobs ) ;
q - > aobs = NULL ;
q - > use_cq = 0 ;
}
2008-07-17 17:16:48 +02:00
int __init qdio_setup_init ( void )
{
2011-08-08 01:33:55 +00:00
int rc ;
2008-07-17 17:16:48 +02:00
qdio_q_cache = kmem_cache_create ( " qdio_q " , sizeof ( struct qdio_q ) ,
256 , 0 , NULL ) ;
if ( ! qdio_q_cache )
return - ENOMEM ;
2011-08-08 01:33:55 +00:00
qdio_aob_cache = kmem_cache_create ( " qdio_aob " ,
sizeof ( struct qaob ) ,
sizeof ( struct qaob ) ,
0 ,
NULL ) ;
if ( ! qdio_aob_cache ) {
rc = - ENOMEM ;
goto free_qdio_q_cache ;
}
2008-07-17 17:16:48 +02:00
/* Check for OSA/FCP thin interrupts (bit 67). */
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " thinint:%1d " ,
( css_general_characteristics . aif_osa ) ? 1 : 0 ) ;
2008-07-17 17:16:48 +02:00
/* Check for QEBSM support in general (bit 58). */
2008-12-25 13:38:46 +01:00
DBF_EVENT ( " cssQEBSM:%1d " , ( qebsm_possible ( ) ) ? 1 : 0 ) ;
2011-08-08 01:33:55 +00:00
rc = 0 ;
out :
return rc ;
free_qdio_q_cache :
kmem_cache_destroy ( qdio_q_cache ) ;
goto out ;
2008-07-17 17:16:48 +02:00
}
2008-08-01 16:39:20 +02:00
void qdio_setup_exit ( void )
2008-07-17 17:16:48 +02:00
{
2011-08-08 01:33:55 +00:00
kmem_cache_destroy ( qdio_aob_cache ) ;
2008-07-17 17:16:48 +02:00
kmem_cache_destroy ( qdio_q_cache ) ;
}