[PATCH] shpchp: fix improper mmio mapping
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Thu, 24 Nov 2005 02:36:59 +0000 (11:36 +0900)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 9 Jan 2006 20:13:17 +0000 (12:13 -0800)
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 <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_core.c
drivers/pci/hotplug/shpchp_hpc.c

index 08ad26a0cae70c2d209e6a30af0408758a4c9eed..55b0cd15f3485b47d4ccce8e0f144e8e7155fc6f 100644 (file)
@@ -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 {
index 63628e01dd436edefa8e0fe8dda89b503e97f7eb..d81f8a75b495d2545169911fc2c798d8d1a467ce 100644 (file)
@@ -377,8 +377,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                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);
index f5a8bf374634a11f871f4fda1a92133768b21663..d82987f075b2dcbb7790068955cf3f51e3b1ad9d 100644 (file)
@@ -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);