brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · 86b92e9 Raw
147 lines · c
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 readq45static 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#endif57 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 based86	 * 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 readq102	case 8:103		io->inputb = mem_inq;104		io->outputb = mem_outq;105		break;106#endif107	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 ACPI115	 * tables.  This causes problems when trying to request the116	 * entire region.  Therefore we must request each register117	 * 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 an130	 * unusual looking calculation, but it avoids claiming any131	 * more memory than it has to.  It will claim everything132	 * between the first address to the end of the last full133	 * 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}147