Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 #include <linux/io.h>
0004 #include "ipmi_si.h"
0005 
0006 static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset)
0007 {
0008     unsigned int addr = io->addr_data;
0009 
0010     return inb(addr + (offset * io->regspacing));
0011 }
0012 
0013 static void port_outb(const struct si_sm_io *io, unsigned int offset,
0014               unsigned char b)
0015 {
0016     unsigned int addr = io->addr_data;
0017 
0018     outb(b, addr + (offset * io->regspacing));
0019 }
0020 
0021 static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset)
0022 {
0023     unsigned int addr = io->addr_data;
0024 
0025     return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
0026 }
0027 
0028 static void port_outw(const struct si_sm_io *io, unsigned int offset,
0029               unsigned char b)
0030 {
0031     unsigned int addr = io->addr_data;
0032 
0033     outw(b << io->regshift, addr + (offset * io->regspacing));
0034 }
0035 
0036 static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset)
0037 {
0038     unsigned int addr = io->addr_data;
0039 
0040     return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
0041 }
0042 
0043 static void port_outl(const struct si_sm_io *io, unsigned int offset,
0044               unsigned char b)
0045 {
0046     unsigned int addr = io->addr_data;
0047 
0048     outl(b << io->regshift, addr+(offset * io->regspacing));
0049 }
0050 
0051 static void port_cleanup(struct si_sm_io *io)
0052 {
0053     unsigned int addr = io->addr_data;
0054     int          idx;
0055 
0056     if (addr) {
0057         for (idx = 0; idx < io->io_size; idx++)
0058             release_region(addr + idx * io->regspacing,
0059                        io->regsize);
0060     }
0061 }
0062 
0063 int ipmi_si_port_setup(struct si_sm_io *io)
0064 {
0065     unsigned int addr = io->addr_data;
0066     int          idx;
0067 
0068     if (!addr)
0069         return -ENODEV;
0070 
0071     /*
0072      * Figure out the actual inb/inw/inl/etc routine to use based
0073      * upon the register size.
0074      */
0075     switch (io->regsize) {
0076     case 1:
0077         io->inputb = port_inb;
0078         io->outputb = port_outb;
0079         break;
0080     case 2:
0081         io->inputb = port_inw;
0082         io->outputb = port_outw;
0083         break;
0084     case 4:
0085         io->inputb = port_inl;
0086         io->outputb = port_outl;
0087         break;
0088     default:
0089         dev_warn(io->dev, "Invalid register size: %d\n",
0090              io->regsize);
0091         return -EINVAL;
0092     }
0093 
0094     /*
0095      * Some BIOSes reserve disjoint I/O regions in their ACPI
0096      * tables.  This causes problems when trying to register the
0097      * entire I/O region.  Therefore we must register each I/O
0098      * port separately.
0099      */
0100     for (idx = 0; idx < io->io_size; idx++) {
0101         if (request_region(addr + idx * io->regspacing,
0102                    io->regsize, SI_DEVICE_NAME) == NULL) {
0103             /* Undo allocations */
0104             while (idx--)
0105                 release_region(addr + idx * io->regspacing,
0106                            io->regsize);
0107             return -EIO;
0108         }
0109     }
0110 
0111     io->io_cleanup = port_cleanup;
0112 
0113     return 0;
0114 }