Allow another driver to provide alternative operations when doing capability register reads and writes to the Slot Capabilities, Slot Control, and Slot Status registers. Add handlers to pciehp to read/write the slot registers. Signed-off-by: Jon Derrick <jonathan.derrick@xxxxxxxxx> --- drivers/pci/hotplug/pciehp.h | 8 +++ drivers/pci/hotplug/pciehp_hpc.c | 116 ++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 31 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index aa61d4c..c898c75 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -28,6 +28,12 @@ extern bool pciehp_poll_mode; extern int pciehp_poll_time; +/* Capability reads/writes but only for SLTCAP, SLTCTL, and SLTSTA. */ +struct slot_ecap_ops { + int (*read)(struct pci_dev *dev, int pos, int len, u32 *val); + int (*write)(struct pci_dev *dev, int pos, int len, u32 val); +}; + /* * Set CONFIG_DYNAMIC_DEBUG=y and boot with 'dyndbg="file pciehp* +p"' to * enable debug messages. @@ -76,6 +82,7 @@ * @request_result: result of last user request submitted to the IRQ thread * @requester: wait queue to wake up on completion of user request, * used for synchronous slot enable/disable request via sysfs + * @slot_ops: slot config registers read/write operations * * PCIe hotplug has a 1:1 relationship between controller and slot, hence * unlike other drivers, the two aren't represented by separate structures. @@ -105,6 +112,7 @@ struct controller { unsigned int ist_running; int request_result; wait_queue_head_t requester; + struct slot_ecap_ops *slot_ops; }; /** diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 8a2cb17..ce1e8c7 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -35,6 +35,52 @@ static inline struct pci_dev *ctrl_dev(struct controller *ctrl) static irqreturn_t pciehp_ist(int irq, void *dev_id); static int pciehp_poll(void *data); +static int pcie_read_slot_capabilities(struct controller *ctrl, u32 *sltcap) +{ + return ctrl->slot_ops->read(ctrl_dev(ctrl), PCI_EXP_SLTCAP, + sizeof(*sltcap), sltcap); +} + +static int pcie_read_slot_control(struct controller *ctrl, u16 *sltctl) +{ + int ret; + u32 l; + + ret = ctrl->slot_ops->read(ctrl_dev(ctrl), PCI_EXP_SLTCTL, + sizeof(*sltctl), &l); + if (ret) + return ret; + + *sltctl = l; + return 0; +} + +static int pcie_write_slot_control(struct controller *ctrl, u16 sltctl) +{ + return ctrl->slot_ops->write(ctrl_dev(ctrl), PCI_EXP_SLTCTL, + sizeof(sltctl), sltctl); +} + +static int pcie_read_slot_status(struct controller *ctrl, u16 *sltsta) +{ + int ret; + u32 l; + + ret = ctrl->slot_ops->read(ctrl_dev(ctrl), PCI_EXP_SLTSTA, + sizeof(*sltsta), &l); + if (ret) + return ret; + + *sltsta = l; + return 0; +} + +static int pcie_write_slot_status(struct controller *ctrl, u16 sltsta) +{ + return ctrl->slot_ops->write(ctrl_dev(ctrl), PCI_EXP_SLTSTA, + sizeof(sltsta), sltsta); +} + static inline int pciehp_request_irq(struct controller *ctrl) { int retval, irq = ctrl->pcie->irq; @@ -65,11 +111,10 @@ static inline void pciehp_free_irq(struct controller *ctrl) static int pcie_poll_cmd(struct controller *ctrl, int timeout) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; do { - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + pcie_read_slot_status(ctrl, &slot_status); if (slot_status == (u16) ~0) { ctrl_info(ctrl, "%s: no response from device\n", __func__); @@ -77,8 +122,7 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout) } if (slot_status & PCI_EXP_SLTSTA_CC) { - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_CC); + pcie_write_slot_status(ctrl, PCI_EXP_SLTSTA_CC); return 1; } msleep(10); @@ -145,7 +189,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, */ pcie_wait_cmd(ctrl); - pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + pcie_read_slot_control(ctrl, &slot_ctrl); if (slot_ctrl == (u16) ~0) { ctrl_info(ctrl, "%s: no response from device\n", __func__); goto out; @@ -157,7 +201,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, ctrl->cmd_busy = 1; smp_mb(); ctrl->slot_ctrl = slot_ctrl; - pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl); + pcie_write_slot_control(ctrl, slot_ctrl); ctrl->cmd_started = jiffies; /* @@ -316,7 +360,7 @@ int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot, u16 slot_ctrl; pci_config_pm_runtime_get(pdev); - pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + pcie_read_slot_control(ctrl, &slot_ctrl); pci_config_pm_runtime_put(pdev); *status = (slot_ctrl & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6; return 0; @@ -329,7 +373,7 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) u16 slot_ctrl; pci_config_pm_runtime_get(pdev); - pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + pcie_read_slot_control(ctrl, &slot_ctrl); pci_config_pm_runtime_put(pdev); ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); @@ -354,10 +398,9 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status) void pciehp_get_power_status(struct controller *ctrl, u8 *status) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_ctrl; - pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + pcie_read_slot_control(ctrl, &slot_ctrl); ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); @@ -376,10 +419,9 @@ void pciehp_get_power_status(struct controller *ctrl, u8 *status) void pciehp_get_latch_status(struct controller *ctrl, u8 *status) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + pcie_read_slot_status(ctrl, &slot_status); *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); } @@ -397,11 +439,10 @@ void pciehp_get_latch_status(struct controller *ctrl, u8 *status) */ int pciehp_card_present(struct controller *ctrl) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; int ret; - ret = pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + ret = pcie_read_slot_status(ctrl, &slot_status); if (ret == PCIBIOS_DEVICE_NOT_FOUND || slot_status == (u16)~0) return -ENODEV; @@ -433,10 +474,9 @@ int pciehp_card_present_or_link_active(struct controller *ctrl) int pciehp_query_power_fault(struct controller *ctrl) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + pcie_read_slot_status(ctrl, &slot_status); return !!(slot_status & PCI_EXP_SLTSTA_PFD); } @@ -491,15 +531,13 @@ void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn) int pciehp_power_on_slot(struct controller *ctrl) { - struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; int retval; /* Clear power-fault bit from previous power failures */ - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + pcie_read_slot_status(ctrl, &slot_status); if (slot_status & PCI_EXP_SLTSTA_PFD) - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PFD); + pcie_write_slot_status(ctrl, PCI_EXP_SLTSTA_PFD); ctrl->power_fault_detected = 0; pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC); @@ -552,7 +590,7 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) } } - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status); + pcie_read_slot_status(ctrl, &status); if (status == (u16) ~0) { ctrl_info(ctrl, "%s: no response from device\n", __func__); if (parent) @@ -581,7 +619,7 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) return IRQ_NONE; } - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, events); + pcie_write_slot_status(ctrl, events); ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events); if (parent) pm_runtime_put(parent); @@ -744,8 +782,7 @@ static void pcie_disable_notification(struct controller *ctrl) void pcie_clear_hotplug_events(struct controller *ctrl) { - pcie_capability_write_word(ctrl_dev(ctrl), PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_write_slot_status(ctrl, PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); } void pcie_enable_interrupt(struct controller *ctrl) @@ -782,7 +819,6 @@ void pcie_disable_interrupt(struct controller *ctrl) int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) { struct controller *ctrl = to_ctrl(hotplug_slot); - struct pci_dev *pdev = ctrl_dev(ctrl); u16 stat_mask = 0, ctrl_mask = 0; int rc; @@ -804,7 +840,7 @@ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, int probe) rc = pci_bridge_secondary_bus_reset(ctrl->pcie->port); - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); + pcie_write_slot_status(ctrl, stat_mask); pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); @@ -833,16 +869,32 @@ void pcie_shutdown_notification(struct controller *ctrl) static inline void dbg_ctrl(struct controller *ctrl) { - struct pci_dev *pdev = ctrl->pcie->port; u16 reg16; ctrl_dbg(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap); - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, ®16); + pcie_read_slot_status(ctrl, ®16); ctrl_dbg(ctrl, "Slot Status : 0x%04x\n", reg16); - pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, ®16); + pcie_read_slot_control(ctrl, ®16); ctrl_dbg(ctrl, "Slot Control : 0x%04x\n", reg16); } +static int pciehp_read_slot(struct pci_dev *dev, int pos, int len, u32 *val) +{ + return (len == 2) ? pcie_capability_read_word(dev, pos, (u16 *)val) : + pcie_capability_read_dword(dev, pos, val); +} + +static int pciehp_write_slot(struct pci_dev *dev, int pos, int len, u32 val) +{ + return (len == 2) ? pcie_capability_write_word(dev, pos, val) : + pcie_capability_write_dword(dev, pos, val); +} + +static struct slot_ecap_ops pciehp_default_slot_ops = { + .read = pciehp_read_slot, + .write = pciehp_write_slot, +}; + #define FLAG(x, y) (((x) & (y)) ? '+' : '-') struct controller *pcie_init(struct pcie_device *dev) @@ -858,7 +910,9 @@ struct controller *pcie_init(struct pcie_device *dev) return NULL; ctrl->pcie = dev; - pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); + + ctrl->slot_ops = &pciehp_default_slot_ops; + pcie_read_slot_capabilities(ctrl, &slot_cap); if (pdev->hotplug_user_indicators) slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP); @@ -887,7 +941,7 @@ struct controller *pcie_init(struct pcie_device *dev) pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap); /* Clear all remaining event bits in Slot Status register. */ - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, + pcie_write_slot_status(ctrl, PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC); -- 1.8.3.1