]> git.pld-linux.org Git - projects/rc-scripts.git/commitdiff
- added Wake-On-Lan work-around for nForce ethernet drivers
authorsiefca <siefca@pld-linux.org>
Sat, 25 Nov 2006 12:09:52 +0000 (12:09 +0000)
committersiefca <siefca@pld-linux.org>
Sat, 25 Nov 2006 12:09:52 +0000 (12:09 +0000)
- added pci-config utility which allows power state manipulation and devices listing

svn-id: @7989

AUTHORS
rc-scripts.spec.in
rc.d/init.d/functions
rc.d/rc.shutdown
src/Makefile.am
src/pci-config.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 2d9d5a655e376a27fd376ffa87cf63f0dc590feb..7c8853c29cb62f9662056bee52ff31deec0322d1 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -29,8 +29,10 @@ Jan R
 Micha³ Kochanowicz <mkochano@pld-linux.org>
        fixes, progress()
        
-Pawe³ Wilk <siefca@pl.qmail.org>
+Pawe³ Wilk <siefca@gnu.org>
        executing scripts on iface up/down
+       timezone setup & resolvesymlink
+       nVidia ethernet Wake-On-Lan work-around
 
 Robert ¦laski <robin@atm.com.pl>
        ATM support
index 34c74f907cc77bd7f548a5c79be3890d1c1a9824..c25fb9ad8023e3ecec84e1a18c91b488ddfd834b 100644 (file)
@@ -218,6 +218,7 @@ mv -f /etc/sysconfig/network-scripts/ifcfg-* /etc/sysconfig/interfaces
 %attr(755,root,root) %{_sbindir}/ppp-watch
 %attr(755,root,root) %{_sbindir}/netreport
 %attr(755,root,root) %{_sbindir}/setsysfont
+%attr(755,root,root) %{_sbindir}/pci-config
 %attr(4755,root,root) %{_sbindir}/usernetctl
 
 %attr(755,root,root) %{_sbindir}/if*
index cbb5b0510fa8a8fbc45449f0c1c380364661db1c..c4b9ddf15e26ae5fb20b5446625d2d657c216059 100644 (file)
@@ -884,6 +884,58 @@ relabel_selinux() {
        echo $SELINUX > $selinuxfs/enforce
 }
 
+# Wake-On-Lan workaround for nForce ethernet drivers.
+# To realy help it also requires patched kernel module.
+# Written by Pawel Wilk using idea from Arjen Verweij,
+# see http://atlas.et.tudelft.nl/verwei90/nforce2/wol.html
+#
+# Call it only when system halts/suspends, there is
+# no return to the D0 power state after execution!
+#
+forcedeth_workaround()
+{
+    [ -x /sbin/ethtool ] || return 2
+    [ -x /sbin/pci-config || return 2
+    grep -qi forcedeth /proc/modules || return 0
+
+    # FIXME: put here condition - kernel/module version checking
+    #        when the problem will be fixed in the driver
+
+    typeset iface bus_dev_fn bus lookfor dev_index cur_state
+
+    for iface in $(ip link show | awk -F'[ :]+' '/eth[0-9]+/ {print $2}')
+    do
+       if LC_ALL=C ethtool -i "${iface}" 2>&1 | egrep -qi 'driver:[[:blank:]]forcedeth'; then
+           case $(LC_ALL=C ethtool "${iface}" 2>&1 | awk 'tolower($1) ~ "wake-on:" {print $2}') in
+               *d*) continue ;; # 'd' letter means that the WON was DISABLED for interface
+               "") continue ;;  # empty string means that the WON is not supported here
+           esac
+           bus_dev_fn=$(LC_ALL=C ethtool -i ${iface} 2>&1 | awk -F'[ :.]+' '/^bus-info:/ {printf ("%d %d %d",$3,$4,$5) }')
+           if [ -n "${bus_dev_fn}" -a "${bus_dev_fn}" != "0 0 0" ]; then
+               bus=$(echo "${bus_dev_fn}" | awk '{print $1}')
+               lookfor=$(echo "${bus_dev_fn}" | awk '{print "at bus "$1" device/function "$2"/"$3}')
+               dev_index=$(LC_ALL=C pci-config -B${bus} 2>&1 | grep -i "${lookfor}" | awk '/Device \#[0-9]+/ {print $2}')
+               if [ -n "${dev_index}" ]; then
+                   show "Forcing sleep state for the nForce interface %s" ${iface} ; busy
+                   ip link set ${iface} up 2>&1 >/dev/null # need it to be up
+                   sleep 1
+                   pci-config -S -$dev_index 2>&1 >/dev/null
+                   RESULT=$?
+                   cur_state=$(pci-config -a -$dev_index 2>&1 | awk -F'[ \t:.]+' ' tolower($2$3) ~ "powerstate" {print tolower($4)}')
+                   if [ "${cur_state}" != "d3" ]; then
+                       RESULT=1
+                   fi
+                   if [ $RESULT -gt 0 ]; then
+                       fail
+                   else
+                        ok
+                    fi
+               fi
+           fi
+       fi
+    done
+}
+
 # Remove duplicate entries from mtab (for vserver guest use only)
 clean_vserver_mtab() {
        :>/etc/mtab.clean
index 525d658926ba9107aa131ffbf648609a34c46f33..e1891d024270753b1849cc18b109f0211c9e7256 100755 (executable)
@@ -48,6 +48,9 @@ fi
 halt -w
 
 if ! is_yes "$VSERVER"; then
+       # Work-around for the nVidia drivers Wake-On-Lan functionality.
+       forcedeth_workaround
+
        # Turn off swap, then unmount file systems.
        run_cmd "Turning off swap" swapoff -a
 
index 48ca4b459ecfcb435ad5a0b78b7b183c7f14b6a0..99588c6ea77f0554540f3662d7a078b9a024a076 100644 (file)
@@ -25,7 +25,8 @@ sbin_PROGRAMS =       \
        netreport \
        ppp-watch \
        start-stop-daemon \
-       usernetctl
+       usernetctl \
+       pci-config
        
 EXTRA_PROGRAMS = \
        testd 
@@ -34,7 +35,7 @@ EXTRA_DIST = $(sysconf_DATA)
 
 doexec_SOURCES = doexec.c
 
-resolvesymlink_SOURCE = resolvesymlink.c
+resolvesymlink_SOURCES = resolvesymlink.c
 
 ipcalc_SOURCES = ipcalc.c
 ipcalc_LDADD = -lpopt
@@ -66,3 +67,5 @@ consoletype_SOURCES = consoletype.c
 
 start_stop_daemon_SOURCES = start-stop-daemon.c
 
+pci-config_SOURCES = pci-config.c
+
diff --git a/src/pci-config.c b/src/pci-config.c
new file mode 100644 (file)
index 0000000..a8f09cc
--- /dev/null
@@ -0,0 +1,446 @@
+/* pci-config-space.c: Read the PCI configuration space.
+
+       Read the PCI configuration space using the Intel bus-bridge interface
+       registers.  This bypasses the BIOS32 entry, and thus we are not assured
+       of working on all systems.
+
+       Copyright 1998-2002 by Donald Becker.
+       This software may be used and distributed according to the terms of
+       the GNU General Public License (GPL), incorporated herein by reference.
+       Contact the author for use under other terms.
+
+       The author may be reached as becker@scyld.com, or C/O
+        Scyld Computing Corporation
+        410 Severn Ave., Suite 210
+        Annapolis MD 21403
+
+       Support and updates available at
+       http://www.scyld.com/diag/index.html
+
+       Common-sense licensing statement: Using any portion of this program in
+       your own program means that you must give credit to the original author
+       and release the resulting code under the GPL.
+ */
+
+static char *version_msg =
+"pci-config.c:v2.03 4/15/2002 Donald Becker (becker@scyld.com)\n"
+" http://www.scyld.com/diag/index.html\n";
+static char *usage_msg =
+"Usage: pci-config [-aDfSvVW] [-# <device_index>]\n";
+
+static char *long_usage_msg ="
+
+  This program shows the contents of PCI configuration space.
+  It reads the hardware registers, and thus must be run as 'root'.
+
+  Running this program with no options shows the installed PCI devices.
+  Each line is prefixed by its index which may be used with -#<index>
+  e.g. \"pci-config -#3\" to specify the device to operate on.
+
+  Commonly use options are
+  -# <device-index>         Operate only on DEVICE-INDEX e.g  -#3
+
+  The operations on the selected device are
+  -a  --show-addresses   Show PCI address registers.
+  -S --sleep             Put device to sleep (ACPI D3 state)
+  -W --wake              Wake a sleeping device (ACPI D0 state)
+
+  Less commonly used options are
+  -B <bus>  --bus <bus>      Show only devices on BUS.
+  -A <addr> --set-addresses  Set PCI address register 1 to the ADDR.
+  -D  --debug                Show details of operations
+  -f  --force                Override checks and perform the operation
+  -u  --usage                Show this long usage message
+  -v  --verbose              Verbose mode
+  -V  --version              Display this program's version information
+
+";
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <getopt.h>
+#if defined(__linux__)  &&  __GNU_LIBRARY__ == 1
+#include <asm/io.h>                    /* Newer libraries use <sys/io.h> instead. */
+#else
+#include <sys/io.h>
+#endif
+#if !defined(__OPTIMIZE__)
+#error You must compile this driver with "-O"!
+#endif
+
+struct option longopts[] = {
+       {"show-addresses",      0, 0, 'a'},     /* Show PCI address registers. */
+       {"set-addresses",       1, 0, 'A'},     /* Show PCI address registers. */
+       {"bus",         1, 0, 'B'},                     /* Show only devices on BUS. */
+       {"debug",       0, 0, 'D'},                     /* Increase debug level. */
+       {"force",       0, 0, 'f'},                     /* Force operation. */
+       {"set-WOL",     0, 0, 'M'},                     /* Set to Wake-On-LAN mode. */
+       {"sleep",       0, 0, 'S'},                     /* Put device to sleep (ACPI D3 state). */
+       {"usage",       0, 0, 'u'},                     /* Show the long usage message. */
+       {"verbose",     0, 0, 'v'},                     /* Verbose mode */
+       {"version", 0, 0, 'V'},                 /* Display version number */
+       {"wake-on-lan", 0, 0, 'W'},             /* Wake (set to D0 state) the device. */
+       {"device-index", 1, 0, '#'},    /* Operate only on device INDEX. */
+       { 0, 0, 0, 0 }
+};
+
+static int verbose=1, opt_a=0, opt_f=0, opt_wake=0, opt_set_WOL=0, debug=0;
+static int opt_sleep = 0;
+static long set_address = -1;
+
+static void show_addr_config(unsigned char pci_bus, unsigned char pci_dev_fn);
+static void show_ext_caps(unsigned int *cfg_space, unsigned char pci_bus,
+                                                 unsigned char pci_dev_fn);
+static void show_one_device(unsigned char pci_bus, unsigned char pci_dev_fn,
+                                                       int dev_num);
+
+static void cyclone_WOL(int pci_bus, int pci_dev_fn, void *pci_config_space);
+static void acpi_wake(unsigned char pci_bus, unsigned char pci_dev_fn,
+                                         void *config);
+static void acpi_sleep(unsigned char bus, unsigned char devfn, void *pci_cfg);
+static int dump_mem_region(long addr);
+
+extern int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
+                                    unsigned char where, unsigned char *val);
+int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
+                                                         unsigned char regnum, unsigned short *val);
+extern int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
+                                                                         unsigned char regnum, unsigned int *val);
+void pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned char val);
+void pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned short val);
+void pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned int val);
+
+\f
+int main(int argc, char **argv)
+{
+       int pci_bus = 0, pci_dev_fn;
+       int errflag = 0, show_version = 0;
+       int c, longind, card_num = 0;
+       int dev_num = 0;
+
+       while ((c = getopt_long(argc, argv, "#:aA:b:B:DfMSuvVW",
+                                                       longopts, &longind))
+                  != -1)
+               switch (c) {
+               case 'a': opt_a++;                      break;
+               case 'A': set_address = strtol(optarg, NULL, 16);       break;
+               case 'b': printf("Setting bus to %s.\n", optarg);
+               case 'B': pci_bus = strtol(optarg, NULL, 0); break;
+               case 'D': debug++;                      break;
+               case 'f': opt_f++;                      break;
+               case 'M': opt_set_WOL++;        break;
+               case 'S': opt_sleep++;          break;
+               case 'u': printf("%s%s", usage_msg, long_usage_msg); return 0;
+               case 'v': verbose++;            break;
+               case 'V': show_version++;       break;
+               case 'W': opt_wake++;           break;
+               case '#': card_num = atoi(optarg); break;
+               case '?':
+                       errflag++;
+               }
+       if (errflag) {
+               fprintf(stderr, "%s%s", usage_msg, "  Use -u for more information.\n");
+               return 3;
+       }
+
+       if (verbose)
+               printf(version_msg);
+
+       /* Get access to all of I/O space. */
+       if (iopl(3) < 0) {
+               perror("pci-config: iopl()");
+               fprintf(stderr, "This program must be run as root.\n");
+               return 2;
+       }
+       for (pci_dev_fn = 0; pci_dev_fn < 256; pci_dev_fn++) {
+               /*unsigned char cb;*/
+               unsigned int pci_id;
+
+               pcibios_read_config_dword(pci_bus, pci_dev_fn, 0, &pci_id);
+               if (pci_id == 0xffffffff)
+                       continue;
+               dev_num++;
+               if (card_num  == 0) {
+                       printf("Device #%d at bus %d device/function %d/%d, %8.8x.\n",
+                                  dev_num, pci_bus, pci_dev_fn>>3, pci_dev_fn&7, pci_id);
+               } else if (card_num == dev_num) {
+                       show_one_device(pci_bus, pci_dev_fn, dev_num);
+               }
+               if ((pci_dev_fn & 7) == 0) {
+                       unsigned int cdw;
+                       pcibios_read_config_dword(pci_bus, pci_dev_fn, 3*4, &cdw);
+                       if ((cdw & 0x00800000) == 0)
+                               pci_dev_fn += 7;
+               }
+       }
+
+       return 0;
+}
+
+static void show_one_device(unsigned char pci_bus, unsigned char pci_dev_fn,
+                                                       int dev_num)
+{
+       unsigned int config[64];
+       int i;
+       int pci_id;
+
+       printf("Device #%d at bus %d device/function %d/%d.",
+                  dev_num, pci_bus, pci_dev_fn>>3, pci_dev_fn&7);
+       for (i = 0; i < 64; i++) {
+               pcibios_read_config_dword(pci_bus, pci_dev_fn, i<<2, &config[i]);
+               printf("%s%8.8x", i % 8 == 0  ?  "\n  " : " ", config[i]);
+       }
+       printf("\n");
+       for (i = 0; i < 5; i++) {
+               unsigned int pciaddr = config[4 + i];
+               if (pciaddr)
+                       printf("  Base Address %d: %s at %8.8x.\n",
+                                  i, pciaddr & 1 ? "I/O" : "Memory", pciaddr & ~1);
+       }
+       if (set_address >= 0) {
+               fprintf(stderr, "Setting PCI address register 1 to 0x%lx.\n",
+                               set_address);
+               pcibios_write_config_dword(pci_bus, pci_dev_fn, 0x14, set_address);
+               pcibios_write_config_dword(pci_bus, pci_dev_fn, 0x04, config[1] | 3);
+       }
+       if (opt_a)
+               show_addr_config(pci_bus, pci_dev_fn);
+       pci_id = config[0];
+       if (config[1] & 0x00100000)
+               show_ext_caps(config, pci_bus, pci_dev_fn);
+       if (config[10]) {
+               char *cis_addr_space[] = {"PCI configuration space", "BAR 0", "BAR 1", "BAR 2", "BAR 3", };
+               int space = config[10] & 7;
+               printf("  CardBus CIS pointer 0x%4.4x (%s), address %x.\n", config[10],
+                          cis_addr_space[space], config[4 + (space-1)]);
+               if (space > 0 && space < 4)
+                       dump_mem_region(config[4 + ((space-1))]);
+       }
+       if (opt_sleep)
+               acpi_sleep(pci_bus, pci_dev_fn, config);
+       if (opt_wake)
+               acpi_wake(pci_bus, pci_dev_fn, config);
+       if (opt_set_WOL)
+               if (pci_id == 0x905510b7)
+                       cyclone_WOL(pci_bus, pci_dev_fn, config);
+}
+
+static void show_addr_config(unsigned char pci_bus, unsigned char pci_dev_fn)
+{
+       int i;
+       unsigned int pciaddr, cdw;
+       for (i = 0; i < 5; i++) {
+               int cfg_i = 0x10 + (i<<2);
+               pcibios_read_config_dword(pci_bus, pci_dev_fn, cfg_i, &pciaddr);
+               pcibios_write_config_dword(pci_bus, pci_dev_fn, cfg_i, 0xffffffff);
+               pcibios_read_config_dword(pci_bus, pci_dev_fn, cfg_i, &cdw);
+               if (cdw == 0)
+                       break;
+               printf("  Address %d %s at %8.8x, decoded bits are %8.8x.\n",
+                          i, cdw & 1 ? "is I/O" : "memory", pciaddr & ~1, ~cdw);
+               pcibios_write_config_dword(pci_bus, pci_dev_fn, cfg_i, pciaddr);
+       }
+       pcibios_read_config_dword(pci_bus, pci_dev_fn, 0x30, &pciaddr);
+       pcibios_write_config_dword(pci_bus, pci_dev_fn, 0x30, 0xfffffffe);
+       pcibios_read_config_dword(pci_bus, pci_dev_fn, 0x30, &cdw);
+       pcibios_write_config_dword(pci_bus, pci_dev_fn, 0x30, pciaddr);
+       if (cdw)
+               printf("  BIOS ROM at %8.8x, decoded bits are %8.8x.\n", pciaddr, cdw);
+       else
+               printf("  No BIOS extension (boot ROM).\n");
+       return;
+}
+static void show_ext_caps(unsigned int *cfg_space, unsigned char pci_bus,
+                                                 unsigned char pci_dev_fn)
+{
+       unsigned char *pcfg = (void *)cfg_space;
+       int cap_idx = cfg_space[13] & 0xff;
+
+       printf("  Extended capabilities, first structure at offset 0x%x.\n",
+                  cap_idx);
+       for (; cap_idx; cap_idx = pcfg[cap_idx + 1]) {
+               printf("  Extended PCI capability type %d at 0x%2.2x, next %d.\n",
+                          pcfg[cap_idx], cap_idx, pcfg[cap_idx + 1]);
+               if (pcfg[cap_idx] == 1) {
+                       printf("   Power management entry ver. %d: Capabilities %2.2x%2.2x"
+                                  ", Ctrl %2.2x%2.2x, Event %2.2x%2.2x.\n",
+                                  pcfg[cap_idx + 2] & 7,
+                                  pcfg[cap_idx + 3], pcfg[cap_idx + 2],
+                                  pcfg[cap_idx + 5], pcfg[cap_idx + 4],
+                                  pcfg[cap_idx + 7], pcfg[cap_idx + 6]);
+                       printf("   Power state D%d.\n", pcfg[cap_idx + 4] & 3);
+               }
+       }
+}
+
+
+static int acpi_find(unsigned char pci_bus, unsigned char pci_dev_fn,
+                                               void *config)
+{
+       unsigned char *pcfg = (void *)config;
+       if (pcfg[6] & 0x10) {
+               int cap_idx = pcfg[0x34];
+
+               printf("  Extended capabilities, first structure at offset 0x%x.\n",
+                          cap_idx);
+               for (; cap_idx; cap_idx = pcfg[cap_idx + 1]) {
+                       if (pcfg[cap_idx] == 1)
+                               return cap_idx;
+               }
+       }
+       return 0;
+}
+
+static void acpi_wake(unsigned char pci_bus, unsigned char pci_dev_fn,
+                                         void *pci_config_space)
+{
+       unsigned char *config = pci_config_space;
+       unsigned short *configw = pci_config_space;
+       unsigned int *configdw = pci_config_space;
+       int pwr_idx = acpi_find(pci_bus, pci_dev_fn, config);
+       unsigned short pwr_command = configw[(pwr_idx + 4)>>1];
+       int i;
+
+       if (debug)
+               printf("Power index is %#x.\n", pwr_idx);
+
+       printf("  Waking up an ACPI device.  Currently powered %s, "
+                  "I/O %#x IRQ %d.\n"
+                  "  Updating the power state of %4.4x->%4.4x.\n",
+                  pwr_command & 3 ? "down" : "up", configdw[0x10>>2], config[0x3c],
+                  pwr_command, pwr_command & ~3);
+       pcibios_write_config_word(pci_bus, pci_dev_fn, pwr_idx + 4,
+                                                         pwr_command & ~3);
+       /* Many devices must have their PCI register state restored when changing
+          from D3 state. */
+       for (i = 0x10; i <= 0x20; i+=4)
+               pcibios_write_config_dword(pci_bus, pci_dev_fn, i, configdw[i >> 2]);
+       /* PCI_ROM_ADDRESS, interrupt line, cache line size, latency timer */
+       pcibios_write_config_dword(pci_bus, pci_dev_fn, 0x30, configdw[0x30 >> 2]);
+       pcibios_write_config_byte(pci_bus, pci_dev_fn, 0x3c, config[0x3c]);
+       pcibios_write_config_byte(pci_bus, pci_dev_fn, 0x0c, config[0x0c]);
+       pcibios_write_config_byte(pci_bus, pci_dev_fn, 0x0d, config[0x0d]);
+       /* Finally, restore the command register. */
+       pcibios_write_config_word(pci_bus, pci_dev_fn, 0x04, configw[4>>1]);
+}
+
+static void acpi_sleep(unsigned char bus, unsigned char devfn,
+                                          void *pci_config_space)
+{
+       unsigned short *configw = pci_config_space;
+       int pwr_idx = acpi_find(bus, devfn, pci_config_space);
+       unsigned short pwr_command = configw[(pwr_idx + 4)>>1];
+       pcibios_write_config_word(bus, devfn, pwr_idx + 4, pwr_command | 0x0103);
+}
+
+/* Put the 3Com Cyclone e.g. 3c905B series into Wake On LAN mode. */
+static void cyclone_WOL(int pci_bus, int pci_dev_fn, void *config)
+{
+       int pwr_idx = acpi_find(pci_bus, pci_dev_fn, config);
+       unsigned short pwr_command = ((unsigned short *)config)[(pwr_idx + 4)>>1];
+       long ioaddr = ((int *)config)[0x10];
+
+       acpi_wake(pci_bus, pci_dev_fn, config);
+
+       outw(0x801f, ioaddr + 0x0e); /* Set RxFilter to accept frames. */
+       outw((1<<11) + 7, ioaddr + 0x0e);
+       outw(7, ioaddr + 0x0c);
+       printf("  Window 7 Power Management Event is %4.4x.\n",
+                  inw(ioaddr + 0x0c));
+       printf("  Changing the power state from %4.4x to 0103.\n", pwr_command);
+       outw(0x2000, ioaddr + 0x0e); /* RxEnable. */
+       pcibios_write_config_word(pci_bus, pci_dev_fn, 0xe0, pwr_command | 0x8103);
+}
+
+\f
+#define PCI_CONFIG_ADDR 0x0cf8
+#define PCI_CONFIG_DATA 0x0cfc
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
+                                                         unsigned char regnum, unsigned char *val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       *val = inb(PCI_CONFIG_DATA + (regnum & 3));
+       return 0;
+}
+int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
+                                                         unsigned char regnum, unsigned short *val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       *val = inw(PCI_CONFIG_DATA + (regnum & 2));
+       return 0;
+}
+int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
+                                                          unsigned char regnum, unsigned int *val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       *val = inl(PCI_CONFIG_DATA);
+       return 0;
+}
+void pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned char val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       outb(val, PCI_CONFIG_DATA + (regnum & 3));
+       return;
+}
+void pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned short val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       outw(val, PCI_CONFIG_DATA + (regnum & 2));
+       return;
+}
+void pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+                                                               unsigned char regnum, unsigned int val)
+{
+       outl(0x80000000 | (bus<<16) | (dev_fn << 8) | (regnum & 0xfc),
+                PCI_CONFIG_ADDR);
+       outl(val, PCI_CONFIG_DATA);
+       return;
+}
+
+\f
+/* Map the board shared memory into our address space -- this code is
+   a good example of non-kernel access to devices on the PCI bus. */
+static int dump_mem_region(long addr)
+{
+       unsigned short *shared_mem;
+       int i;
+       int memfd = open("/dev/kmem", O_RDWR);
+
+       if (memfd < 0) {
+               perror("/dev/kmem (shared memory)");
+               return 2;
+       } else
+         printf("Opened /dev/kmem for PCI memory.\n");
+       shared_mem = mmap(0, 0x8000, PROT_READ|PROT_WRITE,
+                                         MAP_SHARED, memfd, addr);
+       printf("Shared memory at %#x (%#x).\n", (int)addr, (int)shared_mem);
+       for (i = 0; i < 100; i++)
+               printf(" %4.4x", shared_mem[i]);
+       close(memfd);
+       printf(" ...\n");
+       return 0;
+}
+
+/*
+ * Local variables:
+ *  compile-command: "cc -O -Wall -o pci-config pci-config.c"
+ *  tab-width: 4
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ */
This page took 0.066141 seconds and 4 git commands to generate.