diff options
author | Mark Lord <lkml@rtr.ca> | 2007-11-28 15:11:46 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 15:04:23 -0800 |
commit | 08e7a7d27d71e92305980033ec03c0a86b3efb2d (patch) | |
tree | 4916e6831b974087cf17d3d8c0394563139319b4 /drivers/pci/hotplug/pciehp_hpc.c | |
parent | 0a3c33d77ff7ad5b988997536a8f09c49e35ad20 (diff) | |
download | lwn-08e7a7d27d71e92305980033ec03c0a86b3efb2d.tar.gz lwn-08e7a7d27d71e92305980033ec03c0a86b3efb2d.zip |
PCI: more fixes for PCIe Hotplug so that it works with ExpressCard slots on Dell notebooks (and others?) in conjunction with modparam of pciehp_force=1
Split out the hotplug hardware initialization code from pcie_init()
into pcie_init_enable_events(), without changing any functionality.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 185 |
1 files changed, 104 insertions, 81 deletions
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 06d025b8b13f..8b11d80bf651 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1067,99 +1067,22 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) } #endif -int pcie_init(struct controller * ctrl, struct pcie_device *dev) +int pcie_init_hardware(struct controller *ctrl, struct pcie_device *dev) { int rc; u16 temp_word; - u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; - int cap_base; - u16 slot_status, slot_ctrl; + u16 slot_status; struct pci_dev *pdev; pdev = dev->port; - ctrl->pci_dev = pdev; /* save pci_dev in context */ - - dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", - __FUNCTION__, pdev->vendor, pdev->device); - - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { - dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); - goto abort_free_ctlr; - } - - ctrl->cap_base = cap_base; - - dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); - - rc = pciehp_readw(ctrl, CAPREG, &cap_reg); - if (rc) { - err("%s: Cannot read CAPREG register\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: CAPREG offset %x cap_reg %x\n", - __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); - - if (((cap_reg & SLOT_IMPL) == 0) || - (((cap_reg & DEV_PORT_TYPE) != 0x0040) - && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not " - "connected to a slot\n", __FUNCTION__); - goto abort_free_ctlr; - } rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOTCAP offset %x slot_cap %x\n", - __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); - - if (!(slot_cap & HP_CAP)) { - dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); - goto abort_free_ctlr; - } - /* For debugging purpose */ - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: SLOTSTATUS offset %x slot_status %x\n", - __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); - - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); - goto abort_free_ctlr; - } - dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", - __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - - for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, - (unsigned long long)pci_resource_start(pdev, rc), - (unsigned long long)pci_resource_len(pdev, rc)); - - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); - - mutex_init(&ctrl->crit_sect); - mutex_init(&ctrl->ctrl_lock); - spin_lock_init(&ctrl->lock); - - /* setup wait queue */ - init_waitqueue_head(&ctrl->queue); - - /* return PCI Controller Info */ - ctrl->slot_device_offset = 0; - ctrl->num_slots = 1; - ctrl->first_slot = slot_cap >> 19; - ctrl->ctrlcap = slot_cap & 0x0000007f; /* Mask Hot-plug Interrupt Enable */ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); @@ -1280,8 +1203,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) goto abort_disable_intr; } - ctrl->hpc_ops = &pciehp_hpc_ops; - return 0; /* We end up here for the many possible ways to fail this API. */ @@ -1303,3 +1224,105 @@ abort_free_irq: abort_free_ctlr: return -1; } + +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + int rc; + u16 cap_reg; + u32 slot_cap; + int cap_base; + u16 slot_status, slot_ctrl; + struct pci_dev *pdev; + + pdev = dev->port; + ctrl->pci_dev = pdev; /* save pci_dev in context */ + + dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", + __FUNCTION__, pdev->vendor, pdev->device); + + cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (cap_base == 0) { + dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); + goto abort; + } + + ctrl->cap_base = cap_base; + + dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); + + rc = pciehp_readw(ctrl, CAPREG, &cap_reg); + if (rc) { + err("%s: Cannot read CAPREG register\n", __FUNCTION__); + goto abort; + } + dbg("%s: CAPREG offset %x cap_reg %x\n", + __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); + + if (((cap_reg & SLOT_IMPL) == 0) || + (((cap_reg & DEV_PORT_TYPE) != 0x0040) + && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { + dbg("%s : This is not a root port or the port is not " + "connected to a slot\n", __FUNCTION__); + goto abort; + } + + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); + if (rc) { + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); + goto abort; + } + dbg("%s: SLOTCAP offset %x slot_cap %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); + + if (!(slot_cap & HP_CAP)) { + dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); + goto abort; + } + /* For debugging purpose */ + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (rc) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + goto abort; + } + dbg("%s: SLOTSTATUS offset %x slot_status %x\n", + __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); + + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); + goto abort; + } + dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); + + for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + if (pci_resource_len(pdev, rc) > 0) + dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, + (unsigned long long)pci_resource_start(pdev, rc), + (unsigned long long)pci_resource_len(pdev, rc)); + + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + mutex_init(&ctrl->crit_sect); + mutex_init(&ctrl->ctrl_lock); + spin_lock_init(&ctrl->lock); + + /* setup wait queue */ + init_waitqueue_head(&ctrl->queue); + + /* return PCI Controller Info */ + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->first_slot = slot_cap >> 19; + ctrl->ctrlcap = slot_cap & 0x0000007f; + + rc = pcie_init_hardware(ctrl, dev); + if (rc == 0) { + ctrl->hpc_ops = &pciehp_hpc_ops; + return 0; + } +abort: + return -1; +} |