diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2006-05-01 22:11:54 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-19 17:13:23 -0400 |
commit | 795eb5c4a73bee30e8c2dbb29174b329da56051c (patch) | |
tree | 2c489f1f647d46cdc29322839d766cbf37d55485 /drivers/pci/hotplug/shpchp_hpc.c | |
parent | 5858759c2098c6792af1afa6d5ded94044740f9c (diff) |
[PATCH] SHPC: Fix SHPC Logical Slot Register bits access
Current SHPCHP driver doesn't take care of RsvdP/RsvdZ[*] bits
in logical slot registers. This might cause unpredicable results. This
patch fixes this bug.
[*] RsvdP and RsvdZ are defined in SHPC spec as follows:
RsvdP - Reserved and Preserved. Register bits of this type are
reserved for future use as R/W bits. The value read is
undefined. Writes are ignored. Software must follow These rules
when accessing RsvdP bits:
- Software must ignore RsvdP bits when testing values read
from these registers.
- Software must not depend on RsvdP bit's ability to retain
information when written
- Software must always write back the value read in the RsvdP
bits when writing one of these registers.
RsvdZ - Reserved and Zero. Register bits of this type are reserved
for future use as R/WC bits. The value read is undefined. Writes
are ignored. Software must follow these rules when accessing RsvdZ
bits:
- Software must ignore RsvdZ bits when testing values read
from these registers.
- Software must not depends on a RsvdZ bit's ability to retain
information when written.
- Software must always write 0 to RsvdZ bits when writing one
of these register.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Cc: Kristen Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/shpchp_hpc.c')
-rw-r--r-- | drivers/pci/hotplug/shpchp_hpc.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 9731ee8224f2..285a21d36524 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c | |||
@@ -554,11 +554,25 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) | |||
554 | int retval = 0; | 554 | int retval = 0; |
555 | struct controller *ctrl = slot->ctrl; | 555 | struct controller *ctrl = slot->ctrl; |
556 | u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); | 556 | u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); |
557 | u8 pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; | ||
558 | u8 m66_cap = !!(slot_reg & MHZ66_CAP); | 557 | u8 m66_cap = !!(slot_reg & MHZ66_CAP); |
558 | u8 pi, pcix_cap; | ||
559 | 559 | ||
560 | DBG_ENTER_ROUTINE | 560 | DBG_ENTER_ROUTINE |
561 | 561 | ||
562 | if ((retval = hpc_get_prog_int(slot, &pi))) | ||
563 | return retval; | ||
564 | |||
565 | switch (pi) { | ||
566 | case 1: | ||
567 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT; | ||
568 | break; | ||
569 | case 2: | ||
570 | pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT; | ||
571 | break; | ||
572 | default: | ||
573 | return -ENODEV; | ||
574 | } | ||
575 | |||
562 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", | 576 | dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", |
563 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); | 577 | __FUNCTION__, slot_reg, pcix_cap, m66_cap); |
564 | 578 | ||
@@ -773,6 +787,7 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
773 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; | 787 | struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; |
774 | struct php_ctlr_state_s *p, *p_prev; | 788 | struct php_ctlr_state_s *p, *p_prev; |
775 | int i; | 789 | int i; |
790 | u32 slot_reg; | ||
776 | 791 | ||
777 | DBG_ENTER_ROUTINE | 792 | DBG_ENTER_ROUTINE |
778 | 793 | ||
@@ -782,10 +797,17 @@ static void hpc_release_ctlr(struct controller *ctrl) | |||
782 | } | 797 | } |
783 | 798 | ||
784 | /* | 799 | /* |
785 | * Mask all slot event interrupts | 800 | * Mask event interrupts and SERRs of all slots |
786 | */ | 801 | */ |
787 | for (i = 0; i < ctrl->num_slots; i++) | 802 | for (i = 0; i < ctrl->num_slots; i++) { |
788 | shpc_writel(ctrl, SLOT_REG(i), 0xffff3fff); | 803 | slot_reg = shpc_readl(ctrl, SLOT_REG(i)); |
804 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | | ||
805 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | | ||
806 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
807 | CON_PFAULT_SERR_MASK); | ||
808 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
809 | shpc_writel(ctrl, SLOT_REG(i), slot_reg); | ||
810 | } | ||
789 | 811 | ||
790 | cleanup_slots(ctrl); | 812 | cleanup_slots(ctrl); |
791 | 813 | ||
@@ -1072,7 +1094,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) | |||
1072 | hp_slot, php_ctlr->callback_instance_id); | 1094 | hp_slot, php_ctlr->callback_instance_id); |
1073 | 1095 | ||
1074 | /* Clear all slot events */ | 1096 | /* Clear all slot events */ |
1075 | temp_dword = 0xe01f3fff; | 1097 | temp_dword &= ~SLOT_REG_RSVDZ_MASK; |
1076 | shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); | 1098 | shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword); |
1077 | 1099 | ||
1078 | intr_loc2 = shpc_readl(ctrl, INTR_LOC); | 1100 | intr_loc2 = shpc_readl(ctrl, INTR_LOC); |
@@ -1364,8 +1386,12 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1364 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); | 1386 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1365 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1387 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1366 | hp_slot, slot_reg); | 1388 | hp_slot, slot_reg); |
1367 | tempdword = 0xffff3fff; | 1389 | slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1368 | shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); | 1390 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1391 | CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK | | ||
1392 | CON_PFAULT_SERR_MASK); | ||
1393 | slot_reg &= ~SLOT_REG_RSVDZ_MASK; | ||
1394 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1369 | } | 1395 | } |
1370 | 1396 | ||
1371 | if (shpchp_poll_mode) {/* Install interrupt polling code */ | 1397 | if (shpchp_poll_mode) {/* Install interrupt polling code */ |
@@ -1411,12 +1437,17 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) | |||
1411 | 1437 | ||
1412 | ctlr_seq_num++; | 1438 | ctlr_seq_num++; |
1413 | 1439 | ||
1440 | /* | ||
1441 | * Unmask all event interrupts of all slots | ||
1442 | */ | ||
1414 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { | 1443 | for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { |
1415 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); | 1444 | slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot)); |
1416 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, | 1445 | dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, |
1417 | hp_slot, slot_reg); | 1446 | hp_slot, slot_reg); |
1418 | tempdword = 0xe01f3fff; | 1447 | slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK | |
1419 | shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword); | 1448 | BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK | |
1449 | CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK); | ||
1450 | shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); | ||
1420 | } | 1451 | } |
1421 | if (!shpchp_poll_mode) { | 1452 | if (!shpchp_poll_mode) { |
1422 | /* Unmask all general input interrupts and SERR */ | 1453 | /* Unmask all general input interrupts and SERR */ |