1243ac210SCorey Minyard // SPDX-License-Identifier: GPL-2.0+
258e27635SCorey Minyard
358e27635SCorey Minyard #include <linux/io.h>
458e27635SCorey Minyard #include "ipmi_si.h"
558e27635SCorey Minyard
intf_mem_inb(const struct si_sm_io * io,unsigned int offset)658e27635SCorey Minyard static unsigned char intf_mem_inb(const struct si_sm_io *io,
758e27635SCorey Minyard unsigned int offset)
858e27635SCorey Minyard {
958e27635SCorey Minyard return readb((io->addr)+(offset * io->regspacing));
1058e27635SCorey Minyard }
1158e27635SCorey Minyard
intf_mem_outb(const struct si_sm_io * io,unsigned int offset,unsigned char b)1258e27635SCorey Minyard static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset,
1358e27635SCorey Minyard unsigned char b)
1458e27635SCorey Minyard {
1558e27635SCorey Minyard writeb(b, (io->addr)+(offset * io->regspacing));
1658e27635SCorey Minyard }
1758e27635SCorey Minyard
intf_mem_inw(const struct si_sm_io * io,unsigned int offset)1858e27635SCorey Minyard static unsigned char intf_mem_inw(const struct si_sm_io *io,
1958e27635SCorey Minyard unsigned int offset)
2058e27635SCorey Minyard {
2158e27635SCorey Minyard return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
2258e27635SCorey Minyard & 0xff;
2358e27635SCorey Minyard }
2458e27635SCorey Minyard
intf_mem_outw(const struct si_sm_io * io,unsigned int offset,unsigned char b)2558e27635SCorey Minyard static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset,
2658e27635SCorey Minyard unsigned char b)
2758e27635SCorey Minyard {
2858e27635SCorey Minyard writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
2958e27635SCorey Minyard }
3058e27635SCorey Minyard
intf_mem_inl(const struct si_sm_io * io,unsigned int offset)3158e27635SCorey Minyard static unsigned char intf_mem_inl(const struct si_sm_io *io,
3258e27635SCorey Minyard unsigned int offset)
3358e27635SCorey Minyard {
3458e27635SCorey Minyard return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
3558e27635SCorey Minyard & 0xff;
3658e27635SCorey Minyard }
3758e27635SCorey Minyard
intf_mem_outl(const struct si_sm_io * io,unsigned int offset,unsigned char b)3858e27635SCorey Minyard static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset,
3958e27635SCorey Minyard unsigned char b)
4058e27635SCorey Minyard {
4158e27635SCorey Minyard writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
4258e27635SCorey Minyard }
4358e27635SCorey Minyard
4458e27635SCorey Minyard #ifdef readq
mem_inq(const struct si_sm_io * io,unsigned int offset)4558e27635SCorey Minyard static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset)
4658e27635SCorey Minyard {
4758e27635SCorey Minyard return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
4858e27635SCorey Minyard & 0xff;
4958e27635SCorey Minyard }
5058e27635SCorey Minyard
mem_outq(const struct si_sm_io * io,unsigned int offset,unsigned char b)5158e27635SCorey Minyard static void mem_outq(const struct si_sm_io *io, unsigned int offset,
5258e27635SCorey Minyard unsigned char b)
5358e27635SCorey Minyard {
5497a103e6SColin Ian King writeq((u64)b << io->regshift, (io->addr)+(offset * io->regspacing));
5558e27635SCorey Minyard }
5658e27635SCorey Minyard #endif
5758e27635SCorey Minyard
mem_region_cleanup(struct si_sm_io * io,int num)5858e27635SCorey Minyard static void mem_region_cleanup(struct si_sm_io *io, int num)
5958e27635SCorey Minyard {
6058e27635SCorey Minyard unsigned long addr = io->addr_data;
6158e27635SCorey Minyard int idx;
6258e27635SCorey Minyard
6358e27635SCorey Minyard for (idx = 0; idx < num; idx++)
6458e27635SCorey Minyard release_mem_region(addr + idx * io->regspacing,
6558e27635SCorey Minyard io->regsize);
6658e27635SCorey Minyard }
6758e27635SCorey Minyard
mem_cleanup(struct si_sm_io * io)6858e27635SCorey Minyard static void mem_cleanup(struct si_sm_io *io)
6958e27635SCorey Minyard {
7058e27635SCorey Minyard if (io->addr) {
7158e27635SCorey Minyard iounmap(io->addr);
7258e27635SCorey Minyard mem_region_cleanup(io, io->io_size);
7358e27635SCorey Minyard }
7458e27635SCorey Minyard }
7558e27635SCorey Minyard
ipmi_si_mem_setup(struct si_sm_io * io)7658e27635SCorey Minyard int ipmi_si_mem_setup(struct si_sm_io *io)
7758e27635SCorey Minyard {
7858e27635SCorey Minyard unsigned long addr = io->addr_data;
7958e27635SCorey Minyard int mapsize, idx;
8058e27635SCorey Minyard
8158e27635SCorey Minyard if (!addr)
8258e27635SCorey Minyard return -ENODEV;
8358e27635SCorey Minyard
8458e27635SCorey Minyard /*
8558e27635SCorey Minyard * Figure out the actual readb/readw/readl/etc routine to use based
8658e27635SCorey Minyard * upon the register size.
8758e27635SCorey Minyard */
8858e27635SCorey Minyard switch (io->regsize) {
8958e27635SCorey Minyard case 1:
9058e27635SCorey Minyard io->inputb = intf_mem_inb;
9158e27635SCorey Minyard io->outputb = intf_mem_outb;
9258e27635SCorey Minyard break;
9358e27635SCorey Minyard case 2:
9458e27635SCorey Minyard io->inputb = intf_mem_inw;
9558e27635SCorey Minyard io->outputb = intf_mem_outw;
9658e27635SCorey Minyard break;
9758e27635SCorey Minyard case 4:
9858e27635SCorey Minyard io->inputb = intf_mem_inl;
9958e27635SCorey Minyard io->outputb = intf_mem_outl;
10058e27635SCorey Minyard break;
10158e27635SCorey Minyard #ifdef readq
10258e27635SCorey Minyard case 8:
10358e27635SCorey Minyard io->inputb = mem_inq;
10458e27635SCorey Minyard io->outputb = mem_outq;
10558e27635SCorey Minyard break;
10658e27635SCorey Minyard #endif
10758e27635SCorey Minyard default:
10858e27635SCorey Minyard dev_warn(io->dev, "Invalid register size: %d\n",
10958e27635SCorey Minyard io->regsize);
11058e27635SCorey Minyard return -EINVAL;
11158e27635SCorey Minyard }
11258e27635SCorey Minyard
11358e27635SCorey Minyard /*
11458e27635SCorey Minyard * Some BIOSes reserve disjoint memory regions in their ACPI
11558e27635SCorey Minyard * tables. This causes problems when trying to request the
11658e27635SCorey Minyard * entire region. Therefore we must request each register
11758e27635SCorey Minyard * separately.
11858e27635SCorey Minyard */
11958e27635SCorey Minyard for (idx = 0; idx < io->io_size; idx++) {
12058e27635SCorey Minyard if (request_mem_region(addr + idx * io->regspacing,
121*104fb25fSCorey Minyard io->regsize, SI_DEVICE_NAME) == NULL) {
12258e27635SCorey Minyard /* Undo allocations */
12358e27635SCorey Minyard mem_region_cleanup(io, idx);
12458e27635SCorey Minyard return -EIO;
12558e27635SCorey Minyard }
12658e27635SCorey Minyard }
12758e27635SCorey Minyard
12858e27635SCorey Minyard /*
12958e27635SCorey Minyard * Calculate the total amount of memory to claim. This is an
13058e27635SCorey Minyard * unusual looking calculation, but it avoids claiming any
13158e27635SCorey Minyard * more memory than it has to. It will claim everything
13258e27635SCorey Minyard * between the first address to the end of the last full
13358e27635SCorey Minyard * register.
13458e27635SCorey Minyard */
13558e27635SCorey Minyard mapsize = ((io->io_size * io->regspacing)
13658e27635SCorey Minyard - (io->regspacing - io->regsize));
13758e27635SCorey Minyard io->addr = ioremap(addr, mapsize);
13858e27635SCorey Minyard if (io->addr == NULL) {
13958e27635SCorey Minyard mem_region_cleanup(io, io->io_size);
14058e27635SCorey Minyard return -EIO;
14158e27635SCorey Minyard }
142401e7e88SYang Yingliang
143401e7e88SYang Yingliang io->io_cleanup = mem_cleanup;
144401e7e88SYang Yingliang
14558e27635SCorey Minyard return 0;
14658e27635SCorey Minyard }
147