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
nexedi
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
Show 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