From: Mark Lord <lkml@rtr.ca>
To: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: Greg KH <greg@kroah.com>,
Linux Kernel <linux-kernel@vger.kernel.org>,
pcihpd-discuss@lists.sourceforge.net,
Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH] Fix PCIe hotplug for Dell notebook ExpressCard slots
Date: Tue, 16 Oct 2007 17:57:03 -0400 [thread overview]
Message-ID: <471533AF.60100@rtr.ca> (raw)
In-Reply-To: <20071016214143.GC21815@kroah.com>
Fix PCIe Hotplug so that it works with ExpressCard slots on Dell notebooks
in conjunction with modparam of pciehp_force=1.
The PCIe Hotplug driver has two shortcomings when used on Dell notebooks
which lack ACPI BIOS support for PCIe hotplug:
1. The driver does not recognise cards that were inserted prior
to the driver being modprobe'd.
2. The driver stops functioning after a suspend/resume (RAM) cycle,
and needs to be rmmod'd and modprobe'd to get it working again.
This patch addresses both issues.
Issue 1 is fixed by modifying pciehp_probe() to either enable or disable
the slot based on whether or not a card is detected at module init time.
Issue 2 is fixed by implementing pciehp_resume() to do the same
after having it first reinitialize the slot event registers.
The code to reinitialize those registers has been broken away from
pcie_init() so that it can be shared with pciehp_resume().
I'm not certain that locking contraints are correct in pciehp_resume(),
so it would be quite useful for the PCIe hotplug folks to look this all
over and provide suggestions/fixes as needed.
There are also a few minor cosmetic changes to satisfy checkpatch.pl.
pciehp.h | 3
pciehp_core.c | 31 ++++++--
pciehp_ctrl.c | 4 -
pciehp_hpc.c | 207 +++++++++++++++++++++++++++++++++-------------------------
4 files changed, 144 insertions(+), 101 deletions(-)
Signed-off-by: Mark Lord <mlord@pobox.com>
---
--- old/drivers/pci/hotplug/pciehp.h 2007-10-12 12:43:44.000000000 -0400
+++ linux/drivers/pci/hotplug/pciehp.h 2007-10-16 17:53:48.000000000 -0400
@@ -161,6 +161,9 @@
extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work);
int pcie_init(struct controller *ctrl, struct pcie_device *dev);
+int pciehp_enable_slot(struct slot *p_slot);
+int pciehp_disable_slot(struct slot *p_slot);
+int pcie_init_enable_events(struct controller *ctrl, struct pcie_device *dev);
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
--- old/drivers/pci/hotplug/pciehp_core.c 2007-10-12 12:43:44.000000000 -0400
+++ linux/drivers/pci/hotplug/pciehp_core.c 2007-10-16 17:48:24.000000000 -0400
@@ -470,17 +470,14 @@
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
- t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
- if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
- rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
- if (rc)
- goto err_out_free_ctrl_slot;
- }
-
+ /* Check if slot is occupied */
+ t_slot->hpc_ops->get_adapter_status(t_slot, &value);
+ if (value)
+ pciehp_enable_slot(t_slot);
+ else
+ pciehp_disable_slot(t_slot);
return 0;
-err_out_free_ctrl_slot:
- cleanup_slots(ctrl);
err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
@@ -508,7 +505,23 @@
static int pciehp_resume (struct pcie_device *dev)
{
+ struct pci_dev *pdev = dev->port;
+ struct controller *ctrl = pci_get_drvdata(pdev);
+ struct slot *t_slot;
+ u8 status;
+
printk("%s ENTRY\n", __FUNCTION__);
+
+ pcie_init_enable_events(ctrl, dev);
+
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
+
+ /* Check if slot is occupied */
+ t_slot->hpc_ops->get_adapter_status(t_slot, &status);
+ if (status)
+ pciehp_enable_slot(t_slot);
+ else
+ pciehp_disable_slot(t_slot);
return 0;
}
#endif
--- old/drivers/pci/hotplug/pciehp_ctrl.c 2007-10-12 12:43:44.000000000 -0400
+++ linux/drivers/pci/hotplug/pciehp_ctrl.c 2007-10-16 16:53:35.000000000 -0400
@@ -37,8 +37,6 @@
#include "pciehp.h"
static void interrupt_event_handler(struct work_struct *work);
-static int pciehp_enable_slot(struct slot *p_slot);
-static int pciehp_disable_slot(struct slot *p_slot);
static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
{
@@ -520,7 +518,7 @@
case INT_PRESENCE_OFF:
if (!HP_SUPR_RM(ctrl->ctrlcap))
break;
- dbg("Surprise Removal\n");
+ dbg("Surprise Event\n");
update_slot_info(p_slot);
handle_surprise_event(p_slot);
break;
--- old/drivers/pci/hotplug/pciehp_hpc.c 2007-10-12 12:43:44.000000000 -0400
+++ linux/drivers/pci/hotplug/pciehp_hpc.c 2007-10-16 17:53:27.000000000 -0400
@@ -1163,100 +1163,23 @@
}
#endif
-
-
-int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+int pcie_init_enable_events(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;
DBG_ENTER_ROUTINE
-
- 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;
- }
+ pdev = dev->port;
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);
@@ -1267,7 +1190,7 @@
dbg("%s: SLOTCTRL %x value read %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE)|0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
@@ -1330,14 +1253,14 @@
if (ATTN_BUTTN(slot_cap))
intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
+
if (POWER_CTRL(slot_cap))
intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
+
if (MRL_SENS(slot_cap))
intr_enable = intr_enable | MRL_DETECT_ENABLE;
- temp_word = (temp_word & ~intr_enable) | intr_enable;
+ temp_word = (temp_word & ~intr_enable) | intr_enable;
if (pciehp_poll_mode) {
temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1268,7 @@
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
}
- /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+ /* Unmask hp Interrupt Enable for intr notification mechanism case */
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -1356,14 +1279,14 @@
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
temp_word = 0x1F; /* Clear all events */
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
if (pciehp_force) {
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
@@ -1373,8 +1296,6 @@
goto abort_disable_intr;
}
- ctrl->hpc_ops = &pciehp_hpc_ops;
-
DBG_LEAVE_ROUTINE
return 0;
@@ -1398,3 +1319,111 @@
DBG_LEAVE_ROUTINE
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;
+
+ DBG_ENTER_ROUTINE
+
+ 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_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;
+
+ rc = pcie_init_enable_events(ctrl, dev);
+ if (rc)
+ goto abort_free_ctlr;;
+
+ ctrl->hpc_ops = &pciehp_hpc_ops;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+abort_free_ctlr:
+ DBG_LEAVE_ROUTINE
+ return -1;
+}
next prev parent reply other threads:[~2007-10-16 21:57 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-16 13:46 PCIe Hotplug: NFG unless I boot with card already inserted Mark Lord
2007-10-16 15:21 ` Mark Lord
2007-10-16 15:46 ` Kristen Carlson Accardi
2007-10-16 18:39 ` Mark Lord
2007-10-16 18:43 ` Kristen Carlson Accardi
2007-10-16 18:57 ` Mark Lord
2007-10-16 18:59 ` Mark Lord
2007-10-16 19:31 ` Mark Lord
2007-10-16 19:51 ` Kristen Carlson Accardi
2007-10-16 20:07 ` Kristen Carlson Accardi
2007-10-16 20:39 ` Mark Lord
2007-10-16 21:01 ` Kristen Carlson Accardi
2007-10-16 22:33 ` Theodore Tso
2007-10-16 21:41 ` [Pcihpd-discuss] " Greg KH
2007-10-16 21:57 ` Mark Lord [this message]
2007-10-16 22:03 ` [PATCH] Fix PCIe hotplug for Dell notebook ExpressCard slots Greg KH
2007-10-16 22:19 ` Mark Lord
2007-10-16 22:41 ` [Pcihpd-discuss] " Kristen Carlson Accardi
2007-10-16 22:04 ` Kristen Carlson Accardi
2007-10-16 22:17 ` Mark Lord
2007-10-17 1:53 ` [PATCH 0/4] Fix PCIe hotplug for non-ACPI ExpressCard slots (version 2) Mark Lord
2007-10-17 1:54 ` [PATCH 1/4] " Mark Lord
2007-10-17 1:54 ` [PATCH 2/4] " Mark Lord
2007-10-17 1:55 ` [PATCH 3/4] " Mark Lord
2007-10-17 1:55 ` [PATCH 4/4] " Mark Lord
2007-10-18 0:01 ` Kristen Carlson Accardi
2007-10-18 2:28 ` Mark Lord
2007-10-17 3:31 ` [Pcihpd-discuss] [PATCH 2/4] " Matthew Wilcox
2007-10-17 23:54 ` Kristen Carlson Accardi
2007-10-18 2:25 ` Mark Lord
2007-10-17 3:29 ` [Pcihpd-discuss] [PATCH 1/4] " Matthew Wilcox
2007-10-17 13:09 ` Mark Lord
2007-10-17 14:02 ` Matthew Wilcox
2007-10-17 14:33 ` Mark Lord
2007-10-17 22:02 ` [PATCH 0/4] " Andrew Morton
2007-10-17 22:59 ` Mark Lord
2007-10-17 23:25 ` Andrew Morton
2007-10-16 20:29 ` PCIe Hotplug: NFG unless I boot with card already inserted Kristen Carlson Accardi
2007-10-16 20:41 ` Mark Lord
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=471533AF.60100@rtr.ca \
--to=lkml@rtr.ca \
--cc=akpm@linux-foundation.org \
--cc=greg@kroah.com \
--cc=kristen.c.accardi@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=pcihpd-discuss@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.