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_mem_io.c (3401B)


      1// SPDX-License-Identifier: GPL-2.0+
      2
      3#include <linux/io.h>
      4#include "ipmi_si.h"
      5
      6static unsigned char intf_mem_inb(const struct si_sm_io *io,
      7				  unsigned int offset)
      8{
      9	return readb((io->addr)+(offset * io->regspacing));
     10}
     11
     12static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset,
     13			  unsigned char b)
     14{
     15	writeb(b, (io->addr)+(offset * io->regspacing));
     16}
     17
     18static unsigned char intf_mem_inw(const struct si_sm_io *io,
     19				  unsigned int offset)
     20{
     21	return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
     22		& 0xff;
     23}
     24
     25static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset,
     26			  unsigned char b)
     27{
     28	writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
     29}
     30
     31static unsigned char intf_mem_inl(const struct si_sm_io *io,
     32				  unsigned int offset)
     33{
     34	return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
     35		& 0xff;
     36}
     37
     38static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset,
     39			  unsigned char b)
     40{
     41	writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
     42}
     43
     44#ifdef readq
     45static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset)
     46{
     47	return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
     48		& 0xff;
     49}
     50
     51static void mem_outq(const struct si_sm_io *io, unsigned int offset,
     52		     unsigned char b)
     53{
     54	writeq((u64)b << io->regshift, (io->addr)+(offset * io->regspacing));
     55}
     56#endif
     57
     58static void mem_region_cleanup(struct si_sm_io *io, int num)
     59{
     60	unsigned long addr = io->addr_data;
     61	int idx;
     62
     63	for (idx = 0; idx < num; idx++)
     64		release_mem_region(addr + idx * io->regspacing,
     65				   io->regsize);
     66}
     67
     68static void mem_cleanup(struct si_sm_io *io)
     69{
     70	if (io->addr) {
     71		iounmap(io->addr);
     72		mem_region_cleanup(io, io->io_size);
     73	}
     74}
     75
     76int ipmi_si_mem_setup(struct si_sm_io *io)
     77{
     78	unsigned long addr = io->addr_data;
     79	int           mapsize, idx;
     80
     81	if (!addr)
     82		return -ENODEV;
     83
     84	/*
     85	 * Figure out the actual readb/readw/readl/etc routine to use based
     86	 * upon the register size.
     87	 */
     88	switch (io->regsize) {
     89	case 1:
     90		io->inputb = intf_mem_inb;
     91		io->outputb = intf_mem_outb;
     92		break;
     93	case 2:
     94		io->inputb = intf_mem_inw;
     95		io->outputb = intf_mem_outw;
     96		break;
     97	case 4:
     98		io->inputb = intf_mem_inl;
     99		io->outputb = intf_mem_outl;
    100		break;
    101#ifdef readq
    102	case 8:
    103		io->inputb = mem_inq;
    104		io->outputb = mem_outq;
    105		break;
    106#endif
    107	default:
    108		dev_warn(io->dev, "Invalid register size: %d\n",
    109			 io->regsize);
    110		return -EINVAL;
    111	}
    112
    113	/*
    114	 * Some BIOSes reserve disjoint memory regions in their ACPI
    115	 * tables.  This causes problems when trying to request the
    116	 * entire region.  Therefore we must request each register
    117	 * separately.
    118	 */
    119	for (idx = 0; idx < io->io_size; idx++) {
    120		if (request_mem_region(addr + idx * io->regspacing,
    121				       io->regsize, SI_DEVICE_NAME) == NULL) {
    122			/* Undo allocations */
    123			mem_region_cleanup(io, idx);
    124			return -EIO;
    125		}
    126	}
    127
    128	/*
    129	 * Calculate the total amount of memory to claim.  This is an
    130	 * unusual looking calculation, but it avoids claiming any
    131	 * more memory than it has to.  It will claim everything
    132	 * between the first address to the end of the last full
    133	 * register.
    134	 */
    135	mapsize = ((io->io_size * io->regspacing)
    136		   - (io->regspacing - io->regsize));
    137	io->addr = ioremap(addr, mapsize);
    138	if (io->addr == NULL) {
    139		mem_region_cleanup(io, io->io_size);
    140		return -EIO;
    141	}
    142
    143	io->io_cleanup = mem_cleanup;
    144
    145	return 0;
    146}