Skip to content

Commit 2924f7f

Browse files
committed
p8-i2c reset things manually in some error conditions
It appears that our reset code wasn't entirely correct, and what we're meant to do is reset each port and wait for command complete. In the event where that fails, we can then bitbang things to recover to a state where at least the i2c engine isn't in a weird state. Practically, this means that "i2cdetect -y 10; i2cdetect -y 10" (where 10 is the bus where a TPM is attached, typically p8e1p2) doesn't hard lock the machine (things are still bad and you won't reboot successfully, but it's *better*). one downside to this patch is that we spend a *long* time in OPAL (tens of ms) when doing the reset. This is something that we really need to fix, as it's not at all nice. The full fix for this though will involve changing a decent chunk of the p8-i2c code, as we don't want to write *any* registers while doing this extended reset (while existing code checks status a bit later). Signed-off-by: Stewart Smith <[email protected]> (cherry picked from commit cf6ec98) Signed-off-by: Stewart Smith <[email protected]>
1 parent 8b5cf36 commit 2924f7f

File tree

1 file changed

+157
-22
lines changed

1 file changed

+157
-22
lines changed

hw/p8-i2c.c

+157-22
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,11 @@ DEFINE_LOG_ENTRY(OPAL_RC_I2C_RESET, OPAL_INPUT_OUTPUT_ERR_EVT, OPAL_I2C,
171171
#define I2C_RESIDUAL_BACK_END PPC_BITMASK(16, 31)
172172

173173
/* Port busy register */
174-
#define I2C_PORT_BUYS_REG 0xe
174+
#define I2C_PORT_BUSY_REG 0xe
175+
#define I2C_SET_S_SCL_REG 0xd
176+
#define I2C_RESET_S_SCL_REG 0xf
177+
#define I2C_SET_S_SDA_REG 0x10
178+
#define I2C_RESET_S_SDA_REG 0x11
175179

176180
enum p8_i2c_master_type {
177181
I2C_POWER8,
@@ -207,13 +211,15 @@ struct p8_i2c_master {
207211
struct timer sensor_cache;
208212
uint8_t recovery_pass;
209213
struct list_node link;
214+
struct list_head ports;
210215
};
211216

212217
struct p8_i2c_master_port {
213218
struct i2c_bus bus; /* Abstract bus struct for the client */
214219
struct p8_i2c_master *master;
215220
uint32_t port_num;
216221
uint32_t bit_rate_div; /* Divisor to set bus speed*/
222+
struct list_node link;
217223
};
218224

219225
struct p8_i2c_request {
@@ -463,6 +469,153 @@ static void p8_i2c_translate_error(struct i2c_request *req, uint64_t status)
463469
req->result = OPAL_I2C_TIMEOUT;
464470
}
465471

472+
static void p8_i2c_force_reset(struct p8_i2c_master *master)
473+
{
474+
struct p8_i2c_master_port *p;
475+
uint64_t mode;
476+
int rc;
477+
478+
/* Reset the i2c engine */
479+
rc = xscom_write(master->chip_id, master->xscom_base +
480+
I2C_RESET_I2C_REG, 0);
481+
if (rc) {
482+
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed "
483+
"to reset the i2c engine\n");
484+
return;
485+
}
486+
time_wait_us_nopoll(10);
487+
/* Reset port busy */
488+
rc = xscom_write(master->chip_id, master->xscom_base +
489+
I2C_PORT_BUSY_REG, 0x8000000000000000ULL);
490+
if (rc) {
491+
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed "
492+
"to reset port busy on i2c engine\n");
493+
return;
494+
}
495+
time_wait_us_nopoll(10);
496+
list_for_each(&master->ports, p, link) {
497+
mode = 0;
498+
mode = SETFIELD(I2C_MODE_PORT_NUM, mode, p->port_num);
499+
mode = SETFIELD(I2C_MODE_BIT_RATE_DIV, mode, p->bit_rate_div);
500+
mode |= I2C_MODE_DIAGNOSTIC;
501+
rc = xscom_write(master->chip_id,
502+
master->xscom_base + I2C_MODE_REG,
503+
mode);
504+
if (rc)
505+
prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n");
506+
507+
time_wait_us_nopoll(10);
508+
rc = xscom_write(master->chip_id,
509+
master->xscom_base + I2C_RESET_S_SCL_REG,
510+
0);
511+
if (rc)
512+
prlog(PR_ERR, "I2C: Failed to reset S_SCL\n");
513+
514+
time_wait_us_nopoll(10);
515+
rc = xscom_write(master->chip_id,
516+
master->xscom_base + I2C_SET_S_SCL_REG,
517+
0);
518+
if (rc)
519+
prlog(PR_ERR, "I2C: Failed to set S_SCL\n");
520+
521+
/* Manually reset */
522+
time_wait_us_nopoll(10);
523+
rc = xscom_write(master->chip_id,
524+
master->xscom_base + I2C_RESET_S_SCL_REG,
525+
0);
526+
if (rc)
527+
prlog(PR_ERR, "I2C: sendStop: fail reset S_SCL\n");
528+
529+
time_wait_us_nopoll(10);
530+
rc = xscom_write(master->chip_id,
531+
master->xscom_base + I2C_RESET_S_SDA_REG,
532+
0);
533+
if (rc)
534+
prlog(PR_ERR, "I2C: sendStop: fail reset S_SDA\n");
535+
536+
time_wait_us_nopoll(10);
537+
rc = xscom_write(master->chip_id,
538+
master->xscom_base + I2C_SET_S_SCL_REG,
539+
0);
540+
if (rc)
541+
prlog(PR_ERR, "I2C: sendStop: fail set S_SCL\n");
542+
543+
time_wait_us_nopoll(10);
544+
rc = xscom_write(master->chip_id,
545+
master->xscom_base + I2C_SET_S_SDA_REG,
546+
0);
547+
if (rc)
548+
prlog(PR_ERR, "I2C: sendStop: fail set 2 S_SDA\n");
549+
550+
mode ^= I2C_MODE_DIAGNOSTIC;
551+
time_wait_us_nopoll(10);
552+
rc = xscom_write(master->chip_id,
553+
master->xscom_base + I2C_MODE_REG,
554+
mode);
555+
if (rc)
556+
prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n");
557+
}
558+
}
559+
560+
static int p8_i2c_reset_engine(struct p8_i2c_master *master)
561+
{
562+
struct p8_i2c_master_port *p;
563+
int reset_loops;
564+
int rc;
565+
uint64_t status;
566+
567+
list_for_each(&master->ports, p, link) {
568+
/*
569+
* Reset each port by issuing a STOP command to slave.
570+
*
571+
* Reprogram the mode register with 'enhanced bit' set
572+
*/
573+
rc = p8_i2c_prog_mode(p, true);
574+
if (rc) {
575+
log_simple_error(&e_info(OPAL_RC_I2C_RESET),
576+
"I2C: Failed to program the MODE_REG\n");
577+
return -1;
578+
}
579+
580+
/* Send an immediate stop */
581+
master->state = state_error;
582+
rc = xscom_write(master->chip_id, master->xscom_base +
583+
I2C_CMD_REG, I2C_CMD_WITH_STOP);
584+
if (rc) {
585+
log_simple_error(&e_info(OPAL_RC_I2C_RESET),
586+
"I2C: Failed to issue immediate STOP\n");
587+
return -1;
588+
}
589+
590+
/* Wait for COMMAND COMPLETE */
591+
reset_loops = 0;
592+
do {
593+
rc = xscom_read(master->chip_id,
594+
master->xscom_base + I2C_STAT_REG,
595+
&status);
596+
if (rc) {
597+
log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER),
598+
"I2C: Failed to read the STAT_REG\n");
599+
return -1;
600+
}
601+
if (! (status & I2C_STAT_CMD_COMP)) {
602+
time_wait_ms(10);
603+
if (reset_loops++ == 5) {
604+
prlog(PR_WARNING, "I2C: Retrying reset, with force!\n");
605+
p8_i2c_force_reset(master);
606+
continue;
607+
}
608+
if (reset_loops == 10) {
609+
log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER),
610+
"I2C: Failed to recover i2c engine\n");
611+
break;
612+
}
613+
}
614+
} while (! (status & I2C_STAT_CMD_COMP));
615+
}
616+
return 0;
617+
}
618+
466619
static void p8_i2c_status_error(struct p8_i2c_master_port *port,
467620
struct i2c_request *req,
468621
uint64_t status)
@@ -495,30 +648,10 @@ static void p8_i2c_status_error(struct p8_i2c_master_port *port,
495648
*/
496649
p8_i2c_complete_request(master, req, req->result);
497650
} else {
498-
/*
499-
* Reset the bus by issuing a STOP command to slave.
500-
*
501-
* Reprogram the mode register with 'enhanced bit' set
502-
*/
503-
rc = p8_i2c_prog_mode(port, true);
504-
if (rc) {
505-
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: "
506-
"Failed to program the MODE_REG\n");
651+
if (p8_i2c_reset_engine(master))
507652
goto exit;
508-
}
509-
510653
/* Enable the interrupt */
511654
p8_i2c_enable_irqs(master);
512-
513-
/* Send an immediate stop */
514-
master->state = state_error;
515-
rc = xscom_write(master->chip_id, master->xscom_base +
516-
I2C_CMD_REG, I2C_CMD_WITH_STOP);
517-
if (rc) {
518-
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: "
519-
"Failed to issue immediate STOP\n");
520-
goto exit;
521-
}
522655
}
523656
return;
524657

@@ -1363,6 +1496,7 @@ static void p8_i2c_init_one(struct dt_node *i2cm, enum p8_i2c_master_type type)
13631496

13641497
master->fifo_size = GETFIELD(I2C_EXTD_STAT_FIFO_SIZE, ex_stat);
13651498
list_head_init(&master->req_list);
1499+
list_head_init(&master->ports);
13661500

13671501
/* Check if interrupt is usable */
13681502
master->irq_ok = p8_i2c_has_irqs(master);
@@ -1422,6 +1556,7 @@ static void p8_i2c_init_one(struct dt_node *i2cm, enum p8_i2c_master_type type)
14221556
port->bus.set_req_timeout = p8_i2c_set_request_timeout;
14231557
port->bus.run_req = p8_i2c_run_request;
14241558
i2c_add_bus(&port->bus);
1559+
list_add_tail(&master->ports, &port->link);
14251560

14261561
/* Add OPAL properties to the bus node */
14271562
p8_i2c_add_bus_prop(port);

0 commit comments

Comments
 (0)