lkml.org 
[lkml]   [2003]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[Patch] 3/4 PCI Hot-plug driver patch for 2.5.74 kernel
Part 3 of 4 PCI Hot-plug driver patch for 2.5.74 kernel

diff -Nru a/drivers/pci/hotplug/cpqphp_hpc.c b/drivers/pci/hotplug/cpqphp_hpc.c
--- a/drivers/pci/hotplug/cpqphp_hpc.c 1969-12-31 16:00:00.000000000 -0800
+++ b/drivers/pci/hotplug/cpqphp_hpc.c 2003-07-07 09:32:22.000000000 -0700
@@ -0,0 +1,1203 @@
+/*
+ * Compaq PCI Hot Plug Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ *
+ * 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 <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/delay.h> /* for delays */
+#include <asm/system.h>
+#include "cpqphp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
+#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
+#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
+#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
+#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... ) \
+ do { \
+ if ( DEBUG_LEVEL & ( dbg_flags ) ) \
+ { \
+ int len; \
+ len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+ __FILE__, __LINE__, __FUNCTION__ ); \
+ sprintf( __dbg_str_buf + len, args ); \
+ printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+ } \
+ } while (0)
+
+#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif /* DEBUG */
+
+struct ctrl_reg { /* offset */
+ u8 slot_RST; /* 0x00 */
+ u8 slot_enable; /* 0x01 */
+ u16 misc; /* 0x02 */
+ u32 led_control; /* 0x04 */
+ u32 int_input_clear; /* 0x08 */
+ u32 int_mask; /* 0x0a */
+ u8 reserved0; /* 0x10 */
+ u8 reserved1; /* 0x11 */
+ u8 reserved2; /* 0x12 */
+ u8 gen_output_AB; /* 0x13 */
+ u32 non_int_input; /* 0x14 */
+ u32 reserved3; /* 0x18 */
+ u32 reserved4; /* 0x1a */
+ u32 reserved5; /* 0x20 */
+ u8 reserved6; /* 0x24 */
+ u8 reserved7; /* 0x25 */
+ u16 reserved8; /* 0x26 */
+ u8 slot_mask; /* 0x28 */
+ u8 reserved9; /* 0x29 */
+ u8 reserved10; /* 0x2a */
+ u8 reserved11; /* 0x2b */
+ u8 slot_SERR; /* 0x2c */
+ u8 slot_power; /* 0x2d */
+ u8 reserved12; /* 0x2e */
+ u8 reserved13; /* 0x2f */
+ u8 next_curr_freq; /* 0x30 */
+ u8 reset_freq_mode; /* 0x31 */
+
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+ SLOT_RST = offsetof(struct ctrl_reg, slot_RST),
+ SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable),
+ MISC = offsetof(struct ctrl_reg, misc),
+ LED_CONTROL = offsetof(struct ctrl_reg, led_control),
+ INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear),
+ INT_MASK = offsetof(struct ctrl_reg, int_mask),
+ CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0),
+ CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1),
+ CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1),
+ GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB),
+ NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input),
+ CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3),
+ CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4),
+ CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5),
+ CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6),
+ CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7),
+ CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8),
+ SLOT_MASK = offsetof(struct ctrl_reg, slot_mask),
+ CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9),
+ CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10),
+ CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11),
+ SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR),
+ SLOT_POWER = offsetof(struct ctrl_reg, slot_power),
+ CTRL_RESERVED12 = offsetof(struct ctrl_reg, reserved12),
+ CTRL_RESERVED13 = offsetof(struct ctrl_reg, reserved13),
+ NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq),
+ RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode),
+};
+
+
+struct sema_struct {
+ struct semaphore crit_sect;
+ int owner_id;
+ int count;
+};
+
+struct php_ctlr_state_s {
+ struct php_ctlr_state_s *pnext;
+ struct pci_dev *pci_dev;
+ unsigned int irq;
+ struct sema_struct hwlock;
+ unsigned long flags; /* spinlock's */
+ u32 ctrl_int_comp; /* interrupt comparator */
+ u32 first_device_num;
+ u32 num_slots;
+ u16 ctlrcap;
+ php_intr_callback_t switch_change_callback;
+ php_intr_callback_t presence_change_callback;
+ php_intr_callback_t power_fault_callback;
+ void *callback_instance_id;
+ void *creg; /* Ptr to controller register space */
+};
+
+
+spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */
+static int ctlr_seq_num = 0; /* Controller sequenc # */
+
+static irqreturn_t hpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static wait_queue_head_t delay_wait_q_head;
+
+/* delay in jiffies to wait */
+static void longdelay(int delay)
+{
+ init_waitqueue_head(&delay_wait_q_head);
+
+ interruptible_sleep_on_timeout(&delay_wait_q_head, delay);
+}
+
+static void cpqhpc_set_SOGO (struct slot *slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u16 misc;
+
+ misc = readw(php_ctlr->creg + MISC);
+ misc = (misc | 0x0001) & 0xFFFB;
+ writew(misc, php_ctlr->creg + MISC);
+}
+
+static int cpqhpc_wait_for_SOBS (struct slot *slot)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval = 0;
+
+ DBG_ENTER_ROUTINE
+
+ add_wait_queue(&slot->ctrl->queue, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2*HZ);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&slot->ctrl->queue, &wait);
+ if (signal_pending(current))
+ retval = -EINTR;
+
+ DBG_LEAVE_ROUTINE
+ return retval;
+}
+
+static void hpc_update_hpc(struct slot *slot)
+{
+ cpqhpc_set_SOGO(slot);
+ cpqhpc_wait_for_SOBS(slot);
+}
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 led_control;
+
+ DBG_ENTER_ROUTINE
+
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control &= (0x01010000L << slot->hp_slot);
+ *status = led_control ? 1 : 0;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u8 slot_enable;
+
+ DBG_ENTER_ROUTINE
+
+ slot_enable = readb(php_ctlr->creg + SLOT_ENABLE);
+ slot_enable &= (0x01L << slot->hp_slot);
+ *status = slot_enable ? 1 : 0;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 latch_status;
+
+ DBG_ENTER_ROUTINE
+
+ latch_status = (readl(php_ctlr->creg + INT_INPUT_CLEAR) & (0x01L << slot->hp_slot));
+ *status = (latch_status == 0) ? 1 : 0;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+ u8 presence_save = 0;
+ u32 tempdword;
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+
+ tempdword = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+ presence_save = (u8) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> slot->hp_slot) & 0x02;
+
+ *status = (presence_save != 0) ? 1 : 0;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+ u32 status;
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 tempdword;
+
+ DBG_ENTER_ROUTINE
+
+ tempdword = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+ status = (tempdword & (0x00000100 << slot->hp_slot));
+
+ DBG_LEAVE_ROUTINE
+ /* Note: Logic 0 => fault */
+ return status ? 0 : 1;
+}
+
+/*
+ * change to call set_led_state()
+ */
+
+static void hpc_set_attention_status(struct slot *slot, u8 status)
+{
+ struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 led_control;
+
+ switch (status) {
+ case 0:
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control &= ~(0x01010000L << slot->hp_slot);
+ writel(led_control, php_ctlr->creg + LED_CONTROL);
+ break;
+ case 1:
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control |= (0x01010000L << slot->hp_slot);
+ writel(led_control, php_ctlr->creg + LED_CONTROL);
+ break;
+ }
+}
+
+static void hpc_green_led_on(struct slot * slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 led_control;
+
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control |= 0x0101L << slot->hp_slot;
+ writel(led_control, php_ctlr->creg + LED_CONTROL);
+
+}
+
+static void hpc_green_led_off(struct slot * slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 led_control;
+
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control &= ~(0x0101L << slot->hp_slot);
+ writel(led_control, php_ctlr->creg + LED_CONTROL);
+
+}
+
+static void hpc_green_led_blink(struct slot * slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 led_control;
+
+ led_control = readl(php_ctlr->creg + LED_CONTROL);
+ led_control &= ~(0x0101L << slot->hp_slot);
+ led_control |= (0x0001L << slot->hp_slot);
+ writel(led_control, php_ctlr->creg + LED_CONTROL);
+
+}
+
+/*
+ * 0: all 4 variables set
+ * 1: no physical_slot_num
+ */
+int phphpc_get_ctlr_slot_config(struct controller *ctrl,
+ int *num_ctlr_slots, /* number of slots in this HPC */
+ int *first_device_num, /* PCI dev num of the first slot in this HPC */
+ int *physical_slot_num, /* phy slot num of the first slot in this HPC */
+ int *updown, /* physical_slot_num increament: 1 or -1 */
+ int *flags)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+
+ * first_device_num = php_ctlr->first_device_num;
+ *num_ctlr_slots = php_ctlr->num_slots;
+
+ /* this HPC does not conform to SHPC and provides no physical_slot_num. */
+ *physical_slot_num = -1;
+
+ *updown = 1; /* could be -1 in SHPC */
+ *flags = 1;
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+ struct php_ctlr_state_s *p, *p_prev;
+
+ DBG_ENTER_ROUTINE
+
+ if (php_ctlr->irq) {
+ free_irq(php_ctlr->irq, ctrl);
+ php_ctlr->irq = 0;
+ }
+
+ if (php_ctlr->pci_dev) {
+ iounmap((void *) pci_resource_start(php_ctlr->pci_dev, 0));
+ release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0));
+ php_ctlr->pci_dev = 0;
+ }
+
+ p = php_ctlr_list_head;
+ p_prev = NULL;
+ while (p) {
+ if (p == php_ctlr) {
+ if (p_prev)
+ p_prev->pnext = p->pnext;
+ else
+ php_ctlr_list_head = p->pnext;
+ break;
+ } else {
+ p_prev = p;
+ p = p->pnext;
+ }
+ }
+
+ kfree(php_ctlr);
+
+ DBG_LEAVE_ROUTINE
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u8 slot_enable;
+
+ DBG_ENTER_ROUTINE
+
+ slot_enable = readb(php_ctlr->creg + SLOT_ENABLE);
+ slot_enable |= (0x01 << slot->hp_slot);
+ writeb(slot_enable, php_ctlr->creg + SLOT_ENABLE);
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_power_off_slot(struct slot * slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u8 slot_enable;
+
+ DBG_ENTER_ROUTINE
+
+ slot_enable = readb(php_ctlr->creg + SLOT_ENABLE);
+ slot_enable &= ~(0x01 << slot->hp_slot);
+ writeb(slot_enable, php_ctlr->creg + SLOT_ENABLE);
+
+ DBG_LEAVE_ROUTINE
+
+ return 0;
+}
+
+static void hpc_enable_msl_interrupt(struct slot *slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 rc;
+ u16 misc;
+
+ DBG_ENTER_ROUTINE
+
+ if (php_ctlr->creg) {
+ rc = readb(php_ctlr->creg + SLOT_ENABLE);
+
+ writeb(rc, php_ctlr->creg + SLOT_SERR);
+ writel(0xFFFFFFC0L | ~rc, php_ctlr->creg + INT_MASK);
+
+ misc = readw(php_ctlr->creg + MISC);
+ misc &= 0xFFFD;
+ writew(misc, php_ctlr->creg + MISC);
+ }
+
+ DBG_LEAVE_ROUTINE
+}
+
+static u32 hpc_get_slot_capability(struct slot *slot)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 slot_state = 0, temp;
+ u8 slot_enable;
+
+ DBG_ENTER_ROUTINE
+
+ temp = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+
+ /* Check presence */
+ slot_state |= ((((~temp) >> 23) | ((~temp) >> 15)) >> slot->hp_slot) & 0x02;
+ /* Check the switch state */
+ slot_state |= ((~temp & 0xFF) >> slot->hp_slot) & 0x01;
+ /* Check the slot enable */
+ slot_enable = readb(php_ctlr->creg + SLOT_ENABLE);
+ slot_state |= ((slot_enable << 2) >> slot->hp_slot) & 0x04;
+
+ return slot_state;
+
+ DBG_LEAVE_ROUTINE
+}
+
+static irqreturn_t hpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+ struct controller *ctrl = (struct controller *)dev_id;
+ struct php_ctlr_state_s *php_ctlr;
+ u8 schedule_flag = 0;
+ u32 Diff;
+ u32 temp_dword;
+ u16 misc;
+ u8 reset;
+
+ if (!ctrl || !(php_ctlr = ctrl->hpc_ctlr_handle) || !php_ctlr->creg)
+ return IRQ_NONE;
+
+ /* Check to see if it was our interrupt */
+ misc = readw(php_ctlr->creg + MISC);
+ if (!(misc & 0x000C))
+ return IRQ_NONE;
+
+ if (misc & 0x0004) {
+ /* Serial Output interrupt Pending */
+ misc |= 0x0004; /* Clear the interrupt */
+ writew(misc, php_ctlr->creg + MISC);
+ misc = readw(php_ctlr->creg + MISC); /* Read to clear posted writes */
+ wake_up_interruptible(&ctrl->queue);
+ }
+
+ if (misc & 0x0008) {
+ /* General-interrupt-input interrupt Pending */
+ Diff = readl(php_ctlr->creg + INT_INPUT_CLEAR) ^ php_ctlr->ctrl_int_comp;
+
+ php_ctlr->ctrl_int_comp = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+
+ writel(Diff, php_ctlr->creg + INT_INPUT_CLEAR); /* Clear the interrupt */
+
+ /* Read it back to clear any posted writes */
+ temp_dword = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+
+ if (!Diff)
+ writel(0xFFFFFFFF, php_ctlr->creg + INT_INPUT_CLEAR); /* Clear all interrupts */
+
+ if (php_ctlr->switch_change_callback)
+ schedule_flag += php_ctlr->switch_change_callback(
+ (Diff & 0xFFL), php_ctlr->callback_instance_id);
+ if (php_ctlr->presence_change_callback)
+ schedule_flag += php_ctlr->presence_change_callback(
+ ((Diff & 0xFFFF0000L) >> 16), php_ctlr->callback_instance_id);
+ if (php_ctlr->power_fault_callback)
+ schedule_flag += php_ctlr->power_fault_callback(
+ ((Diff & 0xFF00L) >> 8), php_ctlr->callback_instance_id);
+ }
+
+ /* Setting bus speed is applicable only to Compaq HPC with rev >= 0x13
+ * or with subsystem_device == PCI_SUB_HPC_ID4
+ */
+ if ((ctrl->pci_dev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) &&
+ ((ctrl->rev >= 0x13) || (ctrl->pci_dev->subsystem_device == PCI_SUB_HPC_ID4))) {
+ reset = readb(php_ctlr->creg + RESET_FREQ_MODE);
+ if (reset & 0x40) {
+ /* Bus reset has completed */
+ reset &= 0xCF;
+ writeb(reset, php_ctlr->creg + RESET_FREQ_MODE);
+ reset = readb(php_ctlr->creg + RESET_FREQ_MODE);
+ wake_up_interruptible(&ctrl->queue);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+int phphpc_get_ctrl_cap(struct controller *ctrl, u16 * pctlrcap, u8 * prev)
+{
+ u16 vendor_id;
+ u16 subsystem_vid;
+ u16 subsystem_did;
+ u32 rc;
+ u8 bus_cap;
+ struct pci_dev *pdev;
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+
+ if (!ctrl->hpc_ctlr_handle) {
+ err("Process %d: Invalid HPC controller handle!\n", current->pid);
+ return -1;
+ }
+
+ if (!pctlrcap) {
+ err("Process %d: Invalid HPC ctrlcap pointer passed in!\n", current->pid);
+ return -1;
+ }
+
+ if (!prev) {
+ err("Process %d: Invalid HPC rev pointer passed in!\n", current->pid);
+ return -1;
+ }
+
+ dbg("Pass in ctlrcap = %x\n", *pctlrcap);
+
+ if (!php_ctlr->pci_dev) {
+ err("Process %d: Invalid HPC controller pci_dev!\n", current->pid);
+ return -1;
+ }
+
+ pdev = php_ctlr->pci_dev;
+
+ /* Need to read VID early b/c it's used to differentiate CPQ and INTC discovery */
+ vendor_id = pdev->vendor;
+ if ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL)) {
+ err ("%s: HPC controller(vendor=%x) not supported by this driver!\n", __FUNCTION__, vendor_id);
+ return -1;
+ }
+
+ rc = pci_read_config_byte(pdev, PCI_REVISION_ID, prev);
+ dbg("Vendor ID: %x revision: %x\n", vendor_id, *prev);
+ if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!(*prev)))) {
+ err("%s: Unsupported revision of HPC controller found!\n", __FUNCTION__);
+ return -1;
+ }
+
+ /*
+ * Check for the proper subsytem ID's
+ * Intel uses a different SSID programming model than Compaq. For Intel, each
+ * SSID bit identifies a PHP capability.
+ * Also Intel HPC's may have RID=0.
+ */
+ if ((*prev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) {
+ subsystem_vid = pdev->subsystem_vendor;
+ subsystem_did = pdev->subsystem_device;
+ dbg("Sub-Vendor ID: %x, Sub-Device ID: %x\n", subsystem_vid, subsystem_did);
+ if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {
+ err("%s: HPC controller not supported by this driver!\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* Set Default values of "0" for everything */
+ *pctlrcap = 0;
+
+ /*
+ * Interpretation of bit pattern in *pctlrcap
+ * Based on Intel PHPC SSVID/SID Programming Model
+ * Bit 0 Speed_capability: 0 = 33MHz, 1 = 66MHz
+ * Bit 1 Push_button : 0 = pushbutton present, 1 = no pushbutton
+ * Bit 2 Slot_switch_type: 0 = switch present, 1 = no switch
+ * Bit 3 DeFeature PHP: 0 = PHP not supported, 1 = PHP supported
+ * Bit 4 Alternate_base_address: 0 = not supported, 1 = supported
+ * Bit 5 PCI_config_space: Index/data access to working registers
+ * 0 = not supported, 1 = supported
+ * Bit 6 PCIX_speed: 0 = 100Mhz PCI-X if Bit 7 is 1 and Bit 0 is 0,
+ * 66MHz PCI_X if Bit 7 is 1 and Bit 0 is 1
+ * 1 = 133MHz PCI-X if Bit 7 is 1
+ * Bit 7 PCIX_support: 0 = conventional PCI, 1 = PCI-X
+ * Bit 8-15 Reserved
+ */
+ if (subsystem_vid == PCI_VENDOR_ID_COMPAQ) {
+ switch ( *prev >= 0x13) {
+ case 0:
+ if (subsystem_did == PCI_SUB_HPC_ID) {
+ *pctlrcap = 0x2A; /* sw, 33, no pb, no pcix */
+ break;
+ } else if (subsystem_did == PCI_SUB_HPC_ID2) {
+ *pctlrcap = 0x28; /* sw, 33, pb, no pcix */
+ break;
+ } else if (subsystem_did == PCI_SUB_HPC_ID_INTC) {
+ *pctlrcap = 0x2A; /* sw, 33, no pb, no pcix */
+ break;
+ } else if (subsystem_did == PCI_SUB_HPC_ID3) {
+ *pctlrcap = 0x29; /* sw, 66, pb, no pcix */
+ break;
+ } else if (subsystem_did == PCI_SUB_HPC_ID4) {
+ *pctlrcap = 0xA8; /* sw, 100, pb, pcix */
+ break;
+ } else {
+ err("%s: unsupported Sub-Device ID: %x\n", __FUNCTION__, subsystem_did);
+ php_ctlr->ctlrcap = 0;
+ return -1;
+ }
+ case 1: /* True for CIOBX */
+ pci_read_config_byte(pdev, 0x41, &bus_cap);
+ if (bus_cap & 0x80) {
+ *pctlrcap = 0xE8; /* sw, 133, pb, pcix */
+ break;
+ } else if (bus_cap & 0x40) {
+ *pctlrcap = 0xA8; /* sw, 100, pb, pcix */
+ break;
+ } else if (bus_cap & 0x20) {
+ *pctlrcap = 0xA9; /* sw, 66, pb, pcix */
+ break;
+ } else if (bus_cap & 0x10) {
+ *pctlrcap = 0x29; /* sw, 100, pb, no pcix */
+ break;
+ } else {
+ *pctlrcap = 0xA9; /* default to sw, 66, pb, pcix */
+ break;
+ }
+ }
+ } else if (subsystem_vid == PCI_VENDOR_ID_INTEL) {
+ *pctlrcap = subsystem_did;
+ } else
+ err("%s: unsupported Sub-Vendor ID: %x\n", __FUNCTION__, subsystem_vid);
+
+ php_ctlr->ctlrcap = *pctlrcap;
+ }
+
+ dbg("ctlrcap = %x\n", *pctlrcap);
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+ enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+ if (!slot->ctrl->hpc_ctlr_handle) {
+ err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* PCI-X support */
+ if (php_ctlr->ctlrcap & 0x0080) {
+ /* Frequency of operation in PCI-X mode */
+ if (php_ctlr->ctlrcap & 0x0040) {
+ bus_speed = PCI_SPEED_133MHz_PCIX;
+ } else {
+ if (php_ctlr->ctlrcap & 0x0001)
+ bus_speed = PCI_SPEED_66MHz_PCIX;
+ else
+ bus_speed = PCI_SPEED_100MHz_PCIX;
+ }
+ } else {
+ if (php_ctlr->ctlrcap & 0x0001)
+ bus_speed = PCI_SPEED_66MHz;
+ else
+ bus_speed = PCI_SPEED_33MHz;
+ }
+
+ *value = bus_speed;
+
+ dbg("Supported bus speed = %d\n", bus_speed);
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
+{
+ u8 adapter_speed = PCI_SPEED_UNKNOWN;
+ u8 m66cap, pcixcap1, pcixcap2;
+ u8 temp_byte;
+
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+ if (!slot->ctrl->hpc_ctlr_handle) {
+ err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (slot->hp_slot >= php_ctlr->num_slots) {
+ err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+ return -1;
+ }
+
+ down(&slot->ctrl->crit_sect);
+
+ /* turn on board without attaching to the bus */
+ temp_byte = readb(php_ctlr->creg + SLOT_POWER);
+ temp_byte |= (0x01 << slot->hp_slot);
+ writeb(temp_byte, php_ctlr->creg + SLOT_POWER);
+
+ hpc_update_hpc(slot);
+
+ /* Change bits in slot power register to force another shift out */
+ /* NOTE: this is to work around the timer bug */
+ temp_byte = readb(php_ctlr->creg + SLOT_POWER);
+ writeb(0x00, php_ctlr->creg + SLOT_POWER);
+ writeb(temp_byte, php_ctlr->creg + SLOT_POWER);
+
+ hpc_update_hpc(slot);
+
+ longdelay(6 * (HZ / 10));
+
+ m66cap = readl(php_ctlr->creg + NON_INT_INPUT) & 0xff;
+ pcixcap1 = (readl(php_ctlr->creg + NON_INT_INPUT) >> 8) & 0xff;
+ pcixcap2 = (readl(php_ctlr->creg + NON_INT_INPUT) >> 16) & 0xff;
+ dbg("m66cap = %x\n", m66cap);
+
+ if (php_ctlr->ctlrcap & PCIXSupport) {
+ if ((pcixcap1 >> slot->hp_slot) & 1) {
+ if ((pcixcap2 >> slot->hp_slot) & 1)
+ adapter_speed = PCI_SPEED_133MHz_PCIX;
+ else
+ adapter_speed = PCI_SPEED_66MHz_PCIX;
+ } else {
+ if ((m66cap >> slot->hp_slot) & 1)
+ adapter_speed = PCI_SPEED_66MHz;
+ else
+ adapter_speed = PCI_SPEED_33MHz;
+ }
+ } else {
+ if ((m66cap >> slot->hp_slot) & 1)
+ adapter_speed = PCI_SPEED_66MHz;
+ else
+ adapter_speed = PCI_SPEED_33MHz;
+ }
+
+ /* turn off board without attaching to the bus */
+ temp_byte = readb(php_ctlr->creg + SLOT_POWER);
+ temp_byte &= ~(0x01 << slot->hp_slot);
+ writeb(temp_byte, php_ctlr->creg + SLOT_POWER);
+
+ hpc_update_hpc(slot);
+
+ /* Done with exclusive hardware access */
+ up(&slot->ctrl->crit_sect);
+
+ *value = adapter_speed;
+ dbg("Adapter speed = %d\n", adapter_speed);
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+ u32 pci_misc_config;
+ enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+ u16 temp_word;
+ u32 temp_dword;
+ struct pci_dev *dev;
+ u8 curr_freq;
+ struct controller *ctrl;
+
+ DBG_ENTER_ROUTINE
+ if (!slot->ctrl->hpc_ctlr_handle || !php_ctlr->pci_dev) {
+ err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+ return -1;
+ }
+
+ ctrl = slot->ctrl;
+
+ if ((php_ctlr->pci_dev->vendor == PCI_VENDOR_ID_INTEL) &&
+ (php_ctlr->pci_dev->device == PCI_INTC_P64H2_DID)) {
+
+ /*
+ * For P64H2 hpc, bus speed is determined by P64H2_HUB
+ * Let's find P64H2_HUB on this bus.
+ */
+ dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, PCI_INTC_P64H2_HUB_PCI, PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev == NULL)
+ info("Can't find VID-0x8086 DID-0x1460\n");
+
+ while (dev != NULL) {
+ pci_read_config_word(dev, 0x40, &temp_word);
+ pci_read_config_dword(dev, 0x18, &temp_dword);
+ dbg("%s: bus=%x dev=%x, CNF=%x, BNUM=%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), temp_word, temp_dword);
+ if (((temp_dword & 0x0000ff00) >> 8) == php_ctlr->pci_dev->bus->number) {
+ if ((temp_word & 0x0100) == 0x0100) {
+ if ((temp_word & 0x00c0) == 0x00c0)
+ bus_speed = PCI_SPEED_133MHz_PCIX;
+ else if ((temp_word & 0x0080) == 0x0080)
+ bus_speed = PCI_SPEED_100MHz_PCIX;
+ else if ((temp_word & 0x0040) == 0x0040)
+ bus_speed = PCI_SPEED_66MHz_PCIX;
+ } else {
+ if ((temp_word & 0x0040) == 0x0040)
+ bus_speed = PCI_SPEED_66MHz;
+ else if ((temp_word & 0x00c0) == 0)
+ bus_speed = PCI_SPEED_33MHz;
+ }
+ break;
+ }
+ dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, PCI_INTC_P64H2_HUB_PCI, PCI_ANY_ID, PCI_ANY_ID, dev);
+ }
+ } else {
+ if (php_ctlr->ctlrcap & PCIXSupport) {
+ if ((ctrl->pci_dev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) &&
+ ((ctrl->rev >= 0x13) || (ctrl->pci_dev->subsystem_device == PCI_SUB_HPC_ID4))) {
+ /* for Compaq CIOBX or PCI_SUB_HPC_ID4 */
+ curr_freq = readb(php_ctlr->creg + NEXT_CURR_FREQ);
+ if ((curr_freq & 0xB0) == 0xB0)
+ bus_speed = PCI_SPEED_133MHz_PCIX;
+ else if ((curr_freq & 0xA0) == 0xA0)
+ bus_speed = PCI_SPEED_100MHz_PCIX;
+ else if ((curr_freq & 0x90) == 0x90)
+ bus_speed = PCI_SPEED_66MHz_PCIX;
+ else if ((curr_freq & 0x10) == 0x10)
+ bus_speed = PCI_SPEED_66MHz;
+ else bus_speed = PCI_SPEED_33MHz;
+ } else { /* all others */
+
+ pci_read_config_dword(php_ctlr->pci_dev, 0x40, &pci_misc_config);
+ /* Read HPC PCI Misc. Configuration at offset 40h */
+
+ dbg("HPC PCI Misc Config = %x\n", pci_misc_config);
+
+ if (pci_misc_config & 0x00200000) { /* Bit 21 of PCI Misc. Config. */
+ if (readw(php_ctlr->creg + MISC) & 0x8000) { /* Bit 31 - 133 MHZ Prescale indicator */
+ if (readw(php_ctlr->creg + MISC) & 0x0040) /* Bit 22 - frequency range bit */
+ bus_speed = PCI_SPEED_133MHz_PCIX;
+ else
+ bus_speed = PCI_SPEED_100MHz_PCIX;
+ } else
+ bus_speed = PCI_SPEED_66MHz_PCIX;
+ } else {
+ if (readw(php_ctlr->creg + MISC) & 0x0800) /* Bit 27 - 66MHZ Prescale indicator */
+ bus_speed = PCI_SPEED_66MHz;
+ else
+ bus_speed = PCI_SPEED_33MHz;
+ }
+ }
+ } else {
+ if (readw(php_ctlr->creg + MISC) & 0x0800) /* Bit 27 - 66MHZ Prescale indicator */
+ bus_speed = PCI_SPEED_66MHz;
+ else
+ bus_speed = PCI_SPEED_33MHz;
+ }
+ }
+
+ *value = bus_speed;
+ dbg("Current bus speed = %d\n", bus_speed);
+ DBG_LEAVE_ROUTINE
+ return 0;
+}
+
+static int hpc_set_controller_speed (struct slot *slot, enum pci_bus_speed value)
+{
+ struct slot *p_slot;
+ struct controller *ctrl;
+ u8 reg, adapter_speed;
+ u8 slot_power, hp_slot;
+ u16 reg16;
+ u32 leds;
+
+ struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+ DBG_ENTER_ROUTINE
+ if (!slot->ctrl->hpc_ctlr_handle) {
+ err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+ return -1;
+ }
+
+ ctrl = slot->ctrl;
+ hp_slot = slot->hp_slot;
+ slot_power = readb(php_ctlr->creg + SLOT_POWER);
+ leds = readl(php_ctlr->creg + LED_CONTROL);
+ adapter_speed = value;
+
+ /* We don't allow freq/mode changes if we find another adapter running
+ * in another slot on this controller */
+ for(p_slot = ctrl->slot; p_slot; p_slot = p_slot->next) {
+ if (p_slot->device == (hp_slot + ctrl->slot_device_offset))
+ continue;
+ if (!p_slot->hotplug_slot && !p_slot->hotplug_slot->info)
+ continue;
+ if (p_slot->hotplug_slot->info->adapter_status == 0)
+ continue;
+ /* If another adapter is running on the same segment but at a
+ * lower speed/mode, we allow the new adapter to function at
+ * this rate if supported */
+ if (ctrl->speed < adapter_speed)
+ return 0;
+
+ return 1;
+ }
+
+ /* We try to set the max speed supported by both the adapter and
+ * controller */
+ if (ctrl->speed_capability < adapter_speed) {
+ if (ctrl->speed == ctrl->speed_capability)
+ return 0;
+ adapter_speed = ctrl->speed_capability;
+ }
+
+ writel(0x0L, php_ctlr->creg + LED_CONTROL);
+ writeb(0x00, php_ctlr->creg + SLOT_ENABLE);
+
+ hpc_update_hpc(slot);
+
+ if (adapter_speed != PCI_SPEED_133MHz_PCIX)
+ reg = 0xF5;
+ else
+ reg = 0xF4;
+ pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+
+ reg16 = readw(php_ctlr->creg + NEXT_CURR_FREQ);
+ reg16 &= ~0x000F;
+ switch(adapter_speed) {
+ case(PCI_SPEED_133MHz_PCIX):
+ reg = 0x75;
+ reg16 |= 0xB;
+ break;
+ case(PCI_SPEED_100MHz_PCIX):
+ reg = 0x74;
+ reg16 |= 0xA;
+ break;
+ case(PCI_SPEED_66MHz_PCIX):
+ reg = 0x73;
+ reg16 |= 0x9;
+ break;
+ case(PCI_SPEED_66MHz):
+ reg = 0x73;
+ reg16 |= 0x1;
+ break;
+ default: /* 33MHz PCI 2.2 */
+ reg = 0x71;
+ break;
+
+ }
+ reg16 |= 0xB << 12;
+ writew(reg16, php_ctlr->creg + NEXT_CURR_FREQ);
+
+ mdelay(5);
+
+ /* Reenable interrupts */
+ writel(0, php_ctlr->creg + INT_MASK);
+
+ pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+
+ /* Restart state machine */
+ reg = ~0xF;
+ pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
+ pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
+
+ /* Only if mode change...*/
+ if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+ ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz)))
+ hpc_update_hpc(slot);
+
+ mdelay(1100);
+
+ /* Restore LED/Slot state */
+ writel(leds, php_ctlr->creg + LED_CONTROL);
+ writeb(slot_power, php_ctlr->creg + SLOT_ENABLE);
+
+ hpc_update_hpc(slot);
+
+ ctrl->speed = adapter_speed;
+ slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+ info("Successfully changed frequency/mode for adapter in slot %d\n",
+ slot->number);
+ return 0;
+}
+
+static struct hpc_ops cpqphp_hpc_ops = {
+ .power_on_slot = hpc_power_on_slot,
+ .power_off_slot = hpc_power_off_slot,
+ .set_attention_status = hpc_set_attention_status,
+ .get_power_status = hpc_get_power_status,
+ .get_attention_status = hpc_get_attention_status,
+ .get_latch_status = hpc_get_latch_status,
+ .get_adapter_status = hpc_get_adapter_status,
+
+ .get_max_bus_speed = hpc_get_max_bus_speed,
+ .get_cur_bus_speed = hpc_get_cur_bus_speed,
+ .get_adapter_speed = hpc_get_adapter_speed,
+ .set_controller_speed = hpc_set_controller_speed,
+
+ .get_slot_capability = hpc_get_slot_capability,
+ .query_power_fault = hpc_query_power_fault,
+ .green_led_on = hpc_green_led_on,
+ .green_led_off = hpc_green_led_off,
+ .green_led_blink = hpc_green_led_blink,
+
+ .enable_msl_interrupt = hpc_enable_msl_interrupt,
+ .update_hpc = hpc_update_hpc,
+ .release_ctlr = hpc_release_ctlr,
+};
+
+int phphpc_init(struct controller * ctrl,
+ struct pci_dev * pdev,
+ php_intr_callback_t switch_change_callback,
+ php_intr_callback_t presence_change_callback,
+ php_intr_callback_t power_fault_callback)
+{
+ struct php_ctlr_state_s *php_ctlr, *p;
+ void *instance_id = ctrl;
+ unsigned long psw;
+ int rc;
+ u16 temp_word, misc;
+ static int first = 1;
+
+ DBG_ENTER_ROUTINE
+ php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+ if (!php_ctlr) { /* allocate controller state data */
+ err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+ goto abort;
+ }
+
+ memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+ php_ctlr->pci_dev = pdev; /* save pci_dev in context */
+
+ if (first) {
+ spin_lock_init(&hpc_event_lock);
+ first = 0;
+ }
+
+ dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq);
+ for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+ if (pci_resource_len(pdev, rc) > 0)
+ dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
+ pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device);
+
+ if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), MY_NAME)) {
+ err("%s: cannot reserve MMIO region\n", __FUNCTION__);
+ goto abort_free_ctlr;
+ }
+
+ php_ctlr->creg = (struct ctrl_reg *)
+ ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!php_ctlr->creg) {
+ err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
+ release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ goto abort_free_ctlr;
+ }
+
+ init_MUTEX(&ctrl->crit_sect);
+ /* setup wait queue */
+ init_waitqueue_head(&ctrl->queue);
+
+ /* find the IRQ */
+ php_ctlr->irq = pdev->irq;
+ dbg("HPC interrupt = %d\n", php_ctlr->irq);
+
+ /* Save interrupt callback info */
+ php_ctlr->switch_change_callback = switch_change_callback;
+ php_ctlr->presence_change_callback = presence_change_callback;
+ php_ctlr->power_fault_callback = power_fault_callback;
+ php_ctlr->callback_instance_id = instance_id;
+
+ /* return PCI Controller Info */
+ php_ctlr->first_device_num = readb(php_ctlr->creg + SLOT_MASK) >> 4;
+ php_ctlr->num_slots = readb(php_ctlr->creg + SLOT_MASK) & 0xF;
+
+ /* Mask all general input interrupts */
+ writel(0xFFFFFFFFL, php_ctlr->creg + INT_MASK);
+
+ /*Disable interrupts */
+ spin_lock_irqsave(&hpc_event_lock, psw);
+
+ /*this code installs the interrupt handler */
+ rc = request_irq(php_ctlr->irq, hpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+
+ if ((php_ctlr->pci_dev->vendor == PCI_VENDOR_ID_INTEL) &&
+ (php_ctlr->pci_dev->device == PCI_INTC_P64H2_DID)) {
+ /*
+ * If this is the Intel Tiger IA64 platform, Read the ABAR config
+ * space register and clear bit 14 to assure HPC uses normal
+ * interrupts, NOT SCI interrupt.
+ */
+ rc = pci_read_config_word(pdev, 0x80, &temp_word);
+ dbg("ABAR reads %x\n", temp_word);
+ temp_word = temp_word & 0xBFFF;
+ rc |= pci_write_config_word(pdev, 0x80, temp_word);
+ pci_read_config_word(pdev, 0x80, &temp_word);
+ if (rc || (temp_word & ~0xBFFF))
+ err("Unable to set ABAR[%x] rc = %d\n", temp_word, rc);
+ else
+ dbg("ABAR set to %x\n", temp_word);
+ }
+
+ /* Re-enable interrupts */
+ spin_unlock_irqrestore(&hpc_event_lock, psw);
+
+ /* Enable Shift Out interrupt and clear it, also */
+ /* enable SERR on power fault */
+ misc = readw(php_ctlr->creg + MISC);
+ misc |= 0x6006;
+ writew(misc, php_ctlr->creg + MISC);
+
+ /* Changed 05/05/97 to clear all interrupts at start */
+ writel(0xFFFFFFFF, php_ctlr->creg + INT_INPUT_CLEAR);
+
+ php_ctlr->ctrl_int_comp = readl(php_ctlr->creg + INT_INPUT_CLEAR);
+
+ writel(0x0L, php_ctlr->creg + INT_MASK);
+ /*
+ * Initialize the per slot SERR for unexpected switch open to 0
+ * If the bit is et to 1, slot switch interrupt causes the SERR# pin
+ * to be asserted.
+ */
+ writeb(0, php_ctlr->creg + SLOT_SERR);
+
+ /* Add this HPC instance into the HPC list */
+ /* TO DO: Do we need to spinlock this? */
+ if (php_ctlr_list_head == 0) {
+ php_ctlr_list_head = php_ctlr;
+ p = php_ctlr_list_head;
+ p->pnext = 0;
+ } else {
+ p = php_ctlr_list_head;
+
+ while (p->pnext)
+ p = p->pnext;
+
+ p->pnext = php_ctlr;
+ }
+
+ ctlr_seq_num++;
+ ctrl->hpc_ctlr_handle = php_ctlr;
+ ctrl->hpc_ops = &cpqphp_hpc_ops;
+
+ DBG_LEAVE_ROUTINE
+ return 0;
+
+ /* We end up here for the many possible ways to fail this API. */
+abort_free_ctlr:
+ kfree(php_ctlr);
+abort:
+ DBG_LEAVE_ROUTINE
+ return -1;
+}
diff -Nru a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
--- a/drivers/pci/hotplug/cpqphp_pci.c 2003-07-02 13:56:02.000000000 -0700
+++ b/drivers/pci/hotplug/cpqphp_pci.c 2003-07-07 09:32:23.000000000 -0700
@@ -36,50 +36,9 @@
#include <linux/pci.h>
#include "../pci.h"
#include "cpqphp.h"
-#include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */
-
-
-u8 cpqhp_nic_irq;
-u8 cpqhp_disk_irq;
-
-static u16 unused_IRQ;
-
-/*
- * detect_HRT_floating_pointer
- *
- * find the Hot Plug Resource Table in the specified region of memory.
- *
- */
-static void *detect_HRT_floating_pointer(void *begin, void *end)
-{
- void *fp;
- void *endp;
- u8 temp1, temp2, temp3, temp4;
- int status = 0;
-
- endp = (end - sizeof(struct hrt) + 1);
-
- for (fp = begin; fp <= endp; fp += 16) {
- temp1 = readb(fp + SIG0);
- temp2 = readb(fp + SIG1);
- temp3 = readb(fp + SIG2);
- temp4 = readb(fp + SIG3);
- if (temp1 == '$' &&
- temp2 == 'H' &&
- temp3 == 'R' &&
- temp4 == 'T') {
- status = 1;
- break;
- }
- }
-
- if (!status)
- fp = NULL;
-
- dbg("Discovered Hotplug Resource Table at %p\n", fp);
- return fp;
-}
+#ifndef CONFIG_IA64
+#include "../arch/i386/pci/pci.h" /* horrible hack showing how processor dependant we are... */
+#endif


int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
@@ -93,7 +52,7 @@

/* No pci device, we need to create it then */
if (func->pci_dev == NULL) {
- dbg("INFO: pci_dev still null\n");
+ dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);

num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
if (num)
@@ -118,29 +77,37 @@

int cpqhp_unconfigure_device(struct pci_func* func)
{
+ int rc = 0;
int j;
-
+
+
dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function);

for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j);
- if (temp)
+ if (temp) {
pci_remove_bus_device(temp);
+ }
}
- return 0;
+ return rc;
}

static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
{
u32 vendID = 0;
+ int rc;
+
+ rc = pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID);

- if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
+ if (rc == -1)
return -1;
if (vendID == 0xffffffff)
return -1;
- return pci_bus_read_config_dword (bus, devfn, offset, value);
-}

+ rc = pci_bus_read_config_dword (bus, devfn, offset, value);
+
+ return rc;
+}

/*
* cpqhp_set_irq
@@ -151,6 +118,7 @@
*/
int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
{
+#if defined(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM) && defined(CONFIG_X86)
int rc;
u16 temp_word;
struct pci_dev fakedev;
@@ -166,60 +134,53 @@
if (!rc)
return !rc;

- // set the Edge Level Control Register (ELCR)
+ /* set the Edge Level Control Register (ELCR) */
temp_word = inb(0x4d0);
temp_word |= inb(0x4d1) << 8;

temp_word |= 0x01 << irq_num;

- // This should only be for x86 as it sets the Edge Level Control Register
+ /* This should only be for x86 as it sets the Edge Level Control Register */
outb((u8) (temp_word & 0xFF), 0x4d0);
outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
-
+#endif
return 0;
}


-/*
- * WTF??? This function isn't in the code, yet a function calls it, but the
- * compiler optimizes it away? strange. Here as a placeholder to keep the
- * compiler happy.
- */
-static int PCI_ScanBusNonBridge (u8 bus, u8 device)
-{
- return 0;
-}

-static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num)
+static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 * bus_num, u8 * dev_num)
{
u8 tdevice;
u32 work;
u8 tbus;
+ struct pci_bus lpci_bus, *pci_bus;

- ctrl->pci_bus->number = bus_num;
+ memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;
+ pci_bus->number = *bus_num;

- for (tdevice = 0; tdevice < 0xFF; tdevice++) {
- //Scan for access first
- if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
+ for (tdevice = 0; tdevice < 0x100; tdevice++) {
+ if (PCI_RefinedAccessConfig (pci_bus, tdevice, 0x08, &work) == -1)
continue;
- dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
- //Yep we got one. Not a bridge ?
+ dbg("Looking for nonbridge bus_num %d dev_num %d\n", *bus_num, tdevice);
if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
*dev_num = tdevice;
dbg("found it !\n");
return 0;
}
}
- for (tdevice = 0; tdevice < 0xFF; tdevice++) {
- //Scan for access first
- if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
+ for (tdevice = 0; tdevice < 0x100; tdevice++) {
+ if (PCI_RefinedAccessConfig (pci_bus, tdevice, 0x08, &work) == -1)
continue;
- dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
- //Yep we got one. bridge ?
+ dbg("Looking for bridge bus_num %d dev_num %d\n", *bus_num, tdevice);
if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
- dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
- if (PCI_ScanBusNonBridge(tbus, tdevice) == 0)
+ pci_bus_read_config_byte(pci_bus, tdevice, PCI_SECONDARY_BUS, &tbus);
+
+ dbg("Found a new bus %d on bus %d device %d\n", tbus, *bus_num, tdevice);
+ dbg("Recurse on the new bus %d\n", tbus);
+ *bus_num = tbus;
+ if (PCI_ScanBusForNonBridge(ctrl, bus_num, dev_num) == 0)
return 0;
}
}
@@ -227,75 +188,59 @@
return -1;
}

-
-static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge)
+static int PCI_GetBusDevHelper(struct controller *ctrl, u8 * bus_num, u8 * dev_num,
+ struct slot *slot, u8 nobridge)
{
- struct irq_routing_table *PCIIRQRoutingInfoLength;
- long len;
long loop;
u32 work;
+ u8 tbus, tdevice;
+ struct pci_bus lpci_bus, *pci_bus;
+ memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;
+
+ dbg("GetBusDev: bus %d dev %d func %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7);
+ for (loop = 0; loop < 8; ++loop) {
+ tbus = slot->bus;
+ tdevice = slot->device << 3 | loop;
+
+ *bus_num = tbus;
+ *dev_num = tdevice;
+ pci_bus->number = tbus;

- u8 tbus, tdevice, tslot;
+ pci_bus_read_config_dword(pci_bus, *dev_num, PCI_VENDOR_ID, &work);

- PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
- if (!PCIIRQRoutingInfoLength)
- return -1;
+ if (!nobridge || (work == 0xffffffff)) {
+ dbg("GetBusDev: nodev bus %d dev %d func %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7);
+ return 0;
+ }

- len = (PCIIRQRoutingInfoLength->size -
- sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
- // Make sure I got at least one entry
- if (len == 0) {
- if (PCIIRQRoutingInfoLength != NULL)
- kfree(PCIIRQRoutingInfoLength );
- return -1;
- }
+ dbg("bus_num %d dev_num %d func_num %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7);

- for (loop = 0; loop < len; ++loop) {
- tbus = PCIIRQRoutingInfoLength->slots[loop].bus;
- tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn;
- tslot = PCIIRQRoutingInfoLength->slots[loop].slot;
+ pci_bus_read_config_dword(pci_bus, *dev_num, PCI_CLASS_REVISION, &work);

- if (tslot == slot) {
- *bus_num = tbus;
- *dev_num = tdevice;
- ctrl->pci_bus->number = tbus;
- pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
- if (!nobridge || (work == 0xffffffff)) {
- if (PCIIRQRoutingInfoLength != NULL)
- kfree(PCIIRQRoutingInfoLength );
- return 0;
- }
+ dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);

- dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
- pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
- dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
-
- if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
- pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
- dbg("Scan bus for Non Bridge: bus %d\n", tbus);
- if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
- *bus_num = tbus;
- if (PCIIRQRoutingInfoLength != NULL)
- kfree(PCIIRQRoutingInfoLength );
- return 0;
- }
- } else {
- if (PCIIRQRoutingInfoLength != NULL)
- kfree(PCIIRQRoutingInfoLength );
- return 0;
- }
+ if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {

- }
+ pci_bus_read_config_byte(pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
+
+ dbg("Scan bus for Non Bridge: bus %d\n", tbus);
+ *bus_num = tbus;
+ if (PCI_ScanBusForNonBridge(ctrl, bus_num, dev_num) == 0)
+ return 0;
+ else
+ dbg("no Non Bridge under bus %d\n", tbus);
+ } else
+ return 0;
}
- if (PCIIRQRoutingInfoLength != NULL)
- kfree(PCIIRQRoutingInfoLength );
+
+ dbg("GetBusDev: fail bus %d dev %d func %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7);
return -1;
}

-
-int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot)
+int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, struct slot *slot)
{
- return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed)
+ return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); /*plain (bridges allowed) */
}


@@ -311,9 +256,9 @@
*
* returns 0 if success
*/
-int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
+int cpqhp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
{
- long rc;
+ int rc;
u8 class_code;
u8 header_type;
u32 ID;
@@ -329,36 +274,46 @@
int cloop = 0;
int stop_it;
int index;
+ int is_hot_plug = num_ctlr_slots || first_device_num;
+ struct pci_bus lpci_bus, *pci_bus;
+ memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;

- // Decide which slots are supported
+ dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);

+ /* Decide which slots are supported */
if (is_hot_plug) {
- //*********************************
- // is_hot_plug is the slot mask
- //*********************************
- FirstSupported = is_hot_plug >> 4;
- LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
+ /*********************************
+ is_hot_plug is the slot mask
+ *********************************/
+ FirstSupported = first_device_num;
+ LastSupported = FirstSupported + num_ctlr_slots - 1;
} else {
FirstSupported = 0;
LastSupported = 0x1F;
}

- // Save PCI configuration space for all devices in supported slots
- ctrl->pci_bus->number = busnumber;
+ dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported);
+
+ /* Save PCI configuration space for all devices in supported slots */
+ pci_bus->number = busnumber;
for (device = FirstSupported; device <= LastSupported; device++) {
ID = 0xFFFFFFFF;
- rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+ rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);

- if (ID != 0xFFFFFFFF) { // device in slot
- rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
+ if (ID != 0xFFFFFFFF) { /* device in slot */
+ rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
+
if (rc)
return rc;

- rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
+ rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
if (rc)
return rc;

- // If multi-function device, set max_functions to 8
+ dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+ /* If multi-function device, set max_functions to 8 */
if (header_type & 0x80)
max_functions = 8;
else
@@ -369,33 +324,36 @@
do {
DevError = 0;

- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge
- // Recurse the subordinate bus
- // get the subordinate bus number
- rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */
+ /* Recurse the subordinate bus
+ get the subordinate bus number */
+ rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
if (rc) {
return rc;
} else {
sub_bus = (int) secondary_bus;

- // Save secondary bus cfg spc
- // with this recursive call.
- rc = cpqhp_save_config(ctrl, sub_bus, 0);
+ /* Save secondary bus cfg spc
+ with this recursive call. */
+ rc = cpqhp_save_config(ctrl, sub_bus, 0, 0);
if (rc)
return rc;
- ctrl->pci_bus->number = busnumber;
}
}

index = 0;
new_slot = cpqhp_slot_find(busnumber, device, index++);
- while (new_slot &&
- (new_slot->function != (u8) function))
- new_slot = cpqhp_slot_find(busnumber, device, index++);

+ dbg("new_slot = %p\n", new_slot);
+
+ while (new_slot && (new_slot->function != (u8) function)) {
+ new_slot = cpqhp_slot_find(busnumber, device, index++);
+ dbg("new_slot = %p\n", new_slot);
+ }
if (!new_slot) {
- // Setup slot structure.
+ /* Setup slot structure. */
new_slot = cpqhp_slot_create(busnumber);
+ dbg("new_slot = %p\n", new_slot);

if (new_slot == NULL)
return(1);
@@ -406,12 +364,15 @@
new_slot->function = (u8) function;
new_slot->is_a_board = 1;
new_slot->switch_save = 0x10;
- // In case of unsupported board
+ /* In case of unsupported board */
new_slot->status = DevError;
new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
+ dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);

for (cloop = 0; cloop < 0x20; cloop++) {
- rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+ rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
+
+ /*dbg("new_slot->config_space[%x] = %x\n", cloop, new_slot->config_space[cloop]); */
if (rc)
return rc;
}
@@ -420,35 +381,40 @@

stop_it = 0;

- // this loop skips to the next present function
- // reading in Class Code and Header type.
+ /* this loop skips to the next present function
+ reading in Class Code and Header type. */

while ((function < max_functions)&&(!stop_it)) {
- rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
- if (ID == 0xFFFFFFFF) { // nothing there.
+ rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
+
+ if (ID == 0xFFFFFFFF) { /* nothing there. */
function++;
- } else { // Something there
- rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
+ dbg("Nothing there\n");
+ } else { /* Something there */
+
+ rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
if (rc)
return rc;

- rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
+ rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
if (rc)
return rc;

+ dbg("class_code = %x, header_type = %x\n", class_code, header_type);
stop_it++;
}
}

} while (function < max_functions);
- } // End of IF (device in slot?)
+ } /* End of IF (device in slot?) */
else if (is_hot_plug) {
- // Setup slot structure with entry for empty slot
+ /* Setup slot structure with entry for empty slot */
new_slot = cpqhp_slot_create(busnumber);

if (new_slot == NULL) {
return(1);
}
+ dbg("new_slot = %p\n", new_slot);

new_slot->bus = (u8) busnumber;
new_slot->device = (u8) device;
@@ -457,7 +423,7 @@
new_slot->presence_save = 0;
new_slot->switch_save = 0;
}
- } // End of FOR loop
+ } /* End of FOR loop */

return(0);
}
@@ -473,7 +439,7 @@
*/
int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
{
- long rc;
+ int rc;
u8 class_code;
u8 header_type;
u32 ID;
@@ -483,17 +449,21 @@
int function;
int cloop = 0;
int stop_it;
+ struct pci_bus lpci_bus, *pci_bus;
+ memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;
+ pci_bus->number = new_slot->bus;

ID = 0xFFFFFFFF;

- ctrl->pci_bus->number = new_slot->bus;
- pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
+ pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
+
+ if (ID != 0xFFFFFFFF) { /* device in slot */
+ pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);

- if (ID != 0xFFFFFFFF) { // device in slot
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
+ pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);

- if (header_type & 0x80) // Multi-function device
+ if (header_type & 0x80) /* Multi-function device */
max_functions = 8;
else
max_functions = 1;
@@ -501,49 +471,47 @@
function = 0;

do {
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge
- // Recurse the subordinate bus
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+ /* Recurse the subordinate bus */
+ pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);

sub_bus = (int) secondary_bus;

- // Save the config headers for the secondary bus.
- rc = cpqhp_save_config(ctrl, sub_bus, 0);
+ /* Save the config headers for the secondary bus. */
+ rc = cpqhp_save_config(ctrl, sub_bus, 0, 0);
+
if (rc)
return(rc);
- ctrl->pci_bus->number = new_slot->bus;

- } // End of IF
+ } /* End of IF */

new_slot->status = 0;

for (cloop = 0; cloop < 0x20; cloop++) {
- pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+ pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop]));
}

function++;

stop_it = 0;

- // this loop skips to the next present function
- // reading in the Class Code and the Header type.
+ /* this loop skips to the next present function
+ reading in the Class Code and the Header type. */

while ((function < max_functions) && (!stop_it)) {
- pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
+ pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);

- if (ID == 0xFFFFFFFF) { // nothing there.
+ if (ID == 0xFFFFFFFF) { /* nothing there. */
function++;
- } else { // Something there
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
-
- pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
-
+ } else { /* Something there */
+ pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
+ pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
stop_it++;
}
}

} while (function < max_functions);
- } // End of IF (device in slot?)
+ } /* End of IF (device in slot?) */
else {
return(2);
}
@@ -553,136 +521,6 @@


/*
- * cpqhp_save_base_addr_length
- *
- * Saves the length of all base address registers for the
- * specified slot. this is for hot plug REPLACE
- *
- * returns 0 if success
- */
-int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func)
-{
- u8 cloop;
- u8 header_type;
- u8 secondary_bus;
- u8 type;
- int sub_bus;
- u32 temp_register;
- u32 base;
- u32 rc;
- struct pci_func *next;
- int index = 0;
- struct pci_bus *pci_bus = ctrl->pci_bus;
- unsigned int devfn;
-
- func = cpqhp_slot_find(func->bus, func->device, index++);
-
- while (func != NULL) {
- pci_bus->number = func->bus;
- devfn = PCI_DEVFN(func->device, func->function);
-
- // Check for Bridge
- pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
- // PCI-PCI Bridge
- pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
-
- sub_bus = (int) secondary_bus;
-
- next = cpqhp_slot_list[sub_bus];
-
- while (next != NULL) {
- rc = cpqhp_save_base_addr_length(ctrl, next);
-
- if (rc)
- return(rc);
-
- next = next->next;
- }
- pci_bus->number = func->bus;
-
- //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together
- // Figure out IO and memory base lengths
- for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
- temp_register = 0xFFFFFFFF;
- pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
-
- if (base) { // If this register is implemented
- if (base & 0x01L) {
- // IO base
- // set base = amount of IO space requested
- base = base & 0xFFFFFFFE;
- base = (~base) + 1;
-
- type = 1;
- } else {
- // memory base
- base = base & 0xFFFFFFF0;
- base = (~base) + 1;
-
- type = 0;
- }
- } else {
- base = 0x0L;
- type = 0;
- }
-
- // Save information in slot structure
- func->base_length[(cloop - 0x10) >> 2] =
- base;
- func->base_type[(cloop - 0x10) >> 2] = type;
-
- } // End of base register loop
-
-
- } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge
- // Figure out IO and memory base lengths
- for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
- temp_register = 0xFFFFFFFF;
- pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
-
- if (base) { // If this register is implemented
- if (base & 0x01L) {
- // IO base
- // base = amount of IO space requested
- base = base & 0xFFFFFFFE;
- base = (~base) + 1;
-
- type = 1;
- } else {
- // memory base
- // base = amount of memory space requested
- base = base & 0xFFFFFFF0;
- base = (~base) + 1;
-
- type = 0;
- }
- } else {
- base = 0x0L;
- type = 0;
- }
-
- // Save information in slot structure
- func->base_length[(cloop - 0x10) >> 2] = base;
- func->base_type[(cloop - 0x10) >> 2] = type;
-
- } // End of base register loop
-
- } else { // Some other unknown header type
- }
-
- // find the next device in this slot
- func = cpqhp_slot_find(func->bus, func->device, index++);
- }
-
- return(0);
-}
-
-
-/*
* cpqhp_save_used_resources
*
* Stores used resource information for existing boards. this is
@@ -690,50 +528,62 @@
* this function is for hot plug ADD
*
* returns 0 if success
+ * if disable == 1(DISABLE_CARD),
+ * it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
*/
-int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func)
+int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable)
{
u8 cloop;
u8 header_type;
u8 secondary_bus;
u8 temp_byte;
- u8 b_base;
- u8 b_length;
u16 command;
u16 save_command;
- u16 w_base;
- u16 w_length;
+ u16 w_base, w_length;
u32 temp_register;
u32 save_base;
- u32 base;
+ u32 base, length;
+ u64 base64 = 0;
int index = 0;
- struct pci_resource *mem_node;
- struct pci_resource *p_mem_node;
+ unsigned int devfn;
+ struct pci_resource *mem_node = NULL;
+ struct pci_resource *p_mem_node = NULL;
+ struct pci_resource *t_mem_node;
struct pci_resource *io_node;
struct pci_resource *bus_node;
- struct pci_bus *pci_bus = ctrl->pci_bus;
- unsigned int devfn;
+ struct pci_bus lpci_bus, *pci_bus;
+ memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+ pci_bus = &lpci_bus;

- func = cpqhp_slot_find(func->bus, func->device, index++);
+ if (disable)
+ func = cpqhp_slot_find(func->bus, func->device, index++);

while ((func != NULL) && func->is_a_board) {
pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function);

- // Save the command register
+ /* Save the command register */
pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command);

- // disable card
- command = 0x00;
- pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command);
+ if (disable) {
+ /* disable card */
+ command = 0x00;
+
+ pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+ }

- // Check for Bridge
+ /* Check for Bridge */
pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);

- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge
- // Clear Bridge Control Register
- command = 0x00;
- pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+ dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);
+ if (disable) {
+ /* Clear Bridge Control Register */
+ command = 0x00;
+ pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+ }
+
pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);

@@ -741,661 +591,290 @@
if (!bus_node)
return -ENOMEM;

- bus_node->base = secondary_bus;
- bus_node->length = temp_byte - secondary_bus + 1;
+ bus_node->base = (ulong)secondary_bus;
+ bus_node->length = (ulong)(temp_byte - secondary_bus + 1);

bus_node->next = func->bus_head;
func->bus_head = bus_node;

- // Save IO base and Limit registers
- pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base);
- pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length);
+ /* Save IO base and Limit registers */
+ pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &temp_byte);
+ base = temp_byte;
+ pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
+ length = temp_byte;

- if ((b_base <= b_length) && (save_command & 0x01)) {
+ if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!io_node)
return -ENOMEM;

- io_node->base = (b_base & 0xF0) << 8;
- io_node->length = (b_length - b_base + 0x10) << 8;
+ io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
+ io_node->length = (ulong)(length - base + 0x10) << 8;

io_node->next = func->io_head;
func->io_head = io_node;
}

- // Save memory base and Limit registers
+ /* Save memory base and Limit registers */
pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);

- if ((w_base <= w_length) && (save_command & 0x02)) {
+ if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!mem_node)
return -ENOMEM;

- mem_node->base = w_base << 16;
- mem_node->length = (w_length - w_base + 0x10) << 16;
+ mem_node->base = (ulong)w_base << 16;
+ mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;

mem_node->next = func->mem_head;
func->mem_head = mem_node;
}
-
- // Save prefetchable memory base and Limit registers
+ /* Save prefetchable memory base and Limit registers */
pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);

- if ((w_base <= w_length) && (save_command & 0x02)) {
+ if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!p_mem_node)
return -ENOMEM;

- p_mem_node->base = w_base << 16;
- p_mem_node->length = (w_length - w_base + 0x10) << 16;
+ p_mem_node->base = (ulong)w_base << 16;
+ p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;

p_mem_node->next = func->p_mem_head;
func->p_mem_head = p_mem_node;
}
- // Figure out IO and memory base lengths
- for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
+
+ /* Figure out IO and memory base lengths
+ P2P BAR is not for children though... */
+ for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_1; cloop += 4) {
pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);

temp_register = 0xFFFFFFFF;
pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
+ pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);

- temp_register = base;
+ if (!disable) {
+ pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
+ }

- if (base) { // If this register is implemented
- if (((base & 0x03L) == 0x01)
- && (save_command & 0x01)) {
- // IO base
- // set temp_register = amount of IO space requested
- temp_register = base & 0xFFFFFFFE;
- temp_register = (~temp_register) + 1;
-
- io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!io_node)
- return -ENOMEM;
-
- io_node->base =
- save_base & (~0x03L);
- io_node->length = temp_register;
+ if (!temp_register)
+ continue;

- io_node->next = func->io_head;
- func->io_head = io_node;
+ base = temp_register;
+
+ if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) {
+ /* IO base */
+ /* set temp_register = amount of IO space requested */
+ base = base & 0xFFFFFFFCL;
+ base = (~base) + 1;
+
+ io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+ if (!io_node)
+ return -ENOMEM;
+
+ io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+ io_node->length = (ulong)base;
+ dbg("sur: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+
+ io_node->next = func->io_head;
+ func->io_head = io_node;
+ } else { /* map Memory */
+ int prefetchable = 1;
+ char *res_type_str = "PMEM";
+ u32 temp_register2;
+
+ t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+ if (!t_mem_node)
+ return -ENOMEM;
+
+ if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+ prefetchable = 0;
+ mem_node = t_mem_node;
+ res_type_str++;
} else
- if (((base & 0x0BL) == 0x08)
- && (save_command & 0x02)) {
- // prefetchable memory base
- temp_register = base & 0xFFFFFFF0;
- temp_register = (~temp_register) + 1;
-
- p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!p_mem_node)
- return -ENOMEM;
+ p_mem_node = t_mem_node;

- p_mem_node->base = save_base & (~0x0FL);
- p_mem_node->length = temp_register;
+ base = base & 0xFFFFFFF0L;
+ base = (~base) + 1;

- p_mem_node->next = func->p_mem_head;
- func->p_mem_head = p_mem_node;
- } else
- if (((base & 0x0BL) == 0x00)
- && (save_command & 0x02)) {
- // prefetchable memory base
- temp_register = base & 0xFFFFFFF0;
- temp_register = (~temp_register) + 1;
-
- mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!mem_node)
- return -ENOMEM;
+ switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ if (prefetchable) {
+ p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+ p_mem_node->length = (ulong)base;
+ dbg("sur: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+ p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = p_mem_node;
+ } else {
+ mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+ mem_node->length = (ulong)base;
+ dbg("sur: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+ mem_node->next = func->mem_head;
+ func->mem_head = mem_node;
+ }
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+
+ base64 = temp_register2;
+ base64 = (base64 << 32) | save_base;
+
+ if (temp_register2) {
+ dbg("sur: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64);
+ base64 &= 0x00000000FFFFFFFFL;
+ }
+
+ if (prefetchable) {
+ p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+ p_mem_node->length = base;
+ dbg("sur: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+ p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = p_mem_node;
+ } else {
+ mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+ mem_node->length = base;
+ dbg("sur: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+ mem_node->next = func->mem_head;
+ func->mem_head = mem_node;
+ }
+ cloop += 4;
+ break;
+ default:
+ dbg("asur: reserved BAR type=0x%x\n", temp_register);
+ break;

- mem_node->base = save_base & (~0x0FL);
- mem_node->length = temp_register;
+ }
+ }
+ } /* End of base register loop */
+ } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+ dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command);

- mem_node->next = func->mem_head;
- func->mem_head = mem_node;
- } else
- return(1);
- }
- } // End of base register loop
- } else if ((header_type & 0x7F) == 0x00) { // Standard header
- // Figure out IO and memory base lengths
- for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
+ /* Figure out IO and memory base lengths */
+ for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);

temp_register = 0xFFFFFFFF;
- pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
-
- temp_register = base;
-
- if (base) { // If this register is implemented
- if (((base & 0x03L) == 0x01)
- && (save_command & 0x01)) {
- // IO base
- // set temp_register = amount of IO space requested
- temp_register = base & 0xFFFFFFFE;
- temp_register = (~temp_register) + 1;
-
- io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!io_node)
- return -ENOMEM;
-
- io_node->base = save_base & (~0x01L);
- io_node->length = temp_register;
-
- io_node->next = func->io_head;
- func->io_head = io_node;
- } else
- if (((base & 0x0BL) == 0x08)
- && (save_command & 0x02)) {
- // prefetchable memory base
- temp_register = base & 0xFFFFFFF0;
- temp_register = (~temp_register) + 1;
-
- p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!p_mem_node)
- return -ENOMEM;
-
- p_mem_node->base = save_base & (~0x0FL);
- p_mem_node->length = temp_register;
-
- p_mem_node->next = func->p_mem_head;
- func->p_mem_head = p_mem_node;
- } else
- if (((base & 0x0BL) == 0x00)
- && (save_command & 0x02)) {
- // prefetchable memory base
- temp_register = base & 0xFFFFFFF0;
- temp_register = (~temp_register) + 1;
-
- mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!mem_node)
- return -ENOMEM;
-
- mem_node->base = save_base & (~0x0FL);
- mem_node->length = temp_register;

- mem_node->next = func->mem_head;
- func->mem_head = mem_node;
- } else
- return(1);
- }
- } // End of base register loop
- } else { // Some other unknown header type
- }
-
- // find the next device in this slot
- func = cpqhp_slot_find(func->bus, func->device, index++);
- }
-
- return(0);
-}
-
-
-/*
- * cpqhp_configure_board
- *
- * Copies saved configuration information to one slot.
- * this is called recursively for bridge devices.
- * this is for hot plug REPLACE!
- *
- * returns 0 if success
- */
-int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
-{
- int cloop;
- u8 header_type;
- u8 secondary_bus;
- int sub_bus;
- struct pci_func *next;
- u32 temp;
- u32 rc;
- int index = 0;
- struct pci_bus *pci_bus = ctrl->pci_bus;
- unsigned int devfn;
-
- func = cpqhp_slot_find(func->bus, func->device, index++);
-
- while (func != NULL) {
- pci_bus->number = func->bus;
- devfn = PCI_DEVFN(func->device, func->function);
-
- // Start at the top of config space so that the control
- // registers are programmed last
- for (cloop = 0x3C; cloop > 0; cloop -= 4) {
- pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
- }
-
- pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
-
- // If this is a bridge device, restore subordinate devices
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge
- pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
-
- sub_bus = (int) secondary_bus;
-
- next = cpqhp_slot_list[sub_bus];
-
- while (next != NULL) {
- rc = cpqhp_configure_board(ctrl, next);
-
- if (rc)
- return rc;
-
- next = next->next;
- }
- } else {
-
- // Check all the base Address Registers to make sure
- // they are the same. If not, the board is different.
-
- for (cloop = 16; cloop < 40; cloop += 4) {
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
+ pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+ pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);

- if (temp != func->config_space[cloop >> 2]) {
- dbg("Config space compare failure!!! offset = %x\n", cloop);
- dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
- dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
- return 1;
+ if (!disable) {
+ pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
}
- }
- }
-
- func->configured = 1;
-
- func = cpqhp_slot_find(func->bus, func->device, index++);
- }
-
- return 0;
-}

+ if (!temp_register)
+ continue;

-/*
- * cpqhp_valid_replace
- *
- * this function checks to see if a board is the same as the
- * one it is replacing. this check will detect if the device's
- * vendor or device id's are the same
- *
- * returns 0 if the board is the same nonzero otherwise
- */
-int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func)
-{
- u8 cloop;
- u8 header_type;
- u8 secondary_bus;
- u8 type;
- u32 temp_register = 0;
- u32 base;
- u32 rc;
- struct pci_func *next;
- int index = 0;
- struct pci_bus *pci_bus = ctrl->pci_bus;
- unsigned int devfn;
-
- if (!func->is_a_board)
- return(ADD_NOT_SUPPORTED);
-
- func = cpqhp_slot_find(func->bus, func->device, index++);
-
- while (func != NULL) {
- pci_bus->number = func->bus;
- devfn = PCI_DEVFN(func->device, func->function);
-
- pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
-
- // No adapter present
- if (temp_register == 0xFFFFFFFF)
- return(NO_ADAPTER_PRESENT);
-
- if (temp_register != func->config_space[0])
- return(ADAPTER_NOT_SAME);
-
- // Check for same revision number and class code
- pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
-
- // Adapter not the same
- if (temp_register != func->config_space[0x08 >> 2])
- return(ADAPTER_NOT_SAME);
-
- // Check for Bridge
- pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge
- // In order to continue checking, we must program the
- // bus registers in the bridge to respond to accesses
- // for it's subordinate bus(es)
-
- temp_register = func->config_space[0x18 >> 2];
- pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
-
- secondary_bus = (temp_register >> 8) & 0xFF;
-
- next = cpqhp_slot_list[secondary_bus];
-
- while (next != NULL) {
- rc = cpqhp_valid_replace(ctrl, next);
-
- if (rc)
- return(rc);
-
- next = next->next;
- }
-
- }
- // Check to see if it is a standard config header
- else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
- // Check subsystem vendor and ID
- pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
-
- if (temp_register != func->config_space[0x2C >> 2]) {
- // If it's a SMART-2 and the register isn't filled
- // in, ignore the difference because
- // they just have an old rev of the firmware
-
- if (!((func->config_space[0] == 0xAE100E11)
- && (temp_register == 0x00L)))
- return(ADAPTER_NOT_SAME);
- }
- // Figure out IO and memory base lengths
- for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
- temp_register = 0xFFFFFFFF;
- pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
- pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
- if (base) { // If this register is implemented
- if (base & 0x01L) {
- // IO base
- // set base = amount of IO space requested
- base = base & 0xFFFFFFFE;
- base = (~base) + 1;
+ base = temp_register;
+
+ if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) {
+ /* IO base */
+ /* set temp_register = amount of IO space requested */
+ base = base & 0xFFFFFFFCL;
+ base = (~base) + 1;
+
+ io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+ if (!io_node)
+ return -ENOMEM;
+
+ io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+ io_node->length = (ulong)base;
+ dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+
+ io_node->next = func->io_head;
+ func->io_head = io_node;
+ } else { /* map Memory */
+ int prefetchable = 1;
+ char *res_type_str = "PMEM";
+ u32 temp_register2;
+
+ t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+ if (!t_mem_node)
+ return -ENOMEM;
+
+ if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+ prefetchable = 0;
+ mem_node = t_mem_node;
+ res_type_str++;
+ } else
+ p_mem_node = t_mem_node;

- type = 1;
- } else {
- // memory base
- base = base & 0xFFFFFFF0;
- base = (~base) + 1;
+ base = base & 0xFFFFFFF0L;
+ base = (~base) + 1;

- type = 0;
+ switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ if (prefetchable) {
+ p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+ p_mem_node->length = (ulong)base;
+ dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+ p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = p_mem_node;
+ } else {
+ mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+ mem_node->length = (ulong)base;
+ dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+ mem_node->next = func->mem_head;
+ func->mem_head = mem_node;
+ }
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+
+ base64 = temp_register2;
+ base64 = (base64 << 32) | save_base;
+
+ if (temp_register2) {
+ dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64);
+ base64 &= 0x00000000FFFFFFFFL;
+ }
+
+ if (prefetchable) {
+ p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+ p_mem_node->length = base;
+ dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length);
+
+ p_mem_node->next = func->p_mem_head;
+ func->p_mem_head = p_mem_node;
+ } else {
+ mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+ mem_node->length = base;
+ dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length);
+
+ mem_node->next = func->mem_head;
+ func->mem_head = mem_node;
+ }
+ cloop += 4;
+ break;
+ default:
+ dbg("asur: reserved BAR type=0x%x\n", temp_register);
+ break;
}
- } else {
- base = 0x0L;
- type = 0;
- }
-
- // Check information in slot structure
- if (func->base_length[(cloop - 0x10) >> 2] != base)
- return(ADAPTER_NOT_SAME);
-
- if (func->base_type[(cloop - 0x10) >> 2] != type)
- return(ADAPTER_NOT_SAME);
-
- } // End of base register loop
-
- } // End of (type 0 config space) else
- else {
- // this is not a type 0 or 1 config space header so
- // we don't know how to do it
- return(DEVICE_TYPE_NOT_SUPPORTED);
+ }
+ } /* End of base register loop */
+ } else { /* Some other unknown header type */
+ dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func->bus, func->device);
}

- // Get the next function
+ /* find the next device in this slot */
+ if (!disable)
+ break;
func = cpqhp_slot_find(func->bus, func->device, index++);
}

-
return(0);
}


/*
- * cpqhp_find_available_resources
- *
- * Finds available memory, IO, and IRQ resources for programming
- * devices which may be added to the system
- * this function is for hot plug ADD!
- *
- * returns 0 if success
- */
-int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start)
-{
- u8 temp;
- u8 populated_slot;
- u8 bridged_slot;
- void *one_slot;
- struct pci_func *func = NULL;
- int i = 10, index;
- u32 temp_dword, rc;
- struct pci_resource *mem_node;
- struct pci_resource *p_mem_node;
- struct pci_resource *io_node;
- struct pci_resource *bus_node;
- void *rom_resource_table;
-
- rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
- dbg("rom_resource_table = %p\n", rom_resource_table);
-
- if (rom_resource_table == NULL) {
- return -ENODEV;
- }
- // Sum all resources and setup resource maps
- unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
- dbg("unused_IRQ = %x\n", unused_IRQ);
-
- temp = 0;
- while (unused_IRQ) {
- if (unused_IRQ & 1) {
- cpqhp_disk_irq = temp;
- break;
- }
- unused_IRQ = unused_IRQ >> 1;
- temp++;
- }
-
- dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
- unused_IRQ = unused_IRQ >> 1;
- temp++;
-
- while (unused_IRQ) {
- if (unused_IRQ & 1) {
- cpqhp_nic_irq = temp;
- break;
- }
- unused_IRQ = unused_IRQ >> 1;
- temp++;
- }
-
- dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
- unused_IRQ = readl(rom_resource_table + PCIIRQ);
-
- temp = 0;
-
- if (!cpqhp_nic_irq) {
- cpqhp_nic_irq = ctrl->cfgspc_irq;
- }
-
- if (!cpqhp_disk_irq) {
- cpqhp_disk_irq = ctrl->cfgspc_irq;
- }
-
- dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
-
- rc = compaq_nvram_load(rom_start, ctrl);
- if (rc)
- return rc;
-
- one_slot = rom_resource_table + sizeof (struct hrt);
-
- i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
- dbg("number_of_entries = %d\n", i);
-
- if (!readb(one_slot + SECONDARY_BUS)) {
- return(1);
- }
-
- dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
-
- while (i && readb(one_slot + SECONDARY_BUS)) {
- u8 dev_func = readb(one_slot + DEV_FUNC);
- u8 primary_bus = readb(one_slot + PRIMARY_BUS);
- u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
- u8 max_bus = readb(one_slot + MAX_BUS);
- u16 io_base = readw(one_slot + IO_BASE);
- u16 io_length = readw(one_slot + IO_LENGTH);
- u16 mem_base = readw(one_slot + MEM_BASE);
- u16 mem_length = readw(one_slot + MEM_LENGTH);
- u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
- u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
-
- dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
- dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
- primary_bus, secondary_bus, max_bus);
-
- // If this entry isn't for our controller's bus, ignore it
- if (primary_bus != ctrl->bus) {
- i--;
- one_slot += sizeof (struct slot_rt);
- continue;
- }
- // find out if this entry is for an occupied slot
- ctrl->pci_bus->number = primary_bus;
- pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
- dbg("temp_D_word = %x\n", temp_dword);
-
- if (temp_dword != 0xFFFFFFFF) {
- index = 0;
- func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
-
- while (func && (func->function != (dev_func & 0x07))) {
- dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
- func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
- }
-
- // If we can't find a match, skip this table entry
- if (!func) {
- i--;
- one_slot += sizeof (struct slot_rt);
- continue;
- }
- // this may not work and shouldn't be used
- if (secondary_bus != primary_bus)
- bridged_slot = 1;
- else
- bridged_slot = 0;
-
- populated_slot = 1;
- } else {
- populated_slot = 0;
- bridged_slot = 0;
- }
-
-
- // If we've got a valid IO base, use it
-
- temp_dword = io_base + io_length;
-
- if ((io_base) && (temp_dword < 0x10000)) {
- io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!io_node)
- return -ENOMEM;
-
- io_node->base = io_base;
- io_node->length = io_length;
-
- dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length);
- dbg("populated slot =%d \n", populated_slot);
- if (!populated_slot) {
- io_node->next = ctrl->io_head;
- ctrl->io_head = io_node;
- } else {
- io_node->next = func->io_head;
- func->io_head = io_node;
- }
- }
-
- // If we've got a valid memory base, use it
- temp_dword = mem_base + mem_length;
- if ((mem_base) && (temp_dword < 0x10000)) {
- mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!mem_node)
- return -ENOMEM;
-
- mem_node->base = mem_base << 16;
-
- mem_node->length = mem_length << 16;
-
- dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length);
- dbg("populated slot =%d \n", populated_slot);
- if (!populated_slot) {
- mem_node->next = ctrl->mem_head;
- ctrl->mem_head = mem_node;
- } else {
- mem_node->next = func->mem_head;
- func->mem_head = mem_node;
- }
- }
-
- // If we've got a valid prefetchable memory base, and
- // the base + length isn't greater than 0xFFFF
- temp_dword = pre_mem_base + pre_mem_length;
- if ((pre_mem_base) && (temp_dword < 0x10000)) {
- p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!p_mem_node)
- return -ENOMEM;
-
- p_mem_node->base = pre_mem_base << 16;
-
- p_mem_node->length = pre_mem_length << 16;
- dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length);
- dbg("populated slot =%d \n", populated_slot);
-
- if (!populated_slot) {
- p_mem_node->next = ctrl->p_mem_head;
- ctrl->p_mem_head = p_mem_node;
- } else {
- p_mem_node->next = func->p_mem_head;
- func->p_mem_head = p_mem_node;
- }
- }
-
- // If we've got a valid bus number, use it
- // The second condition is to ignore bus numbers on
- // populated slots that don't have PCI-PCI bridges
- if (secondary_bus && (secondary_bus != primary_bus)) {
- bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (!bus_node)
- return -ENOMEM;
-
- bus_node->base = secondary_bus;
- bus_node->length = max_bus - secondary_bus + 1;
- dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length);
- dbg("populated slot =%d \n", populated_slot);
- if (!populated_slot) {
- bus_node->next = ctrl->bus_head;
- ctrl->bus_head = bus_node;
- } else {
- bus_node->next = func->bus_head;
- func->bus_head = bus_node;
- }
- }
-
- i--;
- one_slot += sizeof (struct slot_rt);
- }
-
- // If all of the following fail, we don't have any resources for
- // hot plug add
- rc = 1;
- rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
- rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
- rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
- rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
-
- return(rc);
-}
-
-
-/*
* cpqhp_return_board_resources
*
* this routine returns all resources allocated to a board to
diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
--- a/drivers/pci/hotplug/Kconfig 2003-07-02 13:46:17.000000000 -0700
+++ b/drivers/pci/hotplug/Kconfig 2003-07-07 09:32:25.000000000 -0700
@@ -47,11 +47,11 @@
When in doubt, say N.

config HOTPLUG_PCI_COMPAQ
- tristate "Compaq PCI Hotplug driver"
- depends on HOTPLUG_PCI && X86
+ tristate "Compaq/Intel PCI Hotplug driver"
+ depends on HOTPLUG_PCI
help
Say Y here if you have a motherboard with a Compaq PCI Hotplug
- controller.
+ controller or equivalent Intel controller.

This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -60,9 +60,19 @@

When in doubt, say N.

+config HOTPLUG_PCI_COMPAQ_PHPRM_LEGACY
+ bool "Non-ACPI: Use Hotplug Resource Table ($HRT) for resource information"
+ depends on HOTPLUG_PCI_COMPAQ
+ help
+ Say Y here if Hotplug resource/configuration information is provided
+ by platform BIOS $HRT, not by ACPI.
+ Some ACPI compliant platforms may use this too if $HRT is provided.
+
+ When in doubt, say N.
+
config HOTPLUG_PCI_COMPAQ_NVRAM
bool "Save configuration into NVRAM on Compaq servers"
- depends on HOTPLUG_PCI_COMPAQ
+ depends on HOTPLUG_PCI_COMPAQ_PHPRM_LEGACY
help
Say Y here if you have a Compaq server that has a PCI Hotplug
controller. This will allow the PCI Hotplug driver to store the PCI
diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
--- a/drivers/pci/hotplug/Makefile 2003-07-02 13:51:13.000000000 -0700
+++ b/drivers/pci/hotplug/Makefile 2003-07-07 09:32:25.000000000 -0700
@@ -3,7 +3,7 @@
#

obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
-obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
+obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
@@ -20,7 +20,8 @@
cpqphp-objs := cpqphp_core.o \
cpqphp_ctrl.o \
cpqphp_sysfs.o \
- cpqphp_pci.o
+ cpqphp_pci.o \
+ cpqphp_hpc.o

ibmphp-objs := ibmphp_core.o \
ibmphp_ebda.o \
@@ -40,6 +41,13 @@
endif
endif

+ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_PHPRM_LEGACY),y)
+ cpqphp-objs += phprm_legacy.o
+else
+ cpqphp-objs += phprm_acpi.o
+ EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi -I$(TOPDIR)/drivers/acpi/include -DPHP_ACPI
+endif
+
ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
cpqphp-objs += cpqphp_nvram.o
endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:46    [W:0.091 / U:0.100 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site