2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-04-09 15:05:43 +04:00
/*
* ACPI helpers for DMA request / controller
*
* Based on of - dma . c
*
* Copyright ( C ) 2013 , Intel Corporation
2013-05-08 12:55:48 +04:00
* Authors : Andy Shevchenko < andriy . shevchenko @ linux . intel . com >
* Mika Westerberg < mika . westerberg @ linux . intel . com >
2013-04-09 15:05:43 +04:00
*/
# include <linux/device.h>
2019-08-20 16:15:37 +03:00
# include <linux/dma-mapping.h>
2014-02-06 15:25:40 +04:00
# include <linux/err.h>
2013-04-09 15:05:43 +04:00
# include <linux/module.h>
2015-11-17 14:34:26 +03:00
# include <linux/kernel.h>
2013-04-09 15:05:43 +04:00
# include <linux/list.h>
# include <linux/mutex.h>
# include <linux/slab.h>
2013-05-08 12:55:48 +04:00
# include <linux/ioport.h>
2013-04-09 15:05:43 +04:00
# include <linux/acpi.h>
# include <linux/acpi_dma.h>
acpi-dma: Add support for "dma-names" device property
The current implementation hard codes the two supported channels so that
"tx" is always 0 and "rx" is always 1. This is because there has been no
suitable way in ACPI to name resources.
With _DSD device properties we can finally do this:
Device (SPI1) {
Name (_CRS, ResourceTemplate () {
...
FixedDMA (0x0000, 0x0000, Width32bit)
FixedDMA (0x0001, 0x0001, Width32bit)
})
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"dma-names", Package () {"tx", "rx"}}
},
})
}
The names "tx" and "rx" now provide index of the FixedDMA resource in
question.
Modify acpi_dma_request_slave_chan_by_name() so that it looks for
"dma-names" property first and only then fall back using hardcoded indices.
The DT "dma-names" binding that we reuse for ACPI is documented in
Documentation/devicetree/bindings/dma/dma.txt.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-09-14 17:37:36 +03:00
# include <linux/property.h>
2013-04-09 15:05:43 +04:00
static LIST_HEAD ( acpi_dma_list ) ;
static DEFINE_MUTEX ( acpi_dma_lock ) ;
2013-05-08 12:55:48 +04:00
/**
* acpi_dma_parse_resource_group - match device and parse resource group
* @ grp : CSRT resource group
* @ adev : ACPI device to match with
* @ adma : struct acpi_dma of the given DMA controller
*
* In order to match a device from DSDT table to the corresponding CSRT device
* we use MMIO address and IRQ .
2013-12-02 17:16:28 +04:00
*
* Return :
* 1 on success , 0 when no information is available , or appropriate errno value
* on error .
2013-05-08 12:55:48 +04:00
*/
static int acpi_dma_parse_resource_group ( const struct acpi_csrt_group * grp ,
struct acpi_device * adev , struct acpi_dma * adma )
{
const struct acpi_csrt_shared_info * si ;
struct list_head resource_list ;
2015-02-05 08:44:43 +03:00
struct resource_entry * rentry ;
2013-05-08 12:55:48 +04:00
resource_size_t mem = 0 , irq = 0 ;
int ret ;
if ( grp - > shared_info_length ! = sizeof ( struct acpi_csrt_shared_info ) )
return - ENODEV ;
INIT_LIST_HEAD ( & resource_list ) ;
ret = acpi_dev_get_resources ( adev , & resource_list , NULL , NULL ) ;
if ( ret < = 0 )
return 0 ;
list_for_each_entry ( rentry , & resource_list , node ) {
2015-02-05 08:44:43 +03:00
if ( resource_type ( rentry - > res ) = = IORESOURCE_MEM )
mem = rentry - > res - > start ;
else if ( resource_type ( rentry - > res ) = = IORESOURCE_IRQ )
irq = rentry - > res - > start ;
2013-05-08 12:55:48 +04:00
}
acpi_dev_free_resource_list ( & resource_list ) ;
/* Consider initial zero values as resource not found */
if ( mem = = 0 & & irq = = 0 )
return 0 ;
si = ( const struct acpi_csrt_shared_info * ) & grp [ 1 ] ;
2021-07-30 23:27:15 +03:00
/* Match device by MMIO */
2015-11-17 14:34:26 +03:00
if ( si - > mmio_base_low ! = lower_32_bits ( mem ) | |
2021-07-30 23:27:15 +03:00
si - > mmio_base_high ! = upper_32_bits ( mem ) )
return 0 ;
2021-08-02 20:55:32 +03:00
/*
* acpi_gsi_to_irq ( ) can ' t be used because some platforms do not save
* registered IRQs in the MP table . Instead we just try to register
* the GSI , which is the core part of the above mentioned function .
*/
2021-07-30 23:27:15 +03:00
ret = acpi_register_gsi ( NULL , si - > gsi_interrupt , si - > interrupt_mode , si - > interrupt_polarity ) ;
2021-08-02 20:55:32 +03:00
if ( ret < 0 )
return 0 ;
/* Match device by Linux vIRQ */
2021-07-30 23:27:15 +03:00
if ( ret ! = irq )
2013-05-08 12:55:48 +04:00
return 0 ;
dev_dbg ( & adev - > dev , " matches with %.4s%04X (rev %u) \n " ,
2013-08-21 15:27:06 +04:00
( char * ) & grp - > vendor_id , grp - > device_id , grp - > revision ) ;
2013-05-08 12:55:48 +04:00
/* Check if the request line range is available */
if ( si - > base_request_line = = 0 & & si - > num_handshake_signals = = 0 )
return 0 ;
2019-08-20 16:15:37 +03:00
/* Set up DMA mask based on value from CSRT */
ret = dma_coerce_mask_and_coherent ( & adev - > dev ,
DMA_BIT_MASK ( si - > dma_address_width ) ) ;
if ( ret )
return 0 ;
2013-05-08 12:55:48 +04:00
adma - > base_request_line = si - > base_request_line ;
adma - > end_request_line = si - > base_request_line +
si - > num_handshake_signals - 1 ;
dev_dbg ( & adev - > dev , " request line base: 0x%04x end: 0x%04x \n " ,
adma - > base_request_line , adma - > end_request_line ) ;
return 1 ;
}
/**
* acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources
* @ adev : ACPI device to match with
* @ adma : struct acpi_dma of the given DMA controller
*
* CSRT or Core System Resources Table is a proprietary ACPI table
* introduced by Microsoft . This table can contain devices that are not in
* the system DSDT table . In particular DMA controllers might be described
* here .
*
* We are using this table to get the request line range of the specific DMA
* controller to be used later .
*/
static void acpi_dma_parse_csrt ( struct acpi_device * adev , struct acpi_dma * adma )
{
struct acpi_csrt_group * grp , * end ;
struct acpi_table_csrt * csrt ;
acpi_status status ;
int ret ;
status = acpi_get_table ( ACPI_SIG_CSRT , 0 ,
( struct acpi_table_header * * ) & csrt ) ;
if ( ACPI_FAILURE ( status ) ) {
if ( status ! = AE_NOT_FOUND )
dev_warn ( & adev - > dev , " failed to get the CSRT table \n " ) ;
return ;
}
grp = ( struct acpi_csrt_group * ) ( csrt + 1 ) ;
end = ( struct acpi_csrt_group * ) ( ( void * ) csrt + csrt - > header . length ) ;
while ( grp < end ) {
ret = acpi_dma_parse_resource_group ( grp , adev , adma ) ;
if ( ret < 0 ) {
dev_warn ( & adev - > dev ,
" error in parsing resource group \n " ) ;
2020-07-22 12:54:21 +03:00
break ;
2013-05-08 12:55:48 +04:00
}
grp = ( struct acpi_csrt_group * ) ( ( void * ) grp + grp - > length ) ;
}
2020-07-22 12:54:21 +03:00
acpi_put_table ( ( struct acpi_table_header * ) csrt ) ;
2013-05-08 12:55:48 +04:00
}
2013-04-09 15:05:43 +04:00
/**
* acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers
* @ dev : struct device of DMA controller
* @ acpi_dma_xlate : translation function which converts a dma specifier
* into a dma_chan structure
2019-08-20 16:15:38 +03:00
* @ data : pointer to controller specific data to be used by
2013-04-09 15:05:43 +04:00
* translation function
*
* Allocated memory should be freed with appropriate acpi_dma_controller_free ( )
* call .
2013-12-02 17:16:28 +04:00
*
* Return :
* 0 on success or appropriate errno value on error .
2013-04-09 15:05:43 +04:00
*/
int acpi_dma_controller_register ( struct device * dev ,
struct dma_chan * ( * acpi_dma_xlate )
( struct acpi_dma_spec * , struct acpi_dma * ) ,
void * data )
{
struct acpi_device * adev ;
struct acpi_dma * adma ;
if ( ! dev | | ! acpi_dma_xlate )
return - EINVAL ;
/* Check if the device was enumerated by ACPI */
2015-09-04 16:12:30 +03:00
adev = ACPI_COMPANION ( dev ) ;
if ( ! adev )
2013-04-09 15:05:43 +04:00
return - EINVAL ;
adma = kzalloc ( sizeof ( * adma ) , GFP_KERNEL ) ;
if ( ! adma )
return - ENOMEM ;
adma - > dev = dev ;
adma - > acpi_dma_xlate = acpi_dma_xlate ;
adma - > data = data ;
2013-05-08 12:55:48 +04:00
acpi_dma_parse_csrt ( adev , adma ) ;
2013-04-09 15:05:43 +04:00
/* Now queue acpi_dma controller structure in list */
mutex_lock ( & acpi_dma_lock ) ;
list_add_tail ( & adma - > dma_controllers , & acpi_dma_list ) ;
mutex_unlock ( & acpi_dma_lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( acpi_dma_controller_register ) ;
/**
* acpi_dma_controller_free - Remove a DMA controller from ACPI DMA helpers list
* @ dev : struct device of DMA controller
*
* Memory allocated by acpi_dma_controller_register ( ) is freed here .
2013-12-02 17:16:28 +04:00
*
* Return :
* 0 on success or appropriate errno value on error .
2013-04-09 15:05:43 +04:00
*/
int acpi_dma_controller_free ( struct device * dev )
{
struct acpi_dma * adma ;
if ( ! dev )
return - EINVAL ;
mutex_lock ( & acpi_dma_lock ) ;
list_for_each_entry ( adma , & acpi_dma_list , dma_controllers )
if ( adma - > dev = = dev ) {
list_del ( & adma - > dma_controllers ) ;
mutex_unlock ( & acpi_dma_lock ) ;
kfree ( adma ) ;
return 0 ;
}
mutex_unlock ( & acpi_dma_lock ) ;
return - ENODEV ;
}
EXPORT_SYMBOL_GPL ( acpi_dma_controller_free ) ;
static void devm_acpi_dma_release ( struct device * dev , void * res )
{
acpi_dma_controller_free ( dev ) ;
}
/**
* devm_acpi_dma_controller_register - resource managed acpi_dma_controller_register ( )
* @ dev : device that is registering this DMA controller
* @ acpi_dma_xlate : translation function
2019-08-20 16:15:38 +03:00
* @ data : pointer to controller specific data
2013-04-09 15:05:43 +04:00
*
* Managed acpi_dma_controller_register ( ) . DMA controller registered by this
* function are automatically freed on driver detach . See
* acpi_dma_controller_register ( ) for more information .
2013-12-02 17:16:28 +04:00
*
* Return :
* 0 on success or appropriate errno value on error .
2013-04-09 15:05:43 +04:00
*/
int devm_acpi_dma_controller_register ( struct device * dev ,
struct dma_chan * ( * acpi_dma_xlate )
( struct acpi_dma_spec * , struct acpi_dma * ) ,
void * data )
{
void * res ;
int ret ;
res = devres_alloc ( devm_acpi_dma_release , 0 , GFP_KERNEL ) ;
if ( ! res )
return - ENOMEM ;
ret = acpi_dma_controller_register ( dev , acpi_dma_xlate , data ) ;
if ( ret ) {
devres_free ( res ) ;
return ret ;
}
devres_add ( dev , res ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devm_acpi_dma_controller_register ) ;
/**
* devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free ( )
2019-08-20 16:15:38 +03:00
* @ dev : device that is unregistering as DMA controller
2013-04-09 15:05:43 +04:00
*
* Unregister a DMA controller registered with
* devm_acpi_dma_controller_register ( ) . Normally this function will not need to
* be called and the resource management code will ensure that the resource is
* freed .
*/
void devm_acpi_dma_controller_free ( struct device * dev )
{
2014-02-06 15:25:39 +04:00
WARN_ON ( devres_release ( dev , devm_acpi_dma_release , NULL , NULL ) ) ;
2013-04-09 15:05:43 +04:00
}
EXPORT_SYMBOL_GPL ( devm_acpi_dma_controller_free ) ;
2013-05-08 12:55:48 +04:00
/**
* acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function
* @ adma : struct acpi_dma of DMA controller
* @ dma_spec : dma specifier to update
*
* Accordingly to ACPI 5.0 Specification Table 6 - 170 " Fixed DMA Resource
* Descriptor " :
* DMA Request Line bits is a platform - relative number uniquely
* identifying the request line assigned . Request line - to - Controller
* mapping is done in a controller - specific OS driver .
* That ' s why we can safely adjust slave_id when the appropriate controller is
* found .
2013-12-02 17:16:28 +04:00
*
* Return :
* 0 , if no information is avaiable , - 1 on mismatch , and 1 otherwise .
2013-05-08 12:55:48 +04:00
*/
static int acpi_dma_update_dma_spec ( struct acpi_dma * adma ,
struct acpi_dma_spec * dma_spec )
{
/* Set link to the DMA controller device */
dma_spec - > dev = adma - > dev ;
/* Check if the request line range is available */
if ( adma - > base_request_line = = 0 & & adma - > end_request_line = = 0 )
return 0 ;
/* Check if slave_id falls to the range */
if ( dma_spec - > slave_id < adma - > base_request_line | |
dma_spec - > slave_id > adma - > end_request_line )
return - 1 ;
/*
* Here we adjust slave_id . It should be a relative number to the base
* request line .
*/
dma_spec - > slave_id - = adma - > base_request_line ;
return 1 ;
}
2013-04-09 15:05:43 +04:00
struct acpi_dma_parser_data {
struct acpi_dma_spec dma_spec ;
size_t index ;
size_t n ;
} ;
/**
* acpi_dma_parse_fixed_dma - Parse FixedDMA ACPI resources to a DMA specifier
* @ res : struct acpi_resource to get FixedDMA resources from
* @ data : pointer to a helper struct acpi_dma_parser_data
*/
static int acpi_dma_parse_fixed_dma ( struct acpi_resource * res , void * data )
{
struct acpi_dma_parser_data * pdata = data ;
if ( res - > type = = ACPI_RESOURCE_TYPE_FIXED_DMA ) {
struct acpi_resource_fixed_dma * dma = & res - > data . fixed_dma ;
if ( pdata - > n + + = = pdata - > index ) {
pdata - > dma_spec . chan_id = dma - > channels ;
pdata - > dma_spec . slave_id = dma - > request_lines ;
}
}
/* Tell the ACPI core to skip this resource */
return 1 ;
}
/**
* acpi_dma_request_slave_chan_by_index - Get the DMA slave channel
* @ dev : struct device to get DMA request from
* @ index : index of FixedDMA descriptor for @ dev
*
2013-12-02 17:16:28 +04:00
* Return :
2014-02-06 15:25:40 +04:00
* Pointer to appropriate dma channel on success or an error pointer .
2013-04-09 15:05:43 +04:00
*/
struct dma_chan * acpi_dma_request_slave_chan_by_index ( struct device * dev ,
size_t index )
{
struct acpi_dma_parser_data pdata ;
struct acpi_dma_spec * dma_spec = & pdata . dma_spec ;
2020-06-22 21:13:11 +03:00
struct acpi_device * adev = ACPI_COMPANION ( dev ) ;
2013-04-09 15:05:43 +04:00
struct list_head resource_list ;
struct acpi_dma * adma ;
struct dma_chan * chan = NULL ;
2013-05-08 12:55:48 +04:00
int found ;
2020-06-22 21:13:11 +03:00
int ret ;
2013-04-09 15:05:43 +04:00
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
pdata . index = index ;
/* Initial values for the request line and channel */
dma_spec - > chan_id = - 1 ;
dma_spec - > slave_id = - 1 ;
INIT_LIST_HEAD ( & resource_list ) ;
2020-06-22 21:13:11 +03:00
ret = acpi_dev_get_resources ( adev , & resource_list ,
acpi_dma_parse_fixed_dma , & pdata ) ;
2013-04-09 15:05:43 +04:00
acpi_dev_free_resource_list ( & resource_list ) ;
2020-06-22 21:13:11 +03:00
if ( ret < 0 )
return ERR_PTR ( ret ) ;
2013-04-09 15:05:43 +04:00
if ( dma_spec - > slave_id < 0 | | dma_spec - > chan_id < 0 )
2014-02-06 15:25:40 +04:00
return ERR_PTR ( - ENODEV ) ;
2013-04-09 15:05:43 +04:00
mutex_lock ( & acpi_dma_lock ) ;
list_for_each_entry ( adma , & acpi_dma_list , dma_controllers ) {
2013-05-08 12:55:48 +04:00
/*
* We are not going to call translation function if slave_id
* doesn ' t fall to the request range .
*/
found = acpi_dma_update_dma_spec ( adma , dma_spec ) ;
if ( found < 0 )
continue ;
2013-04-09 15:05:43 +04:00
chan = adma - > acpi_dma_xlate ( dma_spec , adma ) ;
2013-05-08 12:55:48 +04:00
/*
* Try to get a channel only from the DMA controller that
* matches the slave_id . See acpi_dma_update_dma_spec ( )
* description for the details .
*/
if ( found > 0 | | chan )
2013-04-09 15:05:43 +04:00
break ;
}
mutex_unlock ( & acpi_dma_lock ) ;
2014-02-06 15:25:40 +04:00
return chan ? chan : ERR_PTR ( - EPROBE_DEFER ) ;
2013-04-09 15:05:43 +04:00
}
EXPORT_SYMBOL_GPL ( acpi_dma_request_slave_chan_by_index ) ;
/**
* acpi_dma_request_slave_chan_by_name - Get the DMA slave channel
* @ dev : struct device to get DMA request from
* @ name : represents corresponding FixedDMA descriptor for @ dev
*
* In order to support both Device Tree and ACPI in a single driver we
* translate the names " tx " and " rx " here based on the most common case where
* the first FixedDMA descriptor is TX and second is RX .
*
acpi-dma: Add support for "dma-names" device property
The current implementation hard codes the two supported channels so that
"tx" is always 0 and "rx" is always 1. This is because there has been no
suitable way in ACPI to name resources.
With _DSD device properties we can finally do this:
Device (SPI1) {
Name (_CRS, ResourceTemplate () {
...
FixedDMA (0x0000, 0x0000, Width32bit)
FixedDMA (0x0001, 0x0001, Width32bit)
})
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"dma-names", Package () {"tx", "rx"}}
},
})
}
The names "tx" and "rx" now provide index of the FixedDMA resource in
question.
Modify acpi_dma_request_slave_chan_by_name() so that it looks for
"dma-names" property first and only then fall back using hardcoded indices.
The DT "dma-names" binding that we reuse for ACPI is documented in
Documentation/devicetree/bindings/dma/dma.txt.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-09-14 17:37:36 +03:00
* If the device has " dma-names " property the FixedDMA descriptor indices
* are retrieved based on those . Otherwise the function falls back using
* hardcoded indices .
*
2013-12-02 17:16:28 +04:00
* Return :
2014-02-06 15:25:40 +04:00
* Pointer to appropriate dma channel on success or an error pointer .
2013-04-09 15:05:43 +04:00
*/
struct dma_chan * acpi_dma_request_slave_chan_by_name ( struct device * dev ,
const char * name )
{
acpi-dma: Add support for "dma-names" device property
The current implementation hard codes the two supported channels so that
"tx" is always 0 and "rx" is always 1. This is because there has been no
suitable way in ACPI to name resources.
With _DSD device properties we can finally do this:
Device (SPI1) {
Name (_CRS, ResourceTemplate () {
...
FixedDMA (0x0000, 0x0000, Width32bit)
FixedDMA (0x0001, 0x0001, Width32bit)
})
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"dma-names", Package () {"tx", "rx"}}
},
})
}
The names "tx" and "rx" now provide index of the FixedDMA resource in
question.
Modify acpi_dma_request_slave_chan_by_name() so that it looks for
"dma-names" property first and only then fall back using hardcoded indices.
The DT "dma-names" binding that we reuse for ACPI is documented in
Documentation/devicetree/bindings/dma/dma.txt.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-09-14 17:37:36 +03:00
int index ;
index = device_property_match_string ( dev , " dma-names " , name ) ;
if ( index < 0 ) {
if ( ! strcmp ( name , " tx " ) )
index = 0 ;
else if ( ! strcmp ( name , " rx " ) )
index = 1 ;
else
return ERR_PTR ( - ENODEV ) ;
}
2013-04-09 15:05:43 +04:00
2016-02-16 12:26:53 +03:00
dev_dbg ( dev , " Looking for DMA channel \" %s \" at index %d... \n " , name , index ) ;
2013-04-09 15:05:43 +04:00
return acpi_dma_request_slave_chan_by_index ( dev , index ) ;
}
EXPORT_SYMBOL_GPL ( acpi_dma_request_slave_chan_by_name ) ;
/**
* acpi_dma_simple_xlate - Simple ACPI DMA engine translation helper
* @ dma_spec : pointer to ACPI DMA specifier
* @ adma : pointer to ACPI DMA controller data
*
* A simple translation function for ACPI based devices . Passes & struct
2013-12-02 17:16:28 +04:00
* dma_spec to the DMA controller driver provided filter function .
*
* Return :
* Pointer to the channel if found or % NULL otherwise .
2013-04-09 15:05:43 +04:00
*/
struct dma_chan * acpi_dma_simple_xlate ( struct acpi_dma_spec * dma_spec ,
struct acpi_dma * adma )
{
struct acpi_dma_filter_info * info = adma - > data ;
if ( ! info | | ! info - > filter_fn )
return NULL ;
return dma_request_channel ( info - > dma_cap , info - > filter_fn , dma_spec ) ;
}
EXPORT_SYMBOL_GPL ( acpi_dma_simple_xlate ) ;