| 1 | |
| 2 | |
| 3 | * IBM Hot Plug Controller Driver
|
| 4 | *
|
| 5 | * Written By: Tong Yu, IBM Corporation
|
| 6 | *
|
| 7 | * Copyright (C) 2001,2003 Greg Kroah-Hartman ([email protected])
|
| 8 | * Copyright (C) 2001-2003 IBM Corp.
|
| 9 | *
|
| 10 | * All rights reserved.
|
| 11 | *
|
| 12 | * Send feedback to <[email protected]>
|
| 13 | *
|
| 14 |
|
| 15 |
|
| 16 | #include <linux/module.h>
|
| 17 | #include <linux/errno.h>
|
| 18 | #include <linux/mm.h>
|
| 19 | #include <linux/slab.h>
|
| 20 | #include <linux/pci.h>
|
| 21 | #include <linux/list.h>
|
| 22 | #include <linux/init.h>
|
| 23 | #include "ibmphp.h"
|
| 24 |
|
| 25 | |
| 26 | * POST builds data blocks(in this data block definition, a char-1
|
| 27 | * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
|
| 28 | * BIOS Data Area which describe the configuration of the hot-plug
|
| 29 | * controllers and resources used by the PCI Hot-Plug devices.
|
| 30 | *
|
| 31 | * This file walks EBDA, maps data block from physical addr,
|
| 32 | * reconstruct linked lists about all system resource(MEM, PFM, IO)
|
| 33 | * already assigned by POST, as well as linked lists about hot plug
|
| 34 | * controllers (ctlr#, slot#, bus&slot features...)
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 | LIST_HEAD(ibmphp_ebda_pci_rsrc_head);
|
| 39 | LIST_HEAD(ibmphp_slot_head);
|
| 40 |
|
| 41 |
|
| 42 | static struct ebda_hpc_list *hpc_list_ptr;
|
| 43 | static struct ebda_rsrc_list *rsrc_list_ptr;
|
| 44 | static struct rio_table_hdr *rio_table_ptr = NULL;
|
| 45 | static LIST_HEAD(ebda_hpc_head);
|
| 46 | static LIST_HEAD(bus_info_head);
|
| 47 | static LIST_HEAD(rio_vg_head);
|
| 48 | static LIST_HEAD(rio_lo_head);
|
| 49 | static LIST_HEAD(opt_vg_head);
|
| 50 | static LIST_HEAD(opt_lo_head);
|
| 51 | static void __iomem *io_mem;
|
| 52 |
|
| 53 |
|
| 54 | static int ebda_rsrc_controller(void);
|
| 55 | static int ebda_rsrc_rsrc(void);
|
| 56 | static int ebda_rio_table(void);
|
| 57 |
|
| 58 | static struct ebda_hpc_list * __init alloc_ebda_hpc_list(void)
|
| 59 | {
|
| 60 | return kzalloc_obj(struct ebda_hpc_list);
|
| 61 | }
|
| 62 |
|
| 63 | static struct controller *alloc_ebda_hpc(u32 slot_count, u32 bus_count)
|
| 64 | {
|
| 65 | struct controller *controller;
|
| 66 | struct ebda_hpc_slot *slots;
|
| 67 | struct ebda_hpc_bus *buses;
|
| 68 |
|
| 69 | controller = kzalloc_obj(struct controller);
|
| 70 | if (!controller)
|
| 71 | goto error;
|
| 72 |
|
| 73 | slots = kzalloc_objs(struct ebda_hpc_slot, slot_count);
|
| 74 | if (!slots)
|
| 75 | goto error_contr;
|
| 76 | controller->slots = slots;
|
| 77 |
|
| 78 | buses = kzalloc_objs(struct ebda_hpc_bus, bus_count);
|
| 79 | if (!buses)
|
| 80 | goto error_slots;
|
| 81 | controller->buses = buses;
|
| 82 |
|
| 83 | return controller;
|
| 84 | error_slots:
|
| 85 | kfree(controller->slots);
|
| 86 | error_contr:
|
| 87 | kfree(controller);
|
| 88 | error:
|
| 89 | return NULL;
|
| 90 | }
|
| 91 |
|
| 92 | static void free_ebda_hpc(struct controller *controller)
|
| 93 | {
|
| 94 | kfree(controller->slots);
|
| 95 | kfree(controller->buses);
|
| 96 | kfree(controller);
|
| 97 | }
|
| 98 |
|
| 99 | static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list(void)
|
| 100 | {
|
| 101 | return kzalloc_obj(struct ebda_rsrc_list);
|
| 102 | }
|
| 103 |
|
| 104 | static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc(void)
|
| 105 | {
|
| 106 | return kzalloc_obj(struct ebda_pci_rsrc);
|
| 107 | }
|
| 108 |
|
| 109 | static void __init print_bus_info(void)
|
| 110 | {
|
| 111 | struct bus_info *ptr;
|
| 112 |
|
| 113 | list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
|
| 114 | debug("%s - slot_min = %x\n", __func__, ptr->slot_min);
|
| 115 | debug("%s - slot_max = %x\n", __func__, ptr->slot_max);
|
| 116 | debug("%s - slot_count = %x\n", __func__, ptr->slot_count);
|
| 117 | debug("%s - bus# = %x\n", __func__, ptr->busno);
|
| 118 | debug("%s - current_speed = %x\n", __func__, ptr->current_speed);
|
| 119 | debug("%s - controller_id = %x\n", __func__, ptr->controller_id);
|
| 120 |
|
| 121 | debug("%s - slots_at_33_conv = %x\n", __func__, ptr->slots_at_33_conv);
|
| 122 | debug("%s - slots_at_66_conv = %x\n", __func__, ptr->slots_at_66_conv);
|
| 123 | debug("%s - slots_at_66_pcix = %x\n", __func__, ptr->slots_at_66_pcix);
|
| 124 | debug("%s - slots_at_100_pcix = %x\n", __func__, ptr->slots_at_100_pcix);
|
| 125 | debug("%s - slots_at_133_pcix = %x\n", __func__, ptr->slots_at_133_pcix);
|
| 126 |
|
| 127 | }
|
| 128 | }
|
| 129 |
|
| 130 | static void print_lo_info(void)
|
| 131 | {
|
| 132 | struct rio_detail *ptr;
|
| 133 | debug("print_lo_info ----\n");
|
| 134 | list_for_each_entry(ptr, &rio_lo_head, rio_detail_list) {
|
| 135 | debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
|
| 136 | debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
|
| 137 | debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
|
| 138 | debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
|
| 139 | debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
|
| 140 | debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
|
| 141 |
|
| 142 | }
|
| 143 | }
|
| 144 |
|
| 145 | static void print_vg_info(void)
|
| 146 | {
|
| 147 | struct rio_detail *ptr;
|
| 148 | debug("%s ---\n", __func__);
|
| 149 | list_for_each_entry(ptr, &rio_vg_head, rio_detail_list) {
|
| 150 | debug("%s - rio_node_id = %x\n", __func__, ptr->rio_node_id);
|
| 151 | debug("%s - rio_type = %x\n", __func__, ptr->rio_type);
|
| 152 | debug("%s - owner_id = %x\n", __func__, ptr->owner_id);
|
| 153 | debug("%s - first_slot_num = %x\n", __func__, ptr->first_slot_num);
|
| 154 | debug("%s - wpindex = %x\n", __func__, ptr->wpindex);
|
| 155 | debug("%s - chassis_num = %x\n", __func__, ptr->chassis_num);
|
| 156 |
|
| 157 | }
|
| 158 | }
|
| 159 |
|
| 160 | static void __init print_ebda_pci_rsrc(void)
|
| 161 | {
|
| 162 | struct ebda_pci_rsrc *ptr;
|
| 163 |
|
| 164 | list_for_each_entry(ptr, &ibmphp_ebda_pci_rsrc_head, ebda_pci_rsrc_list) {
|
| 165 | debug("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
|
| 166 | __func__, ptr->rsrc_type, ptr->bus_num, ptr->dev_fun, ptr->start_addr, ptr->end_addr);
|
| 167 | }
|
| 168 | }
|
| 169 |
|
| 170 | static void __init print_ibm_slot(void)
|
| 171 | {
|
| 172 | struct slot *ptr;
|
| 173 |
|
| 174 | list_for_each_entry(ptr, &ibmphp_slot_head, ibm_slot_list) {
|
| 175 | debug("%s - slot_number: %x\n", __func__, ptr->number);
|
| 176 | }
|
| 177 | }
|
| 178 |
|
| 179 | static void __init print_opt_vg(void)
|
| 180 | {
|
| 181 | struct opt_rio *ptr;
|
| 182 | debug("%s ---\n", __func__);
|
| 183 | list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
|
| 184 | debug("%s - rio_type %x\n", __func__, ptr->rio_type);
|
| 185 | debug("%s - chassis_num: %x\n", __func__, ptr->chassis_num);
|
| 186 | debug("%s - first_slot_num: %x\n", __func__, ptr->first_slot_num);
|
| 187 | debug("%s - middle_num: %x\n", __func__, ptr->middle_num);
|
| 188 | }
|
| 189 | }
|
| 190 |
|
| 191 | static void __init print_ebda_hpc(void)
|
| 192 | {
|
| 193 | struct controller *hpc_ptr;
|
| 194 | u16 index;
|
| 195 |
|
| 196 | list_for_each_entry(hpc_ptr, &ebda_hpc_head, ebda_hpc_list) {
|
| 197 | for (index = 0; index < hpc_ptr->slot_count; index++) {
|
| 198 | debug("%s - physical slot#: %x\n", __func__, hpc_ptr->slots[index].slot_num);
|
| 199 | debug("%s - pci bus# of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_bus_num);
|
| 200 | debug("%s - index into ctlr addr: %x\n", __func__, hpc_ptr->slots[index].ctl_index);
|
| 201 | debug("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap);
|
| 202 | }
|
| 203 |
|
| 204 | for (index = 0; index < hpc_ptr->bus_count; index++)
|
| 205 | debug("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num);
|
| 206 |
|
| 207 | debug("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type);
|
| 208 | switch (hpc_ptr->ctlr_type) {
|
| 209 | case 1:
|
| 210 | debug("%s - bus: %x\n", __func__, hpc_ptr->u.pci_ctlr.bus);
|
| 211 | debug("%s - dev_fun: %x\n", __func__, hpc_ptr->u.pci_ctlr.dev_fun);
|
| 212 | debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
|
| 213 | break;
|
| 214 |
|
| 215 | case 0:
|
| 216 | debug("%s - io_start: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_start);
|
| 217 | debug("%s - io_end: %x\n", __func__, hpc_ptr->u.isa_ctlr.io_end);
|
| 218 | debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
|
| 219 | break;
|
| 220 |
|
| 221 | case 2:
|
| 222 | case 4:
|
| 223 | debug("%s - wpegbbar: %lx\n", __func__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
|
| 224 | debug("%s - i2c_addr: %x\n", __func__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
|
| 225 | debug("%s - irq: %x\n", __func__, hpc_ptr->irq);
|
| 226 | break;
|
| 227 | }
|
| 228 | }
|
| 229 | }
|
| 230 |
|
| 231 | int __init ibmphp_access_ebda(void)
|
| 232 | {
|
| 233 | u8 format, num_ctlrs, rio_complete, hs_complete, ebda_sz;
|
| 234 | u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
|
| 235 | int rc = 0;
|
| 236 |
|
| 237 |
|
| 238 | rio_complete = 0;
|
| 239 | hs_complete = 0;
|
| 240 |
|
| 241 | io_mem = ioremap((0x40 << 4) + 0x0e, 2);
|
| 242 | if (!io_mem)
|
| 243 | return -ENOMEM;
|
| 244 | ebda_seg = readw(io_mem);
|
| 245 | iounmap(io_mem);
|
| 246 | debug("returned ebda segment: %x\n", ebda_seg);
|
| 247 |
|
| 248 | io_mem = ioremap(ebda_seg<<4, 1);
|
| 249 | if (!io_mem)
|
| 250 | return -ENOMEM;
|
| 251 | ebda_sz = readb(io_mem);
|
| 252 | iounmap(io_mem);
|
| 253 | debug("ebda size: %d(KiB)\n", ebda_sz);
|
| 254 | if (ebda_sz == 0)
|
| 255 | return -ENOMEM;
|
| 256 |
|
| 257 | io_mem = ioremap(ebda_seg<<4, (ebda_sz * 1024));
|
| 258 | if (!io_mem)
|
| 259 | return -ENOMEM;
|
| 260 | next_offset = 0x180;
|
| 261 |
|
| 262 | for (;;) {
|
| 263 | offset = next_offset;
|
| 264 |
|
| 265 |
|
| 266 | if (WARN(offset > (ebda_sz * 1024 - 4),
|
| 267 | "ibmphp_ebda: next read is beyond ebda_sz\n"))
|
| 268 | break;
|
| 269 |
|
| 270 | next_offset = readw(io_mem + offset);
|
| 271 |
|
| 272 | offset += 2;
|
| 273 | if (next_offset == 0)
|
| 274 | break;
|
| 275 | blk_id = readw(io_mem + offset);
|
| 276 |
|
| 277 | offset += 2;
|
| 278 |
|
| 279 | if (blk_id != 0x4853 && blk_id != 0x4752)
|
| 280 | continue;
|
| 281 |
|
| 282 | if (blk_id == 0x4853) {
|
| 283 | debug("now enter hot swap block---\n");
|
| 284 | debug("hot blk id: %x\n", blk_id);
|
| 285 | format = readb(io_mem + offset);
|
| 286 |
|
| 287 | offset += 1;
|
| 288 | if (format != 4)
|
| 289 | goto error_nodev;
|
| 290 | debug("hot blk format: %x\n", format);
|
| 291 |
|
| 292 | base = offset;
|
| 293 |
|
| 294 | sub_addr = base;
|
| 295 | re = readw(io_mem + sub_addr);
|
| 296 |
|
| 297 | sub_addr += 2;
|
| 298 | rc_id = readw(io_mem + sub_addr);
|
| 299 |
|
| 300 | sub_addr += 2;
|
| 301 | if (rc_id != 0x5243)
|
| 302 | goto error_nodev;
|
| 303 |
|
| 304 | num_ctlrs = readb(io_mem + sub_addr);
|
| 305 |
|
| 306 | sub_addr += 1;
|
| 307 | hpc_list_ptr = alloc_ebda_hpc_list();
|
| 308 | if (!hpc_list_ptr) {
|
| 309 | rc = -ENOMEM;
|
| 310 | goto out;
|
| 311 | }
|
| 312 | hpc_list_ptr->format = format;
|
| 313 | hpc_list_ptr->num_ctlrs = num_ctlrs;
|
| 314 | hpc_list_ptr->phys_addr = sub_addr;
|
| 315 | debug("info about hpc descriptor---\n");
|
| 316 | debug("hot blk format: %x\n", format);
|
| 317 | debug("num of controller: %x\n", num_ctlrs);
|
| 318 | debug("offset of hpc data structure entries: %x\n ", sub_addr);
|
| 319 |
|
| 320 | sub_addr = base + re;
|
| 321 |
|
| 322 | rc = readw(io_mem + sub_addr);
|
| 323 |
|
| 324 | sub_addr += 2;
|
| 325 | re_id = readw(io_mem + sub_addr);
|
| 326 |
|
| 327 | sub_addr += 2;
|
| 328 | if (re_id != 0x5245)
|
| 329 | goto error_nodev;
|
| 330 |
|
| 331 |
|
| 332 | num_entries = readw(io_mem + sub_addr);
|
| 333 |
|
| 334 | sub_addr += 2;
|
| 335 | rsrc_list_ptr = alloc_ebda_rsrc_list();
|
| 336 | if (!rsrc_list_ptr) {
|
| 337 | rc = -ENOMEM;
|
| 338 | goto out;
|
| 339 | }
|
| 340 | rsrc_list_ptr->format = format;
|
| 341 | rsrc_list_ptr->num_entries = num_entries;
|
| 342 | rsrc_list_ptr->phys_addr = sub_addr;
|
| 343 |
|
| 344 | debug("info about rsrc descriptor---\n");
|
| 345 | debug("format: %x\n", format);
|
| 346 | debug("num of rsrc: %x\n", num_entries);
|
| 347 | debug("offset of rsrc data structure entries: %x\n ", sub_addr);
|
| 348 |
|
| 349 | hs_complete = 1;
|
| 350 | } else {
|
| 351 |
|
| 352 | debug("now enter io table ---\n");
|
| 353 | debug("rio blk id: %x\n", blk_id);
|
| 354 |
|
| 355 | rio_table_ptr = kzalloc_obj(struct rio_table_hdr);
|
| 356 | if (!rio_table_ptr) {
|
| 357 | rc = -ENOMEM;
|
| 358 | goto out;
|
| 359 | }
|
| 360 | rio_table_ptr->ver_num = readb(io_mem + offset);
|
| 361 | rio_table_ptr->scal_count = readb(io_mem + offset + 1);
|
| 362 | rio_table_ptr->riodev_count = readb(io_mem + offset + 2);
|
| 363 | rio_table_ptr->offset = offset + 3 ;
|
| 364 |
|
| 365 | debug("info about rio table hdr ---\n");
|
| 366 | debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
|
| 367 | rio_table_ptr->ver_num, rio_table_ptr->scal_count,
|
| 368 | rio_table_ptr->riodev_count, rio_table_ptr->offset);
|
| 369 |
|
| 370 | rio_complete = 1;
|
| 371 | }
|
| 372 | }
|
| 373 |
|
| 374 | if (!hs_complete && !rio_complete)
|
| 375 | goto error_nodev;
|
| 376 |
|
| 377 | if (rio_table_ptr) {
|
| 378 | if (rio_complete && rio_table_ptr->ver_num == 3) {
|
| 379 | rc = ebda_rio_table();
|
| 380 | if (rc)
|
| 381 | goto out;
|
| 382 | }
|
| 383 | }
|
| 384 | rc = ebda_rsrc_controller();
|
| 385 | if (rc)
|
| 386 | goto out;
|
| 387 |
|
| 388 | rc = ebda_rsrc_rsrc();
|
| 389 | goto out;
|
| 390 | error_nodev:
|
| 391 | rc = -ENODEV;
|
| 392 | out:
|
| 393 | iounmap(io_mem);
|
| 394 | return rc;
|
| 395 | }
|
| 396 |
|
| 397 | |
| 398 | * map info of scalability details and rio details from physical address
|
| 399 |
|
| 400 | static int __init ebda_rio_table(void)
|
| 401 | {
|
| 402 | u16 offset;
|
| 403 | u8 i;
|
| 404 | struct rio_detail *rio_detail_ptr;
|
| 405 |
|
| 406 | offset = rio_table_ptr->offset;
|
| 407 | offset += 12 * rio_table_ptr->scal_count;
|
| 408 |
|
| 409 | |
| 410 | for (i = 0; i < rio_table_ptr->riodev_count; i++) {
|
| 411 | rio_detail_ptr = kzalloc_obj(struct rio_detail);
|
| 412 | if (!rio_detail_ptr)
|
| 413 | return -ENOMEM;
|
| 414 | rio_detail_ptr->rio_node_id = readb(io_mem + offset);
|
| 415 | rio_detail_ptr->bbar = readl(io_mem + offset + 1);
|
| 416 | rio_detail_ptr->rio_type = readb(io_mem + offset + 5);
|
| 417 | rio_detail_ptr->owner_id = readb(io_mem + offset + 6);
|
| 418 | rio_detail_ptr->port0_node_connect = readb(io_mem + offset + 7);
|
| 419 | rio_detail_ptr->port0_port_connect = readb(io_mem + offset + 8);
|
| 420 | rio_detail_ptr->port1_node_connect = readb(io_mem + offset + 9);
|
| 421 | rio_detail_ptr->port1_port_connect = readb(io_mem + offset + 10);
|
| 422 | rio_detail_ptr->first_slot_num = readb(io_mem + offset + 11);
|
| 423 | rio_detail_ptr->status = readb(io_mem + offset + 12);
|
| 424 | rio_detail_ptr->wpindex = readb(io_mem + offset + 13);
|
| 425 | rio_detail_ptr->chassis_num = readb(io_mem + offset + 14);
|
| 426 | |
| 427 | |
| 428 | if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5)
|
| 429 | list_add(&rio_detail_ptr->rio_detail_list, &rio_vg_head);
|
| 430 | |
| 431 | else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7)
|
| 432 | list_add(&rio_detail_ptr->rio_detail_list, &rio_lo_head);
|
| 433 | else
|
| 434 | |
| 435 | kfree(rio_detail_ptr);
|
| 436 | offset += 15;
|
| 437 | }
|
| 438 | print_lo_info();
|
| 439 | print_vg_info();
|
| 440 | return 0;
|
| 441 | }
|
| 442 |
|
| 443 | |
| 444 | * reorganizing linked list of chassis
|
| 445 |
|
| 446 | static struct opt_rio *search_opt_vg(u8 chassis_num)
|
| 447 | {
|
| 448 | struct opt_rio *ptr;
|
| 449 | list_for_each_entry(ptr, &opt_vg_head, opt_rio_list) {
|
| 450 | if (ptr->chassis_num == chassis_num)
|
| 451 | return ptr;
|
| 452 | }
|
| 453 | return NULL;
|
| 454 | }
|
| 455 |
|
| 456 | static int __init combine_wpg_for_chassis(void)
|
| 457 | {
|
| 458 | struct opt_rio *opt_rio_ptr = NULL;
|
| 459 | struct rio_detail *rio_detail_ptr = NULL;
|
| 460 |
|
| 461 | list_for_each_entry(rio_detail_ptr, &rio_vg_head, rio_detail_list) {
|
| 462 | opt_rio_ptr = search_opt_vg(rio_detail_ptr->chassis_num);
|
| 463 | if (!opt_rio_ptr) {
|
| 464 | opt_rio_ptr = kzalloc_obj(struct opt_rio);
|
| 465 | if (!opt_rio_ptr)
|
| 466 | return -ENOMEM;
|
| 467 | opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
|
| 468 | opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
|
| 469 | opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
|
| 470 | opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
|
| 471 | list_add(&opt_rio_ptr->opt_rio_list, &opt_vg_head);
|
| 472 | } else {
|
| 473 | opt_rio_ptr->first_slot_num = min(opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
|
| 474 | opt_rio_ptr->middle_num = max(opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
|
| 475 | }
|
| 476 | }
|
| 477 | print_opt_vg();
|
| 478 | return 0;
|
| 479 | }
|
| 480 |
|
| 481 | |
| 482 | * reorganizing linked list of expansion box
|
| 483 |
|
| 484 | static struct opt_rio_lo *search_opt_lo(u8 chassis_num)
|
| 485 | {
|
| 486 | struct opt_rio_lo *ptr;
|
| 487 | list_for_each_entry(ptr, &opt_lo_head, opt_rio_lo_list) {
|
| 488 | if (ptr->chassis_num == chassis_num)
|
| 489 | return ptr;
|
| 490 | }
|
| 491 | return NULL;
|
| 492 | }
|
| 493 |
|
| 494 | static int combine_wpg_for_expansion(void)
|
| 495 | {
|
| 496 | struct opt_rio_lo *opt_rio_lo_ptr = NULL;
|
| 497 | struct rio_detail *rio_detail_ptr = NULL;
|
| 498 |
|
| 499 | list_for_each_entry(rio_detail_ptr, &rio_lo_head, rio_detail_list) {
|
| 500 | opt_rio_lo_ptr = search_opt_lo(rio_detail_ptr->chassis_num);
|
| 501 | if (!opt_rio_lo_ptr) {
|
| 502 | opt_rio_lo_ptr = kzalloc_obj(struct opt_rio_lo);
|
| 503 | if (!opt_rio_lo_ptr)
|
| 504 | return -ENOMEM;
|
| 505 | opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
|
| 506 | opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
|
| 507 | opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
|
| 508 | opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
|
| 509 | opt_rio_lo_ptr->pack_count = 1;
|
| 510 |
|
| 511 | list_add(&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
|
| 512 | } else {
|
| 513 | opt_rio_lo_ptr->first_slot_num = min(opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
|
| 514 | opt_rio_lo_ptr->middle_num = max(opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
|
| 515 | opt_rio_lo_ptr->pack_count = 2;
|
| 516 | }
|
| 517 | }
|
| 518 | return 0;
|
| 519 | }
|
| 520 |
|
| 521 |
|
| 522 | |
| 523 | * through the list of all chassis to find out the range
|
| 524 | * Arguments: slot_num, 1st slot number of the chassis we think we are on,
|
| 525 | * var (0 = chassis, 1 = expansion box)
|
| 526 |
|
| 527 | static int first_slot_num(u8 slot_num, u8 first_slot, u8 var)
|
| 528 | {
|
| 529 | struct opt_rio *opt_vg_ptr = NULL;
|
| 530 | struct opt_rio_lo *opt_lo_ptr = NULL;
|
| 531 | int rc = 0;
|
| 532 |
|
| 533 | if (!var) {
|
| 534 | list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
|
| 535 | if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) {
|
| 536 | rc = -ENODEV;
|
| 537 | break;
|
| 538 | }
|
| 539 | }
|
| 540 | } else {
|
| 541 | list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
|
| 542 | if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
|
| 543 | rc = -ENODEV;
|
| 544 | break;
|
| 545 | }
|
| 546 | }
|
| 547 | }
|
| 548 | return rc;
|
| 549 | }
|
| 550 |
|
| 551 | static struct opt_rio_lo *find_rxe_num(u8 slot_num)
|
| 552 | {
|
| 553 | struct opt_rio_lo *opt_lo_ptr;
|
| 554 |
|
| 555 | list_for_each_entry(opt_lo_ptr, &opt_lo_head, opt_rio_lo_list) {
|
| 556 | |
| 557 | if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_lo_ptr->first_slot_num, 1)))
|
| 558 | return opt_lo_ptr;
|
| 559 | }
|
| 560 | return NULL;
|
| 561 | }
|
| 562 |
|
| 563 | static struct opt_rio *find_chassis_num(u8 slot_num)
|
| 564 | {
|
| 565 | struct opt_rio *opt_vg_ptr;
|
| 566 |
|
| 567 | list_for_each_entry(opt_vg_ptr, &opt_vg_head, opt_rio_list) {
|
| 568 | |
| 569 | if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num(slot_num, opt_vg_ptr->first_slot_num, 0)))
|
| 570 | return opt_vg_ptr;
|
| 571 | }
|
| 572 | return NULL;
|
| 573 | }
|
| 574 |
|
| 575 | |
| 576 | * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
|
| 577 |
|
| 578 | static u8 calculate_first_slot(u8 slot_num)
|
| 579 | {
|
| 580 | u8 first_slot = 1;
|
| 581 | struct slot *slot_cur;
|
| 582 |
|
| 583 | list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) {
|
| 584 | if (slot_cur->ctrl) {
|
| 585 | if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num))
|
| 586 | first_slot = slot_cur->ctrl->ending_slot_num;
|
| 587 | }
|
| 588 | }
|
| 589 | return first_slot + 1;
|
| 590 |
|
| 591 | }
|
| 592 |
|
| 593 | #define SLOT_NAME_SIZE 30
|
| 594 |
|
| 595 | static char *create_file_name(struct slot *slot_cur)
|
| 596 | {
|
| 597 | struct opt_rio *opt_vg_ptr = NULL;
|
| 598 | struct opt_rio_lo *opt_lo_ptr = NULL;
|
| 599 | static char str[SLOT_NAME_SIZE];
|
| 600 | int which = 0;
|
| 601 | u8 number = 1;
|
| 602 | u8 first_slot = 1;
|
| 603 | u8 slot_num;
|
| 604 | u8 flag = 0;
|
| 605 |
|
| 606 | if (!slot_cur) {
|
| 607 | err("Structure passed is empty\n");
|
| 608 | return NULL;
|
| 609 | }
|
| 610 |
|
| 611 | slot_num = slot_cur->number;
|
| 612 |
|
| 613 | memset(str, 0, sizeof(str));
|
| 614 |
|
| 615 | if (rio_table_ptr) {
|
| 616 | if (rio_table_ptr->ver_num == 3) {
|
| 617 | opt_vg_ptr = find_chassis_num(slot_num);
|
| 618 | opt_lo_ptr = find_rxe_num(slot_num);
|
| 619 | }
|
| 620 | }
|
| 621 | if (opt_vg_ptr) {
|
| 622 | if (opt_lo_ptr) {
|
| 623 | if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
|
| 624 | number = opt_lo_ptr->chassis_num;
|
| 625 | first_slot = opt_lo_ptr->first_slot_num;
|
| 626 | which = 1;
|
| 627 | } else {
|
| 628 | first_slot = opt_vg_ptr->first_slot_num;
|
| 629 | number = opt_vg_ptr->chassis_num;
|
| 630 | which = 0;
|
| 631 | }
|
| 632 | } else {
|
| 633 | first_slot = opt_vg_ptr->first_slot_num;
|
| 634 | number = opt_vg_ptr->chassis_num;
|
| 635 | which = 0;
|
| 636 | }
|
| 637 | ++flag;
|
| 638 | } else if (opt_lo_ptr) {
|
| 639 | number = opt_lo_ptr->chassis_num;
|
| 640 | first_slot = opt_lo_ptr->first_slot_num;
|
| 641 | which = 1;
|
| 642 | ++flag;
|
| 643 | } else if (rio_table_ptr) {
|
| 644 | if (rio_table_ptr->ver_num == 3) {
|
| 645 |
|
| 646 | return NULL;
|
| 647 | }
|
| 648 | }
|
| 649 | if (!flag) {
|
| 650 | if (slot_cur->ctrl->ctlr_type == 4) {
|
| 651 | first_slot = calculate_first_slot(slot_num);
|
| 652 | which = 1;
|
| 653 | } else {
|
| 654 | which = 0;
|
| 655 | }
|
| 656 | }
|
| 657 |
|
| 658 | sprintf(str, "%s%dslot%d",
|
| 659 | which == 0 ? "chassis" : "rxe",
|
| 660 | number, slot_num - first_slot + 1);
|
| 661 | return str;
|
| 662 | }
|
| 663 |
|
| 664 | static int fillslotinfo(struct hotplug_slot *hotplug_slot)
|
| 665 | {
|
| 666 | struct slot *slot;
|
| 667 | int rc = 0;
|
| 668 |
|
| 669 | slot = to_slot(hotplug_slot);
|
| 670 | rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
|
| 671 | return rc;
|
| 672 | }
|
| 673 |
|
| 674 | static struct pci_driver ibmphp_driver;
|
| 675 |
|
| 676 | |
| 677 | * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
|
| 678 | * each hpc from physical address to a list of hot plug controllers based on
|
| 679 | * hpc descriptors.
|
| 680 |
|
| 681 | static int __init ebda_rsrc_controller(void)
|
| 682 | {
|
| 683 | u16 addr, addr_slot, addr_bus;
|
| 684 | u8 ctlr_id, temp, bus_index;
|
| 685 | u16 ctlr, slot, bus;
|
| 686 | u16 slot_num, bus_num, index;
|
| 687 | struct controller *hpc_ptr;
|
| 688 | struct ebda_hpc_bus *bus_ptr;
|
| 689 | struct ebda_hpc_slot *slot_ptr;
|
| 690 | struct bus_info *bus_info_ptr1, *bus_info_ptr2;
|
| 691 | int rc;
|
| 692 | struct slot *tmp_slot;
|
| 693 | char name[SLOT_NAME_SIZE];
|
| 694 |
|
| 695 | addr = hpc_list_ptr->phys_addr;
|
| 696 | for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
|
| 697 | bus_index = 1;
|
| 698 | ctlr_id = readb(io_mem + addr);
|
| 699 | addr += 1;
|
| 700 | slot_num = readb(io_mem + addr);
|
| 701 |
|
| 702 | addr += 1;
|
| 703 | addr_slot = addr;
|
| 704 | addr += (slot_num * 4);
|
| 705 |
|
| 706 | bus_num = readb(io_mem + addr);
|
| 707 |
|
| 708 | addr += 1;
|
| 709 | addr_bus = addr;
|
| 710 | addr += (bus_num * 9);
|
| 711 | temp = readb(io_mem + addr);
|
| 712 |
|
| 713 | addr += 1;
|
| 714 |
|
| 715 | hpc_ptr = alloc_ebda_hpc(slot_num, bus_num);
|
| 716 | if (!hpc_ptr) {
|
| 717 | return -ENOMEM;
|
| 718 | }
|
| 719 | hpc_ptr->ctlr_id = ctlr_id;
|
| 720 | hpc_ptr->ctlr_relative_id = ctlr;
|
| 721 | hpc_ptr->slot_count = slot_num;
|
| 722 | hpc_ptr->bus_count = bus_num;
|
| 723 | debug("now enter ctlr data structure ---\n");
|
| 724 | debug("ctlr id: %x\n", ctlr_id);
|
| 725 | debug("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
|
| 726 | debug("count of slots controlled by this ctlr: %x\n", slot_num);
|
| 727 | debug("count of buses controlled by this ctlr: %x\n", bus_num);
|
| 728 |
|
| 729 |
|
| 730 | slot_ptr = hpc_ptr->slots;
|
| 731 | for (slot = 0; slot < slot_num; slot++) {
|
| 732 | slot_ptr->slot_num = readb(io_mem + addr_slot);
|
| 733 | slot_ptr->slot_bus_num = readb(io_mem + addr_slot + slot_num);
|
| 734 | slot_ptr->ctl_index = readb(io_mem + addr_slot + 2*slot_num);
|
| 735 | slot_ptr->slot_cap = readb(io_mem + addr_slot + 3*slot_num);
|
| 736 |
|
| 737 | |
| 738 |
|
| 739 | bus_info_ptr2 = ibmphp_find_same_bus_num(slot_ptr->slot_bus_num);
|
| 740 | if (!bus_info_ptr2) {
|
| 741 | bus_info_ptr1 = kzalloc_obj(struct bus_info);
|
| 742 | if (!bus_info_ptr1) {
|
| 743 | rc = -ENOMEM;
|
| 744 | goto error_no_slot;
|
| 745 | }
|
| 746 | bus_info_ptr1->slot_min = slot_ptr->slot_num;
|
| 747 | bus_info_ptr1->slot_max = slot_ptr->slot_num;
|
| 748 | bus_info_ptr1->slot_count += 1;
|
| 749 | bus_info_ptr1->busno = slot_ptr->slot_bus_num;
|
| 750 | bus_info_ptr1->index = bus_index++;
|
| 751 | bus_info_ptr1->current_speed = 0xff;
|
| 752 | bus_info_ptr1->current_bus_mode = 0xff;
|
| 753 |
|
| 754 | bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
|
| 755 |
|
| 756 | list_add_tail(&bus_info_ptr1->bus_info_list, &bus_info_head);
|
| 757 |
|
| 758 | } else {
|
| 759 | bus_info_ptr2->slot_min = min(bus_info_ptr2->slot_min, slot_ptr->slot_num);
|
| 760 | bus_info_ptr2->slot_max = max(bus_info_ptr2->slot_max, slot_ptr->slot_num);
|
| 761 | bus_info_ptr2->slot_count += 1;
|
| 762 |
|
| 763 | }
|
| 764 |
|
| 765 | |
| 766 |
|
| 767 | slot_ptr++;
|
| 768 | addr_slot += 1;
|
| 769 | }
|
| 770 |
|
| 771 |
|
| 772 | bus_ptr = hpc_ptr->buses;
|
| 773 | for (bus = 0; bus < bus_num; bus++) {
|
| 774 | bus_ptr->bus_num = readb(io_mem + addr_bus + bus);
|
| 775 | bus_ptr->slots_at_33_conv = readb(io_mem + addr_bus + bus_num + 8 * bus);
|
| 776 | bus_ptr->slots_at_66_conv = readb(io_mem + addr_bus + bus_num + 8 * bus + 1);
|
| 777 |
|
| 778 | bus_ptr->slots_at_66_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 2);
|
| 779 |
|
| 780 | bus_ptr->slots_at_100_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 3);
|
| 781 |
|
| 782 | bus_ptr->slots_at_133_pcix = readb(io_mem + addr_bus + bus_num + 8 * bus + 4);
|
| 783 |
|
| 784 | bus_info_ptr2 = ibmphp_find_same_bus_num(bus_ptr->bus_num);
|
| 785 | if (bus_info_ptr2) {
|
| 786 | bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
|
| 787 | bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
|
| 788 | bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
|
| 789 | bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
|
| 790 | bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix;
|
| 791 | }
|
| 792 | bus_ptr++;
|
| 793 | }
|
| 794 |
|
| 795 | hpc_ptr->ctlr_type = temp;
|
| 796 |
|
| 797 | switch (hpc_ptr->ctlr_type) {
|
| 798 | case 1:
|
| 799 | hpc_ptr->u.pci_ctlr.bus = readb(io_mem + addr);
|
| 800 | hpc_ptr->u.pci_ctlr.dev_fun = readb(io_mem + addr + 1);
|
| 801 | hpc_ptr->irq = readb(io_mem + addr + 2);
|
| 802 | addr += 3;
|
| 803 | debug("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
|
| 804 | hpc_ptr->u.pci_ctlr.bus,
|
| 805 | hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
|
| 806 | break;
|
| 807 |
|
| 808 | case 0:
|
| 809 | hpc_ptr->u.isa_ctlr.io_start = readw(io_mem + addr);
|
| 810 | hpc_ptr->u.isa_ctlr.io_end = readw(io_mem + addr + 2);
|
| 811 | if (!request_region(hpc_ptr->u.isa_ctlr.io_start,
|
| 812 | (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
|
| 813 | "ibmphp")) {
|
| 814 | rc = -ENODEV;
|
| 815 | goto error_no_slot;
|
| 816 | }
|
| 817 | hpc_ptr->irq = readb(io_mem + addr + 4);
|
| 818 | addr += 5;
|
| 819 | break;
|
| 820 |
|
| 821 | case 2:
|
| 822 | case 4:
|
| 823 | hpc_ptr->u.wpeg_ctlr.wpegbbar = readl(io_mem + addr);
|
| 824 | hpc_ptr->u.wpeg_ctlr.i2c_addr = readb(io_mem + addr + 4);
|
| 825 | hpc_ptr->irq = readb(io_mem + addr + 5);
|
| 826 | addr += 6;
|
| 827 | break;
|
| 828 | default:
|
| 829 | rc = -ENODEV;
|
| 830 | goto error_no_slot;
|
| 831 | }
|
| 832 |
|
| 833 | |
| 834 | combine_wpg_for_chassis();
|
| 835 | combine_wpg_for_expansion();
|
| 836 | hpc_ptr->revision = 0xff;
|
| 837 | hpc_ptr->options = 0xff;
|
| 838 | hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
|
| 839 | hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
|
| 840 |
|
| 841 | |
| 842 | for (index = 0; index < hpc_ptr->slot_count; index++) {
|
| 843 | tmp_slot = kzalloc_obj(*tmp_slot);
|
| 844 | if (!tmp_slot) {
|
| 845 | rc = -ENOMEM;
|
| 846 | goto error_no_slot;
|
| 847 | }
|
| 848 |
|
| 849 | tmp_slot->flag = 1;
|
| 850 |
|
| 851 | tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
|
| 852 | if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
|
| 853 | tmp_slot->supported_speed = 3;
|
| 854 | else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
|
| 855 | tmp_slot->supported_speed = 2;
|
| 856 | else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
|
| 857 | tmp_slot->supported_speed = 1;
|
| 858 |
|
| 859 | if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
|
| 860 | tmp_slot->supported_bus_mode = 1;
|
| 861 | else
|
| 862 | tmp_slot->supported_bus_mode = 0;
|
| 863 |
|
| 864 |
|
| 865 | tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
|
| 866 |
|
| 867 | bus_info_ptr1 = ibmphp_find_same_bus_num(hpc_ptr->slots[index].slot_bus_num);
|
| 868 | if (!bus_info_ptr1) {
|
| 869 | rc = -ENODEV;
|
| 870 | goto error;
|
| 871 | }
|
| 872 | tmp_slot->bus_on = bus_info_ptr1;
|
| 873 | bus_info_ptr1 = NULL;
|
| 874 | tmp_slot->ctrl = hpc_ptr;
|
| 875 |
|
| 876 | tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
|
| 877 | tmp_slot->number = hpc_ptr->slots[index].slot_num;
|
| 878 |
|
| 879 | rc = fillslotinfo(&tmp_slot->hotplug_slot);
|
| 880 | if (rc)
|
| 881 | goto error;
|
| 882 |
|
| 883 | rc = ibmphp_init_devno(&tmp_slot);
|
| 884 | if (rc)
|
| 885 | goto error;
|
| 886 | tmp_slot->hotplug_slot.ops = &ibmphp_hotplug_slot_ops;
|
| 887 |
|
| 888 | |
| 889 |
|
| 890 | list_add(&tmp_slot->ibm_slot_list, &ibmphp_slot_head);
|
| 891 | }
|
| 892 |
|
| 893 | print_bus_info();
|
| 894 | list_add(&hpc_ptr->ebda_hpc_list, &ebda_hpc_head);
|
| 895 |
|
| 896 | }
|
| 897 |
|
| 898 | list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) {
|
| 899 | snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
|
| 900 | pci_hp_register(&tmp_slot->hotplug_slot,
|
| 901 | pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
|
| 902 | }
|
| 903 |
|
| 904 | print_ebda_hpc();
|
| 905 | print_ibm_slot();
|
| 906 | return 0;
|
| 907 |
|
| 908 | error:
|
| 909 | kfree(tmp_slot);
|
| 910 | error_no_slot:
|
| 911 | free_ebda_hpc(hpc_ptr);
|
| 912 | return rc;
|
| 913 | }
|
| 914 |
|
| 915 | |
| 916 | * map info (bus, devfun, start addr, end addr..) of i/o, memory,
|
| 917 | * pfm from the physical addr to a list of resource.
|
| 918 |
|
| 919 | static int __init ebda_rsrc_rsrc(void)
|
| 920 | {
|
| 921 | u16 addr;
|
| 922 | short rsrc;
|
| 923 | u8 type, rsrc_type;
|
| 924 | struct ebda_pci_rsrc *rsrc_ptr;
|
| 925 |
|
| 926 | addr = rsrc_list_ptr->phys_addr;
|
| 927 | debug("now entering rsrc land\n");
|
| 928 | debug("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
|
| 929 |
|
| 930 | for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
|
| 931 | type = readb(io_mem + addr);
|
| 932 |
|
| 933 | addr += 1;
|
| 934 | rsrc_type = type & EBDA_RSRC_TYPE_MASK;
|
| 935 |
|
| 936 | if (rsrc_type == EBDA_IO_RSRC_TYPE) {
|
| 937 | rsrc_ptr = alloc_ebda_pci_rsrc();
|
| 938 | if (!rsrc_ptr) {
|
| 939 | iounmap(io_mem);
|
| 940 | return -ENOMEM;
|
| 941 | }
|
| 942 | rsrc_ptr->rsrc_type = type;
|
| 943 |
|
| 944 | rsrc_ptr->bus_num = readb(io_mem + addr);
|
| 945 | rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
|
| 946 | rsrc_ptr->start_addr = readw(io_mem + addr + 2);
|
| 947 | rsrc_ptr->end_addr = readw(io_mem + addr + 4);
|
| 948 | addr += 6;
|
| 949 |
|
| 950 | debug("rsrc from io type ----\n");
|
| 951 | debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
|
| 952 | rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
|
| 953 |
|
| 954 | list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
|
| 955 | }
|
| 956 |
|
| 957 | if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
|
| 958 | rsrc_ptr = alloc_ebda_pci_rsrc();
|
| 959 | if (!rsrc_ptr) {
|
| 960 | iounmap(io_mem);
|
| 961 | return -ENOMEM;
|
| 962 | }
|
| 963 | rsrc_ptr->rsrc_type = type;
|
| 964 |
|
| 965 | rsrc_ptr->bus_num = readb(io_mem + addr);
|
| 966 | rsrc_ptr->dev_fun = readb(io_mem + addr + 1);
|
| 967 | rsrc_ptr->start_addr = readl(io_mem + addr + 2);
|
| 968 | rsrc_ptr->end_addr = readl(io_mem + addr + 6);
|
| 969 | addr += 10;
|
| 970 |
|
| 971 | debug("rsrc from mem or pfm ---\n");
|
| 972 | debug("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
|
| 973 | rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
|
| 974 |
|
| 975 | list_add(&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
|
| 976 | }
|
| 977 | }
|
| 978 | kfree(rsrc_list_ptr);
|
| 979 | rsrc_list_ptr = NULL;
|
| 980 | print_ebda_pci_rsrc();
|
| 981 | return 0;
|
| 982 | }
|
| 983 |
|
| 984 | u16 ibmphp_get_total_controllers(void)
|
| 985 | {
|
| 986 | return hpc_list_ptr->num_ctlrs;
|
| 987 | }
|
| 988 |
|
| 989 | struct slot *ibmphp_get_slot_from_physical_num(u8 physical_num)
|
| 990 | {
|
| 991 | struct slot *slot;
|
| 992 |
|
| 993 | list_for_each_entry(slot, &ibmphp_slot_head, ibm_slot_list) {
|
| 994 | if (slot->number == physical_num)
|
| 995 | return slot;
|
| 996 | }
|
| 997 | return NULL;
|
| 998 | }
|
| 999 |
|
| 1000 | |
| 1001 | * - the smallest slot number
|
| 1002 | * - the largest slot number
|
| 1003 | * - the total number of the slots based on each bus
|
| 1004 | * (if only one slot per bus slot_min = slot_max )
|
| 1005 |
|
| 1006 | struct bus_info *ibmphp_find_same_bus_num(u32 num)
|
| 1007 | {
|
| 1008 | struct bus_info *ptr;
|
| 1009 |
|
| 1010 | list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
|
| 1011 | if (ptr->busno == num)
|
| 1012 | return ptr;
|
| 1013 | }
|
| 1014 | return NULL;
|
| 1015 | }
|
| 1016 |
|
| 1017 | |
| 1018 | * bus register
|
| 1019 |
|
| 1020 | int ibmphp_get_bus_index(u8 num)
|
| 1021 | {
|
| 1022 | struct bus_info *ptr;
|
| 1023 |
|
| 1024 | list_for_each_entry(ptr, &bus_info_head, bus_info_list) {
|
| 1025 | if (ptr->busno == num)
|
| 1026 | return ptr->index;
|
| 1027 | }
|
| 1028 | return -ENODEV;
|
| 1029 | }
|
| 1030 |
|
| 1031 | void ibmphp_free_bus_info_queue(void)
|
| 1032 | {
|
| 1033 | struct bus_info *bus_info, *next;
|
| 1034 |
|
| 1035 | list_for_each_entry_safe(bus_info, next, &bus_info_head,
|
| 1036 | bus_info_list) {
|
| 1037 | kfree (bus_info);
|
| 1038 | }
|
| 1039 | }
|
| 1040 |
|
| 1041 | void ibmphp_free_ebda_hpc_queue(void)
|
| 1042 | {
|
| 1043 | struct controller *controller = NULL, *next;
|
| 1044 | int pci_flag = 0;
|
| 1045 |
|
| 1046 | list_for_each_entry_safe(controller, next, &ebda_hpc_head,
|
| 1047 | ebda_hpc_list) {
|
| 1048 | if (controller->ctlr_type == 0)
|
| 1049 | release_region(controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
|
| 1050 | else if ((controller->ctlr_type == 1) && (!pci_flag)) {
|
| 1051 | ++pci_flag;
|
| 1052 | pci_unregister_driver(&ibmphp_driver);
|
| 1053 | }
|
| 1054 | free_ebda_hpc(controller);
|
| 1055 | }
|
| 1056 | }
|
| 1057 |
|
| 1058 | void ibmphp_free_ebda_pci_rsrc_queue(void)
|
| 1059 | {
|
| 1060 | struct ebda_pci_rsrc *resource, *next;
|
| 1061 |
|
| 1062 | list_for_each_entry_safe(resource, next, &ibmphp_ebda_pci_rsrc_head,
|
| 1063 | ebda_pci_rsrc_list) {
|
| 1064 | kfree (resource);
|
| 1065 | resource = NULL;
|
| 1066 | }
|
| 1067 | }
|
| 1068 |
|
| 1069 | static const struct pci_device_id id_table[] = {
|
| 1070 | {
|
| 1071 | .vendor = PCI_VENDOR_ID_IBM,
|
| 1072 | .device = HPC_DEVICE_ID,
|
| 1073 | .subvendor = PCI_VENDOR_ID_IBM,
|
| 1074 | .subdevice = HPC_SUBSYSTEM_ID,
|
| 1075 | .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
|
| 1076 | }, {}
|
| 1077 | };
|
| 1078 |
|
| 1079 | MODULE_DEVICE_TABLE(pci, id_table);
|
| 1080 |
|
| 1081 | static int ibmphp_probe(struct pci_dev *, const struct pci_device_id *);
|
| 1082 | static struct pci_driver ibmphp_driver = {
|
| 1083 | .name = "ibmphp",
|
| 1084 | .id_table = id_table,
|
| 1085 | .probe = ibmphp_probe,
|
| 1086 | };
|
| 1087 |
|
| 1088 | int ibmphp_register_pci(void)
|
| 1089 | {
|
| 1090 | struct controller *ctrl;
|
| 1091 | int rc = 0;
|
| 1092 |
|
| 1093 | list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
|
| 1094 | if (ctrl->ctlr_type == 1) {
|
| 1095 | rc = pci_register_driver(&ibmphp_driver);
|
| 1096 | break;
|
| 1097 | }
|
| 1098 | }
|
| 1099 | return rc;
|
| 1100 | }
|
| 1101 | static int ibmphp_probe(struct pci_dev *dev, const struct pci_device_id *ids)
|
| 1102 | {
|
| 1103 | struct controller *ctrl;
|
| 1104 |
|
| 1105 | debug("inside ibmphp_probe\n");
|
| 1106 |
|
| 1107 | list_for_each_entry(ctrl, &ebda_hpc_head, ebda_hpc_list) {
|
| 1108 | if (ctrl->ctlr_type == 1) {
|
| 1109 | if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
|
| 1110 | ctrl->ctrl_dev = dev;
|
| 1111 | debug("found device!!!\n");
|
| 1112 | debug("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
|
| 1113 | return 0;
|
| 1114 | }
|
| 1115 | }
|
| 1116 | }
|
| 1117 | return -ENODEV;
|
| 1118 | }
|