2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0+
2005-04-17 02:20:36 +04:00
/*
* Copyright ( c ) 2001 by David Brownell
*/
/* this file is part of ehci-hcd.c */
/*-------------------------------------------------------------------------*/
/*
* There ' s basically three types of memory :
* - data used only by the HCD . . . kmalloc is fine
* - async and periodic schedules , shared by HC and HCD . . . these
* need to use dma_pool or dma_alloc_coherent
2006-08-31 01:50:06 +04:00
* - driver buffers , read / written by HC . . . single shot DMA mapped
2005-04-17 02:20:36 +04:00
*
2007-05-01 20:29:37 +04:00
* There ' s also " register " data ( e . g . PCI or SOC ) , which is memory mapped .
2005-04-17 02:20:36 +04:00
* No memory seen by this driver is pageable .
*/
/*-------------------------------------------------------------------------*/
/* Allocate the key transfer structures from the previously allocated pool */
2007-05-01 20:29:37 +04:00
static inline void ehci_qtd_init ( struct ehci_hcd * ehci , struct ehci_qtd * qtd ,
dma_addr_t dma )
2005-04-17 02:20:36 +04:00
{
memset ( qtd , 0 , sizeof * qtd ) ;
qtd - > qtd_dma = dma ;
2010-09-28 22:55:21 +04:00
qtd - > hw_token = cpu_to_hc32 ( ehci , QTD_STS_HALT ) ;
2007-05-01 20:29:37 +04:00
qtd - > hw_next = EHCI_LIST_END ( ehci ) ;
qtd - > hw_alt_next = EHCI_LIST_END ( ehci ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & qtd - > qtd_list ) ;
}
2005-10-21 11:21:58 +04:00
static struct ehci_qtd * ehci_qtd_alloc ( struct ehci_hcd * ehci , gfp_t flags )
2005-04-17 02:20:36 +04:00
{
struct ehci_qtd * qtd ;
dma_addr_t dma ;
qtd = dma_pool_alloc ( ehci - > qtd_pool , flags , & dma ) ;
if ( qtd ! = NULL ) {
2007-05-01 20:29:37 +04:00
ehci_qtd_init ( ehci , qtd , dma ) ;
2005-04-17 02:20:36 +04:00
}
return qtd ;
}
static inline void ehci_qtd_free ( struct ehci_hcd * ehci , struct ehci_qtd * qtd )
{
dma_pool_free ( ehci - > qtd_pool , qtd , qtd - > qtd_dma ) ;
}
2012-07-11 19:21:25 +04:00
static void qh_destroy ( struct ehci_hcd * ehci , struct ehci_qh * qh )
2005-04-17 02:20:36 +04:00
{
/* clean qtds first, and know this is not linked */
if ( ! list_empty ( & qh - > qtd_list ) | | qh - > qh_next . ptr ) {
ehci_dbg ( ehci , " unused qh not empty! \n " ) ;
BUG ( ) ;
}
if ( qh - > dummy )
ehci_qtd_free ( ehci , qh - > dummy ) ;
2009-07-14 03:23:29 +04:00
dma_pool_free ( ehci - > qh_pool , qh - > hw , qh - > qh_dma ) ;
kfree ( qh ) ;
2005-04-17 02:20:36 +04:00
}
2005-10-21 11:21:58 +04:00
static struct ehci_qh * ehci_qh_alloc ( struct ehci_hcd * ehci , gfp_t flags )
2005-04-17 02:20:36 +04:00
{
struct ehci_qh * qh ;
dma_addr_t dma ;
2009-07-14 03:23:29 +04:00
qh = kzalloc ( sizeof * qh , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! qh )
2009-07-14 03:23:29 +04:00
goto done ;
qh - > hw = ( struct ehci_qh_hw * )
2021-10-18 16:16:44 +03:00
dma_pool_zalloc ( ehci - > qh_pool , flags , & dma ) ;
2009-07-14 03:23:29 +04:00
if ( ! qh - > hw )
goto fail ;
2005-04-17 02:20:36 +04:00
qh - > qh_dma = dma ;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD ( & qh - > qtd_list ) ;
2013-07-03 18:53:10 +04:00
INIT_LIST_HEAD ( & qh - > unlink_node ) ;
2005-04-17 02:20:36 +04:00
/* dummy td enables safe urb queuing */
qh - > dummy = ehci_qtd_alloc ( ehci , flags ) ;
if ( qh - > dummy = = NULL ) {
ehci_dbg ( ehci , " no dummy td \n " ) ;
2009-07-14 03:23:29 +04:00
goto fail1 ;
2005-04-17 02:20:36 +04:00
}
2009-07-14 03:23:29 +04:00
done :
2005-04-17 02:20:36 +04:00
return qh ;
2009-07-14 03:23:29 +04:00
fail1 :
dma_pool_free ( ehci - > qh_pool , qh - > hw , qh - > qh_dma ) ;
fail :
kfree ( qh ) ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
/*-------------------------------------------------------------------------*/
2006-08-31 01:50:06 +04:00
/* The queue heads and transfer descriptors are managed from pools tied
2005-04-17 02:20:36 +04:00
* to each of the " per device " structures .
* This is the initialisation and cleanup code .
*/
static void ehci_mem_cleanup ( struct ehci_hcd * ehci )
{
if ( ehci - > async )
2012-07-11 19:21:25 +04:00
qh_destroy ( ehci , ehci - > async ) ;
2005-04-17 02:20:36 +04:00
ehci - > async = NULL ;
2010-11-08 12:58:35 +03:00
if ( ehci - > dummy )
2012-07-11 19:21:25 +04:00
qh_destroy ( ehci , ehci - > dummy ) ;
2010-11-08 12:58:35 +03:00
ehci - > dummy = NULL ;
2005-04-17 02:20:36 +04:00
/* DMA consistent memory and pools */
2015-11-16 21:01:44 +03:00
dma_pool_destroy ( ehci - > qtd_pool ) ;
2005-04-17 02:20:36 +04:00
ehci - > qtd_pool = NULL ;
2015-11-16 21:01:44 +03:00
dma_pool_destroy ( ehci - > qh_pool ) ;
ehci - > qh_pool = NULL ;
dma_pool_destroy ( ehci - > itd_pool ) ;
2005-04-17 02:20:36 +04:00
ehci - > itd_pool = NULL ;
2015-11-16 21:01:44 +03:00
dma_pool_destroy ( ehci - > sitd_pool ) ;
2005-04-17 02:20:36 +04:00
ehci - > sitd_pool = NULL ;
if ( ehci - > periodic )
2017-03-13 05:18:45 +03:00
dma_free_coherent ( ehci_to_hcd ( ehci ) - > self . sysdev ,
2005-04-17 02:20:36 +04:00
ehci - > periodic_size * sizeof ( u32 ) ,
ehci - > periodic , ehci - > periodic_dma ) ;
ehci - > periodic = NULL ;
/* shadow periodic table */
2005-04-19 04:39:34 +04:00
kfree ( ehci - > pshadow ) ;
2005-04-17 02:20:36 +04:00
ehci - > pshadow = NULL ;
}
/* remember to add cleanup code (above) if you add anything here */
2005-10-21 11:21:58 +04:00
static int ehci_mem_init ( struct ehci_hcd * ehci , gfp_t flags )
2005-04-17 02:20:36 +04:00
{
int i ;
/* QTDs for control/bulk/intr transfers */
2006-08-31 01:50:06 +04:00
ehci - > qtd_pool = dma_pool_create ( " ehci_qtd " ,
2017-03-13 05:18:45 +03:00
ehci_to_hcd ( ehci ) - > self . sysdev ,
2005-04-17 02:20:36 +04:00
sizeof ( struct ehci_qtd ) ,
32 /* byte alignment (for hw parts) */ ,
4096 /* can't cross 4K */ ) ;
if ( ! ehci - > qtd_pool ) {
goto fail ;
}
/* QHs for control/bulk/intr transfers */
2006-08-31 01:50:06 +04:00
ehci - > qh_pool = dma_pool_create ( " ehci_qh " ,
2017-03-13 05:18:45 +03:00
ehci_to_hcd ( ehci ) - > self . sysdev ,
2009-07-14 03:23:29 +04:00
sizeof ( struct ehci_qh_hw ) ,
2005-04-17 02:20:36 +04:00
32 /* byte alignment (for hw parts) */ ,
4096 /* can't cross 4K */ ) ;
if ( ! ehci - > qh_pool ) {
goto fail ;
}
ehci - > async = ehci_qh_alloc ( ehci , flags ) ;
if ( ! ehci - > async ) {
goto fail ;
}
/* ITD for high speed ISO transfers */
2006-08-31 01:50:06 +04:00
ehci - > itd_pool = dma_pool_create ( " ehci_itd " ,
2017-03-13 05:18:45 +03:00
ehci_to_hcd ( ehci ) - > self . sysdev ,
2005-04-17 02:20:36 +04:00
sizeof ( struct ehci_itd ) ,
32 /* byte alignment (for hw parts) */ ,
4096 /* can't cross 4K */ ) ;
if ( ! ehci - > itd_pool ) {
goto fail ;
}
/* SITD for full/low speed split ISO transfers */
2006-08-31 01:50:06 +04:00
ehci - > sitd_pool = dma_pool_create ( " ehci_sitd " ,
2017-03-13 05:18:45 +03:00
ehci_to_hcd ( ehci ) - > self . sysdev ,
2005-04-17 02:20:36 +04:00
sizeof ( struct ehci_sitd ) ,
32 /* byte alignment (for hw parts) */ ,
4096 /* can't cross 4K */ ) ;
if ( ! ehci - > sitd_pool ) {
goto fail ;
}
/* Hardware periodic table */
ehci - > periodic = ( __le32 * )
2017-03-13 05:18:45 +03:00
dma_alloc_coherent ( ehci_to_hcd ( ehci ) - > self . sysdev ,
2005-04-17 02:20:36 +04:00
ehci - > periodic_size * sizeof ( __le32 ) ,
2014-07-03 18:53:30 +04:00
& ehci - > periodic_dma , flags ) ;
2005-04-17 02:20:36 +04:00
if ( ehci - > periodic = = NULL ) {
goto fail ;
}
2010-11-08 12:58:35 +03:00
if ( ehci - > use_dummy_qh ) {
struct ehci_qh_hw * hw ;
ehci - > dummy = ehci_qh_alloc ( ehci , flags ) ;
if ( ! ehci - > dummy )
goto fail ;
hw = ehci - > dummy - > hw ;
hw - > hw_next = EHCI_LIST_END ( ehci ) ;
hw - > hw_qtd_next = EHCI_LIST_END ( ehci ) ;
hw - > hw_alt_next = EHCI_LIST_END ( ehci ) ;
ehci - > dummy - > hw = hw ;
for ( i = 0 ; i < ehci - > periodic_size ; i + + )
2013-10-18 19:15:14 +04:00
ehci - > periodic [ i ] = cpu_to_hc32 ( ehci ,
ehci - > dummy - > qh_dma ) ;
2010-11-08 12:58:35 +03:00
} else {
for ( i = 0 ; i < ehci - > periodic_size ; i + + )
ehci - > periodic [ i ] = EHCI_LIST_END ( ehci ) ;
}
2005-04-17 02:20:36 +04:00
/* software shadow of hardware table */
2006-02-27 23:29:43 +03:00
ehci - > pshadow = kcalloc ( ehci - > periodic_size , sizeof ( void * ) , flags ) ;
if ( ehci - > pshadow ! = NULL )
return 0 ;
2005-04-17 02:20:36 +04:00
fail :
ehci_dbg ( ehci , " couldn't init memory \n " ) ;
ehci_mem_cleanup ( ehci ) ;
return - ENOMEM ;
}