// SPDX-License-Identifier: GPL-2.0+
/*
* 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.
*
* 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 "../pci.h"
#include <asm/pci_x86.h> /* for struct irq_routing_table */
#include <asm/io_apic.h>
#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 bool debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
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 IRQs we're using so far (in case MPS
* tables don't provide default info for empty slots */
static int init_flag;
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;
u8 slot_count = 0;
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;
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) {
kfree(rtable);
return -1;
}
for (loop