From 6558b6ab145ceead45632e4214cd5ef14f48f412 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 24 Nov 2005 13:44:01 +0900 Subject: [PATCH] shpchp: fix improper reference to Slot Avail Regsister The hpc_get_max_bus_speed() function of the SHPCHP driver seems to refer wrong bits in the "Slot Avail Register I" and "Slot Avail Register II". This patch fixes this bug. And this also cleanup the code. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers/pci/hotplug/shpchp_hpc.c') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 9987a6fd65b..3c1d3b4b040 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -1121,7 +1121,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) int retval = 0; u8 pi; u32 slot_avail1, slot_avail2; - int slot_num; DBG_ENTER_ROUTINE @@ -1140,39 +1139,39 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); if (pi == 2) { - if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27) ) != 0 ) + if (slot_avail2 & SLOT_133MHZ_PCIX_533) bus_speed = PCIX_133MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23) ) != 0 ) + else if (slot_avail2 & SLOT_100MHZ_PCIX_533) bus_speed = PCIX_100MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19) ) != 0 ) + else if (slot_avail2 & SLOT_66MHZ_PCIX_533) bus_speed = PCIX_66MHZ_533; - else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15) ) != 0 ) + else if (slot_avail2 & SLOT_133MHZ_PCIX_266) bus_speed = PCIX_133MHZ_266; - else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11) ) != 0 ) + else if (slot_avail2 & SLOT_100MHZ_PCIX_266) bus_speed = PCIX_100MHZ_266; - else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7) ) != 0 ) + else if (slot_avail2 & SLOT_66MHZ_PCIX_266) bus_speed = PCIX_66MHZ_266; - else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) + else if (slot_avail1 & SLOT_133MHZ_PCIX) bus_speed = PCIX_133MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) + else if (slot_avail1 & SLOT_100MHZ_PCIX) bus_speed = PCIX_100MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) + else if (slot_avail1 & SLOT_66MHZ_PCIX) bus_speed = PCIX_66MHZ; - else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) + else if (slot_avail2 & SLOT_66MHZ) bus_speed = PCI_66MHZ; - else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) + else if (slot_avail1 & SLOT_33MHZ) bus_speed = PCI_33MHZ; else bus_speed = PCI_SPEED_UNKNOWN; } else { - if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) + if (slot_avail1 & SLOT_133MHZ_PCIX) bus_speed = PCIX_133MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) + else if (slot_avail1 & SLOT_100MHZ_PCIX) bus_speed = PCIX_100MHZ; - else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) + else if (slot_avail1 & SLOT_66MHZ_PCIX) bus_speed = PCIX_66MHZ; - else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) + else if (slot_avail2 & SLOT_66MHZ) bus_speed = PCI_66MHZ; - else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) + else if (slot_avail1 & SLOT_33MHZ) bus_speed = PCI_33MHZ; else bus_speed = PCI_SPEED_UNKNOWN; } -- cgit v1.2.3 From 87d6c5593111844f308af7d5106b3fd259b36514 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 24 Nov 2005 11:35:05 +0900 Subject: [PATCH] shpchp: fix improper reference to Mode 1 ECC Capability" bit The hpc_get_mode1_ECC_cap() function of SHPCHP driver seems to refer the wrong bit for refering the "Mode 1 ECC Capability" bit. This bug seems not to cause any problem so far. But I think this should be fixed. This patch fixes this bug. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/hotplug/shpchp_hpc.c') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 3c1d3b4b040..f5a8bf37463 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -604,7 +604,7 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); if (pi == 2) { - *mode = (sec_bus_status & 0x0100) >> 7; + *mode = (sec_bus_status & 0x0100) >> 8; } else { retval = -1; } -- cgit v1.2.3 From 0455986cce45d28511f59a29d6cecc17d6b65720 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 24 Nov 2005 11:36:59 +0900 Subject: [PATCH] shpchp: fix improper mmio mapping Current SHPCHP driver seems not to map MMIO region properly. This patch fixes this bug. This patch also cleanup the code. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 73 +++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 27 deletions(-) (limited to 'drivers/pci/hotplug/shpchp_hpc.c') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index f5a8bf37463..d82987f075b 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -791,7 +791,7 @@ static void hpc_release_ctlr(struct controller *ctrl) } if (php_ctlr->pci_dev) { iounmap(php_ctlr->creg); - release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); php_ctlr->pci_dev = NULL; } @@ -1320,19 +1320,34 @@ static struct hpc_ops shpchp_hpc_ops = { .check_cmd_status = hpc_check_cmd_status, }; +inline static int shpc_indirect_creg_read(struct controller *ctrl, int index, + u32 *value) +{ + int rc; + u32 cap_offset = ctrl->cap_offset; + struct pci_dev *pdev = ctrl->pci_dev; + + rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index); + if (rc) + return rc; + return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value); +} + int shpc_init(struct controller * ctrl, struct pci_dev * pdev) { struct php_ctlr_state_s *php_ctlr, *p; void *instance_id = ctrl; - int rc; + int rc, num_slots = 0; u8 hp_slot; static int first = 1; - u32 shpc_cap_offset, shpc_base_offset; + u32 shpc_base_offset; u32 tempdword, slot_reg; u8 i; DBG_ENTER_ROUTINE + ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ + spin_lock_init(&list_lock); php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); @@ -1347,41 +1362,45 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450)) { - shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ + /* amd shpc driver doesn't use Base Offset; assume 0 */ + ctrl->mmio_base = pci_resource_start(pdev, 0); + ctrl->mmio_size = pci_resource_len(pdev, 0); } else { - if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { - err("%s : shpc_cap_offset == 0\n", __FUNCTION__); + ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC); + if (!ctrl->cap_offset) { + err("%s : cap_offset == 0\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset); - - rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET); + dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); + + rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset); if (rc) { - err("%s : pci_word_config_byte failed\n", __FUNCTION__); + err("%s: cannot read base_offset\n", __FUNCTION__); goto abort_free_ctlr; } - - rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset); + + rc = shpc_indirect_creg_read(ctrl, 3, &tempdword); if (rc) { - err("%s : pci_read_config_dword failed\n", __FUNCTION__); + err("%s: cannot read slot config\n", __FUNCTION__); goto abort_free_ctlr; } + num_slots = tempdword & SLOT_NUM; + dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); - for (i = 0; i <= 14; i++) { - rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i); - if (rc) { - err("%s : pci_word_config_byte failed\n", __FUNCTION__); - goto abort_free_ctlr; - } - - rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword); + for (i = 0; i < 9 + num_slots; i++) { + rc = shpc_indirect_creg_read(ctrl, i, &tempdword); if (rc) { - err("%s : pci_read_config_dword failed\n", __FUNCTION__); + err("%s: cannot read creg (index = %d)\n", + __FUNCTION__, i); goto abort_free_ctlr; } dbg("%s: offset %d: value %x\n", __FUNCTION__,i, tempdword); } + + ctrl->mmio_base = + pci_resource_start(pdev, 0) + shpc_base_offset; + ctrl->mmio_size = 0x24 + 0x4 * num_slots; } if (first) { @@ -1395,16 +1414,16 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) if (pci_enable_device(pdev)) goto abort_free_ctlr; - if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) { + if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) { err("%s: cannot reserve MMIO region\n", __FUNCTION__); goto abort_free_ctlr; } - php_ctlr->creg = ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); + php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size); if (!php_ctlr->creg) { - err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), - pci_resource_start(pdev, 0) + shpc_base_offset); - release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); + err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, + ctrl->mmio_size, ctrl->mmio_base); + release_mem_region(ctrl->mmio_base, ctrl->mmio_size); goto abort_free_ctlr; } dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); -- cgit v1.2.3 From f467f6187fc60c954a9509b3a3e17ef89a4f6f22 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Thu, 24 Nov 2005 11:39:29 +0900 Subject: [PATCH] shpchp: fix improper write to Command Completion Detect bit Current SHPCHP driver writes a '0' to the Command Completion Detect bit to clear the Command Complete Interrupt Pending. But according to the SHPC spec (See 4.7.3.1 System Interrupts), SHPCHP driver must write '1'. This patch fixes this bug. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/pci/hotplug/shpchp_hpc.c') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index d82987f075b..f25e1164507 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -1058,11 +1058,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) if (intr_loc & 0x0001) { /* * Command Complete Interrupt Pending - * RO only - clear by writing 0 to the Command Completion + * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); - temp_dword &= 0xfffeffff; + temp_dword &= 0xfffdffff; writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); wake_up_interruptible(&ctrl->queue); } -- cgit v1.2.3 From bd62e271401c5ebf33a0dd24d89baf706f213251 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 25 Nov 2005 12:28:53 +0900 Subject: [PATCH] shpchp: fix improper wait for command completion Current SHPCHP driver uses msleep_interruptible() function to wait for a command completion event. But I think this would cause an unnecessary long wait until timeout, if command completion interrupt came before task state was changed to TASK_INTERRUPTIBLE. This patch fixes this issue. With this patch, command completion becomes faster as follows: o Without this patch # time echo 1 > power real 0m4.708s user 0m0.000s sys 0m0.524s o With this patch # time echo 1 > power real 0m2.221s user 0m0.000s sys 0m0.532s Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_hpc.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/pci/hotplug/shpchp_hpc.c') diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index f25e1164507..b4226ff3a85 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -275,6 +275,25 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) return; } +static inline int shpc_wait_cmd(struct controller *ctrl) +{ + int retval = 0; + unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000; + unsigned long timeout = msecs_to_jiffies(timeout_msec); + int rc = wait_event_interruptible_timeout(ctrl->queue, + !ctrl->cmd_busy, timeout); + if (!rc) { + retval = -EIO; + err("Command not completed in %d msec\n", timeout_msec); + } else if (rc < 0) { + retval = -EINTR; + info("Command was interrupted by a signal\n"); + } + ctrl->cmd_busy = 0; + + return retval; +} + static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) { struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; @@ -314,8 +333,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) /* To make sure the Controller Busy bit is 0 before we send out the * command. */ + slot->ctrl->cmd_busy = 1; writew(temp_word, php_ctlr->creg + CMD); + /* + * Wait for command completion. + */ + retval = shpc_wait_cmd(slot->ctrl); + DBG_LEAVE_ROUTINE return retval; } @@ -1064,6 +1089,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); temp_dword &= 0xfffdffff; writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } -- cgit v1.2.3