diff options
author | Corey Minyard <cminyard@mvista.com> | 2016-04-26 23:25:12 -0400 |
---|---|---|
committer | Corey Minyard <cminyard@mvista.com> | 2016-05-16 20:49:48 -0400 |
commit | 57a38f1340eb2b036dbc4ec34f4a14603e5dd47c (patch) | |
tree | e639d521e23f8e65d32535ac42ebf430fa830b54 /drivers/char | |
parent | 76824852a941375aad640b35025dac75d077113a (diff) |
IPMI: reserve memio regions separately
Commit d61a3ead2680 ("[PATCH] IPMI: reserve I/O ports separately")
changed the way I/O ports were reserved and includes this comment in
log:
Some BIOSes reserve disjoint I/O regions in their ACPI tables for the IPMI
controller. This causes problems when trying to register the entire I/O
region. Therefore we must register each I/O port separately.
There is a similar problem with memio regions on an arm64 platform
(AMD Seattle). Where I see:
ipmi message handler version 39.2
ipmi_si AMDI0300:00: probing via device tree
ipmi_si AMDI0300:00: ipmi_si: probing via ACPI
ipmi_si AMDI0300:00: [mem 0xe0010000] regsize 1 spacing 4 irq 23
ipmi_si: Adding ACPI-specified kcs state machine
IPMI System Interface driver.
ipmi_si: Trying ACPI-specified kcs state machine at mem \
address 0xe0010000, slave address 0x0, irq 23
ipmi_si: Could not set up I/O space
The problem is that the ACPI core registers disjoint regions for the
platform device:
e0010000-e0010000 : AMDI0300:00
e0010004-e0010004 : AMDI0300:00
and the ipmi_si driver tries to register one region e0010000-e0010004.
Based on a patch from Mark Salter <msalter@redhat.com>, who also wrote
all the above text.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Tested-by: Mark Salter <msalter@redhat.com>
Diffstat (limited to 'drivers/char')
-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; |