[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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
5858759c20
commit
795eb5c4a7
@@ -554,11 +554,25 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct controller *ctrl = slot->ctrl;
|
struct controller *ctrl = slot->ctrl;
|
||||||
u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
|
u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
|
||||||
u8 pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT;
|
|
||||||
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
|
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
|
||||||
|
u8 pi, pcix_cap;
|
||||||
|
|
||||||
DBG_ENTER_ROUTINE
|
DBG_ENTER_ROUTINE
|
||||||
|
|
||||||
|
if ((retval = hpc_get_prog_int(slot, &pi)))
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
switch (pi) {
|
||||||
|
case 1:
|
||||||
|
pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",
|
dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",
|
||||||
__FUNCTION__, slot_reg, pcix_cap, m66_cap);
|
__FUNCTION__, slot_reg, pcix_cap, m66_cap);
|
||||||
|
|
||||||
@@ -773,6 +787,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
|
|||||||
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
|
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
|
||||||
struct php_ctlr_state_s *p, *p_prev;
|
struct php_ctlr_state_s *p, *p_prev;
|
||||||
int i;
|
int i;
|
||||||
|
u32 slot_reg;
|
||||||
|
|
||||||
DBG_ENTER_ROUTINE
|
DBG_ENTER_ROUTINE
|
||||||
|
|
||||||
@@ -782,10 +797,17 @@ static void hpc_release_ctlr(struct controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mask all slot event interrupts
|
* Mask event interrupts and SERRs of all slots
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < ctrl->num_slots; i++)
|
for (i = 0; i < ctrl->num_slots; i++) {
|
||||||
shpc_writel(ctrl, SLOT_REG(i), 0xffff3fff);
|
slot_reg = shpc_readl(ctrl, SLOT_REG(i));
|
||||||
|
slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
|
||||||
|
BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
|
||||||
|
CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK |
|
||||||
|
CON_PFAULT_SERR_MASK);
|
||||||
|
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
|
||||||
|
shpc_writel(ctrl, SLOT_REG(i), slot_reg);
|
||||||
|
}
|
||||||
|
|
||||||
cleanup_slots(ctrl);
|
cleanup_slots(ctrl);
|
||||||
|
|
||||||
@@ -1072,7 +1094,7 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
|
|||||||
hp_slot, php_ctlr->callback_instance_id);
|
hp_slot, php_ctlr->callback_instance_id);
|
||||||
|
|
||||||
/* Clear all slot events */
|
/* Clear all slot events */
|
||||||
temp_dword = 0xe01f3fff;
|
temp_dword &= ~SLOT_REG_RSVDZ_MASK;
|
||||||
shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword);
|
shpc_writel(ctrl, SLOT_REG(hp_slot), temp_dword);
|
||||||
|
|
||||||
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
|
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
|
||||||
@@ -1364,8 +1386,12 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
|
|||||||
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
|
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
|
||||||
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
|
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
|
||||||
hp_slot, slot_reg);
|
hp_slot, slot_reg);
|
||||||
tempdword = 0xffff3fff;
|
slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
|
||||||
shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword);
|
BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
|
||||||
|
CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK |
|
||||||
|
CON_PFAULT_SERR_MASK);
|
||||||
|
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
|
||||||
|
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shpchp_poll_mode) {/* Install interrupt polling code */
|
if (shpchp_poll_mode) {/* Install interrupt polling code */
|
||||||
@@ -1411,12 +1437,17 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
|
|||||||
|
|
||||||
ctlr_seq_num++;
|
ctlr_seq_num++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unmask all event interrupts of all slots
|
||||||
|
*/
|
||||||
for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
|
for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
|
||||||
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
|
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
|
||||||
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
|
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
|
||||||
hp_slot, slot_reg);
|
hp_slot, slot_reg);
|
||||||
tempdword = 0xe01f3fff;
|
slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
|
||||||
shpc_writel(ctrl, SLOT_REG(hp_slot), tempdword);
|
BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
|
||||||
|
CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK);
|
||||||
|
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
|
||||||
}
|
}
|
||||||
if (!shpchp_poll_mode) {
|
if (!shpchp_poll_mode) {
|
||||||
/* Unmask all general input interrupts and SERR */
|
/* Unmask all general input interrupts and SERR */
|
||||||
|
Reference in New Issue
Block a user