diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-06-03 13:06:07 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2011-06-03 13:06:07 +0000 |
commit | 0c37d1b0ed78fb98f91e9e3e44bbefaf9795c052 (patch) | |
tree | 4096e9d0475003e20841f1b1e4b06998b601705b /sys/dev | |
parent | 46f85188c75fff49f7295ee4761f7b573ab029cc (diff) |
Fix em_write_pci_cfg() and em_read_pci_cfg() to avoid unaligned access, and
make em_write_pci_cfg() do a proper read/modify/write cycle, to avoid changing
the neighbouring 16 bits. Also remove the comment in em_pci_set_mwi() and
em_pci_clear_mwi(); writting 0 to the status bits in the command/status word
is the right thing to do. Fixes a panic on sparc64 and other strict alignment
architectures.
ok deraadt@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_em.c | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 43804c17872..8cf06db115e 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.256 2011/04/22 10:09:57 jsg Exp $ */ +/* $OpenBSD: if_em.c,v 1.257 2011/06/03 13:06:06 kettenis Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include <dev/pci/if_em.h> @@ -3014,26 +3014,38 @@ void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value) { struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa; - pci_chipset_tag_t pc = pa->pa_pc; - /* Should we do read/mask/write...? 16 vs 32 bit!!! */ - pci_conf_write(pc, pa->pa_tag, reg, *value); + pcireg_t val; + + val = pci_conf_read(pa->pa_pc, pa->pa_tag, reg & ~0x3); + if (reg & 0x2) { + val &= 0x0000ffff; + val |= (*value << 16); + } else { + val &= 0xffff0000; + val |= *value; + } + pci_conf_write(pa->pa_pc, pa->pa_tag, reg & ~0x3, val); } void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t *value) { struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa; - pci_chipset_tag_t pc = pa->pa_pc; - *value = pci_conf_read(pc, pa->pa_tag, reg); + pcireg_t val; + + val = pci_conf_read(pa->pa_pc, pa->pa_tag, reg & ~0x3); + if (reg & 0x2) + *value = (val >> 16) & 0xffff; + else + *value = val & 0xffff; } void em_pci_set_mwi(struct em_hw *hw) { struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa; - pci_chipset_tag_t pc = pa->pa_pc; - /* Should we do read/mask/write...? 16 vs 32 bit!!! */ - pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE)); } @@ -3041,9 +3053,8 @@ void em_pci_clear_mwi(struct em_hw *hw) { struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa; - pci_chipset_tag_t pc = pa->pa_pc; - /* Should we do read/mask/write...? 16 vs 32 bit!!! */ - pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE)); } |