From kaneshige.kenji@jp.fujitsu.com Wed Nov 23 18:42:59 2005 Message-ID: <4385274B.5010407@jp.fujitsu.com> Date: Thu, 24 Nov 2005 11:36:59 +0900 From: Kenji Kaneshige To: Greg KH , CC: Kenji Kaneshige Subject: 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.h | 3 + drivers/pci/hotplug/shpchp_core.c | 2 - drivers/pci/hotplug/shpchp_hpc.c | 73 +++++++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 29 deletions(-) --- gregkh-2.6.orig/drivers/pci/hotplug/shpchp.h +++ gregkh-2.6/drivers/pci/hotplug/shpchp.h @@ -98,6 +98,9 @@ struct controller { enum pci_bus_speed speed; u32 first_slot; /* First physical slot number */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ + u32 cap_offset; + unsigned long mmio_base; + unsigned long mmio_size; }; struct hotplug_params { --- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_hpc.c +++ gregkh-2.6/drivers/pci/hotplug/shpchp_hpc.c @@ -791,7 +791,7 @@ static void hpc_release_ctlr(struct cont } 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, 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, 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); --- gregkh-2.6.orig/drivers/pci/hotplug/shpchp_core.c +++ gregkh-2.6/drivers/pci/hotplug/shpchp_core.c @@ -377,8 +377,6 @@ static int shpc_probe(struct pci_dev *pd goto err_out_free_ctrl; } - ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ - pci_set_drvdata(pdev, ctrl); ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);