0001
0002
0003 #include <linux/io.h>
0004 #include "ipmi_si.h"
0005
0006 static unsigned char intf_mem_inb(const struct si_sm_io *io,
0007 unsigned int offset)
0008 {
0009 return readb((io->addr)+(offset * io->regspacing));
0010 }
0011
0012 static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset,
0013 unsigned char b)
0014 {
0015 writeb(b, (io->addr)+(offset * io->regspacing));
0016 }
0017
0018 static unsigned char intf_mem_inw(const struct si_sm_io *io,
0019 unsigned int offset)
0020 {
0021 return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
0022 & 0xff;
0023 }
0024
0025 static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset,
0026 unsigned char b)
0027 {
0028 writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
0029 }
0030
0031 static unsigned char intf_mem_inl(const struct si_sm_io *io,
0032 unsigned int offset)
0033 {
0034 return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
0035 & 0xff;
0036 }
0037
0038 static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset,
0039 unsigned char b)
0040 {
0041 writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
0042 }
0043
0044 #ifdef readq
0045 static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset)
0046 {
0047 return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)
0048 & 0xff;
0049 }
0050
0051 static void mem_outq(const struct si_sm_io *io, unsigned int offset,
0052 unsigned char b)
0053 {
0054 writeq((u64)b << io->regshift, (io->addr)+(offset * io->regspacing));
0055 }
0056 #endif
0057
0058 static void mem_region_cleanup(struct si_sm_io *io, int num)
0059 {
0060 unsigned long addr = io->addr_data;
0061 int idx;
0062
0063 for (idx = 0; idx < num; idx++)
0064 release_mem_region(addr + idx * io->regspacing,
0065 io->regsize);
0066 }
0067
0068 static void mem_cleanup(struct si_sm_io *io)
0069 {
0070 if (io->addr) {
0071 iounmap(io->addr);
0072 mem_region_cleanup(io, io->io_size);
0073 }
0074 }
0075
0076 int ipmi_si_mem_setup(struct si_sm_io *io)
0077 {
0078 unsigned long addr = io->addr_data;
0079 int mapsize, idx;
0080
0081 if (!addr)
0082 return -ENODEV;
0083
0084
0085
0086
0087
0088 switch (io->regsize) {
0089 case 1:
0090 io->inputb = intf_mem_inb;
0091 io->outputb = intf_mem_outb;
0092 break;
0093 case 2:
0094 io->inputb = intf_mem_inw;
0095 io->outputb = intf_mem_outw;
0096 break;
0097 case 4:
0098 io->inputb = intf_mem_inl;
0099 io->outputb = intf_mem_outl;
0100 break;
0101 #ifdef readq
0102 case 8:
0103 io->inputb = mem_inq;
0104 io->outputb = mem_outq;
0105 break;
0106 #endif
0107 default:
0108 dev_warn(io->dev, "Invalid register size: %d\n",
0109 io->regsize);
0110 return -EINVAL;
0111 }
0112
0113
0114
0115
0116
0117
0118
0119 for (idx = 0; idx < io->io_size; idx++) {
0120 if (request_mem_region(addr + idx * io->regspacing,
0121 io->regsize, SI_DEVICE_NAME) == NULL) {
0122
0123 mem_region_cleanup(io, idx);
0124 return -EIO;
0125 }
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135 mapsize = ((io->io_size * io->regspacing)
0136 - (io->regspacing - io->regsize));
0137 io->addr = ioremap(addr, mapsize);
0138 if (io->addr == NULL) {
0139 mem_region_cleanup(io, io->io_size);
0140 return -EIO;
0141 }
0142
0143 io->io_cleanup = mem_cleanup;
0144
0145 return 0;
0146 }