1243ac210SCorey Minyard // SPDX-License-Identifier: GPL-2.0+
258e27635SCorey Minyard
358e27635SCorey Minyard #include <linux/io.h>
458e27635SCorey Minyard #include "ipmi_si.h"
558e27635SCorey Minyard
port_inb(const struct si_sm_io * io,unsigned int offset)658e27635SCorey Minyard static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset)
758e27635SCorey Minyard {
858e27635SCorey Minyard unsigned int addr = io->addr_data;
958e27635SCorey Minyard
1058e27635SCorey Minyard return inb(addr + (offset * io->regspacing));
1158e27635SCorey Minyard }
1258e27635SCorey Minyard
port_outb(const struct si_sm_io * io,unsigned int offset,unsigned char b)1358e27635SCorey Minyard static void port_outb(const struct si_sm_io *io, unsigned int offset,
1458e27635SCorey Minyard unsigned char b)
1558e27635SCorey Minyard {
1658e27635SCorey Minyard unsigned int addr = io->addr_data;
1758e27635SCorey Minyard
1858e27635SCorey Minyard outb(b, addr + (offset * io->regspacing));
1958e27635SCorey Minyard }
2058e27635SCorey Minyard
port_inw(const struct si_sm_io * io,unsigned int offset)2158e27635SCorey Minyard static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset)
2258e27635SCorey Minyard {
2358e27635SCorey Minyard unsigned int addr = io->addr_data;
2458e27635SCorey Minyard
2558e27635SCorey Minyard return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
2658e27635SCorey Minyard }
2758e27635SCorey Minyard
port_outw(const struct si_sm_io * io,unsigned int offset,unsigned char b)2858e27635SCorey Minyard static void port_outw(const struct si_sm_io *io, unsigned int offset,
2958e27635SCorey Minyard unsigned char b)
3058e27635SCorey Minyard {
3158e27635SCorey Minyard unsigned int addr = io->addr_data;
3258e27635SCorey Minyard
3358e27635SCorey Minyard outw(b << io->regshift, addr + (offset * io->regspacing));
3458e27635SCorey Minyard }
3558e27635SCorey Minyard
port_inl(const struct si_sm_io * io,unsigned int offset)3658e27635SCorey Minyard static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset)
3758e27635SCorey Minyard {
3858e27635SCorey Minyard unsigned int addr = io->addr_data;
3958e27635SCorey Minyard
4058e27635SCorey Minyard return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
4158e27635SCorey Minyard }
4258e27635SCorey Minyard
port_outl(const struct si_sm_io * io,unsigned int offset,unsigned char b)4358e27635SCorey Minyard static void port_outl(const struct si_sm_io *io, unsigned int offset,
4458e27635SCorey Minyard unsigned char b)
4558e27635SCorey Minyard {
4658e27635SCorey Minyard unsigned int addr = io->addr_data;
4758e27635SCorey Minyard
4858e27635SCorey Minyard outl(b << io->regshift, addr+(offset * io->regspacing));
4958e27635SCorey Minyard }
5058e27635SCorey Minyard
port_cleanup(struct si_sm_io * io)5158e27635SCorey Minyard static void port_cleanup(struct si_sm_io *io)
5258e27635SCorey Minyard {
5358e27635SCorey Minyard unsigned int addr = io->addr_data;
5458e27635SCorey Minyard int idx;
5558e27635SCorey Minyard
5658e27635SCorey Minyard if (addr) {
5758e27635SCorey Minyard for (idx = 0; idx < io->io_size; idx++)
5858e27635SCorey Minyard release_region(addr + idx * io->regspacing,
5958e27635SCorey Minyard io->regsize);
6058e27635SCorey Minyard }
6158e27635SCorey Minyard }
6258e27635SCorey Minyard
ipmi_si_port_setup(struct si_sm_io * io)6358e27635SCorey Minyard int ipmi_si_port_setup(struct si_sm_io *io)
6458e27635SCorey Minyard {
6558e27635SCorey Minyard unsigned int addr = io->addr_data;
6658e27635SCorey Minyard int idx;
6758e27635SCorey Minyard
6858e27635SCorey Minyard if (!addr)
6958e27635SCorey Minyard return -ENODEV;
7058e27635SCorey Minyard
7158e27635SCorey Minyard /*
7258e27635SCorey Minyard * Figure out the actual inb/inw/inl/etc routine to use based
7358e27635SCorey Minyard * upon the register size.
7458e27635SCorey Minyard */
7558e27635SCorey Minyard switch (io->regsize) {
7658e27635SCorey Minyard case 1:
7758e27635SCorey Minyard io->inputb = port_inb;
7858e27635SCorey Minyard io->outputb = port_outb;
7958e27635SCorey Minyard break;
8058e27635SCorey Minyard case 2:
8158e27635SCorey Minyard io->inputb = port_inw;
8258e27635SCorey Minyard io->outputb = port_outw;
8358e27635SCorey Minyard break;
8458e27635SCorey Minyard case 4:
8558e27635SCorey Minyard io->inputb = port_inl;
8658e27635SCorey Minyard io->outputb = port_outl;
8758e27635SCorey Minyard break;
8858e27635SCorey Minyard default:
8958e27635SCorey Minyard dev_warn(io->dev, "Invalid register size: %d\n",
9058e27635SCorey Minyard io->regsize);
9158e27635SCorey Minyard return -EINVAL;
9258e27635SCorey Minyard }
9358e27635SCorey Minyard
9458e27635SCorey Minyard /*
9558e27635SCorey Minyard * Some BIOSes reserve disjoint I/O regions in their ACPI
9658e27635SCorey Minyard * tables. This causes problems when trying to register the
9758e27635SCorey Minyard * entire I/O region. Therefore we must register each I/O
9858e27635SCorey Minyard * port separately.
9958e27635SCorey Minyard */
10058e27635SCorey Minyard for (idx = 0; idx < io->io_size; idx++) {
10158e27635SCorey Minyard if (request_region(addr + idx * io->regspacing,
102*104fb25fSCorey Minyard io->regsize, SI_DEVICE_NAME) == NULL) {
10358e27635SCorey Minyard /* Undo allocations */
10458e27635SCorey Minyard while (idx--)
10558e27635SCorey Minyard release_region(addr + idx * io->regspacing,
10658e27635SCorey Minyard io->regsize);
10758e27635SCorey Minyard return -EIO;
10858e27635SCorey Minyard }
10958e27635SCorey Minyard }
110401e7e88SYang Yingliang
111401e7e88SYang Yingliang io->io_cleanup = port_cleanup;
112401e7e88SYang Yingliang
11358e27635SCorey Minyard return 0;
11458e27635SCorey Minyard }
115