Skip to content

Commit

Permalink
Merge branches 'pci/host-rcar', 'pci/hotplug', 'pci/iommu', 'pci/misc…
Browse files Browse the repository at this point in the history
…' and 'pci/msi' into next

* pci/host-rcar:
  PCI: rcar: Remove rcar_pcie_setup_window() resource argument
  PCI: rcar: Cleanup style and formatting
  PCI: rcar: Use correct initial HW settings
  PCI: rcar: Remove redundant config accessor register number checks

* pci/hotplug:
  PCI: cpqphp: Remove unnecessary null test before debugfs_remove()
  PCI: pciehp: Clear Data Link Layer State Changed during init
  PCI: pciehp: Remove struct controller.no_cmd_complete
  PCI: pciehp: Remove assumptions about which commands cause completion events
  PCI: pciehp: Compute timeout from hotplug command start time
  PCI: pciehp: Wait for hotplug command completion lazily
  PCI: pciehp: Make pcie_wait_cmd() self-contained
  PCI: Prevent NULL dereference during pciehp probe

* pci/iommu:
  PCI: Add bridge DMA alias quirk for Intel 82801 bridge

* pci/misc:
  ACPI / PCI: Fix sysfs acpi_index and label errors
  PCI/portdrv: Remove warning about invalid IRQ for hot-added PCIe ports

* pci/msi:
  PCI/MSI: Cache Multiple Message Capable in struct msi_desc
  PCI/MSI: Remove unused msi_enabled_mask()
  PCI/MSI: Add internal msix_clear_and_set_ctrl() function
  • Loading branch information
Bjorn Helgaas committed Jul 9, 2014
6 parents 7171511 + 0549252 + 5d37818 + 8ab4abb + dcfa9be + 31ea5d4 commit 1d0df48
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 193 deletions.
156 changes: 71 additions & 85 deletions drivers/pci/host/pcie-rcar.c

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions drivers/pci/hotplug/cpqphp_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,7 @@ void cpqhp_create_debugfs_files(struct controller *ctrl)

void cpqhp_remove_debugfs_files(struct controller *ctrl)
{
if (ctrl->dentry)
debugfs_remove(ctrl->dentry);
debugfs_remove(ctrl->dentry);
ctrl->dentry = NULL;
}

3 changes: 2 additions & 1 deletion drivers/pci/hotplug/pciehp.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ struct controller {
struct slot *slot;
wait_queue_head_t queue; /* sleep & wake process */
u32 slot_cap;
u32 slot_ctrl;
struct timer_list poll_timer;
unsigned long cmd_started; /* jiffies */
unsigned int cmd_busy:1;
unsigned int no_cmd_complete:1;
unsigned int link_active_reporting:1;
unsigned int notification_enabled:1;
unsigned int power_fault_detected;
Expand Down
7 changes: 7 additions & 0 deletions drivers/pci/hotplug/pciehp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ static int pciehp_probe(struct pcie_device *dev)
else if (pciehp_acpi_slot_detection_check(dev->port))
goto err_out_none;

if (!dev->port->subordinate) {
/* Can happen if we run out of bus numbers during probe */
dev_err(&dev->device,
"Hotplug bridge without secondary bus, ignoring\n");
goto err_out_none;
}

ctrl = pcie_init(dev);
if (!ctrl) {
dev_err(&dev->device, "Controller initialization failed\n");
Expand Down
101 changes: 45 additions & 56 deletions drivers/pci/hotplug/pciehp_hpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,10 @@ static inline void pciehp_free_irq(struct controller *ctrl)
free_irq(ctrl->pcie->irq, ctrl);
}

static int pcie_poll_cmd(struct controller *ctrl)
static int pcie_poll_cmd(struct controller *ctrl, int timeout)
{
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
int timeout = 1000;

pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (slot_status & PCI_EXP_SLTSTA_CC) {
Expand All @@ -129,18 +128,52 @@ static int pcie_poll_cmd(struct controller *ctrl)
return 0; /* timeout */
}

static void pcie_wait_cmd(struct controller *ctrl, int poll)
static void pcie_wait_cmd(struct controller *ctrl)
{
unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
unsigned long timeout = msecs_to_jiffies(msecs);
unsigned long duration = msecs_to_jiffies(msecs);
unsigned long cmd_timeout = ctrl->cmd_started + duration;
unsigned long now, timeout;
int rc;

if (poll)
rc = pcie_poll_cmd(ctrl);
/*
* If the controller does not generate notifications for command
* completions, we never need to wait between writes.
*/
if (NO_CMD_CMPL(ctrl))
return;

if (!ctrl->cmd_busy)
return;

/*
* Even if the command has already timed out, we want to call
* pcie_poll_cmd() so it can clear PCI_EXP_SLTSTA_CC.
*/
now = jiffies;
if (time_before_eq(cmd_timeout, now))
timeout = 1;
else
timeout = cmd_timeout - now;

if (ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE &&
ctrl->slot_ctrl & PCI_EXP_SLTCTL_CCIE)
rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout);
else
rc = pcie_poll_cmd(ctrl, timeout);

/*
* Controllers with errata like Intel CF118 don't generate
* completion notifications unless the power/indicator/interlock
* control bits are changed. On such controllers, we'll emit this
* timeout message when we wait for completion of commands that
* don't change those bits, e.g., commands that merely enable
* interrupts.
*/
if (!rc)
ctrl_dbg(ctrl, "Command not completed in 1000 msec\n");
ctrl_info(ctrl, "Timeout on hotplug command %#010x (issued %u msec ago)\n",
ctrl->slot_ctrl,
jiffies_to_msecs(now - ctrl->cmd_started));
}

/**
Expand All @@ -152,57 +185,22 @@ static void pcie_wait_cmd(struct controller *ctrl, int poll)
static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
{
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status;
u16 slot_ctrl;

mutex_lock(&ctrl->ctrl_lock);

pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (slot_status & PCI_EXP_SLTSTA_CC) {
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_CC);
if (!ctrl->no_cmd_complete) {
/*
* After 1 sec and CMD_COMPLETED still not set, just
* proceed forward to issue the next command according
* to spec. Just print out the error message.
*/
ctrl_dbg(ctrl, "CMD_COMPLETED not clear after 1 sec\n");
} else if (!NO_CMD_CMPL(ctrl)) {
/*
* This controller seems to notify of command completed
* event even though it supports none of power
* controller, attention led, power led and EMI.
*/
ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Need to wait for command completed event\n");
ctrl->no_cmd_complete = 0;
} else {
ctrl_dbg(ctrl, "Unexpected CMD_COMPLETED. Maybe the controller is broken\n");
}
}
/* Wait for any previous command that might still be in progress */
pcie_wait_cmd(ctrl);

pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
slot_ctrl &= ~mask;
slot_ctrl |= (cmd & mask);
ctrl->cmd_busy = 1;
smp_mb();
pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl);
ctrl->cmd_started = jiffies;
ctrl->slot_ctrl = slot_ctrl;

/*
* Wait for command completion.
*/
if (!ctrl->no_cmd_complete) {
int poll = 0;
/*
* if hotplug interrupt is not enabled or command
* completed interrupt is not enabled, we need to poll
* command completed event.
*/
if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) ||
!(slot_ctrl & PCI_EXP_SLTCTL_CCIE))
poll = 1;
pcie_wait_cmd(ctrl, poll);
}
mutex_unlock(&ctrl->ctrl_lock);
}

Expand Down Expand Up @@ -773,15 +771,6 @@ struct controller *pcie_init(struct pcie_device *dev)
mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue);
dbg_ctrl(ctrl);
/*
* Controller doesn't notify of command completion if the "No
* Command Completed Support" bit is set in Slot Capability
* register or the controller supports none of power
* controller, attention led, power led and EMI.
*/
if (NO_CMD_CMPL(ctrl) ||
!(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
ctrl->no_cmd_complete = 1;

/* Check if Data Link Layer Link Active Reporting is implemented */
pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap);
Expand All @@ -794,7 +783,7 @@ struct controller *pcie_init(struct pcie_device *dev)
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_CC);
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);

/* Disable software notification */
pcie_disable_notification(ctrl);
Expand Down
59 changes: 21 additions & 38 deletions drivers/pci/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,14 @@ static void msi_set_enable(struct pci_dev *dev, int enable)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}

static void msix_set_enable(struct pci_dev *dev, int enable)
static void msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 control;
u16 ctrl;

pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
control &= ~PCI_MSIX_FLAGS_ENABLE;
if (enable)
control |= PCI_MSIX_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}

static inline __attribute_const__ u32 msi_mask(unsigned x)
Expand All @@ -168,16 +167,6 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
return (1 << (1 << x)) - 1;
}

static inline __attribute_const__ u32 msi_capable_mask(u16 control)
{
return msi_mask((control >> 1) & 7);
}

static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
{
return msi_mask((control >> 4) & 7);
}

/*
* PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to
* mask all MSI interrupts by clearing the MSI enable bit does not work
Expand Down Expand Up @@ -460,7 +449,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
arch_restore_msi_irqs(dev);

pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
msi_mask_irq(entry, msi_mask(entry->msi_attrib.multi_cap),
entry->masked);
control &= ~PCI_MSI_FLAGS_QSIZE;
control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
Expand All @@ -469,26 +459,23 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
static void __pci_restore_msix_state(struct pci_dev *dev)
{
struct msi_desc *entry;
u16 control;

if (!dev->msix_enabled)
return;
BUG_ON(list_empty(&dev->msi_list));
entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);

/* route the table */
pci_intx_for_msi(dev, 0);
control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_clear_and_set_ctrl(dev, 0,
PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);

arch_restore_msi_irqs(dev);
list_for_each_entry(entry, &dev->msi_list, list) {
msix_mask_irq(entry, entry->masked);
}

control &= ~PCI_MSIX_FLAGS_MASKALL;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
}

void pci_restore_msi_state(struct pci_dev *dev)
Expand Down Expand Up @@ -626,6 +613,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT);
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.pos = dev->msi_cap;
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;

if (control & PCI_MSI_FLAGS_64BIT)
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
Expand All @@ -634,7 +622,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
/* All MSIs are unmasked by default, Mask them all */
if (entry->msi_attrib.maskbit)
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
mask = msi_capable_mask(control);
mask = msi_mask(entry->msi_attrib.multi_cap);
msi_mask_irq(entry, mask, mask);

list_add_tail(&entry->list, &dev->msi_list);
Expand Down Expand Up @@ -743,12 +731,10 @@ static int msix_capability_init(struct pci_dev *dev,
u16 control;
void __iomem *base;

pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);

/* Ensure MSI-X is disabled while it is set up */
control &= ~PCI_MSIX_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);

pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
/* Request & Map MSI-X table region */
base = msix_map_region(dev, msix_table_size(control));
if (!base)
Expand All @@ -767,8 +753,8 @@ static int msix_capability_init(struct pci_dev *dev,
* MSI-X registers. We need to mask all the vectors to prevent
* interrupts coming in before they're fully set up.
*/
control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_clear_and_set_ctrl(dev, 0,
PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE);

msix_program_entries(dev, entries);

Expand All @@ -780,8 +766,7 @@ static int msix_capability_init(struct pci_dev *dev,
pci_intx_for_msi(dev, 0);
dev->msix_enabled = 1;

control &= ~PCI_MSIX_FLAGS_MASKALL;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);

return 0;

Expand Down Expand Up @@ -882,7 +867,6 @@ void pci_msi_shutdown(struct pci_dev *dev)
{
struct msi_desc *desc;
u32 mask;
u16 ctrl;

if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
Expand All @@ -895,8 +879,7 @@ void pci_msi_shutdown(struct pci_dev *dev)
dev->msi_enabled = 0;

/* Return the device with MSI unmasked as initial states */
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
mask = msi_capable_mask(ctrl);
mask = msi_mask(desc->msi_attrib.multi_cap);
/* Keep cached state to be restored */
arch_msi_mask_irq(desc, mask, ~mask);

Expand Down Expand Up @@ -1001,7 +984,7 @@ void pci_msix_shutdown(struct pci_dev *dev)
arch_msix_mask_irq(entry, 1);
}

msix_set_enable(dev, 0);
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
pci_intx_for_msi(dev, 1);
dev->msix_enabled = 0;
}
Expand Down Expand Up @@ -1065,7 +1048,7 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)

dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (dev->msix_cap)
msix_set_enable(dev, 0);
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
}

/**
Expand Down
18 changes: 12 additions & 6 deletions drivers/pci/pci-label.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ enum acpi_attr_enum {
static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
{
int len;
len = utf16s_to_utf8s((const wchar_t *)obj->string.pointer,
obj->string.length,
len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer,
obj->buffer.length,
UTF16_LITTLE_ENDIAN,
buf, PAGE_SIZE);
buf[len] = '\n';
Expand All @@ -187,16 +187,22 @@ static int dsm_get_label(struct device *dev, char *buf,
tmp = obj->package.elements;
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 2 &&
tmp[0].type == ACPI_TYPE_INTEGER &&
tmp[1].type == ACPI_TYPE_STRING) {
(tmp[1].type == ACPI_TYPE_STRING ||
tmp[1].type == ACPI_TYPE_BUFFER)) {
/*
* The second string element is optional even when
* this _DSM is implemented; when not implemented,
* this entry must return a null string.
*/
if (attr == ACPI_ATTR_INDEX_SHOW)
if (attr == ACPI_ATTR_INDEX_SHOW) {
scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value);
else if (attr == ACPI_ATTR_LABEL_SHOW)
dsm_label_utf16s_to_utf8s(tmp + 1, buf);
} else if (attr == ACPI_ATTR_LABEL_SHOW) {
if (tmp[1].type == ACPI_TYPE_STRING)
scnprintf(buf, PAGE_SIZE, "%s\n",
tmp[1].string.pointer);
else if (tmp[1].type == ACPI_TYPE_BUFFER)
dsm_label_utf16s_to_utf8s(tmp + 1, buf);
}
len = strlen(buf) > 0 ? strlen(buf) : -1;
}

Expand Down
Loading

0 comments on commit 1d0df48

Please sign in to comment.