2019-05-29 16:57:35 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2010-05-17 17:08:21 +01:00
/******************************************************************************
* platform - pci . c
*
* Xen platform PCI device driver
2016-02-21 19:06:08 -05:00
*
* Authors : ssmith @ xensource . com and stefano . stabellini @ eu . citrix . com
*
2010-05-17 17:08:21 +01:00
* Copyright ( c ) 2005 , Intel Corporation .
* Copyright ( c ) 2007 , XenSource Inc .
* Copyright ( c ) 2010 , Citrix
*/
# include <linux/interrupt.h>
# include <linux/io.h>
2016-02-21 19:06:08 -05:00
# include <linux/init.h>
2010-05-17 17:08:21 +01:00
# include <linux/pci.h>
2010-05-14 12:44:30 +01:00
# include <xen/platform_pci.h>
2010-05-17 17:08:21 +01:00
# include <xen/grant_table.h>
# include <xen/xenbus.h>
# include <xen/events.h>
# include <xen/hvm.h>
2010-05-14 12:45:07 +01:00
# include <xen/xen-ops.h>
2010-05-17 17:08:21 +01:00
# define DRV_NAME "xen-platform-pci"
static unsigned long platform_mmio ;
static unsigned long platform_mmio_alloc ;
static unsigned long platform_mmiolen ;
2017-01-13 10:07:23 -08:00
static uint64_t callback_via ;
2010-05-17 17:08:21 +01:00
2014-02-09 16:29:30 +05:30
static unsigned long alloc_xen_mmio ( unsigned long len )
2010-05-17 17:08:21 +01:00
{
unsigned long addr ;
addr = platform_mmio + platform_mmio_alloc ;
platform_mmio_alloc + = len ;
BUG_ON ( platform_mmio_alloc > platform_mmiolen ) ;
return addr ;
}
2017-01-13 10:07:23 -08:00
static uint64_t get_callback_via ( struct pci_dev * pdev )
{
u8 pin ;
int irq ;
irq = pdev - > irq ;
if ( irq < 16 )
return irq ; /* ISA IRQ */
pin = pdev - > pin ;
/* We don't know the GSI. Specify the PCI INTx line instead. */
2022-11-14 14:29:37 +01:00
return ( ( uint64_t ) HVM_PARAM_CALLBACK_TYPE_PCI_INTX < <
HVM_CALLBACK_VIA_TYPE_SHIFT ) |
2017-01-13 10:07:23 -08:00
( ( uint64_t ) pci_domain_nr ( pdev - > bus ) < < 32 ) |
( ( uint64_t ) pdev - > bus - > number < < 16 ) |
( ( uint64_t ) ( pdev - > devfn & 0xff ) < < 8 ) |
( ( uint64_t ) ( pin - 1 ) & 3 ) ;
}
static irqreturn_t do_hvm_evtchn_intr ( int irq , void * dev_id )
{
xen_hvm_evtchn_do_upcall ( ) ;
return IRQ_HANDLED ;
}
static int xen_allocate_irq ( struct pci_dev * pdev )
{
return request_irq ( pdev - > irq , do_hvm_evtchn_intr ,
IRQF_NOBALANCING | IRQF_TRIGGER_RISING ,
" xen-platform-pci " , pdev ) ;
}
2019-11-01 08:20:40 -05:00
static int platform_pci_resume ( struct device * dev )
2017-01-13 10:07:23 -08:00
{
int err ;
2017-04-24 15:04:53 -04:00
if ( xen_have_vector_callback )
2017-01-13 10:07:23 -08:00
return 0 ;
2017-04-24 15:04:53 -04:00
2017-01-13 10:07:23 -08:00
err = xen_set_callback_via ( callback_via ) ;
if ( err ) {
2019-11-01 08:20:40 -05:00
dev_err ( dev , " platform_pci_resume failure! \n " ) ;
2017-01-13 10:07:23 -08:00
return err ;
}
return 0 ;
}
2016-02-21 19:06:08 -05:00
static int platform_pci_probe ( struct pci_dev * pdev ,
const struct pci_device_id * ent )
2010-05-17 17:08:21 +01:00
{
int i , ret ;
2011-01-11 11:50:28 +00:00
long ioaddr ;
2010-05-17 17:08:21 +01:00
long mmio_addr , mmio_len ;
unsigned int max_nr_gframes ;
2014-01-06 10:40:36 -05:00
unsigned long grant_frames ;
2010-05-17 17:08:21 +01:00
2012-07-10 15:31:39 +02:00
if ( ! xen_domain ( ) )
return - ENODEV ;
2010-05-17 17:08:21 +01:00
i = pci_enable_device ( pdev ) ;
if ( i )
return i ;
ioaddr = pci_resource_start ( pdev , 0 ) ;
mmio_addr = pci_resource_start ( pdev , 1 ) ;
mmio_len = pci_resource_len ( pdev , 1 ) ;
if ( mmio_addr = = 0 | | ioaddr = = 0 ) {
dev_err ( & pdev - > dev , " no resources found \n " ) ;
ret = - ENOENT ;
goto pci_out ;
}
2011-01-11 11:50:28 +00:00
ret = pci_request_region ( pdev , 1 , DRV_NAME ) ;
if ( ret < 0 )
2010-05-17 17:08:21 +01:00
goto pci_out ;
2011-01-11 11:50:28 +00:00
ret = pci_request_region ( pdev , 0 , DRV_NAME ) ;
if ( ret < 0 )
2010-05-17 17:08:21 +01:00
goto mem_out ;
platform_mmio = mmio_addr ;
platform_mmiolen = mmio_len ;
2017-04-24 15:04:53 -04:00
if ( ! xen_have_vector_callback ) {
2017-01-13 10:07:23 -08:00
ret = xen_allocate_irq ( pdev ) ;
if ( ret ) {
dev_warn ( & pdev - > dev , " request_irq failed err=%d \n " , ret ) ;
goto out ;
}
2021-01-06 15:39:55 +00:00
/*
* It doesn ' t strictly * have * to run on CPU0 but it sure
* as hell better process the event channel ports delivered
* to CPU0 .
*/
irq_set_affinity ( pdev - > irq , cpumask_of ( 0 ) ) ;
2017-01-13 10:07:23 -08:00
callback_via = get_callback_via ( pdev ) ;
ret = xen_set_callback_via ( callback_via ) ;
if ( ret ) {
dev_warn ( & pdev - > dev , " Unable to set the evtchn callback "
" err=%d \n " , ret ) ;
2022-11-14 19:21:24 +08:00
goto irq_out ;
2017-01-13 10:07:23 -08:00
}
}
2010-05-17 17:08:21 +01:00
max_nr_gframes = gnttab_max_grant_frames ( ) ;
2014-01-06 10:40:36 -05:00
grant_frames = alloc_xen_mmio ( PAGE_SIZE * max_nr_gframes ) ;
2014-01-07 21:11:05 +08:00
ret = gnttab_setup_auto_xlat_frames ( grant_frames ) ;
if ( ret )
2022-11-14 19:21:24 +08:00
goto irq_out ;
2010-05-17 17:08:21 +01:00
ret = gnttab_init ( ) ;
if ( ret )
2014-01-06 10:40:36 -05:00
goto grant_out ;
2010-05-17 17:08:21 +01:00
return 0 ;
2014-01-06 10:40:36 -05:00
grant_out :
gnttab_free_auto_xlat_frames ( ) ;
2022-11-14 19:21:24 +08:00
irq_out :
if ( ! xen_have_vector_callback )
free_irq ( pdev - > irq , pdev ) ;
2010-05-17 17:08:21 +01:00
out :
2011-01-11 11:50:28 +00:00
pci_release_region ( pdev , 0 ) ;
2010-05-17 17:08:21 +01:00
mem_out :
2011-01-11 11:50:28 +00:00
pci_release_region ( pdev , 1 ) ;
2010-05-17 17:08:21 +01:00
pci_out :
pci_disable_device ( pdev ) ;
return ret ;
}
2017-08-02 23:16:57 +05:30
static const struct pci_device_id platform_pci_tbl [ ] = {
2010-05-17 17:08:21 +01:00
{ PCI_VENDOR_ID_XEN , PCI_DEVICE_ID_XEN_PLATFORM ,
PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ 0 , }
} ;
2020-05-09 15:47:55 +02:00
static const struct dev_pm_ops platform_pm_ops = {
2019-11-01 08:20:40 -05:00
. resume_noirq = platform_pci_resume ,
} ;
2010-05-17 17:08:21 +01:00
static struct pci_driver platform_driver = {
. name = DRV_NAME ,
2016-02-21 19:06:08 -05:00
. probe = platform_pci_probe ,
2010-05-17 17:08:21 +01:00
. id_table = platform_pci_tbl ,
2019-11-01 08:20:40 -05:00
. driver = {
. pm = & platform_pm_ops ,
} ,
2010-05-17 17:08:21 +01:00
} ;
2016-11-14 20:52:26 +08:00
builtin_pci_driver ( platform_driver ) ;