patch-2.4.19 linux-2.4.19/drivers/hotplug/ibmphp_core.c
Next file: linux-2.4.19/drivers/hotplug/ibmphp_ebda.c
Previous file: linux-2.4.19/drivers/hotplug/ibmphp.h
Back to the patch index
Back to the overall index
- Lines: 1481
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/drivers/hotplug/ibmphp_core.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.18/drivers/hotplug/ibmphp_core.c linux-2.4.19/drivers/hotplug/ibmphp_core.c
@@ -0,0 +1,1480 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 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 <linux/smp_lock.h>
+#include "../../arch/i386/kernel/pci-i386.h" /* for struct irq_routing_table */
+#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.1"
+#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver"
+
+int ibmphp_debug;
+
+static int debug;
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "Debugging mode enabled or not");
+MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+static int *ops[MAX_OPS + 1];
+struct pci_ops *ibmphp_pci_root_ops;
+static int max_slots;
+
+static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */
+
+static int init_flag;
+
+/*
+static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8);
+
+static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value)
+{
+ return get_max_adapter_speed_1 (hs, value, 1);
+}
+*/
+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);
+
+ 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)
+ return get_cur_bus_info (sl);
+ return rc;
+}
+
+static int get_max_slots (void)
+{
+ struct list_head * tmp;
+ int slot_count = 0;
+
+ list_for_each (tmp, &ibmphp_slot_head)
+ ++slot_count;
+ 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)
+ return -1;
+ for (loop = 0; loop < len; loop++) {
+ if ((*cur_slot)->number == rtable->slots[loop].slot) {
+ if ((*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->exlusive_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");
+ return 0;
+ }
+ }
+ }
+
+ 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;
+ }
+ long_delay (3 * HZ); /* 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");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
+{
+ int rc = 0;
+ struct slot *pslot;
+ u8 cmd;
+ int hpcrc = 0;
+
+ debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value);
+ ibmphp_lock_operations ();
+ cmd = 0x00; // avoid compiler warning
+
+ 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 = (struct slot *) hotplug_slot->private;
+ if (pslot)
+ hpcrc = ibmphp_hpc_writeslot (pslot, cmd);
+ else
+ rc = -ENODEV;
+ }
+ } else
+ rc = -ENODEV;
+
+ if (hpcrc)
+ rc = hpcrc;
+
+ 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;
+ int hpcrc = 0;
+ 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 && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+ if (!hpcrc)
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status));
+ if (!hpcrc) {
+ *value = SLOT_ATTN (myslot.status, myslot.ext_status);
+ rc = 0;
+ }
+ }
+ } else
+ rc = -ENODEV;
+
+ if (hpcrc)
+ rc = hpcrc;
+
+ ibmphp_unlock_operations ();
+ debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+ return rc;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ int hpcrc = 0;
+ 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 && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+ if (!hpcrc) {
+ *value = SLOT_LATCH (myslot.status);
+ rc = 0;
+ }
+ }
+ } else
+ rc = -ENODEV;
+
+ if (hpcrc)
+ rc = hpcrc;
+
+ ibmphp_unlock_operations ();
+ debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+ return rc;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ int hpcrc = 0;
+ 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 && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+ if (!hpcrc) {
+ *value = SLOT_POWER (myslot.status);
+ rc = 0;
+ }
+ }
+ } else
+ rc = -ENODEV;
+
+ if (hpcrc)
+ rc = hpcrc;
+
+ ibmphp_unlock_operations ();
+ debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+ return rc;
+}
+
+static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ u8 present;
+ int hpcrc = 0;
+ 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 && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+ if (!hpcrc) {
+ present = SLOT_PRESENT (myslot.status);
+ if (present == HPC_SLOT_EMPTY)
+ *value = 0;
+ else
+ *value = 1;
+ rc = 0;
+ }
+ }
+ } else
+ rc = -ENODEV;
+ if (hpcrc)
+ rc = hpcrc;
+
+ ibmphp_unlock_operations ();
+ debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+ return rc;
+}
+/*
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ u8 mode = 0;
+
+ debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+ ibmphp_lock_operations ();
+
+ if (hotplug_slot && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ rc = 0;
+ mode = pslot->bus_on->supported_bus_mode;
+ *value = pslot->bus_on->supported_speed;
+ *value &= 0x0f;
+
+ if (mode == BUS_MODE_PCIX)
+ *value |= 0x80;
+ else if (mode == BUS_MODE_PCI)
+ *value |= 0x40;
+ else
+ *value |= 0x20;
+ }
+ } else
+ rc = -ENODEV;
+
+ ibmphp_unlock_operations ();
+ debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+ return rc;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ u8 mode = 0;
+
+ debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+ ibmphp_lock_operations ();
+
+ if (hotplug_slot && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ rc = get_cur_bus_info (&pslot);
+ if (!rc) {
+ mode = pslot->bus_on->current_bus_mode;
+ *value = pslot->bus_on->current_speed;
+ *value &= 0x0f;
+
+ if (mode == BUS_MODE_PCIX)
+ *value |= 0x80;
+ else if (mode == BUS_MODE_PCI)
+ *value |= 0x40;
+ else
+ *value |= 0x20;
+ }
+ }
+ } else
+ rc = -ENODEV;
+
+ ibmphp_unlock_operations ();
+ debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+ return rc;
+}
+
+static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
+{
+ int rc = -ENODEV;
+ struct slot *pslot;
+ int hpcrc = 0;
+ struct slot myslot;
+
+ debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+ if (flag)
+ ibmphp_lock_operations ();
+
+ if (hotplug_slot && value) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+
+ if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) {
+ hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status));
+ if (!hpcrc) {
+ *value = SLOT_SPEED (myslot.ext_status);
+ rc = 0;
+ }
+ } else {
+ *value = MAX_ADAPTER_NONE;
+ rc = 0;
+ }
+ }
+ } else
+ rc = -ENODEV;
+
+ if (hpcrc)
+ rc = hpcrc;
+
+ if (flag)
+ ibmphp_unlock_operations ();
+
+ debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+ return rc;
+}
+
+static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
+{
+ int rc = -ENODEV;
+ struct slot *pslot = NULL;
+ struct pci_dev * dev = NULL;
+
+ debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
+
+ ibmphp_lock_operations ();
+
+ if (hotplug_slot) {
+ pslot = (struct slot *) hotplug_slot->private;
+ if (pslot) {
+ rc = 0;
+ if (pslot->func)
+ dev = pslot->func->dev;
+ else
+ dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7));
+ if (dev)
+ snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name);
+ else
+ snprintf (value, 100, "Bus %d", pslot->bus);
+
+
+ }
+ } else
+ rc = -ENODEV;
+
+ ibmphp_unlock_operations ();
+ debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value);
+ 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_ops (void)
+{
+ struct slot *slot_cur;
+ int retval;
+ int j;
+ int rc;
+
+ for (j = 0; j < MAX_OPS; j++) {
+ ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL);
+ if (!ops[j]) {
+ err ("out of system memory \n");
+ return -ENOMEM;
+ }
+ }
+
+ ops[ADD][0] = 0;
+ ops[REMOVE][0] = 0;
+ ops[DETAIL][0] = 0;
+
+ for (j = 1; j <= max_slots; j++) {
+
+ slot_cur = ibmphp_get_slot_from_physical_num (j);
+
+ 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;
+
+ 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, ext_status = %x\n", slot_cur->status, slot_cur->ext_status);
+ debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status));
+
+ if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+ /* No power, adapter, and latch closed */
+ ops[ADD][j] = 1;
+ else
+ ops[ADD][j] = 0;
+
+ ops[DETAIL][j] = 1;
+
+ if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+ /*Power,adapter,latch closed */
+ ops[REMOVE][j] = 1;
+ else
+ ops[REMOVE][j] = 0;
+
+ if ((SLOT_POWER (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;
+
+ if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+ && !(SLOT_LATCH (slot_cur->status)))
+ ops[ADD][number] = 1;
+ else
+ ops[ADD][number] = 0;
+
+ ops[DETAIL][number] = 1;
+
+ if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+ && !(SLOT_LATCH (slot_cur->status)))
+ ops[REMOVE][number] = 1;
+ else
+ ops[REMOVE][number] = 0;
+
+ switch (opn) {
+ case ENABLE:
+ if (ops[ADD][number])
+ return 0;
+ break;
+ case DISABLE:
+ if (ops[REMOVE][number])
+ return 0;
+ break;
+ case DETAIL:
+ if (ops[DETAIL][number])
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ 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)
+{
+ struct hotplug_slot_info *info;
+ char buffer[10];
+ int rc;
+// u8 bus_speed;
+
+ info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+ if (!info) {
+ err ("out of system memory \n");
+ return -ENOMEM;
+ }
+
+ snprintf (buffer, 10, "%d", slot_cur->number);
+ info->power_status = SLOT_POWER (slot_cur->status);
+ info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
+ info->latch_status = SLOT_LATCH (slot_cur->status);
+ if (!SLOT_PRESENT (slot_cur->status)) {
+ info->adapter_status = 0;
+// info->max_adapter_speed_status = MAX_ADAPTER_NONE;
+ } else {
+ info->adapter_status = 1;
+// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0);
+ }
+/*
+ bus_speed = slot_cur->bus_on->current_speed;
+ bus_speed &= 0x0f;
+
+ if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+ bus_speed |= 0x80;
+ else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI)
+ bus_speed |= 0x40;
+ else
+ bus_speed |= 0x20;
+
+ info->cur_bus_speed_status = bus_speed;
+ info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status;
+ // To do: card_bus_names
+*/
+ rc = pci_hp_change_slot_info (buffer, info);
+ kfree (info);
+ return rc;
+}
+
+
+/******************************************************************************
+ * This function will return the pci_func, given bus and devfunc, or NULL. It
+ * is called from visit routines
+ ******************************************************************************/
+
+static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function)
+{
+ struct pci_func *func_cur;
+ struct slot *slot_cur;
+ struct list_head * tmp;
+ list_for_each (tmp, &ibmphp_slot_head) {
+ slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+ if (slot_cur->func) {
+ func_cur = slot_cur->func;
+ while (func_cur) {
+ if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function))
+ return func_cur;
+ func_cur = func_cur->next;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* This routine is to find the pci_bus from kernel structures.
+ * Parameters: bus number
+ * Returns : pci_bus * or NULL if not found
+ */
+static struct pci_bus *find_bus (u8 busno)
+{
+ const struct list_head *tmp;
+ struct pci_bus *bus;
+ debug ("inside find_bus, busno = %x \n", busno);
+
+ list_for_each (tmp, &pci_root_buses) {
+ bus = (struct pci_bus *) pci_bus_b (tmp);
+ if (bus)
+ if (bus->number == busno)
+ return bus;
+ }
+ return NULL;
+}
+
+/******************************************************************
+ * This function is here because we can no longer use pci_root_ops
+ ******************************************************************/
+static struct pci_ops *get_root_pci_ops (void)
+{
+ struct pci_bus * bus;
+
+ if ((bus = find_bus (0)))
+ return bus->ops;
+ return NULL;
+}
+
+/*************************************************************
+ * This routine frees up memory used by struct slot, including
+ * the pointers to pci_func, bus, hotplug_slot, controller,
+ * and deregistering from the hotplug core
+ *************************************************************/
+static void free_slots (void)
+{
+ struct slot *slot_cur;
+ struct list_head * tmp;
+ struct list_head * next;
+
+ list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+
+ slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+
+ pci_hp_deregister (slot_cur->hotplug_slot);
+
+ if (slot_cur->hotplug_slot) {
+ kfree (slot_cur->hotplug_slot);
+ slot_cur->hotplug_slot = NULL;
+ }
+
+ if (slot_cur->ctrl)
+ slot_cur->ctrl = NULL;
+
+ if (slot_cur->bus_on)
+ slot_cur->bus_on = NULL;
+
+ ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */
+
+ kfree (slot_cur);
+ }
+}
+
+static int ibm_is_pci_dev_in_use (struct pci_dev *dev)
+{
+ int i = 0;
+ int inuse = 0;
+
+ if (dev->driver)
+ return 1;
+
+ for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+
+ if (!pci_resource_start (dev, i))
+ continue;
+
+ if (pci_resource_flags (dev, i) & IORESOURCE_IO)
+ inuse = check_region (pci_resource_start (dev, i), pci_resource_len (dev, i));
+
+ else if (pci_resource_flags (dev, i) & IORESOURCE_MEM)
+ inuse = check_mem_region (pci_resource_start (dev, i), pci_resource_len (dev, i));
+ }
+
+ return inuse;
+}
+
+static int ibm_pci_hp_remove_device (struct pci_dev *dev)
+{
+ if (ibm_is_pci_dev_in_use (dev)) {
+ err ("***Cannot safely power down device -- it appears to be in use***\n");
+ return -EBUSY;
+ }
+ pci_remove_device (dev);
+ return 0;
+}
+
+static int ibm_unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+ struct pci_dev *dev = wrapped_dev->dev;
+ struct pci_func *temp_func;
+ int i = 0;
+
+ do {
+ temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++);
+ } while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+ if (dev) {
+ if (ibm_pci_hp_remove_device (dev) == 0)
+ kfree (dev); /* Now, remove */
+ else
+ return -1;
+ }
+
+ if (temp_func)
+ temp_func->dev = NULL;
+ else
+ err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+
+ return 0;
+}
+
+static int ibm_unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev)
+{
+ struct pci_bus *bus = wrapped_bus->bus;
+
+ pci_proc_detach_bus (bus);
+ /* The cleanup code should live in the kernel... */
+ bus->self->subordinate = NULL;
+ /* unlink from parent bus */
+ list_del (&bus->node);
+
+ /* Now, remove */
+ if (bus)
+ kfree (bus);
+
+ return 0;
+}
+
+static int ibm_unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+ struct pci_dev *dev = wrapped_dev->dev;
+
+ debug ("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn));
+
+ /* Now, remove the Linux Driver Representation */
+ if (dev->driver) {
+ debug ("is there a driver?\n");
+ if (dev->driver->remove) {
+ dev->driver->remove (dev);
+ debug ("driver was properly removed\n");
+ }
+ dev->driver = NULL;
+ }
+
+ return ibm_is_pci_dev_in_use (dev);
+}
+
+static struct pci_visit ibm_unconfigure_functions_phase1 = {
+ post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase1,
+};
+
+static struct pci_visit ibm_unconfigure_functions_phase2 = {
+ post_visit_pci_bus: ibm_unconfigure_visit_pci_bus_phase2,
+ post_visit_pci_dev: ibm_unconfigure_visit_pci_dev_phase2,
+};
+
+static int ibm_unconfigure_device (struct pci_func *func)
+{
+ int rc = 0;
+ struct pci_dev_wrapped wrapped_dev;
+ struct pci_bus_wrapped wrapped_bus;
+ struct pci_dev *temp;
+ u8 j;
+
+ memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+ memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+ debug ("inside ibm_unconfigure_device\n");
+ debug ("func->device = %x, func->function = %x\n", func->device, func->function);
+ debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0);
+
+ for (j = 0; j < 0x08; j++) {
+ temp = pci_find_slot (func->busno, (func->device << 3) | j);
+ if (temp) {
+ wrapped_dev.dev = temp;
+ wrapped_bus.bus = temp->bus;
+ rc = pci_visit_dev (&ibm_unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+ if (rc)
+ break;
+
+ rc = pci_visit_dev (&ibm_unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+ if (rc)
+ break;
+ }
+ }
+ debug ("rc in ibm_unconfigure_device b4 returning is %d \n", rc);
+ return rc;
+}
+
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+ // struct pci_bus *bus = wrapped_bus->bus; /* We don't need this, since we don't create in the else statement */
+ struct pci_dev *dev = wrapped_dev->dev;
+ struct pci_func *temp_func;
+ int i = 0;
+
+ do {
+ temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++);
+ } while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+ if (temp_func)
+ temp_func->dev = dev;
+ else {
+ /* This should not really happen, since we create functions
+ first and then call to configure */
+ debug (" We shouldn't come here \n");
+ }
+
+ if (temp_func->dev) {
+ pci_proc_attach_device (temp_func->dev);
+ pci_announce_device_to_drivers (temp_func->dev);
+ }
+
+ return 0;
+}
+
+static struct pci_visit configure_functions = {
+ visit_pci_dev: configure_visit_pci_dev,
+};
+
+static int ibm_configure_device (struct pci_func *func)
+{
+ unsigned char bus;
+ struct pci_dev dev0;
+ struct pci_bus *child;
+ struct pci_dev *temp;
+ int rc = 0;
+
+ struct pci_dev_wrapped wrapped_dev;
+ struct pci_bus_wrapped wrapped_bus;
+
+ memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+ memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+ memset (&dev0, 0, sizeof (struct pci_dev));
+
+ if (func->dev == NULL)
+ func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
+
+ if (func->dev == NULL) {
+ dev0.bus = find_bus (func->busno);
+ dev0.devfn = ((func->device << 3) + (func->function & 0x7));
+ dev0.sysdata = dev0.bus->sysdata;
+
+ func->dev = pci_scan_slot (&dev0);
+
+ if (func->dev == NULL) {
+ err ("ERROR... : pci_dev still NULL \n");
+ return 0;
+ }
+ }
+ if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus);
+ child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus);
+ pci_do_scan_bus (child);
+ }
+
+ temp = func->dev;
+ if (temp) {
+ wrapped_dev.dev = temp;
+ wrapped_bus.bus = temp->bus;
+ rc = pci_visit_dev (&configure_functions, &wrapped_dev, &wrapped_bus);
+ }
+ return rc;
+}
+/*******************************************************
+ * Returns whether the bus is empty or not
+ *******************************************************/
+static int is_bus_empty (struct slot * slot_cur)
+{
+ int rc;
+ struct slot * tmp_slot;
+ u8 i = slot_cur->bus_on->slot_min;
+
+ while (i <= slot_cur->bus_on->slot_max) {
+ if (i == slot_cur->number) {
+ i++;
+ continue;
+ }
+ tmp_slot = ibmphp_get_slot_from_physical_num (i);
+ rc = slot_update (&tmp_slot);
+ if (rc)
+ return 0;
+ if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status))
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+/***********************************************************
+ * If the HPC permits and the bus currently empty, tries to set the
+ * bus speed and mode at the maximum card capability
+ ***********************************************************/
+static int set_bus (struct slot * slot_cur)
+{
+ int rc;
+ u8 speed;
+ u8 cmd = 0x0;
+
+ debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number);
+ if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
+ rc = slot_update (&slot_cur);
+ if (rc)
+ return rc;
+ speed = SLOT_SPEED (slot_cur->ext_status);
+ debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed);
+ switch (speed) {
+ case HPC_SLOT_SPEED_33:
+ cmd = HPC_BUS_33CONVMODE;
+ break;
+ case HPC_SLOT_SPEED_66:
+ if (SLOT_PCIX (slot_cur->ext_status))
+ cmd = HPC_BUS_66PCIXMODE;
+ else
+ cmd = HPC_BUS_66CONVMODE;
+ break;
+ case HPC_SLOT_SPEED_133:
+ if (slot_cur->bus_on->slot_count > 1)
+ cmd = HPC_BUS_100PCIXMODE;
+ else
+ cmd = HPC_BUS_133PCIXMODE;
+ break;
+ default:
+ err ("wrong slot speed \n");
+ return -ENODEV;
+ }
+ debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
+ rc = ibmphp_hpc_writeslot (slot_cur, cmd);
+ if (rc)
+ return rc;
+ }
+ debug ("%s -Exit \n", __FUNCTION__);
+ return 0;
+}
+
+static inline void print_card_capability (struct slot *slot_cur)
+{
+ info ("capability of the card is ");
+ if ((slot_cur->ext_status & CARD_INFO) == PCIX133)
+ info (" 133 MHz PCI-X \n");
+ else if ((slot_cur->ext_status & CARD_INFO) == PCIX66)
+ info (" 66 MHz PCI-X \n");
+ else if ((slot_cur->ext_status & CARD_INFO) == PCI66)
+ info (" 66 MHz PCI \n");
+ else
+ info (" 33 MHz PCI \n");
+
+}
+
+/* This routine will power on the slot, configure the device(s) and find the
+ * drivers for them.
+ * Parameters: hotplug_slot
+ * Returns: 0 or failure codes
+ */
+static int enable_slot (struct hotplug_slot *hs)
+{
+ int rc, i, rcpr;
+ struct slot *slot_cur;
+ u8 function;
+ u8 faulted = 0;
+ struct pci_func *tmp_func;
+
+ ibmphp_lock_operations ();
+
+ debug ("ENABLING SLOT........ \n");
+ slot_cur = (struct slot *) hs->private;
+
+ if ((rc = validate (slot_cur, ENABLE))) {
+ err ("validate function failed \n");
+ attn_off (slot_cur); /* need to turn off if was blinking b4 */
+ attn_on (slot_cur);
+ rc = slot_update (&slot_cur);
+ if (rc) {
+ ibmphp_unlock_operations();
+ return rc;
+ }
+ ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+
+ attn_LED_blink (slot_cur);
+
+ rc = set_bus (slot_cur);
+ if (rc) {
+ err ("was not able to set the bus \n");
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ ibmphp_unlock_operations ();
+ return -ENODEV;
+ }
+
+ rc = power_on (slot_cur);
+
+ if (rc) {
+ err ("something wrong when powering up... please see below for details\n");
+ /* need to turn off before on, otherwise, blinking overwrites */
+ attn_off(slot_cur);
+ attn_on (slot_cur);
+ if (slot_update (&slot_cur)) {
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ ibmphp_unlock_operations ();
+ return -ENODEV;
+ }
+ /* Check to see the error of why it failed */
+ if (!(SLOT_PWRGD (slot_cur->status)))
+ err ("power fault occured trying to power up \n");
+ else if (SLOT_BUS_SPEED (slot_cur->status)) {
+ err ("bus speed mismatch occured. please check current bus speed and card capability \n");
+ print_card_capability (slot_cur);
+ } else if (SLOT_BUS_MODE (slot_cur->ext_status))
+ err ("bus mode mismatch occured. please check current bus mode and card capability \n");
+
+ ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+ debug ("after power_on\n");
+
+ rc = slot_update (&slot_cur);
+ if (rc) {
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ rcpr = power_off (slot_cur);
+ if (rcpr) {
+ ibmphp_unlock_operations ();
+ return rcpr;
+ }
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+
+ if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
+ faulted = 1;
+ err ("power fault occured trying to power up...\n");
+ } else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
+ faulted = 1;
+ err ("bus speed mismatch occured. please check current bus speed and card capability \n");
+ print_card_capability (slot_cur);
+ }
+ /* Don't think this case will happen after above checks... but just in case, for paranoia sake */
+ else if (!(SLOT_POWER (slot_cur->status))) {
+ err ("power on failed... \n");
+ faulted = 1;
+ }
+ if (faulted) {
+ attn_off (slot_cur); /* need to turn off b4 on */
+ attn_on (slot_cur);
+ rcpr = power_off (slot_cur);
+ if (rcpr) {
+ ibmphp_unlock_operations ();
+ return rcpr;
+ }
+
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -ENODEV;
+ }
+ ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations ();
+ return -EINVAL;
+ }
+
+ slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+ if (!slot_cur->func) { /* We cannot do update_slot_info here, since no memory for kmalloc n.e.ways, and update_slot_info allocates some */
+ err ("out of system memory \n");
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ rcpr = power_off (slot_cur);
+ if (rcpr) {
+ ibmphp_unlock_operations ();
+ return rcpr;
+ }
+ ibmphp_unlock_operations ();
+ return -ENOMEM;
+ }
+ memset (slot_cur->func, 0, sizeof (struct pci_func));
+ slot_cur->func->busno = slot_cur->bus;
+ slot_cur->func->device = slot_cur->device;
+ for (i = 0; i < 4; i++)
+ slot_cur->func->irq[i] = slot_cur->irq[i];
+
+ debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device);
+
+ if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) {
+ err ("configure_card was unsuccessful... \n");
+ ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */
+ debug ("after unconfigure_card\n");
+ slot_cur->func = NULL;
+ attn_off (slot_cur); /* need to turn off in case was blinking */
+ attn_on (slot_cur);
+ rcpr = power_off (slot_cur);
+ if (rcpr) {
+ ibmphp_unlock_operations ();
+ return rcpr;
+ }
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations();
+ return -ENODEV;
+ }
+ ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations ();
+ return -ENOMEM;
+ }
+ function = 0x00;
+ do {
+ tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++);
+ if (tmp_func && !(tmp_func->dev))
+ ibm_configure_device (tmp_func);
+ } while (tmp_func);
+
+ attn_off (slot_cur);
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+ ibmphp_print_test ();
+ rc = ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations();
+ return rc;
+}
+
+/**************************************************************
+* HOT REMOVING ADAPTER CARD *
+* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE *
+* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE *
+ DISABLE POWER , *
+**************************************************************/
+int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot)
+{
+ int rc;
+ struct slot *slot_cur = (struct slot *) hotplug_slot->private;
+ u8 flag = slot_cur->flag;
+
+ slot_cur->flag = TRUE;
+ debug ("DISABLING SLOT... \n");
+
+ ibmphp_lock_operations ();
+ if (slot_cur == NULL) {
+ ibmphp_unlock_operations ();
+ return -ENODEV;
+ }
+ if (slot_cur->ctrl == NULL) {
+ ibmphp_unlock_operations ();
+ return -ENODEV;
+ }
+ if (flag == TRUE) {
+ rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */
+ if (rc) {
+ /* Need to turn off if was blinking b4 */
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+
+ ibmphp_update_slot_info (slot_cur);
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+ }
+ attn_LED_blink (slot_cur);
+
+ if (slot_cur->func == NULL) {
+ /* We need this for fncs's that were there on bootup */
+ slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+ if (!slot_cur->func) {
+ err ("out of system memory \n");
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ ibmphp_unlock_operations ();
+ return -ENOMEM;
+ }
+ memset (slot_cur->func, 0, sizeof (struct pci_func));
+ slot_cur->func->busno = slot_cur->bus;
+ slot_cur->func->device = slot_cur->device;
+ }
+
+ if ((rc = ibm_unconfigure_device (slot_cur->func))) {
+ err ("removing from kernel failed... \n");
+ err ("Please check to see if it was statically linked or is in use otherwise. (perhaps the driver is not 'hot-removable')\n");
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+
+ rc = ibmphp_unconfigure_card (&slot_cur, 0);
+ slot_cur->func = NULL;
+ debug ("in disable_slot. after unconfigure_card \n");
+ if (rc) {
+ err ("could not unconfigure card.\n");
+ attn_off (slot_cur); /* need to turn off if was blinking b4 */
+ attn_on (slot_cur);
+
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+
+ if (flag)
+ ibmphp_update_slot_info (slot_cur);
+
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+
+ rc = ibmphp_hpc_writeslot (hotplug_slot->private, HPC_SLOT_OFF);
+ if (rc) {
+ attn_off (slot_cur);
+ attn_on (slot_cur);
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+
+ if (flag)
+ ibmphp_update_slot_info (slot_cur);
+
+ ibmphp_unlock_operations ();
+ return rc;
+ }
+
+ attn_off (slot_cur);
+ if (slot_update (&slot_cur)) {
+ ibmphp_unlock_operations ();
+ return -EFAULT;
+ }
+ if (flag)
+ rc = ibmphp_update_slot_info (slot_cur);
+ else
+ rc = 0;
+
+ ibmphp_print_test ();
+ ibmphp_unlock_operations();
+ return rc;
+}
+
+struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
+ owner: THIS_MODULE,
+ set_attention_status: set_attention_status,
+ enable_slot: enable_slot,
+ disable_slot: ibmphp_disable_slot,
+ hardware_test: NULL,
+ get_power_status: get_power_status,
+ get_attention_status: get_attention_status,
+ get_latch_status: get_latch_status,
+ get_adapter_status: get_adapter_present,
+/* get_max_bus_speed_status: get_max_bus_speed,
+ get_max_adapter_speed_status: get_max_adapter_speed,
+ get_cur_bus_speed_status: get_cur_bus_speed,
+ get_card_bus_names_status: get_card_bus_names,
+*/
+};
+
+static void ibmphp_unload (void)
+{
+ free_slots ();
+ debug ("after slots \n");
+ ibmphp_free_resources ();
+ debug ("after resources \n");
+ ibmphp_free_bus_info_queue ();
+ debug ("after bus info \n");
+ ibmphp_free_ebda_hpc_queue ();
+ debug ("after ebda hpc \n");
+ ibmphp_free_ebda_pci_rsrc_queue ();
+ debug ("after ebda pci rsrc \n");
+}
+
+static int __init ibmphp_init (void)
+{
+ int i = 0;
+ int rc = 0;
+
+ init_flag = 1;
+ ibmphp_pci_root_ops = get_root_pci_ops ();
+ if (ibmphp_pci_root_ops == NULL) {
+ err ("cannot read bus operations... will not be able to read the cards. Please check your system \n");
+ return -ENODEV;
+ }
+
+ ibmphp_debug = debug;
+
+ ibmphp_hpc_initvars ();
+
+ for (i = 0; i < 16; i++)
+ irqs[i] = 0;
+
+ if ((rc = ibmphp_access_ebda ())) {
+ ibmphp_unload ();
+ return rc;
+ }
+ debug ("after ibmphp_access_ebda () \n");
+
+ if ((rc = ibmphp_rsrc_init ())) {
+ ibmphp_unload ();
+ return rc;
+ }
+ debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+
+ max_slots = get_max_slots ();
+
+ if (init_ops ()) {
+ ibmphp_unload ();
+ return -ENODEV;
+ }
+ ibmphp_print_test ();
+ if ((rc = ibmphp_hpc_start_poll_thread ())) {
+ ibmphp_unload ();
+ return -ENODEV;
+ }
+
+ /* lock ourselves into memory with a module count of -1
+ * so that no one can unload us. */
+ MOD_DEC_USE_COUNT;
+
+ info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+ return 0;
+}
+
+static void __exit ibmphp_exit (void)
+{
+ ibmphp_hpc_stop_poll_thread ();
+ debug ("after polling \n");
+ ibmphp_unload ();
+ debug ("done \n");
+}
+
+module_init (ibmphp_init);
+module_exit (ibmphp_exit);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)