Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.17-rc5 145 lines 3.4 kB view raw
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 readq 45static 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(b << io->regshift, (io->addr)+(offset * io->regspacing)); 55} 56#endif 57 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 io->io_cleanup = mem_cleanup; 85 86 /* 87 * Figure out the actual readb/readw/readl/etc routine to use based 88 * upon the register size. 89 */ 90 switch (io->regsize) { 91 case 1: 92 io->inputb = intf_mem_inb; 93 io->outputb = intf_mem_outb; 94 break; 95 case 2: 96 io->inputb = intf_mem_inw; 97 io->outputb = intf_mem_outw; 98 break; 99 case 4: 100 io->inputb = intf_mem_inl; 101 io->outputb = intf_mem_outl; 102 break; 103#ifdef readq 104 case 8: 105 io->inputb = mem_inq; 106 io->outputb = mem_outq; 107 break; 108#endif 109 default: 110 dev_warn(io->dev, "Invalid register size: %d\n", 111 io->regsize); 112 return -EINVAL; 113 } 114 115 /* 116 * Some BIOSes reserve disjoint memory regions in their ACPI 117 * tables. This causes problems when trying to request the 118 * entire region. Therefore we must request each register 119 * separately. 120 */ 121 for (idx = 0; idx < io->io_size; idx++) { 122 if (request_mem_region(addr + idx * io->regspacing, 123 io->regsize, DEVICE_NAME) == NULL) { 124 /* Undo allocations */ 125 mem_region_cleanup(io, idx); 126 return -EIO; 127 } 128 } 129 130 /* 131 * Calculate the total amount of memory to claim. This is an 132 * unusual looking calculation, but it avoids claiming any 133 * more memory than it has to. It will claim everything 134 * between the first address to the end of the last full 135 * register. 136 */ 137 mapsize = ((io->io_size * io->regspacing) 138 - (io->regspacing - io->regsize)); 139 io->addr = ioremap(addr, mapsize); 140 if (io->addr == NULL) { 141 mem_region_cleanup(io, io->io_size); 142 return -EIO; 143 } 144 return 0; 145}