[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 <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
87d6c55931
commit
0455986cce
|
@ -98,6 +98,9 @@ struct controller {
|
||||||
enum pci_bus_speed speed;
|
enum pci_bus_speed speed;
|
||||||
u32 first_slot; /* First physical slot number */
|
u32 first_slot; /* First physical slot number */
|
||||||
u8 slot_bus; /* Bus where the slots handled by this controller sit */
|
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 {
|
struct hotplug_params {
|
||||||
|
|
|
@ -377,8 +377,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
goto err_out_free_ctrl;
|
goto err_out_free_ctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
|
|
||||||
|
|
||||||
pci_set_drvdata(pdev, ctrl);
|
pci_set_drvdata(pdev, ctrl);
|
||||||
|
|
||||||
ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
|
ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
|
||||||
|
|
|
@ -791,7 +791,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
|
||||||
}
|
}
|
||||||
if (php_ctlr->pci_dev) {
|
if (php_ctlr->pci_dev) {
|
||||||
iounmap(php_ctlr->creg);
|
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;
|
php_ctlr->pci_dev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1320,19 +1320,34 @@ static struct hpc_ops shpchp_hpc_ops = {
|
||||||
.check_cmd_status = hpc_check_cmd_status,
|
.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)
|
int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
|
||||||
{
|
{
|
||||||
struct php_ctlr_state_s *php_ctlr, *p;
|
struct php_ctlr_state_s *php_ctlr, *p;
|
||||||
void *instance_id = ctrl;
|
void *instance_id = ctrl;
|
||||||
int rc;
|
int rc, num_slots = 0;
|
||||||
u8 hp_slot;
|
u8 hp_slot;
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
u32 shpc_cap_offset, shpc_base_offset;
|
u32 shpc_base_offset;
|
||||||
u32 tempdword, slot_reg;
|
u32 tempdword, slot_reg;
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
DBG_ENTER_ROUTINE
|
DBG_ENTER_ROUTINE
|
||||||
|
|
||||||
|
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
|
||||||
|
|
||||||
spin_lock_init(&list_lock);
|
spin_lock_init(&list_lock);
|
||||||
php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
|
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 ==
|
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
|
||||||
PCI_DEVICE_ID_AMD_GOLAM_7450)) {
|
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 {
|
} else {
|
||||||
if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
|
ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
|
||||||
err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
|
if (!ctrl->cap_offset) {
|
||||||
|
err("%s : cap_offset == 0\n", __FUNCTION__);
|
||||||
goto abort_free_ctlr;
|
goto abort_free_ctlr;
|
||||||
}
|
}
|
||||||
dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset);
|
dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
|
||||||
|
|
||||||
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
|
rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
err("%s : pci_word_config_byte failed\n", __FUNCTION__);
|
err("%s: cannot read base_offset\n", __FUNCTION__);
|
||||||
goto abort_free_ctlr;
|
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) {
|
if (rc) {
|
||||||
err("%s : pci_read_config_dword failed\n", __FUNCTION__);
|
err("%s: cannot read slot config\n", __FUNCTION__);
|
||||||
goto abort_free_ctlr;
|
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++) {
|
for (i = 0; i < 9 + num_slots; i++) {
|
||||||
rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i);
|
rc = shpc_indirect_creg_read(ctrl, i, &tempdword);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
err("%s : pci_word_config_byte failed\n", __FUNCTION__);
|
err("%s: cannot read creg (index = %d)\n",
|
||||||
goto abort_free_ctlr;
|
__FUNCTION__, i);
|
||||||
}
|
|
||||||
|
|
||||||
rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
|
|
||||||
if (rc) {
|
|
||||||
err("%s : pci_read_config_dword failed\n", __FUNCTION__);
|
|
||||||
goto abort_free_ctlr;
|
goto abort_free_ctlr;
|
||||||
}
|
}
|
||||||
dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
|
dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
|
||||||
tempdword);
|
tempdword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctrl->mmio_base =
|
||||||
|
pci_resource_start(pdev, 0) + shpc_base_offset;
|
||||||
|
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -1395,16 +1414,16 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
|
||||||
if (pci_enable_device(pdev))
|
if (pci_enable_device(pdev))
|
||||||
goto abort_free_ctlr;
|
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__);
|
err("%s: cannot reserve MMIO region\n", __FUNCTION__);
|
||||||
goto abort_free_ctlr;
|
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) {
|
if (!php_ctlr->creg) {
|
||||||
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0),
|
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
|
||||||
pci_resource_start(pdev, 0) + shpc_base_offset);
|
ctrl->mmio_size, ctrl->mmio_base);
|
||||||
release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
|
release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
|
||||||
goto abort_free_ctlr;
|
goto abort_free_ctlr;
|
||||||
}
|
}
|
||||||
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
|
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
|
||||||
|
|
Loading…
Reference in New Issue