// SPDX-License-Identifier: GPL-2.0+ /* * IBM Hot Plug Controller Driver * * Written By: Jyoti Shah, IBM Corporation * * Copyright (C) 2001-2003 IBM Corp. * * All rights reserved. * * Send feedback to <gregkh@us.ibm.com> * <jshah@us.ibm.com> *
*/
//---------------------------------------------------------------------------- // Winnipeg Store Type commands (Add this commands to the register offset) //---------------------------------------------------------------------------- #define WPG_I2C_AND 0x1000 // I2C AND operation #define WPG_I2C_OR 0x2000 // I2C OR operation
//---------------------------------------------------------------------------- // bit masks for I2C Master Control Register //---------------------------------------------------------------------------- #define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation
//---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- #define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval
//---------------------------------------------------------------------------- // command index //---------------------------------------------------------------------------- #define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr #define WPG_CTLR_INDEX 0x0F // index - ctlr #define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr #define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr
//---------------------------------------------------------------------------- // macro utilities //---------------------------------------------------------------------------- // if bits 20,22,25,26,27,29,30 are OFF return 1 #define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? 0 : 1))
//-------------------------------------------------------------------- // READ - step 1 // read at address, byte length, I2C address (shifted), index // or read direct, byte length, index if (ctlr_ptr->ctlr_type == 0x02) {
data = WPG_READATADDR_MASK; // fill in I2C address
ultemp = (unsignedlong)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
ultemp = ultemp >> 1;
data |= (ultemp << 8);
// fill in index
data |= (unsignedlong)index;
} elseif (ctlr_ptr->ctlr_type == 0x04) {
data = WPG_READDIRECT_MASK;
// fill in index
ultemp = (unsignedlong)index;
ultemp = ultemp << 8;
data |= ultemp;
} else {
err("this controller type is not supported \n"); return HPC_ERROR;
}
wpg_data = swab32(data); // swap data before writing
wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
writel(wpg_data, wpg_addr);
rc = 0; //-------------------------------------------------------------------- // WRITE - step 1 // write at address, byte length, I2C address (shifted), index // or write direct, byte length, index
data = 0x00000000;
if (ctlr_ptr->ctlr_type == 0x02) {
data = WPG_WRITEATADDR_MASK; // fill in I2C address
ultemp = (unsignedlong)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
ultemp = ultemp >> 1;
data |= (ultemp << 8);
// fill in index
data |= (unsignedlong)index;
} elseif (ctlr_ptr->ctlr_type == 0x04) {
data = WPG_WRITEDIRECT_MASK;
// fill in index
ultemp = (unsignedlong)index;
ultemp = ultemp << 8;
data |= ultemp;
} else {
err("this controller type is not supported \n"); return HPC_ERROR;
}
wpg_data = swab32(data); // swap data before writing
wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
writel(wpg_data, wpg_addr);
static u8 ctrl_write(struct controller *ctlr, void __iomem *base, u8 offset, u8 data)
{
u8 rc = 0; switch (ctlr->ctlr_type) { case 0:
isa_ctrl_write(ctlr, offset, data); break; case 1:
rc = pci_ctrl_write(ctlr, offset, data); break; case 2: case 4:
rc = i2c_ctrl_write(ctlr, base, offset, data); break; default: return -ENODEV;
} return rc;
} /*---------------------------------------------------------------------- * Name: hpc_writecmdtoindex() * * Action: convert a write command to proper index within a controller * * Return index, HPC_ERROR
*---------------------------------------------------------------------*/ static u8 hpc_writecmdtoindex(u8 cmd, u8 index)
{
u8 rc;
switch (cmd) { case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 case HPC_CTLR_CLEARIRQ: // 0x06.N.15 case HPC_CTLR_RESET: // 0x07.N.15 case HPC_CTLR_IRQSTEER: // 0x08.N.15 case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 case HPC_ALLSLOT_ON: // 0x11.N.15 case HPC_ALLSLOT_OFF: // 0x12.N.15
rc = 0x0F; break;
case HPC_SLOT_OFF: // 0x02.Y.0-14 case HPC_SLOT_ON: // 0x03.Y.0-14 case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 case HPC_SLOT_ATTNON: // 0x05.N.0-14 case HPC_SLOT_BLINKLED: // 0x13.N.0-14
rc = index; break;
case HPC_BUS_33CONVMODE: case HPC_BUS_66CONVMODE: case HPC_BUS_66PCIXMODE: case HPC_BUS_100PCIXMODE: case HPC_BUS_133PCIXMODE:
rc = index + WPG_1ST_BUS_INDEX - 1; break;
/*---------------------------------------------------------------------- * Name: get_hpc_access() * * Action: make sure only one process can access HPC at one time
*---------------------------------------------------------------------*/ staticvoid get_hpc_access(void)
{
mutex_lock(&sem_hpcaccess);
}
/*---------------------------------------------------------------------- * Name: ibmphp_lock_operations() * * Action: make sure only one process can change the data structure
*---------------------------------------------------------------------*/ void ibmphp_lock_operations(void)
{
mutex_lock(&operations_mutex);
to_debug = 1;
}
while (!kthread_should_stop()) { /* try to get the lock to do some kind of hardware access */
mutex_lock(&operations_mutex);
switch (poll_state) { case POLL_LATCH_REGISTER:
oldlatchlow = curlatchlow;
ctrl_count = 0x00;
list_for_each_entry(pslot, &ibmphp_slot_head,
ibm_slot_list) { if (ctrl_count >= ibmphp_get_total_controllers()) break; if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
ctrl_count++; if (READ_SLOT_LATCH(pslot->ctrl)) {
rc = ibmphp_hpc_readslot(pslot,
READ_SLOTLATCHLOWREG,
&curlatchlow); if (oldlatchlow != curlatchlow)
process_changeinlatch(oldlatchlow,
curlatchlow,
pslot->ctrl);
}
}
}
++poll_count;
poll_state = POLL_SLEEP; break; case POLL_SLOTS:
list_for_each_entry(pslot, &ibmphp_slot_head,
ibm_slot_list) { // make a copy of the old status
memcpy((void *) &myslot, (void *) pslot, sizeof(struct slot));
rc = ibmphp_hpc_readslot(pslot, READ_ALLSTAT, NULL); if ((myslot.status != pslot->status)
|| (myslot.ext_status != pslot->ext_status))
process_changeinstatus(pslot, &myslot);
}
ctrl_count = 0x00;
list_for_each_entry(pslot, &ibmphp_slot_head,
ibm_slot_list) { if (ctrl_count >= ibmphp_get_total_controllers()) break; if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
ctrl_count++; if (READ_SLOT_LATCH(pslot->ctrl))
rc = ibmphp_hpc_readslot(pslot,
READ_SLOTLATCHLOWREG,
&curlatchlow);
}
}
++poll_count;
poll_state = POLL_SLEEP; break; case POLL_SLEEP: /* don't sleep with a lock on the hardware */
mutex_unlock(&operations_mutex);
msleep(POLL_INTERVAL_SEC * 1000);
if (kthread_should_stop()) goto out_sleep;
mutex_lock(&operations_mutex);
if (poll_count >= POLL_LATCH_CNT) {
poll_count = 0;
poll_state = POLL_SLOTS;
} else
poll_state = POLL_LATCH_REGISTER; break;
} /* give up the hardware semaphore */
mutex_unlock(&operations_mutex); /* sleep for a short time just for good measure */
out_sleep:
msleep(100);
}
complete(&exit_complete);
debug("%s - Exit\n", __func__); return 0;
}
/*---------------------------------------------------------------------- * Name: process_changeinstatus * * Action: compare old and new slot status, process the change in status * * Input: pointer to slot struct, old slot struct * * Return 0 or error codes * Value: * * Side * Effects: None. * * Notes:
*---------------------------------------------------------------------*/ staticint process_changeinstatus(struct slot *pslot, struct slot *poldslot)
{
u8 status; int rc = 0;
u8 disable = 0;
u8 update = 0;
// bit 0 - HPC_SLOT_POWER if ((pslot->status & 0x01) != (poldslot->status & 0x01))
update = 1;
// bit 1 - HPC_SLOT_CONNECT // ignore
// bit 2 - HPC_SLOT_ATTN if ((pslot->status & 0x04) != (poldslot->status & 0x04))
update = 1;
// bit 3 - HPC_SLOT_PRSNT2 // bit 4 - HPC_SLOT_PRSNT1 if (((pslot->status & 0x08) != (poldslot->status & 0x08))
|| ((pslot->status & 0x10) != (poldslot->status & 0x10)))
update = 1;
// bit 5 - HPC_SLOT_PWRGD if ((pslot->status & 0x20) != (poldslot->status & 0x20)) // OFF -> ON: ignore, ON -> OFF: disable slot if ((poldslot->status & 0x20) && (SLOT_CONNECT(poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT(poldslot->status)))
disable = 1;
// bit 6 - HPC_SLOT_BUS_SPEED // ignore
// bit 7 - HPC_SLOT_LATCH if ((pslot->status & 0x80) != (poldslot->status & 0x80)) {
update = 1; // OPEN -> CLOSE if (pslot->status & 0x80) { if (SLOT_PWRGD(pslot->status)) { // power goes on and off after closing latch // check again to make sure power is still ON
msleep(1000);
rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS, &status); if (SLOT_PWRGD(status))
update = 1; else// overwrite power in pslot to OFF
pslot->status &= ~HPC_SLOT_POWER;
}
} // CLOSE -> OPEN elseif ((SLOT_PWRGD(poldslot->status) == HPC_SLOT_PWRGD_GOOD)
&& (SLOT_CONNECT(poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT(poldslot->status))) {
disable = 1;
} // else - ignore
} // bit 4 - HPC_SLOT_BLINK_ATTN if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08))
update = 1;
/*---------------------------------------------------------------------- * Name: hpc_wait_ctlr_notworking * * Action: wait until the controller is in a not working state * * Return 0, HPC_ERROR * Value:
*---------------------------------------------------------------------*/ staticint hpc_wait_ctlr_notworking(int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar,
u8 *pstatus)
{ int rc = 0;
u8 done = 0;
¤ 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.