// SPDX-License-Identifier: GPL-2.0+/* * IBM Hot Plug Controller Driver * * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation * * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001-2003 IBM Corp. * * All rights reserved. * * Send feedback to <gregkh@us.ibm.com> * */ #include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/wait.h>#include "../pci.h"#include <asm/pci_x86.h> /* for struct irq_routing_table */#include <asm/io_apic.h>#include "ibmphp.h" #define attn_on(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_ATTNON)#define attn_off(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_ATTNOFF)#define attn_LED_blink(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_BLINKLED)#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot(sl, READ_REVLEVEL, rev)#define get_hpc_options(sl, opt) ibmphp_hpc_readslot(sl, READ_HPCOPTIONS, opt) #define DRIVER_VERSION "0.6"#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" int ibmphp_debug; static bool debug;module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debugging mode enabled or not");MODULE_LICENSE("GPL");MODULE_DESCRIPTION(DRIVER_DESC); struct pci_bus *ibmphp_pci_bus;static int max_slots; static int irqs[16]; /* PIC mode IRQs we're using so far (in case MPS * tables don't provide default info for empty slots */ static int init_flag; static inline int get_cur_bus_info(struct slot **sl){ int rc = 1; struct slot *slot_cur = *sl; debug("options = %x\n", slot_cur->ctrl->options); debug("revision = %x\n", slot_cur->ctrl->revision); if (READ_BUS_STATUS(slot_cur->ctrl)) rc = ibmphp_hpc_readslot(slot_cur, READ_BUSSTATUS, NULL); if (rc) return rc; slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED(slot_cur->busstatus); if (READ_BUS_MODE(slot_cur->ctrl)) slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE(slot_cur->busstatus); else slot_cur->bus_on->current_bus_mode = 0xFF; debug("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); *sl = slot_cur; return 0;} static inline int slot_update(struct slot **sl){ int rc; rc = ibmphp_hpc_readslot(*sl, READ_ALLSTAT, NULL); if (rc) return rc; if (!init_flag) rc = get_cur_bus_info(sl); return rc;} static int __init get_max_slots(void){ struct slot *slot_cur; u8 slot_count = 0; list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { /* sometimes the hot-pluggable slots start with 4 (not always from 1) */ slot_count = max(slot_count, slot_cur->number); } return slot_count;} /* This routine will put the correct slot->device information per slot. It's * called from initialization of the slot structures. It will also assign * interrupt numbers per each slot. * Parameters: struct slot * Returns 0 or errors */int ibmphp_init_devno(struct slot **cur_slot){ struct irq_routing_table *rtable; int len; int loop; int i; rtable = pcibios_get_irq_routing_table(); if (!rtable) { err("no BIOS routing table...\n"); return -ENOMEM; } len = (rtable->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); if (!len) { kfree(rtable); return -1; } for (loop = 0; loop < len; loop++) { if ((*cur_slot)->number == rtable->slots[loop].slot && (*cur_slot)->bus == rtable->slots[loop].bus) { (*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn); for (i = 0; i < 4; i++) (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); debug("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); debug("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); debug("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); debug("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); debug("rtable->exclusive_irqs = %x\n", rtable->exclusive_irqs); debug("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); debug("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); debug("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); debug("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); debug("rtable->slots[loop].irq[0].link = %x\n", rtable->slots[loop].irq[0].link); debug("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); debug("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); debug("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); debug("end of init_devno\n"); kfree(rtable); return 0; } } kfree(rtable); return -1;} static inline int power_on(struct slot *slot_cur){ u8 cmd = HPC_SLOT_ON; int retval; retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) { err("power on failed\n"); return retval; } if (CTLR_RESULT(slot_cur->ctrl->status)) { err("command not completed successfully in power_on\n"); return -EIO; } msleep(3000); /* For ServeRAID cards, and some 66 PCI */ return 0;} static inline int power_off(struct slot *slot_cur){ u8 cmd = HPC_SLOT_OFF; int retval; retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) { err("power off failed\n"); return retval; } if (CTLR_RESULT(slot_cur->ctrl->status)) { err("command not completed successfully in power_off\n"); retval = -EIO; } return retval;} static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value){ int rc = 0; struct slot *pslot; u8 cmd = 0x00; /* avoid compiler warning */ debug("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); ibmphp_lock_operations(); if (hotplug_slot) { switch (value) { case HPC_SLOT_ATTN_OFF: cmd = HPC_SLOT_ATTNOFF; break; case HPC_SLOT_ATTN_ON: cmd = HPC_SLOT_ATTNON; break; case HPC_SLOT_ATTN_BLINK: cmd = HPC_SLOT_BLINKLED; break; default: rc = -ENODEV; err("set_attention_status - Error : invalid input [%x]\n", value); break; } if (rc == 0) { pslot = to_slot(hotplug_slot); rc = ibmphp_hpc_writeslot(pslot, cmd); } } else rc = -ENODEV; ibmphp_unlock_operations(); debug("set_attention_status - Exit rc[%d]\n", rc); return rc;} static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) rc = ibmphp_hpc_readslot(pslot, READ_EXTSLOTSTATUS, &myslot.ext_status); if (!rc) *value = SLOT_ATTN(myslot.status, myslot.ext_status); } ibmphp_unlock_operations(); debug("get_attention_status - Exit rc[%d] value[%x]\n", rc, *value); return rc;} static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) *value = SLOT_LATCH(myslot.status); } ibmphp_unlock_operations(); debug("get_latch_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc;} static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) *value = SLOT_PWRGD(myslot.status); } ibmphp_unlock_operations(); debug("get_power_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc;} static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value){ int rc = -ENODEV; struct slot *pslot; u8 present; struct slot myslot; debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) { present = SLOT_PRESENT(myslot.status); if (present == HPC_SLOT_EMPTY) *value = 0; else *value = 1; } } ibmphp_unlock_operations(); debug("get_adapter_present - Exit rc[%d] value[%x]\n", rc, *value); return rc;} static int get_max_bus_speed(struct slot *slot){ int rc = 0; u8 mode = 0; enum pci_bus_speed speed; struct pci_bus *bus = slot->hotplug_slot.pci_slot->bus; debug("%s - Entry slot[%p]\n", __func__, slot); ibmphp_lock_operations(); mode = slot->supported_bus_mode; speed = slot->supported_speed; ibmphp_unlock_operations(); switch (speed) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX) speed += 0x01; break; case BUS_SPEED_100: case BUS_SPEED_133: speed += 0x01; break; default: /* Note (will need to change): there would be soon 256, 512 also */ rc = -ENODEV; } if (!rc) bus->max_bus_speed = speed; debug("%s - Exit rc[%d] speed[%x]\n", __func__, rc, speed); return rc;} /**************************************************************************** * This routine will initialize the ops data structure used in the validate * function. It will also power off empty slots that are powered on since BIOS * leaves those on, albeit disconnected ****************************************************************************/static int __init init_ops(void){ struct slot *slot_cur; int retval; int rc; list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { debug("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); if (slot_cur->ctrl->revision == 0xFF) if (get_ctrl_revision(slot_cur, &slot_cur->ctrl->revision)) return -1; if (slot_cur->bus_on->current_speed == 0xFF) if (get_cur_bus_info(&slot_cur)) return -1; get_max_bus_speed(slot_cur); if (slot_cur->ctrl->options == 0xFF) if (get_hpc_options(slot_cur, &slot_cur->ctrl->options)) return -1; retval = slot_update(&slot_cur); if (retval) return retval; debug("status = %x\n", slot_cur->status); debug("ext_status = %x\n", slot_cur->ext_status); debug("SLOT_POWER = %x\n", SLOT_POWER(slot_cur->status)); debug("SLOT_PRESENT = %x\n", SLOT_PRESENT(slot_cur->status)); debug("SLOT_LATCH = %x\n", SLOT_LATCH(slot_cur->status)); if ((SLOT_PWRGD(slot_cur->status)) && !(SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) { debug("BEFORE POWER OFF COMMAND\n"); rc = power_off(slot_cur); if (rc) return rc; /* retval = slot_update(&slot_cur); * if (retval) * return retval; * ibmphp_update_slot_info(slot_cur); */ } } init_flag = 0; return 0;} /* This operation will check whether the slot is within the bounds and * the operation is valid to perform on that slot * Parameters: slot, operation * Returns: 0 or error codes */static int validate(struct slot *slot_cur, int opn){ int number; int retval; if (!slot_cur) return -ENODEV; number = slot_cur->number; if ((number > max_slots) || (number < 0)) return -EBADSLT; debug("slot_number in validate is %d\n", slot_cur->number); retval = slot_update(&slot_cur); if (retval) return retval; switch (opn) { case ENABLE: if (!(SLOT_PWRGD(slot_cur->status)) && (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; break; case DISABLE: if ((SLOT_PWRGD(slot_cur->status)) && (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; break; default: break; } err("validate failed....\n"); return -EINVAL;} /**************************************************************************** * This routine is for updating the data structures in the hotplug core * Parameters: struct slot * Returns: 0 or error ****************************************************************************/int ibmphp_update_slot_info(struct slot *slot_cur){Lines 1–500 of 1252. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * IBM Hot Plug Controller Driver * * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation * * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001-2003 IBM Corp. * * All rights reserved. * * Send feedback to <gregkh@us.ibm.com> * */ #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/wait.h> #include "../pci.h" #include <asm/pci_x86.h> /* for struct irq_routing_table */ #include <asm/io_apic.h> #include "ibmphp.h" #define attn_on(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_ATTNON) #define attn_off(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_ATTNOFF) #define attn_LED_blink(sl) ibmphp_hpc_writeslot(sl, HPC_SLOT_BLINKLED) #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot(sl, READ_REVLEVEL, rev) #define get_hpc_options(sl, opt) ibmphp_hpc_readslot(sl, READ_HPCOPTIONS, opt) #define DRIVER_VERSION "0.6" #define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" int ibmphp_debug; static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRIVER_DESC); struct pci_bus *ibmphp_pci_bus; static int max_slots; static int irqs[16]; /* PIC mode IRQs we're using so far (in case MPS * tables don't provide default info for empty slots */ static int init_flag; static inline int get_cur_bus_info(struct slot **sl) { int rc = 1; struct slot *slot_cur = *sl; debug("options = %x\n", slot_cur->ctrl->options); debug("revision = %x\n", slot_cur->ctrl->revision); if (READ_BUS_STATUS(slot_cur->ctrl)) rc = ibmphp_hpc_readslot(slot_cur, READ_BUSSTATUS, NULL); if (rc) return rc; slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED(slot_cur->busstatus); if (READ_BUS_MODE(slot_cur->ctrl)) slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE(slot_cur->busstatus); else slot_cur->bus_on->current_bus_mode = 0xFF; debug("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); *sl = slot_cur; return 0; } static inline int slot_update(struct slot **sl) { int rc; rc = ibmphp_hpc_readslot(*sl, READ_ALLSTAT, NULL); if (rc) return rc; if (!init_flag) rc = get_cur_bus_info(sl); return rc; } static int __init get_max_slots(void) { struct slot *slot_cur; u8 slot_count = 0; list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { /* sometimes the hot-pluggable slots start with 4 (not always from 1) */ slot_count = max(slot_count, slot_cur->number); } return slot_count; } /* This routine will put the correct slot->device information per slot. It's * called from initialization of the slot structures. It will also assign * interrupt numbers per each slot. * Parameters: struct slot * Returns 0 or errors */ int ibmphp_init_devno(struct slot **cur_slot) { struct irq_routing_table *rtable; int len; int loop; int i; rtable = pcibios_get_irq_routing_table(); if (!rtable) { err("no BIOS routing table...\n"); return -ENOMEM; } len = (rtable->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); if (!len) { kfree(rtable); return -1; } for (loop = 0; loop < len; loop++) { if ((*cur_slot)->number == rtable->slots[loop].slot && (*cur_slot)->bus == rtable->slots[loop].bus) { (*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn); for (i = 0; i < 4; i++) (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); debug("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); debug("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); debug("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); debug("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); debug("rtable->exclusive_irqs = %x\n", rtable->exclusive_irqs); debug("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); debug("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); debug("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); debug("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); debug("rtable->slots[loop].irq[0].link = %x\n", rtable->slots[loop].irq[0].link); debug("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); debug("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); debug("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); debug("end of init_devno\n"); kfree(rtable); return 0; } } kfree(rtable); return -1; } static inline int power_on(struct slot *slot_cur) { u8 cmd = HPC_SLOT_ON; int retval; retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) { err("power on failed\n"); return retval; } if (CTLR_RESULT(slot_cur->ctrl->status)) { err("command not completed successfully in power_on\n"); return -EIO; } msleep(3000); /* For ServeRAID cards, and some 66 PCI */ return 0; } static inline int power_off(struct slot *slot_cur) { u8 cmd = HPC_SLOT_OFF; int retval; retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) { err("power off failed\n"); return retval; } if (CTLR_RESULT(slot_cur->ctrl->status)) { err("command not completed successfully in power_off\n"); retval = -EIO; } return retval; } static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value) { int rc = 0; struct slot *pslot; u8 cmd = 0x00; /* avoid compiler warning */ debug("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); ibmphp_lock_operations(); if (hotplug_slot) { switch (value) { case HPC_SLOT_ATTN_OFF: cmd = HPC_SLOT_ATTNOFF; break; case HPC_SLOT_ATTN_ON: cmd = HPC_SLOT_ATTNON; break; case HPC_SLOT_ATTN_BLINK: cmd = HPC_SLOT_BLINKLED; break; default: rc = -ENODEV; err("set_attention_status - Error : invalid input [%x]\n", value); break; } if (rc == 0) { pslot = to_slot(hotplug_slot); rc = ibmphp_hpc_writeslot(pslot, cmd); } } else rc = -ENODEV; ibmphp_unlock_operations(); debug("set_attention_status - Exit rc[%d]\n", rc); return rc; } static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) rc = ibmphp_hpc_readslot(pslot, READ_EXTSLOTSTATUS, &myslot.ext_status); if (!rc) *value = SLOT_ATTN(myslot.status, myslot.ext_status); } ibmphp_unlock_operations(); debug("get_attention_status - Exit rc[%d] value[%x]\n", rc, *value); return rc; } static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) *value = SLOT_LATCH(myslot.status); } ibmphp_unlock_operations(); debug("get_latch_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc; } static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) *value = SLOT_PWRGD(myslot.status); } ibmphp_unlock_operations(); debug("get_power_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc; } static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value) { int rc = -ENODEV; struct slot *pslot; u8 present; struct slot myslot; debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations(); if (hotplug_slot) { pslot = to_slot(hotplug_slot); memcpy(&myslot, pslot, sizeof(struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &myslot.status); if (!rc) { present = SLOT_PRESENT(myslot.status); if (present == HPC_SLOT_EMPTY) *value = 0; else *value = 1; } } ibmphp_unlock_operations(); debug("get_adapter_present - Exit rc[%d] value[%x]\n", rc, *value); return rc; } static int get_max_bus_speed(struct slot *slot) { int rc = 0; u8 mode = 0; enum pci_bus_speed speed; struct pci_bus *bus = slot->hotplug_slot.pci_slot->bus; debug("%s - Entry slot[%p]\n", __func__, slot); ibmphp_lock_operations(); mode = slot->supported_bus_mode; speed = slot->supported_speed; ibmphp_unlock_operations(); switch (speed) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX) speed += 0x01; break; case BUS_SPEED_100: case BUS_SPEED_133: speed += 0x01; break; default: /* Note (will need to change): there would be soon 256, 512 also */ rc = -ENODEV; } if (!rc) bus->max_bus_speed = speed; debug("%s - Exit rc[%d] speed[%x]\n", __func__, rc, speed); return rc; } /**************************************************************************** * This routine will initialize the ops data structure used in the validate * function. It will also power off empty slots that are powered on since BIOS * leaves those on, albeit disconnected ****************************************************************************/ static int __init init_ops(void) { struct slot *slot_cur; int retval; int rc; list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { debug("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); if (slot_cur->ctrl->revision == 0xFF) if (get_ctrl_revision(slot_cur, &slot_cur->ctrl->revision)) return -1; if (slot_cur->bus_on->current_speed == 0xFF) if (get_cur_bus_info(&slot_cur)) return -1; get_max_bus_speed(slot_cur); if (slot_cur->ctrl->options == 0xFF) if (get_hpc_options(slot_cur, &slot_cur->ctrl->options)) return -1; retval = slot_update(&slot_cur); if (retval) return retval; debug("status = %x\n", slot_cur->status); debug("ext_status = %x\n", slot_cur->ext_status); debug("SLOT_POWER = %x\n", SLOT_POWER(slot_cur->status)); debug("SLOT_PRESENT = %x\n", SLOT_PRESENT(slot_cur->status)); debug("SLOT_LATCH = %x\n", SLOT_LATCH(slot_cur->status)); if ((SLOT_PWRGD(slot_cur->status)) && !(SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) { debug("BEFORE POWER OFF COMMAND\n"); rc = power_off(slot_cur); if (rc) return rc; /* retval = slot_update(&slot_cur); * if (retval) * return retval; * ibmphp_update_slot_info(slot_cur); */ } } init_flag = 0; return 0; } /* This operation will check whether the slot is within the bounds and * the operation is valid to perform on that slot * Parameters: slot, operation * Returns: 0 or error codes */ static int validate(struct slot *slot_cur, int opn) { int number; int retval; if (!slot_cur) return -ENODEV; number = slot_cur->number; if ((number > max_slots) || (number < 0)) return -EBADSLT; debug("slot_number in validate is %d\n", slot_cur->number); retval = slot_update(&slot_cur); if (retval) return retval; switch (opn) { case ENABLE: if (!(SLOT_PWRGD(slot_cur->status)) && (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; break; case DISABLE: if ((SLOT_PWRGD(slot_cur->status)) && (SLOT_PRESENT(slot_cur->status)) && !(SLOT_LATCH(slot_cur->status))) return 0; break; default: break; } err("validate failed....\n"); return -EINVAL; } /**************************************************************************** * This routine is for updating the data structures in the hotplug core * Parameters: struct slot * Returns: 0 or error ****************************************************************************/ int ibmphp_update_slot_info(struct slot *slot_cur) {