00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <linux/version.h>
00026 #include <linux/kernel.h>
00027 #include <linux/module.h>
00028 #include <linux/pci.h>
00029 #include <linux/pci_ids.h>
00030 #include <linux/reboot.h>
00031
00032 #include <rtai_wrappers.h>
00033
00034 int smiReset = 0;
00035 RTAI_MODULE_PARM(smiReset, int);
00036
00037
00038 #define CONFIG_RTAI_HW_SMI_ALL 1
00039 #define CONFIG_RTAI_HW_SMI_INTEL_USB2 0
00040 #define CONFIG_RTAI_HW_SMI_LEGACY_USB2 0
00041 #define CONFIG_RTAI_HW_SMI_PERIODIC 0
00042 #define CONFIG_RTAI_HW_SMI_TCO 0
00043 #define CONFIG_RTAI_HW_SMI_MC 0
00044 #define CONFIG_RTAI_HW_SMI_APMC 0
00045 #define CONFIG_RTAI_HW_SMI_LEGACY_USB 0
00046 #define CONFIG_RTAI_HW_SMI_BIOS 0
00047
00048 #ifndef PCI_DEVICE_ID_INTEL_ICH7_0
00049 #define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8
00050 #endif
00051 #ifndef PCI_DEVICE_ID_INTEL_ICH7_1
00052 #define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9
00053 #endif
00054 #ifndef PCI_DEVICE_ID_INTEL_ICH8_4
00055 #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815
00056 #endif
00057
00058
00059 static struct pci_device_id hal_smi_pci_tbl[] = {
00060 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) },
00061 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) },
00062 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) },
00063 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) },
00064 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) },
00065 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) },
00066 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) },
00067 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) },
00068 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) },
00069 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) },
00070 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0) },
00071 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1) },
00072 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2) },
00073 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
00074 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
00075 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4) },
00076 { 0, },
00077 };
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 #define DEVFN 0xf8
00088
00089 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
00090 #define pci_get_device(a, b, c) pci_find_device(a, b, c)
00091 #define pci_dev_put(a) do { } while(0)
00092 #endif
00093
00094 #define PMBASE_B0 0x40
00095 #define PMBASE_B1 0x41
00096
00097 #define SMI_CTRL_ADDR 0x30
00098 #define SMI_STATUS_ADDR 0x34
00099 #define SMI_MON_ADDR 0x40
00100
00101
00102 #define INTEL_USB2_EN_BIT (0x01 << 18)
00103 #define LEGACY_USB2_EN_BIT (0x01 << 17)
00104 #define PERIODIC_EN_BIT (0x01 << 14)
00105 #define TCO_EN_BIT (0x01 << 13)
00106 #define MCSMI_EN_BIT (0x01 << 11)
00107 #define SWSMI_TMR_EN_BIT (0x01 << 6)
00108 #define APMC_EN_BIT (0x01 << 5)
00109 #define SLP_EN_BIT (0x01 << 4)
00110 #define LEGACY_USB_EN_BIT (0x01 << 3)
00111 #define BIOS_EN_BIT (0x01 << 2)
00112 #define GBL_SMI_EN_BIT (0x01 << 0)
00113
00114 unsigned long hal_smi_masked_bits = 0
00115 #if CONFIG_RTAI_HW_SMI_ALL
00116 | GBL_SMI_EN_BIT
00117 #else
00118 #if CONFIG_RTAI_HW_SMI_INTEL_USB2
00119 | INTEL_USB2_EN_BIT
00120 #endif
00121 #if CONFIG_RTAI_HW_SMI_LEGACY_USB2
00122 | LEGACY_USB2_EN_BIT
00123 #endif
00124 #if CONFIG_RTAI_HW_SMI_PERIODIC
00125 | PERIODIC_EN_BIT
00126 #endif
00127 #if CONFIG_RTAI_HW_SMI_TCO
00128 | TCO_EN_BIT
00129 #endif
00130 #if CONFIG_RTAI_HW_SMI_MC
00131 | MCSMI_EN_BIT
00132 #endif
00133 #if CONFIG_RTAI_HW_SMI_APMC
00134 | APMC_EN_BIT
00135 #endif
00136 #if CONFIG_RTAI_HW_SMI_LEGACY_USB
00137 | LEGACY_USB_EN_BIT
00138 #endif
00139 #if CONFIG_RTAI_HW_SMI_BIOS
00140 | BIOS_EN_BIT
00141 #endif
00142 #endif
00143 ;
00144
00145 RTAI_MODULE_PARM(hal_smi_masked_bits, ulong);
00146
00147 static unsigned long hal_smi_saved_bits;
00148 static unsigned short hal_smi_en_addr;
00149 static struct pci_dev *smi_dev;
00150
00151 #define mask_bits(v, p) outl(inl(p) & ~(v), (p))
00152 #define set_bits(v, p) outl(inl(p) | (v), (p))
00153
00154 static int rtai_smi_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
00155 {
00156 switch (event) {
00157 case SYS_DOWN:
00158 case SYS_HALT:
00159 case SYS_POWER_OFF:
00160 if (hal_smi_en_addr) {
00161 set_bits(hal_smi_saved_bits, hal_smi_en_addr);
00162 }
00163 }
00164 return NOTIFY_DONE;
00165 }
00166
00167 static struct notifier_block rtai_smi_reboot_notifier = {
00168 .notifier_call = &rtai_smi_notify_reboot,
00169 .next = NULL,
00170 .priority = 0
00171 };
00172
00173 void hal_smi_restore(void)
00174 {
00175 if (hal_smi_en_addr) {
00176 set_bits(hal_smi_saved_bits, hal_smi_en_addr);
00177 pci_dev_put(smi_dev);
00178 unregister_reboot_notifier(&rtai_smi_reboot_notifier);
00179 }
00180 }
00181
00182 void hal_smi_disable(void)
00183 {
00184 if (hal_smi_en_addr) {
00185 hal_smi_saved_bits = inl(hal_smi_en_addr) & hal_smi_masked_bits;
00186 mask_bits(hal_smi_masked_bits, hal_smi_en_addr);
00187 register_reboot_notifier(&rtai_smi_reboot_notifier);
00188 }
00189 }
00190
00191 static unsigned short __devinit get_smi_en_addr(struct pci_dev *dev)
00192 {
00193 u_int8_t byte0, byte1;
00194
00195 pci_read_config_byte (dev, PMBASE_B0, &byte0);
00196 pci_read_config_byte (dev, PMBASE_B1, &byte1);
00197 return SMI_CTRL_ADDR + (((byte1 << 1) | (byte0 >> 7)) << 7);
00198 }
00199
00200 int __devinit hal_smi_init(void)
00201 {
00202 struct pci_dev *dev = NULL;
00203 struct pci_device_id *id;
00204
00205
00206
00207
00208
00209 for (id = &hal_smi_pci_tbl[0]; dev == NULL && id->vendor != 0; id++) {
00210 dev = pci_get_device(id->vendor, id->device, NULL);
00211 }
00212
00213 if (dev == NULL || dev->bus->number || dev->devfn != DEVFN) {
00214 pci_dev_put(dev);
00215 printk("RTAI: Intel chipset not found.\n");
00216 return -ENODEV;
00217 }
00218
00219 printk("RTAI: Intel chipset found, enabling SMI workaround.\n");
00220 hal_smi_en_addr = get_smi_en_addr(dev);
00221 smi_dev = dev;
00222 hal_smi_disable();
00223 return 0;
00224 }
00225
00226
00227
00228 int init_module(void)
00229 {
00230 int retval;
00231 if (smiReset) {
00232 hal_smi_restore();
00233 printk("SMI configuration has been reset, mask used = %lx.\n", hal_smi_saved_bits);
00234 retval = 0;
00235 } else if (!(retval = hal_smi_init())) {
00236 printk("SMI configuration has been set, mask used = %lx.\n", hal_smi_masked_bits);
00237 }
00238 return retval;
00239 }
00240
00241 void cleanup_module(void)
00242 {
00243 return;
00244 }
00245
00246 MODULE_LICENSE("GPL");
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293