📄 ibmphp_core.c
字号:
/* * IBM Hot Plug Controller Driver * * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation * * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001-2003 IBM Corp. * * All rights reserved. * * 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 "../pci.h"#include "../../../arch/i386/pci/pci.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.6"#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);struct pci_bus *ibmphp_pci_bus;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); else slot_cur->bus_on->current_bus_mode = 0xFF; debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); *sl = slot_cur; return 0;}static inline int slot_update (struct slot **sl){ int rc; rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); if (rc) return rc; if (!init_flag) rc = get_cur_bus_info(sl); return rc;}static int __init get_max_slots (void){ struct slot * slot_cur; struct list_head * tmp; u8 slot_count = 0; list_for_each (tmp, &ibmphp_slot_head) { slot_cur = list_entry (tmp, struct slot, ibm_slot_list); /* sometimes the hot-pluggable slots start with 4 (not always from 1) */ slot_count = max (slot_count, slot_cur->number); } return slot_count;}/* This routine will put the correct slot->device information per slot. It's * called from initialization of the slot structures. It will also assign * interrupt numbers per each slot. * Parameters: struct slot * Returns 0 or errors */int ibmphp_init_devno (struct slot **cur_slot){ struct irq_routing_table *rtable; int len; int loop; int i; rtable = pcibios_get_irq_routing_table (); if (!rtable) { err ("no BIOS routing table...\n"); return -ENOMEM; } len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); if (!len) 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"); retval = -EIO; } return retval;}static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value){ int rc = 0; struct slot *pslot; u8 cmd; 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) rc = ibmphp_hpc_writeslot(pslot, cmd); else rc = -ENODEV; } } else rc = -ENODEV; ibmphp_unlock_operations (); debug ("set_attention_status - Exit rc[%d]\n", rc); return rc;}static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations (); if (hotplug_slot && value) { pslot = (struct slot *) hotplug_slot->private; if (pslot) { memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &(myslot.status)); if (!rc) rc = ibmphp_hpc_readslot(pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); if (!rc) *value = SLOT_ATTN (myslot.status, myslot.ext_status); } } ibmphp_unlock_operations (); debug("get_attention_status - Exit rc[%d] value[%x]\n", rc, *value); return rc;}static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations (); if (hotplug_slot && value) { pslot = (struct slot *) hotplug_slot->private; if (pslot) { memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &(myslot.status)); if (!rc) *value = SLOT_LATCH (myslot.status); } } ibmphp_unlock_operations (); debug("get_latch_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc;}static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value){ int rc = -ENODEV; struct slot *pslot; struct slot myslot; debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations (); if (hotplug_slot && value) { pslot = (struct slot *) hotplug_slot->private; if (pslot) { memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &(myslot.status)); if (!rc) *value = SLOT_PWRGD (myslot.status); } } ibmphp_unlock_operations (); debug("get_power_status - Exit rc[%d] rc[%x] value[%x]\n", rc, rc, *value); return rc;}static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value){ int rc = -ENODEV; struct slot *pslot; u8 present; struct slot myslot; debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); ibmphp_lock_operations (); if (hotplug_slot && value) { pslot = (struct slot *) hotplug_slot->private; if (pslot) { memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &(myslot.status)); if (!rc) { present = SLOT_PRESENT (myslot.status); if (present == HPC_SLOT_EMPTY) *value = 0; else *value = 1; } } } ibmphp_unlock_operations (); debug("get_adapter_present - Exit rc[%d] value[%x]\n", rc, *value); return rc;}static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value){ int rc = -ENODEV; struct slot *pslot; u8 mode = 0; debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, hotplug_slot, value); ibmphp_lock_operations (); if (hotplug_slot && value) { pslot = (struct slot *) hotplug_slot->private; if (pslot) { rc = 0; mode = pslot->supported_bus_mode; *value = pslot->supported_speed; switch (*value) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX) *value += 0x01; break; case BUS_SPEED_100: case BUS_SPEED_133: *value = pslot->supported_speed + 0x01; break; default: /* Note (will need to change): there would be soon 256, 512 also */ rc = -ENODEV; } } } ibmphp_unlock_operations (); debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); return rc;}static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value){ int rc = -ENODEV; struct slot *pslot; u8 mode = 0; debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, hotplug_slot, 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; switch (*value) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX) *value += 0x01; else if (mode == BUS_MODE_PCI) ; else *value = PCI_SPEED_UNKNOWN; break; case BUS_SPEED_100: case BUS_SPEED_133: *value += 0x01; break; default: /* Note of change: there would also be 256, 512 soon */ rc = -ENODEV; } } } } ibmphp_unlock_operations (); debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, 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; struct slot myslot; debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -