2005-04-16 15:20:36 -07:00
/*
* File : portdrv_pci . c
* Purpose : PCI Express Port Bus Driver
*
* Copyright ( C ) 2004 Intel
* Copyright ( C ) Tom Long Nguyen ( tom . l . nguyen @ intel . com )
*/
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/pm.h>
# include <linux/init.h>
2005-10-30 15:03:48 -08:00
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include <linux/pcieport_if.h>
# include "portdrv.h"
/*
* Version Information
*/
# define DRIVER_VERSION "v1.0"
# define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
# define DRIVER_DESC "PCIE Port Bus Driver"
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
/* global data */
static const char device_name [ ] = " pcieport-driver " ;
2005-06-22 09:09:54 -07:00
static void pci_save_msi_state ( struct pci_dev * dev )
{
struct pcie_port_device_ext * p_ext = pci_get_drvdata ( dev ) ;
int i = 0 , pos ;
u16 control ;
if ( ( pos = pci_find_capability ( dev , PCI_CAP_ID_MSI ) ) < = 0 )
return ;
pci_read_config_dword ( dev , pos , & p_ext - > saved_msi_config_space [ i + + ] ) ;
control = p_ext - > saved_msi_config_space [ 0 ] > > 16 ;
pci_read_config_dword ( dev , pos + PCI_MSI_ADDRESS_LO ,
& p_ext - > saved_msi_config_space [ i + + ] ) ;
if ( control & PCI_MSI_FLAGS_64BIT ) {
pci_read_config_dword ( dev , pos + PCI_MSI_ADDRESS_HI ,
& p_ext - > saved_msi_config_space [ i + + ] ) ;
pci_read_config_dword ( dev , pos + PCI_MSI_DATA_64 ,
& p_ext - > saved_msi_config_space [ i + + ] ) ;
} else
pci_read_config_dword ( dev , pos + PCI_MSI_DATA_32 ,
& p_ext - > saved_msi_config_space [ i + + ] ) ;
if ( control & PCI_MSI_FLAGS_MASKBIT )
pci_read_config_dword ( dev , pos + PCI_MSI_MASK_BIT ,
& p_ext - > saved_msi_config_space [ i + + ] ) ;
}
static void pci_restore_msi_state ( struct pci_dev * dev )
{
struct pcie_port_device_ext * p_ext = pci_get_drvdata ( dev ) ;
int i = 0 , pos ;
u16 control ;
if ( ( pos = pci_find_capability ( dev , PCI_CAP_ID_MSI ) ) < = 0 )
return ;
control = p_ext - > saved_msi_config_space [ i + + ] > > 16 ;
pci_write_config_word ( dev , pos + PCI_MSI_FLAGS , control ) ;
pci_write_config_dword ( dev , pos + PCI_MSI_ADDRESS_LO ,
p_ext - > saved_msi_config_space [ i + + ] ) ;
if ( control & PCI_MSI_FLAGS_64BIT ) {
pci_write_config_dword ( dev , pos + PCI_MSI_ADDRESS_HI ,
p_ext - > saved_msi_config_space [ i + + ] ) ;
pci_write_config_dword ( dev , pos + PCI_MSI_DATA_64 ,
p_ext - > saved_msi_config_space [ i + + ] ) ;
} else
pci_write_config_dword ( dev , pos + PCI_MSI_DATA_32 ,
p_ext - > saved_msi_config_space [ i + + ] ) ;
if ( control & PCI_MSI_FLAGS_MASKBIT )
pci_write_config_dword ( dev , pos + PCI_MSI_MASK_BIT ,
p_ext - > saved_msi_config_space [ i + + ] ) ;
}
static void pcie_portdrv_save_config ( struct pci_dev * dev )
{
struct pcie_port_device_ext * p_ext = pci_get_drvdata ( dev ) ;
pci_save_state ( dev ) ;
if ( p_ext - > interrupt_mode = = PCIE_PORT_MSI_MODE )
pci_save_msi_state ( dev ) ;
}
2005-07-28 11:37:33 -07:00
static int pcie_portdrv_restore_config ( struct pci_dev * dev )
2005-06-22 09:09:54 -07:00
{
struct pcie_port_device_ext * p_ext = pci_get_drvdata ( dev ) ;
2005-07-28 11:37:33 -07:00
int retval ;
2005-06-22 09:09:54 -07:00
pci_restore_state ( dev ) ;
if ( p_ext - > interrupt_mode = = PCIE_PORT_MSI_MODE )
pci_restore_msi_state ( dev ) ;
2005-07-28 11:37:33 -07:00
retval = pci_enable_device ( dev ) ;
if ( retval )
return retval ;
2005-06-22 09:09:54 -07:00
pci_set_master ( dev ) ;
2005-07-28 11:37:33 -07:00
return 0 ;
2005-06-22 09:09:54 -07:00
}
2005-04-16 15:20:36 -07:00
/*
* pcie_portdrv_probe - Probe PCI - Express port devices
* @ dev : PCI - Express port device being probed
*
* If detected invokes the pcie_port_device_register ( ) method for
* this port device .
*
*/
static int __devinit pcie_portdrv_probe ( struct pci_dev * dev ,
const struct pci_device_id * id )
{
int status ;
status = pcie_port_device_probe ( dev ) ;
if ( status )
return status ;
if ( pci_enable_device ( dev ) < 0 )
return - ENODEV ;
pci_set_master ( dev ) ;
if ( ! dev - > irq ) {
printk ( KERN_WARNING
" %s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS \n " ,
__FUNCTION__ , dev - > device , dev - > vendor ) ;
}
if ( pcie_port_device_register ( dev ) )
return - ENOMEM ;
return 0 ;
}
static void pcie_portdrv_remove ( struct pci_dev * dev )
{
pcie_port_device_remove ( dev ) ;
2005-06-22 09:09:54 -07:00
kfree ( pci_get_drvdata ( dev ) ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_PM
2005-04-16 15:25:33 -07:00
static int pcie_portdrv_suspend ( struct pci_dev * dev , pm_message_t state )
2005-04-16 15:20:36 -07:00
{
2005-06-22 09:09:54 -07:00
int ret = pcie_port_device_suspend ( dev , state ) ;
pcie_portdrv_save_config ( dev ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
static int pcie_portdrv_resume ( struct pci_dev * dev )
{
2005-06-22 09:09:54 -07:00
pcie_portdrv_restore_config ( dev ) ;
2005-04-16 15:20:36 -07:00
return pcie_port_device_resume ( dev ) ;
}
# endif
/*
* LINUX Device Driver Model
*/
static const struct pci_device_id port_pci_ids [ ] = { {
/* handle any PCI-Express port */
PCI_DEVICE_CLASS ( ( ( PCI_CLASS_BRIDGE_PCI < < 8 ) | 0x00 ) , ~ 0 ) ,
} , { /* end: all zeroes */ }
} ;
MODULE_DEVICE_TABLE ( pci , port_pci_ids ) ;
static struct pci_driver pcie_portdrv = {
. name = ( char * ) device_name ,
. id_table = & port_pci_ids [ 0 ] ,
. probe = pcie_portdrv_probe ,
. remove = pcie_portdrv_remove ,
# ifdef CONFIG_PM
. suspend = pcie_portdrv_suspend ,
. resume = pcie_portdrv_resume ,
# endif /* PM */
} ;
static int __init pcie_portdrv_init ( void )
{
int retval = 0 ;
pcie_port_bus_register ( ) ;
retval = pci_register_driver ( & pcie_portdrv ) ;
if ( retval )
pcie_port_bus_unregister ( ) ;
return retval ;
}
static void __exit pcie_portdrv_exit ( void )
{
pci_unregister_driver ( & pcie_portdrv ) ;
pcie_port_bus_unregister ( ) ;
}
module_init ( pcie_portdrv_init ) ;
module_exit ( pcie_portdrv_exit ) ;