1 2 #include <linux/io.h> 3 #include "ipmi_si.h" 4 5 static unsigned char intf_mem_inb(const struct si_sm_io *io, 6 unsigned int offset) 7 { 8 return readb((io->addr)+(offset * io->regspacing)); 9 } 10 11 static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, 12 unsigned char b) 13 { 14 writeb(b, (io->addr)+(offset * io->regspacing)); 15 } 16 17 static unsigned char intf_mem_inw(const struct si_sm_io *io, 18 unsigned int offset) 19 { 20 return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) 21 & 0xff; 22 } 23 24 static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, 25 unsigned char b) 26 { 27 writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); 28 } 29 30 static unsigned char intf_mem_inl(const struct si_sm_io *io, 31 unsigned int offset) 32 { 33 return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) 34 & 0xff; 35 } 36 37 static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, 38 unsigned char b) 39 { 40 writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); 41 } 42 43 #ifdef readq 44 static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) 45 { 46 return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) 47 & 0xff; 48 } 49 50 static void mem_outq(const struct si_sm_io *io, unsigned int offset, 51 unsigned char b) 52 { 53 writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); 54 } 55 #endif 56 57 static void mem_region_cleanup(struct si_sm_io *io, int num) 58 { 59 unsigned long addr = io->addr_data; 60 int idx; 61 62 for (idx = 0; idx < num; idx++) 63 release_mem_region(addr + idx * io->regspacing, 64 io->regsize); 65 } 66 67 static void mem_cleanup(struct si_sm_io *io) 68 { 69 if (io->addr) { 70 iounmap(io->addr); 71 mem_region_cleanup(io, io->io_size); 72 } 73 } 74 75 int ipmi_si_mem_setup(struct si_sm_io *io) 76 { 77 unsigned long addr = io->addr_data; 78 int mapsize, idx; 79 80 if (!addr) 81 return -ENODEV; 82 83 io->io_cleanup = mem_cleanup; 84 85 /* 86 * Figure out the actual readb/readw/readl/etc routine to use based 87 * upon the register size. 88 */ 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; 112 } 113 114 /* 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. 119 */ 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; 126 } 127 } 128 129 /* 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. 135 */ 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; 142 } 143 return 0; 144 } 145