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

rsrc_iodyn.c (3691B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * rsrc_iodyn.c -- Resource management routines for MEM-static sockets.
      4 *
      5 * The initial developer of the original code is David A. Hinds
      6 * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
      7 * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
      8 *
      9 * (C) 1999		David A. Hinds
     10 */
     11
     12#include <linux/slab.h>
     13#include <linux/module.h>
     14#include <linux/kernel.h>
     15
     16#include <pcmcia/ss.h>
     17#include <pcmcia/cistpl.h>
     18#include "cs_internal.h"
     19
     20
     21struct pcmcia_align_data {
     22	unsigned long	mask;
     23	unsigned long	offset;
     24};
     25
     26static resource_size_t pcmcia_align(void *align_data,
     27				const struct resource *res,
     28				resource_size_t size, resource_size_t align)
     29{
     30	struct pcmcia_align_data *data = align_data;
     31	resource_size_t start;
     32
     33	start = (res->start & ~data->mask) + data->offset;
     34	if (start < res->start)
     35		start += data->mask + 1;
     36
     37#ifdef CONFIG_X86
     38	if (res->flags & IORESOURCE_IO) {
     39		if (start & 0x300)
     40			start = (start + 0x3ff) & ~0x3ff;
     41	}
     42#endif
     43
     44#ifdef CONFIG_M68K
     45	if (res->flags & IORESOURCE_IO) {
     46		if ((res->start + size - 1) >= 1024)
     47			start = res->end;
     48	}
     49#endif
     50
     51	return start;
     52}
     53
     54
     55static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
     56					unsigned long base, int num,
     57					unsigned long align)
     58{
     59	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
     60						dev_name(&s->dev));
     61	struct pcmcia_align_data data;
     62	unsigned long min = base;
     63	int ret;
     64
     65	data.mask = align - 1;
     66	data.offset = base & data.mask;
     67
     68#ifdef CONFIG_PCI
     69	if (s->cb_dev) {
     70		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
     71					     min, 0, pcmcia_align, &data);
     72	} else
     73#endif
     74		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
     75					1, pcmcia_align, &data);
     76
     77	if (ret != 0) {
     78		kfree(res);
     79		res = NULL;
     80	}
     81	return res;
     82}
     83
     84static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
     85			unsigned int *base, unsigned int num,
     86			unsigned int align, struct resource **parent)
     87{
     88	int i, ret = 0;
     89
     90	/* Check for an already-allocated window that must conflict with
     91	 * what was asked for.  It is a hack because it does not catch all
     92	 * potential conflicts, just the most obvious ones.
     93	 */
     94	for (i = 0; i < MAX_IO_WIN; i++) {
     95		if (!s->io[i].res)
     96			continue;
     97
     98		if (!*base)
     99			continue;
    100
    101		if ((s->io[i].res->start & (align-1)) == *base)
    102			return -EBUSY;
    103	}
    104
    105	for (i = 0; i < MAX_IO_WIN; i++) {
    106		struct resource *res = s->io[i].res;
    107		unsigned int try;
    108
    109		if (res && (res->flags & IORESOURCE_BITS) !=
    110			(attr & IORESOURCE_BITS))
    111			continue;
    112
    113		if (!res) {
    114			if (align == 0)
    115				align = 0x10000;
    116
    117			res = s->io[i].res = __iodyn_find_io_region(s, *base,
    118								num, align);
    119			if (!res)
    120				return -EINVAL;
    121
    122			*base = res->start;
    123			s->io[i].res->flags =
    124				((res->flags & ~IORESOURCE_BITS) |
    125					(attr & IORESOURCE_BITS));
    126			s->io[i].InUse = num;
    127			*parent = res;
    128			return 0;
    129		}
    130
    131		/* Try to extend top of window */
    132		try = res->end + 1;
    133		if ((*base == 0) || (*base == try)) {
    134			if (adjust_resource(s->io[i].res, res->start,
    135					    resource_size(res) + num))
    136				continue;
    137			*base = try;
    138			s->io[i].InUse += num;
    139			*parent = res;
    140			return 0;
    141		}
    142
    143		/* Try to extend bottom of window */
    144		try = res->start - num;
    145		if ((*base == 0) || (*base == try)) {
    146			if (adjust_resource(s->io[i].res,
    147					    res->start - num,
    148					    resource_size(res) + num))
    149				continue;
    150			*base = try;
    151			s->io[i].InUse += num;
    152			*parent = res;
    153			return 0;
    154		}
    155	}
    156
    157	return -EINVAL;
    158}
    159
    160
    161struct pccard_resource_ops pccard_iodyn_ops = {
    162	.validate_mem = NULL,
    163	.find_io = iodyn_find_io,
    164	.find_mem = NULL,
    165	.init = static_init,
    166	.exit = NULL,
    167};
    168EXPORT_SYMBOL(pccard_iodyn_ops);