lkml.org 
[lkml]   [2008]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
SubjectRe: post 2.6.26 requires pciehp_slot_with_bus
Date
On Thursday, July 24, 2008 9:50 pm Kenji Kaneshige wrote:
> Thank you for debug info, Pierre.
>
> According to the debugging output, five slots are detected (five
> slots on laptop!?) and two of them have the same physical slots
> number '2'. This is the reason why Pierre's machine needs
> 'pciehp_slot_with_bus' option.
>
> Before 2.6.26 (from 2.6.xx), pciehp did the workaround for the
> problem (some platform wrongly assign the same physical slot
> number to multiple slots) by default. But this was not a good
> idea because of the several reasons like follows:
>
> - Slot name should be a physical identifier of physical slot
> on the system. Using bus number as a part of slot name is
> not a idea because bus number is logical number and it can
> be changed.
>
> - As Jesse explained, some hotplug slot can be handled through
> several type of controllers. For example, some hotplug slot
> can be handled by either acpiphp or pciehp. But those drivers
> must not handle the same slot at the same time. The pci
> hotplug core is checking this by checking duplicate names.
> This check didn't work because pciehp had started using bus
> number as a part of slot name and slot names became different
> between acpiphp and pciehp.
>
> About the former, I'm ok with using bus number as a part of slot
> name on the problematic platform. But it should not be used on
> the normal platform.
>
> About the latter, IIRC, thanks to Alex's pci slot framework from
> 2.6.26, pci hotplug core can check if multiple drivers attempts
> to handle the same slot even if those drivers uses the different
> names.
>
> Based on my thought above, I have a following idea to remove
> "pciehp_slot_with_bus".
>
> - Try to use physical slot number as a slot name, first.
>
> - If pci_hp_register() success, no problem.
>
> - If pci_hp_register() returns -EBUSY, that means another
> hotplug driver already handling the slot. So return as error.
>
> - If pci_hp_register() returns -EEXIST, that means there is a
> existing slot with the same name. In this case, retry to
> register slots with logical name (bus number + physical slot
> number, or other).
>
> With this idea, slots names will become as follows on Pierre's
> machine.
>
> <Before 2.6.26>
> 0001_0001, 0002_0002, 0003_0003, 0004_0004, 0005_0005, 000d_0002
>
> <Current>
> 1, 2, 3, 4, 5
>
> <With my idea>
> 1, 2, 3, 4, 5, 000d_0002
>
>
> Please give me comments.

I think that's fine (automatically creating duplicate devices with names to
differentiate them), but I think we should also try harder to avoid adding
duplicates.
In Pierre's case, and on my T61, there's only one actual hotplug slot
available, but the firmware creates duplicate physical slot numbers and sets
the HP_CAP bit on everything, both of which are obviously wrong (well I
suppose you could pop these chips off the board, but it's not very
practical). However, afaict that "other" OS uses the _RMV method to
determine whether a given slot is actually hot pluggable. On my T61 at
least, this seems to be accurate: only one of my EXP* objects has a _RMV
method.

So maybe the PCIe hotplug driver should be checking for that method when ACPI
is available? We already try to use _OSC etc., so checking for _RMV first
would make sense...

I tried and failed to do this (naive patch attached), I think somehow I've got
to traverse child devices too... (and of course add the appropriate #ifdef
ACPI etc stuff).

Kenji-san and Alex, maybe you can take a look and clue me in?

Thanks,
Jesse
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index e3a1e7e..6ab29d8 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -136,6 +136,7 @@ struct controller {
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
+#define HP_CAP_SUP 0x00000040
#define EMI_PRSN 0x00020000
#define NO_CMD_CMPL_SUP 0x00040000

@@ -145,6 +146,7 @@ struct controller {
#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN)
#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN)
#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP)
+#define HP_CAP(ctrl) ((ctrl)->slot_cap & HP_CAP_SUP)
#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN)
#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP)

diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 3677495..896ca5f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -386,6 +386,17 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
return 0;
}

+static bool acpi_rmv_present(struct pci_dev *pdev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(&pdev->dev);
+
+ if (acpi_dev && acpi_dev->flags.removable)
+ return true;
+
+ dbg("%s: no ACPI device (%p) or not removable\n", pci_name(pdev), acpi_dev);
+ return false;
+}
+
static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id)
{
int rc;
@@ -397,8 +408,15 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
if (pciehp_force)
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(pdev));
- else if (pciehp_get_hp_hw_control_from_firmware(pdev))
- goto err_out_none;
+ else {
+ if (!acpi_rmv_present(pdev))
+ goto err_out_none;
+ if (pciehp_get_hp_hw_control_from_firmware(pdev)) {
+ dbg("Failed to get control from firmware for %s\n",
+ pci_name(pdev));
+ goto err_out_none;
+ }
+ }

ctrl = pcie_init(dev);
if (!ctrl) {
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 1323a43..445b0b1 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -149,7 +149,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
-#define HP_CAP 0x00000040
+#define HP_CAP_SUP 0x00000040
#define SLOT_PWR_VALUE 0x000003F8
#define SLOT_PWR_LIMIT 0x00000C00
#define PSN 0xFFF80000 /* PSN: Physical Slot Number */
@@ -1102,6 +1102,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no");
dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
+ dbg(" Hot-Plug Capable : %3s\n", HP_CAP(ctrl) ? "yes" : "no");
dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
pciehp_readw(ctrl, SLOTSTATUS, &reg16);
@@ -1127,18 +1128,25 @@ struct controller *pcie_init(struct pcie_device *dev)
ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!ctrl->cap_base) {
err("%s: Cannot find PCI Express capability\n", __func__);
- goto abort;
+ goto abort_ctrl;
}
if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) {
err("%s: Cannot read SLOTCAP register\n", __func__);
- goto abort;
+ goto abort_ctrl;
}

+
ctrl->slot_cap = slot_cap;
ctrl->first_slot = slot_cap >> 19;
ctrl->slot_device_offset = 0;
ctrl->num_slots = 1;
ctrl->hpc_ops = &pciehp_hpc_ops;
+
+ if (!HP_CAP(ctrl)) {
+ dbg("%s: not hotplug capable, skipping\n", pci_name(pdev));
+ goto abort_ctrl;
+ }
+
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue);
\
 
 \ /
  Last update: 2008-07-26 00:21    [from the cache]
©2003-2011 Jasper Spaans