EXPORT_SYMBOL(pci_bus_write_config_byte);
 EXPORT_SYMBOL(pci_bus_write_config_word);
 EXPORT_SYMBOL(pci_bus_write_config_dword);
+
+static u32 pci_user_cached_config(struct pci_dev *dev, int pos)
+{
+       u32 data;
+
+       data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])];
+       data >>= (pos % sizeof(dev->saved_config_space[0])) * 8;
+       return data;
+}
+
+#define PCI_USER_READ_CONFIG(size,type)                                        \
+int pci_user_read_config_##size                                                \
+       (struct pci_dev *dev, int pos, type *val)                       \
+{                                                                      \
+       unsigned long flags;                                            \
+       int ret = 0;                                                    \
+       u32 data = -1;                                                  \
+       if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
+       spin_lock_irqsave(&pci_lock, flags);                            \
+       if (likely(!dev->block_ucfg_access))                            \
+               ret = dev->bus->ops->read(dev->bus, dev->devfn,         \
+                                       pos, sizeof(type), &data);      \
+       else if (pos < sizeof(dev->saved_config_space))                 \
+               data = pci_user_cached_config(dev, pos);                \
+       spin_unlock_irqrestore(&pci_lock, flags);                       \
+       *val = (type)data;                                              \
+       return ret;                                                     \
+}
+
+#define PCI_USER_WRITE_CONFIG(size,type)                               \
+int pci_user_write_config_##size                                       \
+       (struct pci_dev *dev, int pos, type val)                        \
+{                                                                      \
+       unsigned long flags;                                            \
+       int ret = -EIO;                                                 \
+       if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;       \
+       spin_lock_irqsave(&pci_lock, flags);                            \
+       if (likely(!dev->block_ucfg_access))                            \
+               ret = dev->bus->ops->write(dev->bus, dev->devfn,        \
+                                       pos, sizeof(type), val);        \
+       spin_unlock_irqrestore(&pci_lock, flags);                       \
+       return ret;                                                     \
+}
+
+PCI_USER_READ_CONFIG(byte, u8)
+PCI_USER_READ_CONFIG(word, u16)
+PCI_USER_READ_CONFIG(dword, u32)
+PCI_USER_WRITE_CONFIG(byte, u8)
+PCI_USER_WRITE_CONFIG(word, u16)
+PCI_USER_WRITE_CONFIG(dword, u32)
+
+/**
+ * pci_block_user_cfg_access - Block userspace PCI config reads/writes
+ * @dev:       pci device struct
+ *
+ * This function blocks any userspace PCI config accesses from occurring.
+ * When blocked, any writes will be bit bucketed and reads will return the
+ * data saved using pci_save_state for the first 64 bytes of config
+ * space and return 0xff for all other config reads.
+ **/
+void pci_block_user_cfg_access(struct pci_dev *dev)
+{
+       unsigned long flags;
+
+       pci_save_state(dev);
+
+       /* spinlock to synchronize with anyone reading config space now */
+       spin_lock_irqsave(&pci_lock, flags);
+       dev->block_ucfg_access = 1;
+       spin_unlock_irqrestore(&pci_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pci_block_user_cfg_access);
+
+/**
+ * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes
+ * @dev:       pci device struct
+ *
+ * This function allows userspace PCI config accesses to resume.
+ **/
+void pci_unblock_user_cfg_access(struct pci_dev *dev)
+{
+       unsigned long flags;
+
+       /* spinlock to synchronize with anyone reading saved config space */
+       spin_lock_irqsave(&pci_lock, flags);
+       dev->block_ucfg_access = 0;
+       spin_unlock_irqrestore(&pci_lock, flags);
+}
+EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access);
 
 
        if ((off & 1) && size) {
                u8 val;
-               pci_read_config_byte(dev, off, &val);
+               pci_user_read_config_byte(dev, off, &val);
                data[off - init_off] = val;
                off++;
                size--;
 
        if ((off & 3) && size > 2) {
                u16 val;
-               pci_read_config_word(dev, off, &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;
 
        while (size > 3) {
                u32 val;
-               pci_read_config_dword(dev, off, &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;
 
        if (size >= 2) {
                u16 val;
-               pci_read_config_word(dev, off, &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;
 
        if (size > 0) {
                u8 val;
-               pci_read_config_byte(dev, off, &val);
+               pci_user_read_config_byte(dev, off, &val);
                data[off - init_off] = val;
                off++;
                --size;
        }
        
        if ((off & 1) && size) {
-               pci_write_config_byte(dev, off, data[off - init_off]);
+               pci_user_write_config_byte(dev, off, data[off - init_off]);
                off++;
                size--;
        }
        if ((off & 3) && size > 2) {
                u16 val = data[off - init_off];
                val |= (u16) data[off - init_off + 1] << 8;
-                pci_write_config_word(dev, off, val);
+                pci_user_write_config_word(dev, off, val);
                 off += 2;
                 size -= 2;
         }
                val |= (u32) data[off - init_off + 1] << 8;
                val |= (u32) data[off - init_off + 2] << 16;
                val |= (u32) data[off - init_off + 3] << 24;
-               pci_write_config_dword(dev, off, val);
+               pci_user_write_config_dword(dev, off, val);
                off += 4;
                size -= 4;
        }
        if (size >= 2) {
                u16 val = data[off - init_off];
                val |= (u16) data[off - init_off + 1] << 8;
-               pci_write_config_word(dev, off, val);
+               pci_user_write_config_word(dev, off, val);
                off += 2;
                size -= 2;
        }
 
        if (size) {
-               pci_write_config_byte(dev, off, data[off - init_off]);
+               pci_user_write_config_byte(dev, off, data[off - init_off]);
                off++;
                --size;
        }
 
 extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
 extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
 
+extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
+extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
+extern int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val);
+extern int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val);
+extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val);
+extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
+
 /* PCI /proc functions */
 #ifdef CONFIG_PROC_FS
 extern int pci_proc_attach_device(struct pci_dev *dev);
 
 
        if ((pos & 1) && cnt) {
                unsigned char val;
-               pci_read_config_byte(dev, pos, &val);
+               pci_user_read_config_byte(dev, pos, &val);
                __put_user(val, buf);
                buf++;
                pos++;
 
        if ((pos & 3) && cnt > 2) {
                unsigned short val;
-               pci_read_config_word(dev, pos, &val);
+               pci_user_read_config_word(dev, pos, &val);
                __put_user(cpu_to_le16(val), (unsigned short __user *) buf);
                buf += 2;
                pos += 2;
 
        while (cnt >= 4) {
                unsigned int val;
-               pci_read_config_dword(dev, pos, &val);
+               pci_user_read_config_dword(dev, pos, &val);
                __put_user(cpu_to_le32(val), (unsigned int __user *) buf);
                buf += 4;
                pos += 4;
 
        if (cnt >= 2) {
                unsigned short val;
-               pci_read_config_word(dev, pos, &val);
+               pci_user_read_config_word(dev, pos, &val);
                __put_user(cpu_to_le16(val), (unsigned short __user *) buf);
                buf += 2;
                pos += 2;
 
        if (cnt) {
                unsigned char val;
-               pci_read_config_byte(dev, pos, &val);
+               pci_user_read_config_byte(dev, pos, &val);
                __put_user(val, buf);
                buf++;
                pos++;
        if ((pos & 1) && cnt) {
                unsigned char val;
                __get_user(val, buf);
-               pci_write_config_byte(dev, pos, val);
+               pci_user_write_config_byte(dev, pos, val);
                buf++;
                pos++;
                cnt--;
        if ((pos & 3) && cnt > 2) {
                unsigned short val;
                __get_user(val, (unsigned short __user *) buf);
-               pci_write_config_word(dev, pos, le16_to_cpu(val));
+               pci_user_write_config_word(dev, pos, le16_to_cpu(val));
                buf += 2;
                pos += 2;
                cnt -= 2;
        while (cnt >= 4) {
                unsigned int val;
                __get_user(val, (unsigned int __user *) buf);
-               pci_write_config_dword(dev, pos, le32_to_cpu(val));
+               pci_user_write_config_dword(dev, pos, le32_to_cpu(val));
                buf += 4;
                pos += 4;
                cnt -= 4;
        if (cnt >= 2) {
                unsigned short val;
                __get_user(val, (unsigned short __user *) buf);
-               pci_write_config_word(dev, pos, le16_to_cpu(val));
+               pci_user_write_config_word(dev, pos, le16_to_cpu(val));
                buf += 2;
                pos += 2;
                cnt -= 2;
        if (cnt) {
                unsigned char val;
                __get_user(val, buf);
-               pci_write_config_byte(dev, pos, val);
+               pci_user_write_config_byte(dev, pos, val);
                buf++;
                pos++;
                cnt--;
 
        drv = pci_dev_driver(dev);
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
-       pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
-       pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
+       pci_user_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+       pci_user_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+       pci_user_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
+       pci_user_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
        seq_printf(m, "  Bus %2d, device %3d, function %2d:\n",
               dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
        seq_printf(m, "    Class %04x", class_rev >> 16);
 
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <asm/uaccess.h>
-
+#include "pci.h"
 
 asmlinkage long
 sys_pciconfig_read(unsigned long bus, unsigned long dfn,
        lock_kernel();
        switch (len) {
        case 1:
-               cfg_ret = pci_read_config_byte(dev, off, &byte);
+               cfg_ret = pci_user_read_config_byte(dev, off, &byte);
                break;
        case 2:
-               cfg_ret = pci_read_config_word(dev, off, &word);
+               cfg_ret = pci_user_read_config_word(dev, off, &word);
                break;
        case 4:
-               cfg_ret = pci_read_config_dword(dev, off, &dword);
+               cfg_ret = pci_user_read_config_dword(dev, off, &dword);
                break;
        default:
                err = -EINVAL;
                err = get_user(byte, (u8 __user *)buf);
                if (err)
                        break;
-               err = pci_write_config_byte(dev, off, byte);
+               err = pci_user_write_config_byte(dev, off, byte);
                if (err != PCIBIOS_SUCCESSFUL)
                        err = -EIO;
                break;
                err = get_user(word, (u16 __user *)buf);
                if (err)
                        break;
-               err = pci_write_config_word(dev, off, word);
+               err = pci_user_write_config_word(dev, off, word);
                if (err != PCIBIOS_SUCCESSFUL)
                        err = -EIO;
                break;
                err = get_user(dword, (u32 __user *)buf);
                if (err)
                        break;
-               err = pci_write_config_dword(dev, off, dword);
+               err = pci_user_write_config_dword(dev, off, dword);
                if (err != PCIBIOS_SUCCESSFUL)
                        err = -EIO;
                break;
 
        unsigned int    is_enabled:1;   /* pci_enable_device has been called */
        unsigned int    is_busmaster:1; /* device is busmaster */
        unsigned int    no_msi:1;       /* device may not use msi */
+       unsigned int    block_ucfg_access:1;    /* userspace config space access is blocked */
 
        u32             saved_config_space[16]; /* config space saved at suspend time */
        struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
 #endif
 
+extern void pci_block_user_cfg_access(struct pci_dev *dev);
+extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
+
 /*
  * PCI domain support.  Sometimes called PCI segment (eg by ACPI),
  * a PCI domain is defined to be a set of PCI busses which share
 
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
+static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
+static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { }
+
 #endif /* CONFIG_PCI */
 
 /* Include architecture-dependent settings and functions */