diff options
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 8d984f9ec5d7..7b1c412b40a2 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -1637,25 +1637,28 @@ static void mem_outq(const struct si_sm_io *io, unsigned int offset, | |||
1637 | } | 1637 | } |
1638 | #endif | 1638 | #endif |
1639 | 1639 | ||
1640 | static void mem_cleanup(struct smi_info *info) | 1640 | static void mem_region_cleanup(struct smi_info *info, int num) |
1641 | { | 1641 | { |
1642 | unsigned long addr = info->io.addr_data; | 1642 | unsigned long addr = info->io.addr_data; |
1643 | int mapsize; | 1643 | int idx; |
1644 | |||
1645 | for (idx = 0; idx < num; idx++) | ||
1646 | release_mem_region(addr + idx * info->io.regspacing, | ||
1647 | info->io.regsize); | ||
1648 | } | ||
1644 | 1649 | ||
1650 | static void mem_cleanup(struct smi_info *info) | ||
1651 | { | ||
1645 | if (info->io.addr) { | 1652 | if (info->io.addr) { |
1646 | iounmap(info->io.addr); | 1653 | iounmap(info->io.addr); |
1647 | 1654 | mem_region_cleanup(info, info->io_size); | |
1648 | mapsize = ((info->io_size * info->io.regspacing) | ||
1649 | - (info->io.regspacing - info->io.regsize)); | ||
1650 | |||
1651 | release_mem_region(addr, mapsize); | ||
1652 | } | 1655 | } |
1653 | } | 1656 | } |
1654 | 1657 | ||
1655 | static int mem_setup(struct smi_info *info) | 1658 | static int mem_setup(struct smi_info *info) |
1656 | { | 1659 | { |
1657 | unsigned long addr = info->io.addr_data; | 1660 | unsigned long addr = info->io.addr_data; |
1658 | int mapsize; | 1661 | int mapsize, idx; |
1659 | 1662 | ||
1660 | if (!addr) | 1663 | if (!addr) |
1661 | return -ENODEV; | 1664 | return -ENODEV; |
@@ -1692,6 +1695,21 @@ static int mem_setup(struct smi_info *info) | |||
1692 | } | 1695 | } |
1693 | 1696 | ||
1694 | /* | 1697 | /* |
1698 | * Some BIOSes reserve disjoint memory regions in their ACPI | ||
1699 | * tables. This causes problems when trying to request the | ||
1700 | * entire region. Therefore we must request each register | ||
1701 | * separately. | ||
1702 | */ | ||
1703 | for (idx = 0; idx < info->io_size; idx++) { | ||
1704 | if (request_mem_region(addr + idx * info->io.regspacing, | ||
1705 | info->io.regsize, DEVICE_NAME) == NULL) { | ||
1706 | /* Undo allocations */ | ||
1707 | mem_region_cleanup(info, idx); | ||
1708 | return -EIO; | ||
1709 | } | ||
1710 | } | ||
1711 | |||
1712 | /* | ||
1695 | * Calculate the total amount of memory to claim. This is an | 1713 | * Calculate the total amount of memory to claim. This is an |
1696 | * unusual looking calculation, but it avoids claiming any | 1714 | * unusual looking calculation, but it avoids claiming any |
1697 | * more memory than it has to. It will claim everything | 1715 | * more memory than it has to. It will claim everything |
@@ -1700,13 +1718,9 @@ static int mem_setup(struct smi_info *info) | |||
1700 | */ | 1718 | */ |
1701 | mapsize = ((info->io_size * info->io.regspacing) | 1719 | mapsize = ((info->io_size * info->io.regspacing) |
1702 | - (info->io.regspacing - info->io.regsize)); | 1720 | - (info->io.regspacing - info->io.regsize)); |
1703 | |||
1704 | if (request_mem_region(addr, mapsize, DEVICE_NAME) == NULL) | ||
1705 | return -EIO; | ||
1706 | |||
1707 | info->io.addr = ioremap(addr, mapsize); | 1721 | info->io.addr = ioremap(addr, mapsize); |
1708 | if (info->io.addr == NULL) { | 1722 | if (info->io.addr == NULL) { |
1709 | release_mem_region(addr, mapsize); | 1723 | mem_region_cleanup(info, info->io_size); |
1710 | return -EIO; | 1724 | return -EIO; |
1711 | } | 1725 | } |
1712 | return 0; | 1726 | return 0; |