root/drivers/char/ipmi/ipmi_si_mem_io.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intf_mem_inb
  2. intf_mem_outb
  3. intf_mem_inw
  4. intf_mem_outw
  5. intf_mem_inl
  6. intf_mem_outl
  7. mem_inq
  8. mem_outq
  9. mem_region_cleanup
  10. mem_cleanup
  11. ipmi_si_mem_setup

   1 // SPDX-License-Identifier: GPL-2.0+
   2 
   3 #include <linux/io.h>
   4 #include "ipmi_si.h"
   5 
   6 static 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 
  12 static 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 
  18 static 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 
  25 static 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 
  31 static 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 
  38 static 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
  45 static 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 
  51 static 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 #endif
  57 
  58 static 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 
  68 static 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 
  76 int 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 based
  86          * 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 readq
 102         case 8:
 103                 io->inputb = mem_inq;
 104                 io->outputb = mem_outq;
 105                 break;
 106 #endif
 107         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 ACPI
 115          * tables.  This causes problems when trying to request the
 116          * entire region.  Therefore we must request each register
 117          * 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 an
 130          * unusual looking calculation, but it avoids claiming any
 131          * more memory than it has to.  It will claim everything
 132          * between the first address to the end of the last full
 133          * 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 }

/* [<][>][^][v][top][bottom][index][help] */