t for the i.MX6 processor family.
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
blob: 5b4a9d9cd200dd5a6ee32c3d343bbae0cf2ff8ac (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                           
                         
                        

                       
                         

                           
                     
                             
                           
                           
                       
                         
                             






                                                                         
                                                                                                         













                                                                         












                                                                        
                          
 





                                             

 

                                                                 
                
                                   

                
                  

                                                                            
     
                                                       
      
                                                        








                                                                 
                                   

                
                  

                                                                            
     
                                                       
      
                                                        


                          

 

































                                                                      

                    
                                                                             



                                                   
                
                                   


                                            

                                           

                                   





                                                                     



                           
                                                                                          








                                                                             



                                                                               

                                               




                                                      


                                                                        
                              
 
                   
                                         


                                                 
              
                                                 
 






                                                                        
 

                                                                     

 







                                                                            
              














                                                                                















                                                                                



                                             



                                                              
                              
 

                                                                                


                               



                                                                            
 

                                                                               



                     
 






















                                                                      
 

















                                                                   




                                               
                                             








                                                                



                                             








                                                                         












                                                                       



                                                                       




                                                       
























                                                                            






                                                                 
                                                                  








                                                               
                                                          


  

                                       

                                            
                                      





                                                                

                    
 








                                                       


                                                              
                                                                                               


                               





                                                             

         




                                                                                                

         


                                                           
 




                                                                           







                                                                               








                                           
                                 
                            


                             

                                            
                                                                

                                                                      
                                                           
                                                              
                                                                  


                                                                                


                    
                                              
                                                                      

                                                                             


                    
              


                                                                           



                                                               







                                                           

                                                        
                                                    



                                                                                
                             

                                                                         
                                                                                













                                                              

                                       

                                
                                                          
                                           
                      




                                    
                                                          



                                                             


                          
                        
                                                           



                                                              



                          

                        
                                                          







                                                             
                                                          
                                           



                       

                                       



                     

                                                         
                                                     



                                                                                
                             






                                           
        

                                       
                                
                                                                           
                      
                       
         



                                                           
                                                          


                          

                          



                                                            
                                                           


                          



                                                           
                                                          


                          
 
                   
                                                                           



                       

                                       


                     
              

                                                      
                                                  


                                                                    




                                              
 
                                                  


              

                                                       
                                                   


                                                                    




                                              
 
                                                   

 


                                                               
                         
                                                    
                                                






                                                                           
              

                                                           
                                                       

                                                           
                                                                    










                                                               
                         
                                                    
                                                






                                                                            
              

                                                            
                                                        

                                                           
                                                                    









                                                                     
                         



                                                      
                                                                          


                                                                        
          

                                                            


                                                           
                                                                    

                                                             




                                                                  
                         








                                                                         

                                                           









                                                                    












                                                                        






                                                                         
                                                               










                                                                
                                          





                                                    
                                               





                                                              
                                           



                                                     
                                                























                                                                             



                            
 

                                                                              
 
                                                 
 

                                               
                            
                              
                                                                       
                                                   


                                                                          
                         


                 




                                                                
                                              

                                                                             


                                                                   
                                                                


                                                                             
                                             
                                      
                                   
              
 





                                              




                                                                                       

                                                         
                               
         
 





                                                                            

                                                                             


                                                                     



                                                                        

                                                             





                                                     

                                                             


                                                     

 































































                                                                             
   
                                                     
                        
  
                                                                     














                                                                         





                                                                         


         










                                                                            
                                              








                                                                     



                                                                    










                                                                          
   
                                                                      
                         
  
                                                                          
   
                                                          

              
                   


                                                                




                                               







                                                                             

                 
                 

                          

                                                                       



                                                               
                    
                              
                                                






                                       

                                                      
                                                  












                                                                                   
                    
                              
                                                







                                                                      

                                                     
                                                 








                                                                                   

                            

















                                                     
          
                                   







                                                
          
                                       



                                  
                                                            
 
                 

 












                                                                          





                                          



                                                                                   










                                                               
                                          


                                                    

                                             

                                                                     
                                    







                                              





                                                                    
                 








                                                                      

 
                                                                  
 
                   

                                   
 


                               
                                                    
                                                                                  
            


                                                                                   
 

                                                 





                                                                                

                                                                 
                       
                                                          
                            
                                         
                                                
                 
                                          

                                        
                                                    







                                                                      
         
 
                                              

                                                    
                                  
 


                                                        
                                  
 

                                              
                 
 
             
                       
                                                                       


                                      

                                        
                
                                                    




                                                                          

 







                                                                      



                                                           

 







                                                                

                         


                               
                                            
 
                                                    





                                                                          







                                                                                
         


                                              




                                      

                   
                              

                                                          

                                          
                                      
                 
         



                 
                              

                                                
                       





                                                                           






                                                                     


                       























                                                                     






                                                              


                              





                                      
/*
 * drivers/pci/pci-sysfs.c
 *
 * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
 * (C) Copyright 2002-2004 IBM Corp.
 * (C) Copyright 2003 Matthew Wilcox
 * (C) Copyright 2003 Hewlett-Packard
 * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
 * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
 *
 * File attributes for PCI devices
 *
 * Modeled after usb's driverfs.c 
 *
 */


#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/stat.h>
#include <linux/export.h>
#include <linux/topology.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/capability.h>
#include <linux/security.h>
#include <linux/pci-aspm.h>
#include <linux/slab.h>
#include <linux/vgaarb.h>
#include <linux/pm_runtime.h>
#include "pci.h"

static int sysfs_initialized;	/* = 0 */

/* show configuration fields */
#define pci_config_attr(field, format_string)				\
static ssize_t								\
field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
{									\
	struct pci_dev *pdev;						\
									\
	pdev = to_pci_dev (dev);					\
	return sprintf (buf, format_string, pdev->field);		\
}

pci_config_attr(vendor, "0x%04x\n");
pci_config_attr(device, "0x%04x\n");
pci_config_attr(subsystem_vendor, "0x%04x\n");
pci_config_attr(subsystem_device, "0x%04x\n");
pci_config_attr(class, "0x%06x\n");
pci_config_attr(irq, "%u\n");

static ssize_t broken_parity_status_show(struct device *dev,
					 struct device_attribute *attr,
					 char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	return sprintf (buf, "%u\n", pdev->broken_parity_status);
}

static ssize_t broken_parity_status_store(struct device *dev,
					  struct device_attribute *attr,
					  const char *buf, size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	unsigned long val;

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	pdev->broken_parity_status = !!val;

	return count;
}

static ssize_t local_cpus_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{		
	const struct cpumask *mask;
	int len;

#ifdef CONFIG_NUMA
	mask = (dev_to_node(dev) == -1) ? cpu_online_mask :
					  cpumask_of_node(dev_to_node(dev));
#else
	mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
#endif
	len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
	buf[len++] = '\n';
	buf[len] = '\0';
	return len;
}


static ssize_t local_cpulist_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	const struct cpumask *mask;
	int len;

#ifdef CONFIG_NUMA
	mask = (dev_to_node(dev) == -1) ? cpu_online_mask :
					  cpumask_of_node(dev_to_node(dev));
#else
	mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
#endif
	len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask);
	buf[len++] = '\n';
	buf[len] = '\0';
	return len;
}

/*
 * PCI Bus Class Devices
 */
static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
					int type,
					struct device_attribute *attr,
					char *buf)
{
	int ret;
	const struct cpumask *cpumask;

	cpumask = cpumask_of_pcibus(to_pci_bus(dev));
	ret = type ?
		cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) :
		cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask);
	buf[ret++] = '\n';
	buf[ret] = '\0';
	return ret;
}

static inline ssize_t pci_bus_show_cpumaskaffinity(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{
	return pci_bus_show_cpuaffinity(dev, 0, attr, buf);
}

static inline ssize_t pci_bus_show_cpulistaffinity(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{
	return pci_bus_show_cpuaffinity(dev, 1, attr, buf);
}

/* show resources */
static ssize_t
resource_show(struct device * dev, struct device_attribute *attr, char * buf)
{
	struct pci_dev * pci_dev = to_pci_dev(dev);
	char * str = buf;
	int i;
	int max;
	resource_size_t start, end;

	if (pci_dev->subordinate)
		max = DEVICE_COUNT_RESOURCE;
	else
		max = PCI_BRIDGE_RESOURCES;

	for (i = 0; i < max; i++) {
		struct resource *res =  &pci_dev->resource[i];
		pci_resource_to_user(pci_dev, i, res, &start, &end);
		str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",
			       (unsigned long long)start,
			       (unsigned long long)end,
			       (unsigned long long)res->flags);
	}
	return (str - buf);
}

static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pci_dev = to_pci_dev(dev);

	return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
		       pci_dev->vendor, pci_dev->device,
		       pci_dev->subsystem_vendor, pci_dev->subsystem_device,
		       (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
		       (u8)(pci_dev->class));
}

static ssize_t is_enabled_store(struct device *dev,
				struct device_attribute *attr, const char *buf,
				size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	unsigned long val;
	ssize_t result = strict_strtoul(buf, 0, &val);

	if (result < 0)
		return result;

	/* this can crash the machine when done on the "wrong" device */
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	if (!val) {
		if (pci_is_enabled(pdev))
			pci_disable_device(pdev);
		else
			result = -EIO;
	} else
		result = pci_enable_device(pdev);

	return result < 0 ? result : count;
}

static ssize_t is_enabled_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	struct pci_dev *pdev;

	pdev = to_pci_dev (dev);
	return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt));
}

#ifdef CONFIG_NUMA
static ssize_t
numa_node_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf (buf, "%d\n", dev->numa_node);
}
#endif

static ssize_t
dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);

	return sprintf (buf, "%d\n", fls64(pdev->dma_mask));
}

static ssize_t
consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr,
				 char *buf)
{
	return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask));
}

static ssize_t
msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);

	if (!pdev->subordinate)
		return 0;

	return sprintf (buf, "%u\n",
			!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
}

static ssize_t
msi_bus_store(struct device *dev, struct device_attribute *attr,
	      const char *buf, size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	unsigned long val;

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	/* bad things may happen if the no_msi flag is changed
	 * while some drivers are loaded */
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	/* Maybe pci devices without subordinate busses shouldn't even have this
	 * attribute in the first place?  */
	if (!pdev->subordinate)
		return count;

	/* Is the flag going to change, or keep the value it already had? */
	if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^
	    !!val) {
		pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI;

		dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI,"
			 " bad things could happen\n", val ? "" : " not");
	}

	return count;
}

static DEFINE_MUTEX(pci_remove_rescan_mutex);
static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
				size_t count)
{
	unsigned long val;
	struct pci_bus *b = NULL;

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	if (val) {
		mutex_lock(&pci_remove_rescan_mutex);
		while ((b = pci_find_next_bus(b)) != NULL)
			pci_rescan_bus(b);
		mutex_unlock(&pci_remove_rescan_mutex);
	}
	return count;
}

struct bus_attribute pci_bus_attrs[] = {
	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store),
	__ATTR_NULL
};

static ssize_t
dev_rescan_store(struct device *dev, struct device_attribute *attr,
		 const char *buf, size_t count)
{
	unsigned long val;
	struct pci_dev *pdev = to_pci_dev(dev);

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	if (val) {
		mutex_lock(&pci_remove_rescan_mutex);
		pci_rescan_bus(pdev->bus);
		mutex_unlock(&pci_remove_rescan_mutex);
	}
	return count;
}

static void remove_callback(struct device *dev)
{
	struct pci_dev *pdev = to_pci_dev(dev);

	mutex_lock(&pci_remove_rescan_mutex);
	pci_stop_and_remove_bus_device(pdev);
	mutex_unlock(&pci_remove_rescan_mutex);
}

static ssize_t
remove_store(struct device *dev, struct device_attribute *dummy,
	     const char *buf, size_t count)
{
	int ret = 0;
	unsigned long val;

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	/* An attribute cannot be unregistered by one of its own methods,
	 * so we have to use this roundabout approach.
	 */
	if (val)
		ret = device_schedule_callback(dev, remove_callback);
	if (ret)
		count = ret;
	return count;
}

static ssize_t
dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
		 const char *buf, size_t count)
{
	unsigned long val;
	struct pci_bus *bus = to_pci_bus(dev);

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	if (val) {
		mutex_lock(&pci_remove_rescan_mutex);
		if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
			pci_rescan_bus_bridge_resize(bus->self);
		else
			pci_rescan_bus(bus);
		mutex_unlock(&pci_remove_rescan_mutex);
	}
	return count;
}

#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
static ssize_t d3cold_allowed_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	unsigned long val;

	if (strict_strtoul(buf, 0, &val) < 0)
		return -EINVAL;

	pdev->d3cold_allowed = !!val;
	pm_runtime_resume(dev);

	return count;
}

static ssize_t d3cold_allowed_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	return sprintf (buf, "%u\n", pdev->d3cold_allowed);
}
#endif

#ifdef CONFIG_PCI_IOV
static ssize_t sriov_totalvfs_show(struct device *dev,
				   struct device_attribute *attr,
				   char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);

	return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
}


static ssize_t sriov_numvfs_show(struct device *dev,
				 struct device_attribute *attr,
				 char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);

	return sprintf(buf, "%u\n", pdev->sriov->num_VFs);
}

/*
 * num_vfs > 0; number of VFs to enable
 * num_vfs = 0; disable all VFs
 *
 * Note: SRIOV spec doesn't allow partial VF
 *       disable, so it's all or none.
 */
static ssize_t sriov_numvfs_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	int ret;
	u16 num_vfs;

	ret = kstrtou16(buf, 0, &num_vfs);
	if (ret < 0)
		return ret;

	if (num_vfs > pci_sriov_get_totalvfs(pdev))
		return -ERANGE;

	if (num_vfs == pdev->sriov->num_VFs)
		return count;		/* no change */

	/* is PF driver loaded w/callback */
	if (!pdev->driver || !pdev->driver->sriov_configure) {
		dev_info(&pdev->dev, "Driver doesn't support SRIOV configuration via sysfs\n");
		return -ENOSYS;
	}

	if (num_vfs == 0) {
		/* disable VFs */
		ret = pdev->driver->sriov_configure(pdev, 0);
		if (ret < 0)
			return ret;
		return count;
	}

	/* enable VFs */
	if (pdev->sriov->num_VFs) {
		dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n",
			 pdev->sriov->num_VFs, num_vfs);
		return -EBUSY;
	}

	ret = pdev->driver->sriov_configure(pdev, num_vfs);
	if (ret < 0)
		return ret;

	if (ret != num_vfs)
		dev_warn(&pdev->dev, "%d VFs requested; only %d enabled\n",
			 num_vfs, ret);

	return count;
}

static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
static struct device_attribute sriov_numvfs_attr =
		__ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP),
		       sriov_numvfs_show, sriov_numvfs_store);
#endif /* CONFIG_PCI_IOV */

struct device_attribute pci_dev_attrs[] = {
	__ATTR_RO(resource),
	__ATTR_RO(vendor),
	__ATTR_RO(device),
	__ATTR_RO(subsystem_vendor),
	__ATTR_RO(subsystem_device),
	__ATTR_RO(class),
	__ATTR_RO(irq),
	__ATTR_RO(local_cpus),
	__ATTR_RO(local_cpulist),
	__ATTR_RO(modalias),
#ifdef CONFIG_NUMA
	__ATTR_RO(numa_node),
#endif
	__ATTR_RO(dma_mask_bits),
	__ATTR_RO(consistent_dma_mask_bits),
	__ATTR(enable, 0600, is_enabled_show, is_enabled_store),
	__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
		broken_parity_status_show,broken_parity_status_store),
	__ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
	__ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store),
#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
	__ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store),
#endif
	__ATTR_NULL,
};

struct device_attribute pcibus_dev_attrs[] = {
	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
	__ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
	__ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),
	__ATTR_NULL,
};

static ssize_t
boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pdev = to_pci_dev(dev);
	struct pci_dev *vga_dev = vga_default_device();

	if (vga_dev)
		return sprintf(buf, "%u\n", (pdev == vga_dev));

	return sprintf(buf, "%u\n",
		!!(pdev->resource[PCI_ROM_RESOURCE].flags &
		   IORESOURCE_ROM_SHADOW));
}
struct device_attribute vga_attr = __ATTR_RO(boot_vga);

static ssize_t
pci_read_config(struct file *filp, struct kobject *kobj,
		struct bin_attribute *bin_attr,
		char *buf, loff_t off, size_t count)
{
	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
	unsigned int size = 64;
	loff_t init_off = off;
	u8 *data = (u8*) buf;

	/* Several chips lock up trying to read undefined config space */
	if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) {
		size = dev->cfg_size;
	} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
		size = 128;
	}

	if (off > size)
		return 0;
	if (off + count > size) {
		size -= off;
		count = size;
	} else {
		size = count;
	}

	pci_config_pm_runtime_get(dev);

	if ((off & 1) && size) {
		u8 val;
		pci_user_read_config_byte(dev, off, &val);
		data[off - init_off] = val;
		off++;
		size--;
	}

	if ((off & 3) && size > 2) {
		u16 val;
		pci_user_read_config_word(dev, off, &val);
		data[off - init_off] = val & 0xff;
		data[off - init_off + 1] = (val >> 8) & 0xff;
		off += 2;
		size -= 2;
	}

	while (size > 3) {
		u32 val;
		pci_user_read_config_dword(dev, off, &val);
		data[off - init_off] = val & 0xff;
		data[off - init_off + 1] = (val >> 8) & 0xff;
		data[off - init_off + 2] = (val >> 16) & 0xff;
		data[off - init_off + 3] = (val >> 24) & 0xff;
		off += 4;
		size -= 4;
	}

	if (size >= 2) {
		u16 val;
		pci_user_read_config_word(dev, off, &val);
		data[off - init_off] = val & 0xff;
		data[off - init_off + 1] = (val >> 8) & 0xff;
		off += 2;
		size -= 2;
	}

	if (size > 0) {
		u8 val;
		pci_user_read_config_byte(dev, off, &val);
		data[off - init_off] = val;
		off++;
		--size;
	}

	pci_config_pm_runtime_put(dev);

	return count;
}

static ssize_t
pci_write_config(struct file* filp, struct kobject *kobj,
		 struct bin_attribute *bin_attr,
		 char *buf, loff_t off, size_t count)
{
	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
	unsigned int size = count;
	loff_t init_off = off;
	u8 *data = (u8*) buf;