cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipmi_si_port_io.c (2549B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3#include <linux/io.h>
      4#include "ipmi_si.h"
      5
      6static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset)
      7{
      8	unsigned int addr = io->addr_data;
      9
     10	return inb(addr + (offset * io->regspacing));
     11}
     12
     13static void port_outb(const struct si_sm_io *io, unsigned int offset,
     14		      unsigned char b)
     15{
     16	unsigned int addr = io->addr_data;
     17
     18	outb(b, addr + (offset * io->regspacing));
     19}
     20
     21static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset)
     22{
     23	unsigned int addr = io->addr_data;
     24
     25	return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
     26}
     27
     28static void port_outw(const struct si_sm_io *io, unsigned int offset,
     29		      unsigned char b)
     30{
     31	unsigned int addr = io->addr_data;
     32
     33	outw(b << io->regshift, addr + (offset * io->regspacing));
     34}
     35
     36static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset)
     37{
     38	unsigned int addr = io->addr_data;
     39
     40	return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
     41}
     42
     43static void port_outl(const struct si_sm_io *io, unsigned int offset,
     44		      unsigned char b)
     45{
     46	unsigned int addr = io->addr_data;
     47
     48	outl(b << io->regshift, addr+(offset * io->regspacing));
     49}
     50
     51static void port_cleanup(struct si_sm_io *io)
     52{
     53	unsigned int addr = io->addr_data;
     54	int          idx;
     55
     56	if (addr) {
     57		for (idx = 0; idx < io->io_size; idx++)
     58			release_region(addr + idx * io->regspacing,
     59				       io->regsize);
     60	}
     61}
     62
     63int ipmi_si_port_setup(struct si_sm_io *io)
     64{
     65	unsigned int addr = io->addr_data;
     66	int          idx;
     67
     68	if (!addr)
     69		return -ENODEV;
     70
     71	/*
     72	 * Figure out the actual inb/inw/inl/etc routine to use based
     73	 * upon the register size.
     74	 */
     75	switch (io->regsize) {
     76	case 1:
     77		io->inputb = port_inb;
     78		io->outputb = port_outb;
     79		break;
     80	case 2:
     81		io->inputb = port_inw;
     82		io->outputb = port_outw;
     83		break;
     84	case 4:
     85		io->inputb = port_inl;
     86		io->outputb = port_outl;
     87		break;
     88	default:
     89		dev_warn(io->dev, "Invalid register size: %d\n",
     90			 io->regsize);
     91		return -EINVAL;
     92	}
     93
     94	/*
     95	 * Some BIOSes reserve disjoint I/O regions in their ACPI
     96	 * tables.  This causes problems when trying to register the
     97	 * entire I/O region.  Therefore we must register each I/O
     98	 * port separately.
     99	 */
    100	for (idx = 0; idx < io->io_size; idx++) {
    101		if (request_region(addr + idx * io->regspacing,
    102				   io->regsize, SI_DEVICE_NAME) == NULL) {
    103			/* Undo allocations */
    104			while (idx--)
    105				release_region(addr + idx * io->regspacing,
    106					       io->regsize);
    107			return -EIO;
    108		}
    109	}
    110
    111	io->io_cleanup = port_cleanup;
    112
    113	return 0;
    114}