Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
3ebb9566
Commit
3ebb9566
authored
Jun 18, 2012
by
Joerg Roedel
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'pci-bjorn/topic/alex-vfio-prep' into groups
parents
485802a6
a0dee2ed
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
312 additions
and
25 deletions
+312
-25
drivers/pci/access.c
drivers/pci/access.c
+4
-2
drivers/pci/pci.c
drivers/pci/pci.c
+69
-0
drivers/pci/pci.h
drivers/pci/pci.h
+0
-7
drivers/pci/quirks.c
drivers/pci/quirks.c
+84
-0
drivers/xen/xen-pciback/conf_space.c
drivers/xen/xen-pciback/conf_space.c
+3
-3
include/linux/pci.h
include/linux/pci.h
+51
-1
include/linux/pci_regs.h
include/linux/pci_regs.h
+101
-12
No files found.
drivers/pci/access.c
View file @
3ebb9566
...
...
@@ -162,7 +162,8 @@ int pci_user_read_config_##size \
if (ret > 0) \
ret = -EINVAL; \
return ret; \
}
} \
EXPORT_SYMBOL_GPL(pci_user_read_config_##size);
/* Returns 0 on success, negative values indicate error. */
#define PCI_USER_WRITE_CONFIG(size,type) \
...
...
@@ -181,7 +182,8 @@ int pci_user_write_config_##size \
if (ret > 0) \
ret = -EINVAL; \
return ret; \
}
} \
EXPORT_SYMBOL_GPL(pci_user_write_config_##size);
PCI_USER_READ_CONFIG
(
byte
,
u8
)
PCI_USER_READ_CONFIG
(
word
,
u16
)
...
...
drivers/pci/pci.c
View file @
3ebb9566
...
...
@@ -2364,6 +2364,75 @@ void pci_enable_acs(struct pci_dev *dev)
pci_write_config_word
(
dev
,
pos
+
PCI_ACS_CTRL
,
ctrl
);
}
/**
* pci_acs_enabled - test ACS against required flags for a given device
* @pdev: device to test
* @acs_flags: required PCI ACS flags
*
* Return true if the device supports the provided flags. Automatically
* filters out flags that are not implemented on multifunction devices.
*/
bool
pci_acs_enabled
(
struct
pci_dev
*
pdev
,
u16
acs_flags
)
{
int
pos
,
ret
;
u16
ctrl
;
ret
=
pci_dev_specific_acs_enabled
(
pdev
,
acs_flags
);
if
(
ret
>=
0
)
return
ret
>
0
;
if
(
!
pci_is_pcie
(
pdev
))
return
false
;
/* Filter out flags not applicable to multifunction */
if
(
pdev
->
multifunction
)
acs_flags
&=
(
PCI_ACS_RR
|
PCI_ACS_CR
|
PCI_ACS_EC
|
PCI_ACS_DT
);
if
(
pdev
->
pcie_type
==
PCI_EXP_TYPE_DOWNSTREAM
||
pdev
->
pcie_type
==
PCI_EXP_TYPE_ROOT_PORT
||
pdev
->
multifunction
)
{
pos
=
pci_find_ext_capability
(
pdev
,
PCI_EXT_CAP_ID_ACS
);
if
(
!
pos
)
return
false
;
pci_read_config_word
(
pdev
,
pos
+
PCI_ACS_CTRL
,
&
ctrl
);
if
((
ctrl
&
acs_flags
)
!=
acs_flags
)
return
false
;
}
return
true
;
}
/**
* pci_acs_path_enable - test ACS flags from start to end in a hierarchy
* @start: starting downstream device
* @end: ending upstream device or NULL to search to the root bus
* @acs_flags: required flags
*
* Walk up a device tree from start to end testing PCI ACS support. If
* any step along the way does not support the required flags, return false.
*/
bool
pci_acs_path_enabled
(
struct
pci_dev
*
start
,
struct
pci_dev
*
end
,
u16
acs_flags
)
{
struct
pci_dev
*
pdev
,
*
parent
=
start
;
do
{
pdev
=
parent
;
if
(
!
pci_acs_enabled
(
pdev
,
acs_flags
))
return
false
;
if
(
pci_is_root_bus
(
pdev
->
bus
))
return
(
end
==
NULL
);
parent
=
pdev
->
bus
->
self
;
}
while
(
pdev
!=
end
);
return
true
;
}
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
...
...
drivers/pci/pci.h
View file @
3ebb9566
...
...
@@ -86,13 +86,6 @@ static inline bool pci_is_bridge(struct pci_dev *pci_dev)
return
!!
(
pci_dev
->
subordinate
);
}
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
);
struct
pci_vpd_ops
{
ssize_t
(
*
read
)(
struct
pci_dev
*
dev
,
loff_t
pos
,
size_t
count
,
void
*
buf
);
ssize_t
(
*
write
)(
struct
pci_dev
*
dev
,
loff_t
pos
,
size_t
count
,
const
void
*
buf
);
...
...
drivers/pci/quirks.c
View file @
3ebb9566
...
...
@@ -3205,3 +3205,87 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
return
-
ENOTTY
;
}
static
struct
pci_dev
*
pci_func_0_dma_source
(
struct
pci_dev
*
dev
)
{
if
(
!
PCI_FUNC
(
dev
->
devfn
))
return
pci_dev_get
(
dev
);
return
pci_get_slot
(
dev
->
bus
,
PCI_DEVFN
(
PCI_SLOT
(
dev
->
devfn
),
0
));
}
static
const
struct
pci_dev_dma_source
{
u16
vendor
;
u16
device
;
struct
pci_dev
*
(
*
dma_source
)(
struct
pci_dev
*
dev
);
}
pci_dev_dma_source
[]
=
{
/*
* https://bugzilla.redhat.com/show_bug.cgi?id=605888
*
* Some Ricoh devices use the function 0 source ID for DMA on
* other functions of a multifunction device. The DMA devices
* is therefore function 0, which will have implications of the
* iommu grouping of these devices.
*/
{
PCI_VENDOR_ID_RICOH
,
0xe822
,
pci_func_0_dma_source
},
{
PCI_VENDOR_ID_RICOH
,
0xe230
,
pci_func_0_dma_source
},
{
PCI_VENDOR_ID_RICOH
,
0xe832
,
pci_func_0_dma_source
},
{
PCI_VENDOR_ID_RICOH
,
0xe476
,
pci_func_0_dma_source
},
{
0
}
};
/*
* IOMMUs with isolation capabilities need to be programmed with the
* correct source ID of a device. In most cases, the source ID matches
* the device doing the DMA, but sometimes hardware is broken and will
* tag the DMA as being sourced from a different device. This function
* allows that translation. Note that the reference count of the
* returned device is incremented on all paths.
*/
struct
pci_dev
*
pci_get_dma_source
(
struct
pci_dev
*
dev
)
{
const
struct
pci_dev_dma_source
*
i
;
for
(
i
=
pci_dev_dma_source
;
i
->
dma_source
;
i
++
)
{
if
((
i
->
vendor
==
dev
->
vendor
||
i
->
vendor
==
(
u16
)
PCI_ANY_ID
)
&&
(
i
->
device
==
dev
->
device
||
i
->
device
==
(
u16
)
PCI_ANY_ID
))
return
i
->
dma_source
(
dev
);
}
return
pci_dev_get
(
dev
);
}
static
const
struct
pci_dev_acs_enabled
{
u16
vendor
;
u16
device
;
int
(
*
acs_enabled
)(
struct
pci_dev
*
dev
,
u16
acs_flags
);
}
pci_dev_acs_enabled
[]
=
{
{
0
}
};
int
pci_dev_specific_acs_enabled
(
struct
pci_dev
*
dev
,
u16
acs_flags
)
{
const
struct
pci_dev_acs_enabled
*
i
;
int
ret
;
/*
* Allow devices that do not expose standard PCIe ACS capabilities
* or control to indicate their support here. Multi-function express
* devices which do not allow internal peer-to-peer between functions,
* but do not implement PCIe ACS may wish to return true here.
*/
for
(
i
=
pci_dev_acs_enabled
;
i
->
acs_enabled
;
i
++
)
{
if
((
i
->
vendor
==
dev
->
vendor
||
i
->
vendor
==
(
u16
)
PCI_ANY_ID
)
&&
(
i
->
device
==
dev
->
device
||
i
->
device
==
(
u16
)
PCI_ANY_ID
))
{
ret
=
i
->
acs_enabled
(
dev
,
acs_flags
);
if
(
ret
>=
0
)
return
ret
;
}
}
return
-
ENOTTY
;
}
drivers/xen/xen-pciback/conf_space.c
View file @
3ebb9566
...
...
@@ -124,7 +124,7 @@ static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
return
val
;
}
static
int
pcibios_err_to_errno
(
int
err
)
static
int
xen_
pcibios_err_to_errno
(
int
err
)
{
switch
(
err
)
{
case
PCIBIOS_SUCCESSFUL
:
...
...
@@ -202,7 +202,7 @@ int xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
pci_name
(
dev
),
size
,
offset
,
value
);
*
ret_val
=
value
;
return
pcibios_err_to_errno
(
err
);
return
xen_
pcibios_err_to_errno
(
err
);
}
int
xen_pcibk_config_write
(
struct
pci_dev
*
dev
,
int
offset
,
int
size
,
u32
value
)
...
...
@@ -290,7 +290,7 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
}
}
return
pcibios_err_to_errno
(
err
);
return
xen_
pcibios_err_to_errno
(
err
);
}
void
xen_pcibk_config_free_dyn_fields
(
struct
pci_dev
*
dev
)
...
...
include/linux/pci.h
View file @
3ebb9566
...
...
@@ -476,6 +476,32 @@ static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { return false;
#define PCIBIOS_SET_FAILED 0x88
#define PCIBIOS_BUFFER_TOO_SMALL 0x89
/*
* Translate above to generic errno for passing back through non-pci.
*/
static
inline
int
pcibios_err_to_errno
(
int
err
)
{
if
(
err
<=
PCIBIOS_SUCCESSFUL
)
return
err
;
/* Assume already errno */
switch
(
err
)
{
case
PCIBIOS_FUNC_NOT_SUPPORTED
:
return
-
ENOENT
;
case
PCIBIOS_BAD_VENDOR_ID
:
return
-
EINVAL
;
case
PCIBIOS_DEVICE_NOT_FOUND
:
return
-
ENODEV
;
case
PCIBIOS_BAD_REGISTER_NUMBER
:
return
-
EFAULT
;
case
PCIBIOS_SET_FAILED
:
return
-
EIO
;
case
PCIBIOS_BUFFER_TOO_SMALL
:
return
-
ENOSPC
;
}
return
-
ENOTTY
;
}
/* Low-level architecture-dependent routines */
struct
pci_ops
{
...
...
@@ -779,6 +805,14 @@ static inline int pci_write_config_dword(const struct pci_dev *dev, int where,
return
pci_bus_write_config_dword
(
dev
->
bus
,
dev
->
devfn
,
where
,
val
);
}
/* user-space driven config access */
int
pci_user_read_config_byte
(
struct
pci_dev
*
dev
,
int
where
,
u8
*
val
);
int
pci_user_read_config_word
(
struct
pci_dev
*
dev
,
int
where
,
u16
*
val
);
int
pci_user_read_config_dword
(
struct
pci_dev
*
dev
,
int
where
,
u32
*
val
);
int
pci_user_write_config_byte
(
struct
pci_dev
*
dev
,
int
where
,
u8
val
);
int
pci_user_write_config_word
(
struct
pci_dev
*
dev
,
int
where
,
u16
val
);
int
pci_user_write_config_dword
(
struct
pci_dev
*
dev
,
int
where
,
u32
val
);
int
__must_check
pci_enable_device
(
struct
pci_dev
*
dev
);
int
__must_check
pci_enable_device_io
(
struct
pci_dev
*
dev
);
int
__must_check
pci_enable_device_mem
(
struct
pci_dev
*
dev
);
...
...
@@ -1334,6 +1368,9 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
static
inline
int
pci_domain_nr
(
struct
pci_bus
*
bus
)
{
return
0
;
}
static
inline
struct
pci_dev
*
pci_dev_get
(
struct
pci_dev
*
dev
)
{
return
NULL
;
}
#define dev_is_pci(d) (false)
#define dev_is_pf(d) (false)
#define dev_num_vf(d) (0)
...
...
@@ -1488,9 +1525,20 @@ enum pci_fixup_pass {
#ifdef CONFIG_PCI_QUIRKS
void
pci_fixup_device
(
enum
pci_fixup_pass
pass
,
struct
pci_dev
*
dev
);
struct
pci_dev
*
pci_get_dma_source
(
struct
pci_dev
*
dev
);
int
pci_dev_specific_acs_enabled
(
struct
pci_dev
*
dev
,
u16
acs_flags
);
#else
static
inline
void
pci_fixup_device
(
enum
pci_fixup_pass
pass
,
struct
pci_dev
*
dev
)
{}
static
inline
struct
pci_dev
*
pci_get_dma_source
(
struct
pci_dev
*
dev
)
{
return
pci_dev_get
(
dev
);
}
static
inline
int
pci_dev_specific_acs_enabled
(
struct
pci_dev
*
dev
,
u16
acs_flags
)
{
return
-
ENOTTY
;
}
#endif
void
__iomem
*
pcim_iomap
(
struct
pci_dev
*
pdev
,
int
bar
,
unsigned
long
maxlen
);
...
...
@@ -1593,7 +1641,9 @@ static inline bool pci_is_pcie(struct pci_dev *dev)
}
void
pci_request_acs
(
void
);
bool
pci_acs_enabled
(
struct
pci_dev
*
pdev
,
u16
acs_flags
);
bool
pci_acs_path_enabled
(
struct
pci_dev
*
start
,
struct
pci_dev
*
end
,
u16
acs_flags
);
#define PCI_VPD_LRDT 0x80
/* Large Resource Data Type */
#define PCI_VPD_LRDT_ID(x) (x | PCI_VPD_LRDT)
...
...
include/linux/pci_regs.h
View file @
3ebb9566
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment