bucts.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /* compile: gcc -s -o bucts bucts.c -lpci or: make
  2. * run as root: ./bucts [0|1]
  3. */
  4. /*
  5. * Copyright (C) 2011 Peter Stuge <peter@stuge.se>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; version 2 of the License.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <stdlib.h>
  25. #include <stdint.h>
  26. #include <string.h>
  27. #include <errno.h>
  28. #include <unistd.h>
  29. #include <sys/mman.h>
  30. #if defined(__GLIBC__)
  31. #include <sys/io.h>
  32. #endif
  33. #include <pci/pci.h>
  34. #if defined (__sun) && (defined(__i386) || defined(__amd64))
  35. #define MEM_DEV "/dev/xsvc"
  36. #else
  37. #define MEM_DEV "/dev/mem"
  38. #endif
  39. static int fd_mem=-1;
  40. static void *sys_physmap(unsigned long phys_addr, size_t len) {
  41. void *virt_addr = mmap(0, len, PROT_WRITE|PROT_READ, MAP_SHARED, fd_mem, (off_t)phys_addr);
  42. return MAP_FAILED == virt_addr ? NULL : virt_addr;
  43. }
  44. static void physunmap(void *virt_addr, size_t len) {
  45. if (!len) {
  46. printf("Not unmapping zero size at %p\n", virt_addr);
  47. return;
  48. }
  49. munmap(virt_addr, len);
  50. }
  51. static void *physmap(const char *descr, unsigned long phys_addr, size_t len) {
  52. void *virt_addr;
  53. if (!descr)
  54. descr = "memory";
  55. if (!len) {
  56. printf("Not mapping %s, zero size at 0x%08lx.\n", descr, phys_addr);
  57. return NULL;
  58. }
  59. if ((getpagesize() - 1) & len)
  60. fprintf(stderr, "Unaligned size 0x%lx for %s at 0x%08lx!\n", (unsigned long)len, descr, phys_addr);
  61. if ((getpagesize() - 1) & phys_addr)
  62. fprintf(stderr, "Unaligned address 0x%08lx for %s!\n", phys_addr, descr);
  63. virt_addr = sys_physmap(phys_addr, len);
  64. if (!virt_addr) {
  65. fprintf(stderr, "Error accessing 0x%lx bytes %s at 0x%08lx!\n", (unsigned long)len, descr, phys_addr);
  66. perror("mmap(" MEM_DEV ")");
  67. if (EINVAL == errno) {
  68. fprintf(stderr, "\n");
  69. fprintf(stderr, "In Linux this error can be caused by the CONFIG_NONPROMISC_DEVMEM (<2.6.27),\n");
  70. fprintf(stderr, "CONFIG_STRICT_DEVMEM (>=2.6.27) and CONFIG_X86_PAT kernel options.\n");
  71. fprintf(stderr, "Please check if either is enabled in your kernel before reporting a failure.\n");
  72. fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n");
  73. fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n");
  74. }
  75. }
  76. return virt_addr;
  77. }
  78. int bucts(struct pci_dev *sb, int8_t newts) {
  79. uint8_t buc, ts;
  80. uint32_t rcba_addr;
  81. volatile uint8_t *rcba;
  82. const char *str[2]={
  83. "128kb address range 0xFFFE0000-0xFFFFFFFF is untranslated",
  84. "64kb address ranges at 0xFFFE0000 and 0xFFFF0000 are swapped"
  85. };
  86. switch (sb->device_id) {
  87. case 0x27b9:
  88. rcba_addr = pci_read_long(sb, 0xf0) & ~1;
  89. break;
  90. default:
  91. fprintf(stderr, "Unsupported LPC bridge. Sorry.\n");
  92. return 1;
  93. }
  94. rcba = physmap("RCBA", rcba_addr, 0x4000);
  95. if (!rcba)
  96. return 1;
  97. buc = rcba[0x3414];
  98. ts = buc & 1;
  99. printf("Current BUC.TS=%d - %s\n", ts, str[ts]);
  100. if (0 == newts || 1 == newts) {
  101. if (ts == newts) {
  102. printf("Not writing BUC register since TS is already correct.\n");
  103. goto unmap;
  104. }
  105. buc &= ~1;
  106. buc |= newts;
  107. rcba[0x3414] = buc;
  108. buc = rcba[0x3414];
  109. ts = buc & 1;
  110. printf("Updated BUC.TS=%d - %s\n", ts, str[ts]);
  111. }
  112. unmap:
  113. physunmap((void *)rcba, 0x4000);
  114. return 0;
  115. }
  116. int main(int argc, const char *argv[], const char *envp[]) {
  117. int ret;
  118. char *endp;
  119. int8_t newts = -1;
  120. struct pci_access *pacc;
  121. struct pci_dev *dev, *sb = NULL;
  122. #if defined(__FreeBSD__)
  123. int io_fd;
  124. #endif
  125. printf("bucts utility version '" VERSION "'\n");
  126. #if defined(__FreeBSD__)
  127. if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
  128. perror("open(/dev/io)");
  129. #else
  130. if (iopl(3)) {
  131. perror("iopl");
  132. #endif
  133. printf("You need to be root.\n");
  134. return 1;
  135. }
  136. if (-1 == (fd_mem = open(MEM_DEV, O_RDWR|O_SYNC))) {
  137. perror("Error: open(" MEM_DEV ")");
  138. return 1;
  139. }
  140. pacc=pci_alloc();
  141. pci_init(pacc);
  142. pci_scan_bus(pacc);
  143. for (dev=pacc->devices; dev && !sb; dev=dev->next) {
  144. pci_fill_info(dev, PCI_FILL_IDENT|PCI_FILL_CLASS);
  145. if (dev->vendor_id != 0x8086 || dev->device_class != 0x0601)
  146. continue;
  147. sb = dev;
  148. }
  149. if (!sb) {
  150. fprintf(stderr, "Error: LPC bridge not found!\n");
  151. return 1;
  152. }
  153. printf("Using LPC bridge %04x:%04x at %02x%02x:%02x.%02x\n", sb->vendor_id, sb->device_id, sb->domain, sb->bus, sb->dev, sb->func);
  154. if (argc > 1) {
  155. newts = strtoul(argv[1], &endp, 10);
  156. if (endp == argv[1]) {
  157. fprintf(stderr, "Invalid new TS value '%s', please specify 0 or 1.\n", argv[1]);
  158. newts = -1;
  159. }
  160. }
  161. ret = bucts(sb, newts);
  162. close(fd_mem);
  163. return ret;
  164. }