ipmi_si_port_io.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/io.h>
  3. #include "ipmi_si.h"
  4. static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset)
  5. {
  6. unsigned int addr = io->addr_data;
  7. return inb(addr + (offset * io->regspacing));
  8. }
  9. static void port_outb(const struct si_sm_io *io, unsigned int offset,
  10. unsigned char b)
  11. {
  12. unsigned int addr = io->addr_data;
  13. outb(b, addr + (offset * io->regspacing));
  14. }
  15. static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset)
  16. {
  17. unsigned int addr = io->addr_data;
  18. return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
  19. }
  20. static void port_outw(const struct si_sm_io *io, unsigned int offset,
  21. unsigned char b)
  22. {
  23. unsigned int addr = io->addr_data;
  24. outw(b << io->regshift, addr + (offset * io->regspacing));
  25. }
  26. static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset)
  27. {
  28. unsigned int addr = io->addr_data;
  29. return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
  30. }
  31. static void port_outl(const struct si_sm_io *io, unsigned int offset,
  32. unsigned char b)
  33. {
  34. unsigned int addr = io->addr_data;
  35. outl(b << io->regshift, addr+(offset * io->regspacing));
  36. }
  37. static void port_cleanup(struct si_sm_io *io)
  38. {
  39. unsigned int addr = io->addr_data;
  40. int idx;
  41. if (addr) {
  42. for (idx = 0; idx < io->io_size; idx++)
  43. release_region(addr + idx * io->regspacing,
  44. io->regsize);
  45. }
  46. }
  47. int ipmi_si_port_setup(struct si_sm_io *io)
  48. {
  49. unsigned int addr = io->addr_data;
  50. int idx;
  51. if (!addr)
  52. return -ENODEV;
  53. /*
  54. * Figure out the actual inb/inw/inl/etc routine to use based
  55. * upon the register size.
  56. */
  57. switch (io->regsize) {
  58. case 1:
  59. io->inputb = port_inb;
  60. io->outputb = port_outb;
  61. break;
  62. case 2:
  63. io->inputb = port_inw;
  64. io->outputb = port_outw;
  65. break;
  66. case 4:
  67. io->inputb = port_inl;
  68. io->outputb = port_outl;
  69. break;
  70. default:
  71. dev_warn(io->dev, "Invalid register size: %d\n",
  72. io->regsize);
  73. return -EINVAL;
  74. }
  75. /*
  76. * Some BIOSes reserve disjoint I/O regions in their ACPI
  77. * tables. This causes problems when trying to register the
  78. * entire I/O region. Therefore we must register each I/O
  79. * port separately.
  80. */
  81. for (idx = 0; idx < io->io_size; idx++) {
  82. if (request_region(addr + idx * io->regspacing,
  83. io->regsize, DEVICE_NAME) == NULL) {
  84. /* Undo allocations */
  85. while (idx--)
  86. release_region(addr + idx * io->regspacing,
  87. io->regsize);
  88. return -EIO;
  89. }
  90. }
  91. io->io_cleanup = port_cleanup;
  92. return 0;
  93. }