Skip to content

Commit

Permalink
Support for Naples LPC serial interrupts
Browse files Browse the repository at this point in the history
This adds support for the HW SerIRQ deserializer of the P8 LPC
bridge which is properly wired up on Naples. It also adds support
for detecting and reporting LPC error interrupts on all P8s.

On most platforms (Rhesus is the exception here due to the way it
lets Linux handle the UART interrupts directly), we modify the
device-tree to properly represent the LPC controller as a cascaded
interrupt-controller and the "interrupts" property of LPC devices
to contain the actual LPC interrupt number for the device.

We add a mechanism for drivers to register specific LPC interrupts,
and a "workaround" for pre-Naples P8 which platforms can use to call
all of them for when the external FPGA based deserializer is used.

There's also a callback on LPC resets which isn't used yet, we need
a bit more work on the general LPC error handling, but it can be
done a separate patches.

Signed-off-by: Benjamin Herrenschmidt <[email protected]>
Signed-off-by: Stewart Smith <[email protected]>
  • Loading branch information
ozbenh authored and stewartsmith committed Jun 19, 2015
1 parent a921764 commit 35b433b
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 51 deletions.
1 change: 1 addition & 0 deletions core/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,6 @@ void init_chips(void)
chip->pcid = dt_prop_get_u32_def(xn, "ibm,proc-chip-id",
0xffffffff);
list_head_init(&chip->i2cms);
list_head_init(&chip->lpc_clients);
};
}
12 changes: 11 additions & 1 deletion hw/bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ static int bt_add_ipmi_msg(struct ipmi_msg *ipmi_msg)
return 0;
}

void bt_irq(void)
static void bt_irq(uint32_t chip_id __unused, uint32_t irq_mask __unused)
{
uint8_t ireg;

Expand Down Expand Up @@ -504,10 +504,15 @@ static struct ipmi_backend bt_backend = {
.dequeue_msg = bt_del_ipmi_msg,
};

static struct lpc_client bt_lpc_client = {
.interrupt = bt_irq,
};

void bt_init(void)
{
struct dt_node *n;
const struct dt_property *prop;
uint32_t irq;

/* We support only one */
n = dt_find_compatible_node(dt_root, NULL, "ipmi-bt");
Expand Down Expand Up @@ -547,4 +552,9 @@ void bt_init(void)
* point we turn it into a background poller
*/
schedule_timer(&bt.poller, msecs_to_tb(BT_DEFAULT_POLL_MS));

irq = dt_prop_get_u32(n, "interrupts");
bt_lpc_client.interrupts = LPC_IRQ(irq);
lpc_register_client(dt_get_chip_id(n), &bt_lpc_client);
prlog(PR_DEBUG, "BT: Using LPC IRQ %d\n", irq);
}
33 changes: 21 additions & 12 deletions hw/lpc-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <trace.h>
#include <timebase.h>
#include <cpu.h>
#include <chip.h>

DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART,
OPAL_CEC_HARDWARE, OPAL_PREDICTIVE_ERR_GENERAL,
Expand Down Expand Up @@ -365,7 +366,7 @@ static void uart_console_poll(void *data __unused)
__uart_do_poll(TRACE_UART_CTX_POLL);
}

void uart_irq(void)
static void uart_irq(uint32_t chip_id __unused, uint32_t irq_mask __unused)
{
if (!irq_ok) {
prlog(PR_DEBUG, "UART: IRQ functional !\n");
Expand Down Expand Up @@ -464,12 +465,16 @@ static bool uart_init_hw(unsigned int speed, unsigned int clock)
return false;
}

void uart_init(bool enable_interrupt)
static struct lpc_client uart_lpc_client = {
.interrupt = uart_irq,
};

void uart_init(bool use_interrupt)
{
const struct dt_property *prop;
struct dt_node *n;
char *path __unused;
uint32_t irqchip, irq;
uint32_t chip_id, irq;

if (!lpc_present())
return;
Expand Down Expand Up @@ -504,6 +509,7 @@ void uart_init(bool enable_interrupt)
dt_add_property_strings(n, "status", "bad");
return;
}
chip_id = dt_get_chip_id(uart_node);

/*
* Mark LPC used by the console (will mark the relevant
Expand All @@ -514,13 +520,16 @@ void uart_init(bool enable_interrupt)
/* Install console backend for printf() */
set_console(&uart_con_driver);

/* Setup the interrupts properties since HB couldn't do it */
irqchip = dt_prop_get_u32(n, "ibm,irq-chip-id");
irq = get_psi_interrupt(irqchip) + P8_IRQ_PSI_HOST_ERR;
prlog(PR_DEBUG, "UART: IRQ connected to chip %d, irq# is 0x%x\n", irqchip, irq);
has_irq = enable_interrupt;
if (has_irq) {
dt_add_property_cells(n, "interrupts", irq);
dt_add_property_cells(n, "interrupt-parent", get_ics_phandle());
}
/* On Naples, use the SerIRQ, which Linux will have to share with
* OPAL as we don't really play the cascaded interrupt game at this
* point...
*/
if (use_interrupt) {
irq = dt_prop_get_u32(n, "interrupts");
uart_lpc_client.interrupts = LPC_IRQ(irq);
lpc_register_client(chip_id, &uart_lpc_client);
has_irq = true;
prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq);
} else
has_irq = false;
}
Loading

0 comments on commit 35b433b

Please sign in to comment.