1/* 2 * linux/arch/i386/kernel/mca.c 3 * Written by Martin Kolinek, February 1996 4 * 5 * Changes: 6 * 7 * Chris Beauregard July 28th, 1996 8 * - Fixed up integrated SCSI detection 9 * 10 * Chris Beauregard August 3rd, 1996 11 * - Made mca_info local 12 * - Made integrated registers accessible through standard function calls 13 * - Added name field 14 * - More sanity checking 15 * 16 * Chris Beauregard August 9th, 1996 17 * - Rewrote /proc/mca 18 * 19 * Chris Beauregard January 7th, 1997 20 * - Added basic NMI-processing 21 * - Added more information to mca_info structure 22 * 23 * David Weinehall October 12th, 1998 24 * - Made a lot of cleaning up in the source 25 * - Added use of save_flags / restore_flags 26 * - Added the 'driver_loaded' flag in MCA_adapter 27 * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter 28 * 29 * David Weinehall March 24th, 1999 30 * - Fixed the output of 'Driver Installed' in /proc/mca/pos 31 * - Made the Integrated Video & SCSI show up even if they have id 0000 32 * 33 * Alexander Viro November 9th, 1999 34 * - Switched to regular procfs methods 35 * 36 * Alfred Arnold & David Weinehall August 23rd, 2000 37 * - Added support for Planar POS-registers 38 */ 39 40#include <linux/module.h> 41#include <linux/types.h> 42#include <linux/errno.h> 43#include <linux/kernel.h> 44#include <linux/mca.h> 45#include <linux/kprobes.h> 46#include <asm/system.h> 47#include <asm/io.h> 48#include <linux/proc_fs.h> 49#include <linux/mman.h> 50#include <linux/mm.h> 51#include <linux/pagemap.h> 52#include <linux/ioport.h> 53#include <asm/uaccess.h> 54#include <linux/init.h> 55#include <asm/arch_hooks.h> 56 57static unsigned char which_scsi = 0; 58 59int MCA_bus = 0; 60EXPORT_SYMBOL(MCA_bus); 61 62/* 63 * Motherboard register spinlock. Untested on SMP at the moment, but 64 * are there any MCA SMP boxes? 65 * 66 * Yes - Alan 67 */ 68static DEFINE_SPINLOCK(mca_lock); 69 70/* Build the status info for the adapter */ 71 72static void mca_configure_adapter_status(struct mca_device *mca_dev) { 73 mca_dev->status = MCA_ADAPTER_NONE; 74 75 mca_dev->pos_id = mca_dev->pos[0] 76 + (mca_dev->pos[1] << 8); 77 78 if(!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) { 79 80 /* id = 0x0000 usually indicates hardware failure, 81 * however, ZP Gu (zpg@castle.net> reports that his 9556 82 * has 0x0000 as id and everything still works. There 83 * also seem to be an adapter with id = 0x0000; the 84 * NCR Parallel Bus Memory Card. Until this is confirmed, 85 * however, this code will stay. 86 */ 87 88 mca_dev->status = MCA_ADAPTER_ERROR; 89 90 return; 91 } else if(mca_dev->pos_id != 0xffff) { 92 93 /* 0xffff usually indicates that there's no adapter, 94 * however, some integrated adapters may have 0xffff as 95 * their id and still be valid. Examples are on-board 96 * VGA of the 55sx, the integrated SCSI of the 56 & 57, 97 * and possibly also the 95 ULTIMEDIA. 98 */ 99 100 mca_dev->status = MCA_ADAPTER_NORMAL; 101 } 102 103 if((mca_dev->pos_id == 0xffff || 104 mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) { 105 int j; 106 107 for(j = 2; j < 8; j++) { 108 if(mca_dev->pos[j] != 0xff) { 109 mca_dev->status = MCA_ADAPTER_NORMAL; 110 break; 111 } 112 } 113 } 114 115 if(!(mca_dev->pos[2] & MCA_ENABLED)) { 116 117 /* enabled bit is in POS 2 */ 118 119 mca_dev->status = MCA_ADAPTER_DISABLED; 120 } 121} /* mca_configure_adapter_status */ 122 123/*--------------------------------------------------------------------*/ 124 125static struct resource mca_standard_resources[] = { 126 { .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" }, 127 { .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" }, 128 { .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" }, 129 { .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" }, 130 { .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" }, 131 { .start = 0x96, .end = 0x97, .name = "POS (MCA)" }, 132 { .start = 0x100, .end = 0x107, .name = "POS (MCA)" } 133}; 134 135#define MCA_STANDARD_RESOURCES ARRAY_SIZE(mca_standard_resources) 136 137/** 138 * mca_read_and_store_pos - read the POS registers into a memory buffer 139 * @pos: a char pointer to 8 bytes, contains the POS register value on 140 * successful return 141 * 142 * Returns 1 if a card actually exists (i.e. the pos isn't 143 * all 0xff) or 0 otherwise 144 */ 145static int mca_read_and_store_pos(unsigned char *pos) { 146 int j; 147 int found = 0; 148 149 for(j=0; j<8; j++) { 150 if((pos[j] = inb_p(MCA_POS_REG(j))) != 0xff) { 151 /* 0xff all across means no device. 0x00 means 152 * something's broken, but a device is 153 * probably there. However, if you get 0x00 154 * from a motherboard register it won't matter 155 * what we find. For the record, on the 156 * 57SLC, the integrated SCSI adapter has 157 * 0xffff for the adapter ID, but nonzero for 158 * other registers. */ 159 160 found = 1; 161 } 162 } 163 return found; 164} 165 166static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg) 167{ 168 unsigned char byte; 169 unsigned long flags; 170 171 if(reg < 0 || reg >= 8) 172 return 0; 173 174 spin_lock_irqsave(&mca_lock, flags); 175 if(mca_dev->pos_register) { 176 /* Disable adapter setup, enable motherboard setup */ 177 178 outb_p(0, MCA_ADAPTER_SETUP_REG); 179 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); 180 181 byte = inb_p(MCA_POS_REG(reg)); 182 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); 183 } else { 184 185 /* Make sure motherboard setup is off */ 186 187 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); 188 189 /* Read the appropriate register */ 190 191 outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG); 192 byte = inb_p(MCA_POS_REG(reg)); 193 outb_p(0, MCA_ADAPTER_SETUP_REG); 194 } 195 spin_unlock_irqrestore(&mca_lock, flags); 196 197 mca_dev->pos[reg] = byte; 198 199 return byte; 200} 201 202static void mca_pc_write_pos(struct mca_device *mca_dev, int reg, 203 unsigned char byte) 204{ 205 unsigned long flags; 206 207 if(reg < 0 || reg >= 8) 208 return; 209 210 spin_lock_irqsave(&mca_lock, flags); 211 212 /* Make sure motherboard setup is off */ 213 214 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); 215 216 /* Read in the appropriate register */ 217 218 outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG); 219 outb_p(byte, MCA_POS_REG(reg)); 220 outb_p(0, MCA_ADAPTER_SETUP_REG); 221 222 spin_unlock_irqrestore(&mca_lock, flags); 223 224 /* Update the global register list, while we have the byte */ 225 226 mca_dev->pos[reg] = byte; 227 228} 229 230/* for the primary MCA bus, we have identity transforms */ 231static int mca_dummy_transform_irq(struct mca_device * mca_dev, int irq) 232{ 233 return irq; 234} 235 236static int mca_dummy_transform_ioport(struct mca_device * mca_dev, int port) 237{ 238 return port; 239} 240 241static void *mca_dummy_transform_memory(struct mca_device * mca_dev, void *mem) 242{ 243 return mem; 244} 245 246 247static int __init mca_init(void) 248{ 249 unsigned int i, j; 250 struct mca_device *mca_dev; 251 unsigned char pos[8]; 252 short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00}; 253 struct mca_bus *bus; 254 255 /* WARNING: Be careful when making changes here. Putting an adapter 256 * and the motherboard simultaneously into setup mode may result in 257 * damage to chips (according to The Indispensible PC Hardware Book 258 * by Hans-Peter Messmer). Also, we disable system interrupts (so 259 * that we are not disturbed in the middle of this). 260 */ 261 262 /* Make sure the MCA bus is present */ 263 264 if (mca_system_init()) { 265 printk(KERN_ERR "MCA bus system initialisation failed\n"); 266 return -ENODEV; 267 } 268 269 if (!MCA_bus) 270 return -ENODEV; 271 272 printk(KERN_INFO "Micro Channel bus detected.\n"); 273 274 /* All MCA systems have at least a primary bus */ 275 bus = mca_attach_bus(MCA_PRIMARY_BUS); 276 if (!bus) 277 goto out_nomem; 278 bus->default_dma_mask = 0xffffffffLL; 279 bus->f.mca_write_pos = mca_pc_write_pos; 280 bus->f.mca_read_pos = mca_pc_read_pos; 281 bus->f.mca_transform_irq = mca_dummy_transform_irq; 282 bus->f.mca_transform_ioport = mca_dummy_transform_ioport; 283 bus->f.mca_transform_memory = mca_dummy_transform_memory; 284 285 /* get the motherboard device */ 286 mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL); 287 if(unlikely(!mca_dev)) 288 goto out_nomem; 289 290 /* 291 * We do not expect many MCA interrupts during initialization, 292 * but let us be safe: 293 */ 294 spin_lock_irq(&mca_lock); 295 296 /* Make sure adapter setup is off */ 297 298 outb_p(0, MCA_ADAPTER_SETUP_REG); 299 300 /* Read motherboard POS registers */ 301 302 mca_dev->pos_register = 0x7f; 303 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); 304 mca_dev->name[0] = 0; 305 mca_read_and_store_pos(mca_dev->pos); 306 mca_configure_adapter_status(mca_dev); 307 /* fake POS and slot for a motherboard */ 308 mca_dev->pos_id = MCA_MOTHERBOARD_POS; 309 mca_dev->slot = MCA_MOTHERBOARD; 310 mca_register_device(MCA_PRIMARY_BUS, mca_dev); 311 312 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); 313 if(unlikely(!mca_dev)) 314 goto out_unlock_nomem; 315 316 /* Put motherboard into video setup mode, read integrated video 317 * POS registers, and turn motherboard setup off. 318 */ 319 320 mca_dev->pos_register = 0xdf; 321 outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG); 322 mca_dev->name[0] = 0; 323 mca_read_and_store_pos(mca_dev->pos); 324 mca_configure_adapter_status(mca_dev); 325 /* fake POS and slot for the integrated video */ 326 mca_dev->pos_id = MCA_INTEGVIDEO_POS; 327 mca_dev->slot = MCA_INTEGVIDEO; 328 mca_register_device(MCA_PRIMARY_BUS, mca_dev); 329 330 /* Put motherboard into scsi setup mode, read integrated scsi 331 * POS registers, and turn motherboard setup off. 332 * 333 * It seems there are two possible SCSI registers. Martin says that 334 * for the 56,57, 0xf7 is the one, but fails on the 76. 335 * Alfredo (apena@vnet.ibm.com) says 336 * 0xfd works on his machine. We'll try both of them. I figure it's 337 * a good bet that only one could be valid at a time. This could 338 * screw up though if one is used for something else on the other 339 * machine. 340 */ 341 342 for(i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) { 343 outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG); 344 if(mca_read_and_store_pos(pos)) 345 break; 346 } 347 if(which_scsi) { 348 /* found a scsi card */ 349 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); 350 if(unlikely(!mca_dev)) 351 goto out_unlock_nomem; 352 353 for(j = 0; j < 8; j++) 354 mca_dev->pos[j] = pos[j]; 355 356 mca_configure_adapter_status(mca_dev); 357 /* fake POS and slot for integrated SCSI controller */ 358 mca_dev->pos_id = MCA_INTEGSCSI_POS; 359 mca_dev->slot = MCA_INTEGSCSI; 360 mca_dev->pos_register = which_scsi; 361 mca_register_device(MCA_PRIMARY_BUS, mca_dev); 362 } 363 364 /* Turn off motherboard setup */ 365 366 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); 367 368 /* Now loop over MCA slots: put each adapter into setup mode, and 369 * read its POS registers. Then put adapter setup off. 370 */ 371 372 for(i=0; i<MCA_MAX_SLOT_NR; i++) { 373 outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG); 374 if(!mca_read_and_store_pos(pos)) 375 continue; 376 377 mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC); 378 if(unlikely(!mca_dev)) 379 goto out_unlock_nomem; 380 381 for(j=0; j<8; j++) 382 mca_dev->pos[j]=pos[j]; 383 384 mca_dev->driver_loaded = 0; 385 mca_dev->slot = i; 386 mca_dev->pos_register = 0; 387 mca_configure_adapter_status(mca_dev); 388 mca_register_device(MCA_PRIMARY_BUS, mca_dev); 389 } 390 outb_p(0, MCA_ADAPTER_SETUP_REG); 391 392 /* Enable interrupts and return memory start */ 393 spin_unlock_irq(&mca_lock); 394 395 for (i = 0; i < MCA_STANDARD_RESOURCES; i++) 396 request_resource(&ioport_resource, mca_standard_resources + i); 397 398 mca_do_proc_init(); 399 400 return 0; 401 402 out_unlock_nomem: 403 spin_unlock_irq(&mca_lock); 404 out_nomem: 405 printk(KERN_EMERG "Failed memory allocation in MCA setup!\n"); 406 return -ENOMEM; 407} 408 409subsys_initcall(mca_init); 410 411/*--------------------------------------------------------------------*/ 412 413static __kprobes void 414mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag) 415{ 416 int slot = mca_dev->slot; 417 418 if(slot == MCA_INTEGSCSI) { 419 printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n", 420 mca_dev->name); 421 } else if(slot == MCA_INTEGVIDEO) { 422 printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n", 423 mca_dev->name); 424 } else if(slot == MCA_MOTHERBOARD) { 425 printk(KERN_CRIT "NMI: caused by motherboard (%s)\n", 426 mca_dev->name); 427 } 428 429 /* More info available in POS 6 and 7? */ 430 431 if(check_flag) { 432 unsigned char pos6, pos7; 433 434 pos6 = mca_device_read_pos(mca_dev, 6); 435 pos7 = mca_device_read_pos(mca_dev, 7); 436 437 printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7); 438 } 439 440} /* mca_handle_nmi_slot */ 441 442/*--------------------------------------------------------------------*/ 443 444static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data) 445{ 446 struct mca_device *mca_dev = to_mca_device(dev); 447 unsigned char pos5; 448 449 pos5 = mca_device_read_pos(mca_dev, 5); 450 451 if(!(pos5 & 0x80)) { 452 /* Bit 7 of POS 5 is reset when this adapter has a hardware 453 * error. Bit 7 it reset if there's error information 454 * available in POS 6 and 7. 455 */ 456 mca_handle_nmi_device(mca_dev, !(pos5 & 0x40)); 457 return 1; 458 } 459 return 0; 460} 461 462void __kprobes mca_handle_nmi(void) 463{ 464 /* First try - scan the various adapters and see if a specific 465 * adapter was responsible for the error. 466 */ 467 bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback); 468 469 mca_nmi_hook(); 470} /* mca_handle_nmi */ 471