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