Linux 4.16.11
[linux/fpc-iii.git] / drivers / char / ipmi / ipmi_si_mem_io.c
blob8796396ecd0faedc698558612ddda42d9cf58582
2 #include <linux/io.h>
3 #include "ipmi_si.h"
5 static unsigned char intf_mem_inb(const struct si_sm_io *io,
6 unsigned int offset)
8 return readb((io->addr)+(offset * io->regspacing));
11 static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset,
12 unsigned char b)
14 writeb(b, (io->addr)+(offset * io->regspacing));
17 static unsigned char intf_mem_inw(const struct si_sm_io *io,
18 unsigned int offset)
20 return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
21 & 0xff;
24 static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset,
25 unsigned char b)
27 writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
30 static unsigned char intf_mem_inl(const struct si_sm_io *io,
31 unsigned int offset)
33 return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
34 & 0xff;
37 static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset,
38 unsigned char b)
40 writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
43 #ifdef readq
44 static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset)
46 return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
47 & 0xff;
50 static void mem_outq(const struct si_sm_io *io, unsigned int offset,
51 unsigned char b)
53 writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));
55 #endif
57 static void mem_region_cleanup(struct si_sm_io *io, int num)
59 unsigned long addr = io->addr_data;
60 int idx;
62 for (idx = 0; idx < num; idx++)
63 release_mem_region(addr + idx * io->regspacing,
64 io->regsize);
67 static void mem_cleanup(struct si_sm_io *io)
69 if (io->addr) {
70 iounmap(io->addr);
71 mem_region_cleanup(io, io->io_size);
75 int ipmi_si_mem_setup(struct si_sm_io *io)
77 unsigned long addr = io->addr_data;
78 int mapsize, idx;
80 if (!addr)
81 return -ENODEV;
83 io->io_cleanup = mem_cleanup;
86 * Figure out the actual readb/readw/readl/etc routine to use based
87 * upon the register size.
89 switch (io->regsize) {
90 case 1:
91 io->inputb = intf_mem_inb;
92 io->outputb = intf_mem_outb;
93 break;
94 case 2:
95 io->inputb = intf_mem_inw;
96 io->outputb = intf_mem_outw;
97 break;
98 case 4:
99 io->inputb = intf_mem_inl;
100 io->outputb = intf_mem_outl;
101 break;
102 #ifdef readq
103 case 8:
104 io->inputb = mem_inq;
105 io->outputb = mem_outq;
106 break;
107 #endif
108 default:
109 dev_warn(io->dev, "Invalid register size: %d\n",
110 io->regsize);
111 return -EINVAL;
115 * Some BIOSes reserve disjoint memory regions in their ACPI
116 * tables. This causes problems when trying to request the
117 * entire region. Therefore we must request each register
118 * separately.
120 for (idx = 0; idx < io->io_size; idx++) {
121 if (request_mem_region(addr + idx * io->regspacing,
122 io->regsize, DEVICE_NAME) == NULL) {
123 /* Undo allocations */
124 mem_region_cleanup(io, idx);
125 return -EIO;
130 * Calculate the total amount of memory to claim. This is an
131 * unusual looking calculation, but it avoids claiming any
132 * more memory than it has to. It will claim everything
133 * between the first address to the end of the last full
134 * register.
136 mapsize = ((io->io_size * io->regspacing)
137 - (io->regspacing - io->regsize));
138 io->addr = ioremap(addr, mapsize);
139 if (io->addr == NULL) {
140 mem_region_cleanup(io, io->io_size);
141 return -EIO;
143 return 0;