Commit 608235a3 authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/vc' into next

* pci/vc:
  PCI: Rename PCI_VC_PORT_REG1/2 to PCI_VC_PORT_CAP1/2
  PCI: Add Virtual Channel to save/restore support
  PCI: Add support for save/restore of extended capabilities
  PCI: Add pci_wait_for_pending() (refactor pci_wait_for_pending_transaction())
parents a737f76b 274127a1
......@@ -4,7 +4,7 @@
obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
irq.o vpd.o setup-bus.o
irq.o vpd.o setup-bus.o vc.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
......
......@@ -430,6 +430,32 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
return best;
}
/**
* pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
* @dev: the PCI device to operate on
* @pos: config space offset of status word
* @mask: mask of bit(s) to care about in status word
*
* Return 1 when mask bit(s) in status word clear, 0 otherwise.
*/
int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
{
int i;
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
u16 status;
if (i)
msleep((1 << (i - 1)) * 100);
pci_read_config_word(dev, pos, &status);
if (!(status & mask))
return 1;
}
return 0;
}
/**
* pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored
......@@ -835,18 +861,28 @@ EXPORT_SYMBOL(pci_choose_state);
#define PCI_EXP_SAVE_REGS 7
static struct pci_cap_saved_state *pci_find_saved_cap(
struct pci_dev *pci_dev, char cap)
static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
u16 cap, bool extended)
{
struct pci_cap_saved_state *tmp;
hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) {
if (tmp->cap.cap_nr == cap)
if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap)
return tmp;
}
return NULL;
}
struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap)
{
return _pci_find_saved_cap(dev, cap, false);
}
struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap)
{
return _pci_find_saved_cap(dev, cap, true);
}
static int pci_save_pcie_state(struct pci_dev *dev)
{
int i = 0;
......@@ -948,6 +984,8 @@ pci_save_state(struct pci_dev *dev)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
return i;
if ((i = pci_save_vc_state(dev)) != 0)
return i;
return 0;
}
......@@ -1010,6 +1048,7 @@ void pci_restore_state(struct pci_dev *dev)
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
pci_restore_config_space(dev);
......@@ -1087,7 +1126,7 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
while (cap->size) {
struct pci_cap_saved_state *tmp;
tmp = pci_find_saved_cap(dev, cap->cap_nr);
tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended);
if (!tmp || tmp->cap.size != cap->size)
return -EINVAL;
......@@ -2021,18 +2060,24 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev,
}
/**
* pci_add_cap_save_buffer - allocate buffer for saving given capability registers
* _pci_add_cap_save_buffer - allocate buffer for saving given
* capability registers
* @dev: the PCI device
* @cap: the capability to allocate the buffer for
* @extended: Standard or Extended capability ID
* @size: requested size of the buffer
*/
static int pci_add_cap_save_buffer(
struct pci_dev *dev, char cap, unsigned int size)
static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
bool extended, unsigned int size)
{
int pos;
struct pci_cap_saved_state *save_state;
pos = pci_find_capability(dev, cap);
if (extended)
pos = pci_find_ext_capability(dev, cap);
else
pos = pci_find_capability(dev, cap);
if (pos <= 0)
return 0;
......@@ -2041,12 +2086,23 @@ static int pci_add_cap_save_buffer(
return -ENOMEM;
save_state->cap.cap_nr = cap;
save_state->cap.cap_extended = extended;
save_state->cap.size = size;
pci_add_saved_cap(dev, save_state);
return 0;
}
int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, false, size);
}
int pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, true, size);
}
/**
* pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
* @dev: the PCI device
......@@ -2065,6 +2121,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
}
void pci_free_cap_save_buffers(struct pci_dev *dev)
......@@ -3204,20 +3262,10 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary);
*/
int pci_wait_for_pending_transaction(struct pci_dev *dev)
{
int i;
u16 status;
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
return 1;
}
if (!pci_is_pcie(dev))
return 1;
return 0;
return pci_wait_for_pending(dev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_TRPND);
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
......@@ -3244,10 +3292,8 @@ static int pcie_flr(struct pci_dev *dev, int probe)
static int pci_af_flr(struct pci_dev *dev, int probe)
{
int i;
int pos;
u8 cap;
u8 status;
pos = pci_find_capability(dev, PCI_CAP_ID_AF);
if (!pos)
......@@ -3261,14 +3307,8 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
return 0;
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status);
if (!(status & PCI_AF_STATUS_TP))
goto clear;
}
if (pci_wait_for_pending(dev, PCI_AF_STATUS, PCI_AF_STATUS_TP))
goto clear;
dev_err(&dev->dev, "transaction is not cleared; "
"proceeding with reset anyway\n");
......
This diff is collapsed.
......@@ -975,20 +975,20 @@ static int vfio_vc_cap_len(struct vfio_pci_device *vdev, u16 pos)
int ret, evcc, phases, vc_arb;
int len = PCI_CAP_VC_BASE_SIZEOF;
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG1, &tmp);
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP1, &tmp);
if (ret)
return pcibios_err_to_errno(ret);
evcc = tmp & PCI_VC_REG1_EVCC; /* extended vc count */
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG2, &tmp);
evcc = tmp & PCI_VC_CAP1_EVCC; /* extended vc count */
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP2, &tmp);
if (ret)
return pcibios_err_to_errno(ret);
if (tmp & PCI_VC_REG2_128_PHASE)
if (tmp & PCI_VC_CAP2_128_PHASE)
phases = 128;
else if (tmp & PCI_VC_REG2_64_PHASE)
else if (tmp & PCI_VC_CAP2_64_PHASE)
phases = 64;
else if (tmp & PCI_VC_REG2_32_PHASE)
else if (tmp & PCI_VC_CAP2_32_PHASE)
phases = 32;
else
phases = 0;
......
......@@ -224,7 +224,8 @@ enum pci_bus_speed {
};
struct pci_cap_saved_data {
char cap_nr;
u16 cap_nr;
bool cap_extended;
unsigned int size;
u32 data[0];
};
......@@ -938,6 +939,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev);
void pci_msi_off(struct pci_dev *dev);
int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask);
int pci_wait_for_pending_transaction(struct pci_dev *dev);
int pcix_get_max_mmrbc(struct pci_dev *dev);
int pcix_get_mmrbc(struct pci_dev *dev);
......@@ -976,6 +978,12 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev);
int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state);
int pci_load_and_free_saved_state(struct pci_dev *dev,
struct pci_saved_state **state);
struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap);
struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
u16 cap);
int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size);
int pci_add_ext_cap_save_buffer(struct pci_dev *dev,
u16 cap, unsigned int size);
int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
......@@ -997,6 +1005,11 @@ static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
return __pci_enable_wake(dev, state, false, enable);
}
/* PCI Virtual Channel */
int pci_save_vc_state(struct pci_dev *dev);
void pci_restore_vc_state(struct pci_dev *dev);
void pci_allocate_vc_save_buffers(struct pci_dev *dev);
#define PCI_EXP_IDO_REQUEST (1<<0)
#define PCI_EXP_IDO_COMPLETION (1<<1)
void pci_enable_ido(struct pci_dev *dev, unsigned long type);
......
......@@ -685,17 +685,34 @@
#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */
/* Virtual Channel */
#define PCI_VC_PORT_REG1 4
#define PCI_VC_REG1_EVCC 0x7 /* extended VC count */
#define PCI_VC_PORT_REG2 8
#define PCI_VC_REG2_32_PHASE 0x2
#define PCI_VC_REG2_64_PHASE 0x4
#define PCI_VC_REG2_128_PHASE 0x8
#define PCI_VC_PORT_CAP1 4
#define PCI_VC_CAP1_EVCC 0x00000007 /* extended VC count */
#define PCI_VC_CAP1_LPEVCC 0x00000070 /* low prio extended VC count */
#define PCI_VC_CAP1_ARB_SIZE 0x00000c00
#define PCI_VC_PORT_CAP2 8
#define PCI_VC_CAP2_32_PHASE 0x00000002
#define PCI_VC_CAP2_64_PHASE 0x00000004
#define PCI_VC_CAP2_128_PHASE 0x00000008
#define PCI_VC_CAP2_ARB_OFF 0xff000000
#define PCI_VC_PORT_CTRL 12
#define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001
#define PCI_VC_PORT_STATUS 14
#define PCI_VC_PORT_STATUS_TABLE 0x00000001
#define PCI_VC_RES_CAP 16
#define PCI_VC_RES_CAP_32_PHASE 0x00000002
#define PCI_VC_RES_CAP_64_PHASE 0x00000004
#define PCI_VC_RES_CAP_128_PHASE 0x00000008
#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010
#define PCI_VC_RES_CAP_256_PHASE 0x00000020
#define PCI_VC_RES_CAP_ARB_OFF 0xff000000
#define PCI_VC_RES_CTRL 20
#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000
#define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000
#define PCI_VC_RES_CTRL_ID 0x07000000
#define PCI_VC_RES_CTRL_ENABLE 0x80000000
#define PCI_VC_RES_STATUS 26
#define PCI_VC_RES_STATUS_TABLE 0x00000001
#define PCI_VC_RES_STATUS_NEGO 0x00000002
#define PCI_CAP_VC_BASE_SIZEOF 0x10
#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment