list_for_each_entry(slot_cur, &ibmphp_slot_head, ibm_slot_list) { /* sometimes the hot-pluggable slots start with 4 (not always from 1) */
slot_count = max(slot_count, slot_cur->number);
} return slot_count;
}
/* This routine will put the correct slot->device information per slot. It's * called from initialization of the slot structures. It will also assign * interrupt numbers per each slot. * Parameters: struct slot * Returns 0 or errors
*/ int ibmphp_init_devno(struct slot **cur_slot)
{ struct irq_routing_table *rtable; int len; int loop; int i;
retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) {
err("power on failed\n"); return retval;
} if (CTLR_RESULT(slot_cur->ctrl->status)) {
err("command not completed successfully in power_on\n"); return -EIO;
}
msleep(3000); /* For ServeRAID cards, and some 66 PCI */ return 0;
}
switch (speed) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX)
speed += 0x01; break; case BUS_SPEED_100: case BUS_SPEED_133:
speed += 0x01; break; default: /* Note (will need to change): there would be soon 256, 512 also */
rc = -ENODEV;
}
/**************************************************************************** * This routine will initialize the ops data structure used in the validate * function. It will also power off empty slots that are powered on since BIOS * leaves those on, albeit disconnected
****************************************************************************/ staticint __init init_ops(void)
{ struct slot *slot_cur; int retval; int rc;
if ((SLOT_PWRGD(slot_cur->status)) &&
!(SLOT_PRESENT(slot_cur->status)) &&
!(SLOT_LATCH(slot_cur->status))) {
debug("BEFORE POWER OFF COMMAND\n");
rc = power_off(slot_cur); if (rc) return rc;
/* This operation will check whether the slot is within the bounds and * the operation is valid to perform on that slot * Parameters: slot, operation * Returns: 0 or error codes
*/ staticint validate(struct slot *slot_cur, int opn)
{ int number; int retval;
if (!slot_cur) return -ENODEV;
number = slot_cur->number; if ((number > max_slots) || (number < 0)) return -EBADSLT;
debug("slot_number in validate is %d\n", slot_cur->number);
retval = slot_update(&slot_cur); if (retval) return retval;
switch (opn) { case ENABLE: if (!(SLOT_PWRGD(slot_cur->status)) &&
(SLOT_PRESENT(slot_cur->status)) &&
!(SLOT_LATCH(slot_cur->status))) return 0; break; case DISABLE: if ((SLOT_PWRGD(slot_cur->status)) &&
(SLOT_PRESENT(slot_cur->status)) &&
!(SLOT_LATCH(slot_cur->status))) return 0; break; default: break;
}
err("validate failed....\n"); return -EINVAL;
}
/**************************************************************************** * This routine is for updating the data structures in the hotplug core * Parameters: struct slot * Returns: 0 or error
****************************************************************************/ int ibmphp_update_slot_info(struct slot *slot_cur)
{ struct pci_bus *bus = slot_cur->hotplug_slot.pci_slot->bus;
u8 bus_speed;
u8 mode;
switch (bus_speed) { case BUS_SPEED_33: break; case BUS_SPEED_66: if (mode == BUS_MODE_PCIX)
bus_speed += 0x01; elseif (mode == BUS_MODE_PCI)
; else
bus_speed = PCI_SPEED_UNKNOWN; break; case BUS_SPEED_100: case BUS_SPEED_133:
bus_speed += 0x01; break; default:
bus_speed = PCI_SPEED_UNKNOWN;
}
bus->cur_bus_speed = bus_speed; // To do: bus_names
return 0;
}
/****************************************************************************** * This function will return the pci_func, given bus and devfunc, or NULL. It * is called from visit routines
******************************************************************************/
/************************************************************* * This routine frees up memory used by struct slot, including * the pointers to pci_func, bus, hotplug_slot, controller, * and deregistering from the hotplug core
*************************************************************/ staticvoid free_slots(void)
{ struct slot *slot_cur, *next;
/* * The following function is to fix kernel bug regarding * getting bus entries, here we manually add those primary * bus entries to kernel bus structure whenever apply
*/ static u8 bus_structure_fixup(u8 busno)
{ struct pci_bus *bus, *b; struct pci_dev *dev;
u16 l;
if (pci_find_bus(0, busno) || !(ibmphp_find_same_bus_num(busno))) return 1;
bus = kmalloc(sizeof(*bus), GFP_KERNEL); if (!bus) return 1;
dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) {
kfree(bus); return 1;
}
staticint ibm_configure_device(struct pci_func *func)
{ struct pci_bus *child; int num; int flag = 0; /* this is to make sure we don't double scan the bus,
for bridged devices primarily */
pci_lock_rescan_remove();
if (!(bus_structure_fixup(func->busno)))
flag = 1; if (func->dev == NULL)
func->dev = pci_get_domain_bus_and_slot(0, func->busno,
PCI_DEVFN(func->device, func->function));
if (func->dev == NULL) { struct pci_bus *bus = pci_find_bus(0, func->busno); if (!bus) goto out;
num = pci_scan_slot(bus,
PCI_DEVFN(func->device, func->function)); if (num)
pci_bus_add_devices(bus);
func->dev = pci_get_domain_bus_and_slot(0, func->busno,
PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) {
err("ERROR... : pci_dev still NULL\n"); goto out;
}
} if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
pci_hp_add_bridge(func->dev);
child = func->dev->subordinate; if (child)
pci_bus_add_devices(child);
}
out:
pci_unlock_rescan_remove(); return 0;
}
/******************************************************* * Returns whether the bus is empty or not
*******************************************************/ staticint is_bus_empty(struct slot *slot_cur)
{ int rc; struct slot *tmp_slot;
u8 i = slot_cur->bus_on->slot_min;
while (i <= slot_cur->bus_on->slot_max) { if (i == slot_cur->number) {
i++; continue;
}
tmp_slot = ibmphp_get_slot_from_physical_num(i); if (!tmp_slot) return 0;
rc = slot_update(&tmp_slot); if (rc) return 0; if (SLOT_PRESENT(tmp_slot->status) &&
SLOT_PWRGD(tmp_slot->status)) return 0;
i++;
} return 1;
}
/*********************************************************** * If the HPC permits and the bus currently empty, tries to set the * bus speed and mode at the maximum card and bus capability * Parameters: slot * Returns: bus is set (0) or error code
***********************************************************/ staticint set_bus(struct slot *slot_cur)
{ int rc;
u8 speed;
u8 cmd = 0x0; int retval; staticconststruct pci_device_id ciobx[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, 0x0101) },
{ },
};
debug("%s - entry slot # %d\n", __func__, slot_cur->number); if (SET_BUS_STATUS(slot_cur->ctrl) && is_bus_empty(slot_cur)) {
rc = slot_update(&slot_cur); if (rc) return rc;
speed = SLOT_SPEED(slot_cur->ext_status);
debug("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); switch (speed) { case HPC_SLOT_SPEED_33:
cmd = HPC_BUS_33CONVMODE; break; case HPC_SLOT_SPEED_66: if (SLOT_PCIX(slot_cur->ext_status)) { if ((slot_cur->supported_speed >= BUS_SPEED_66) &&
(slot_cur->supported_bus_mode == BUS_MODE_PCIX))
cmd = HPC_BUS_66PCIXMODE; elseif (!SLOT_BUS_MODE(slot_cur->ext_status)) /* if max slot/bus capability is 66 pci and there's no bus mode mismatch, then
the adapter supports 66 pci */
cmd = HPC_BUS_66CONVMODE; else
cmd = HPC_BUS_33CONVMODE;
} else { if (slot_cur->supported_speed >= BUS_SPEED_66)
cmd = HPC_BUS_66CONVMODE; else
cmd = HPC_BUS_33CONVMODE;
} break; case HPC_SLOT_SPEED_133: switch (slot_cur->supported_speed) { case BUS_SPEED_33:
cmd = HPC_BUS_33CONVMODE; break; case BUS_SPEED_66: if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
cmd = HPC_BUS_66PCIXMODE; else
cmd = HPC_BUS_66CONVMODE; break; case BUS_SPEED_100:
cmd = HPC_BUS_100PCIXMODE; break; case BUS_SPEED_133: /* This is to take care of the bug in CIOBX chip */ if (pci_dev_present(ciobx))
ibmphp_hpc_writeslot(slot_cur,
HPC_BUS_100PCIXMODE);
cmd = HPC_BUS_133PCIXMODE; break; default:
err("Wrong bus speed\n"); return -ENODEV;
} break; default:
err("wrong slot speed\n"); return -ENODEV;
}
debug("setting bus speed for slot %d, cmd %x\n",
slot_cur->number, cmd);
retval = ibmphp_hpc_writeslot(slot_cur, cmd); if (retval) {
err("setting bus speed failed\n"); return retval;
} if (CTLR_RESULT(slot_cur->ctrl->status)) {
err("command not completed successfully in set_bus\n"); return -EIO;
}
} /* This is for x440, once Brandon fixes the firmware,
will not need this delay */
msleep(1000);
debug("%s -Exit\n", __func__); return 0;
}
/* This routine checks the bus limitations that the slot is on from the BIOS. * This is used in deciding whether or not to power up the slot. * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on * same bus) * Parameters: slot * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
*/ staticint check_limitations(struct slot *slot_cur)
{
u8 i; struct slot *tmp_slot;
u8 count = 0;
u8 limitation = 0;
for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
tmp_slot = ibmphp_get_slot_from_physical_num(i); if (!tmp_slot) return -ENODEV; if ((SLOT_PWRGD(tmp_slot->status)) &&
!(SLOT_CONNECT(tmp_slot->status)))
count++;
}
get_cur_bus_info(&slot_cur); switch (slot_cur->bus_on->current_speed) { case BUS_SPEED_33:
limitation = slot_cur->bus_on->slots_at_33_conv; break; case BUS_SPEED_66: if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
limitation = slot_cur->bus_on->slots_at_66_pcix; else
limitation = slot_cur->bus_on->slots_at_66_conv; break; case BUS_SPEED_100:
limitation = slot_cur->bus_on->slots_at_100_pcix; break; case BUS_SPEED_133:
limitation = slot_cur->bus_on->slots_at_133_pcix; break;
}
/* This routine will power on the slot, configure the device(s) and find the * drivers for them. * Parameters: hotplug_slot * Returns: 0 or failure codes
*/ staticint enable_slot(struct hotplug_slot *hs)
{ int rc, i, rcpr; struct slot *slot_cur;
u8 function; struct pci_func *tmp_func;
rc = validate(slot_cur, ENABLE); if (rc) {
err("validate function failed\n"); goto error_nopower;
}
attn_LED_blink(slot_cur);
rc = set_bus(slot_cur); if (rc) {
err("was not able to set the bus\n"); goto error_nopower;
}
/*-----------------debugging------------------------------*/
get_cur_bus_info(&slot_cur);
debug("the current bus speed right after set_bus = %x\n",
slot_cur->bus_on->current_speed); /*----------------------------------------------------------*/
rc = check_limitations(slot_cur); if (rc) {
err("Adding this card exceeds the limitations of this bus.\n");
err("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus.\n");
err("Try hot-adding into another bus\n");
rc = -EINVAL; goto error_nopower;
}
rc = power_on(slot_cur);
if (rc) {
err("something wrong when powering up... please see below for details\n"); /* need to turn off before on, otherwise, blinking overwrites */
attn_off(slot_cur);
attn_on(slot_cur); if (slot_update(&slot_cur)) {
attn_off(slot_cur);
attn_on(slot_cur);
rc = -ENODEV; gotoexit;
} /* Check to see the error of why it failed */ if ((SLOT_POWER(slot_cur->status)) &&
!(SLOT_PWRGD(slot_cur->status)))
err("power fault occurred trying to power up\n"); elseif (SLOT_BUS_SPEED(slot_cur->status)) {
err("bus speed mismatch occurred. please check current bus speed and card capability\n");
print_card_capability(slot_cur);
} elseif (SLOT_BUS_MODE(slot_cur->ext_status)) {
err("bus mode mismatch occurred. please check current bus mode and card capability\n");
print_card_capability(slot_cur);
}
ibmphp_update_slot_info(slot_cur); gotoexit;
}
debug("after power_on\n"); /*-----------------------debugging---------------------------*/
get_cur_bus_info(&slot_cur);
debug("the current bus speed right after power_on = %x\n",
slot_cur->bus_on->current_speed); /*----------------------------------------------------------*/
rc = slot_update(&slot_cur); if (rc) goto error_power;
rc = -EINVAL; if (SLOT_POWER(slot_cur->status) && !(SLOT_PWRGD(slot_cur->status))) {
err("power fault occurred trying to power up...\n"); goto error_power;
} if (SLOT_POWER(slot_cur->status) && (SLOT_BUS_SPEED(slot_cur->status))) {
err("bus speed mismatch occurred. please check current bus speed and card capability\n");
print_card_capability(slot_cur); goto error_power;
} /* Don't think this case will happen after above checks...
* but just in case, for paranoia sake */ if (!(SLOT_POWER(slot_cur->status))) {
err("power on failed...\n"); goto error_power;
}
slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL); if (!slot_cur->func) { /* do update_slot_info here? */
rc = -ENOMEM; goto error_power;
}
slot_cur->func->busno = slot_cur->bus;
slot_cur->func->device = slot_cur->device; for (i = 0; i < 4; i++)
slot_cur->func->irq[i] = slot_cur->irq[i];
if (ibmphp_configure_card(slot_cur->func, slot_cur->number)) {
err("configure_card was unsuccessful...\n"); /* true because don't need to actually deallocate resources,
* just remove references */
ibmphp_unconfigure_card(&slot_cur, 1);
debug("after unconfigure_card\n");
slot_cur->func = NULL;
rc = -ENOMEM; goto error_power;
}
function = 0x00; do {
tmp_func = ibm_slot_find(slot_cur->bus, slot_cur->func->device,
function++); if (tmp_func && !(tmp_func->dev))
ibm_configure_device(tmp_func);
} while (tmp_func);
error_nopower:
attn_off(slot_cur); /* need to turn off if was blinking b4 */
attn_on(slot_cur);
error_cont:
rcpr = slot_update(&slot_cur); if (rcpr) {
rc = rcpr; gotoexit;
}
ibmphp_update_slot_info(slot_cur); gotoexit;
error_power:
attn_off(slot_cur); /* need to turn off if was blinking b4 */
attn_on(slot_cur);
rcpr = power_off(slot_cur); if (rcpr) {
rc = rcpr; gotoexit;
} goto error_cont;
}
/************************************************************** * HOT REMOVING ADAPTER CARD * * INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * * OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * * DISABLE POWER , *
**************************************************************/ staticint ibmphp_disable_slot(struct hotplug_slot *hotplug_slot)
{ struct slot *slot = to_slot(hotplug_slot); int rc;
int ibmphp_do_disable_slot(struct slot *slot_cur)
{ int rc;
u8 flag;
debug("DISABLING SLOT...\n");
if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) return -ENODEV;
flag = slot_cur->flag;
slot_cur->flag = 1;
if (flag == 1) {
rc = validate(slot_cur, DISABLE); /* checking if powered off already & valid slot # */ if (rc) goto error;
}
attn_LED_blink(slot_cur);
if (slot_cur->func == NULL) { /* We need this for functions that were there on bootup */
slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL); if (!slot_cur->func) {
rc = -ENOMEM; goto error;
}
slot_cur->func->busno = slot_cur->bus;
slot_cur->func->device = slot_cur->device;
}
ibm_unconfigure_device(slot_cur->func);
/* * If we got here from latch suddenly opening on operating card or * a power fault, there's no power to the card, so cannot * read from it to determine what resources it occupied. This operation * is forbidden anyhow. The best we can do is remove it from kernel
* lists at least */
if (!flag) {
attn_off(slot_cur); return 0;
}
rc = ibmphp_unconfigure_card(&slot_cur, 0);
slot_cur->func = NULL;
debug("in disable_slot. after unconfigure_card\n"); if (rc) {
err("could not unconfigure card.\n"); goto error;
}
rc = ibmphp_hpc_writeslot(slot_cur, HPC_SLOT_OFF); if (rc) goto error;
attn_off(slot_cur);
rc = slot_update(&slot_cur); if (rc) gotoexit;
error: /* Need to turn off if was blinking b4 */
attn_off(slot_cur);
attn_on(slot_cur); if (slot_update(&slot_cur)) {
rc = -EFAULT; gotoexit;
} if (flag)
ibmphp_update_slot_info(slot_cur); gotoexit;
}
bus = pci_find_bus(0, 0); if (!bus) {
err("Can't find the root pci bus, can not continue\n");
rc = -ENODEV; goto error;
}
memcpy(ibmphp_pci_bus, bus, sizeof(*ibmphp_pci_bus));
ibmphp_debug = debug;
for (i = 0; i < 16; i++)
irqs[i] = 0;
rc = ibmphp_access_ebda(); if (rc) goto error;
debug("after ibmphp_access_ebda()\n");
rc = ibmphp_rsrc_init(); if (rc) goto error;
debug("AFTER Resource & EBDA INITIALIZATIONS\n");
max_slots = get_max_slots();
rc = ibmphp_register_pci(); if (rc) goto error;
if (init_ops()) {
rc = -ENODEV; goto error;
}
ibmphp_print_test();
rc = ibmphp_hpc_start_poll_thread(); if (rc) goto error;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.