cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adb-iop.c (6446B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * I/O Processor (IOP) ADB Driver
      4 * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
      5 * Based on via-cuda.c by Paul Mackerras.
      6 *
      7 * 1999-07-01 (jmt) - First implementation for new driver architecture.
      8 *
      9 * 1999-07-31 (jmt) - First working version.
     10 */
     11
     12#include <linux/types.h>
     13#include <linux/kernel.h>
     14#include <linux/mm.h>
     15#include <linux/delay.h>
     16#include <linux/init.h>
     17
     18#include <asm/macintosh.h>
     19#include <asm/macints.h>
     20#include <asm/mac_iop.h>
     21#include <asm/adb_iop.h>
     22#include <asm/unaligned.h>
     23
     24#include <linux/adb.h>
     25
     26static struct adb_request *current_req;
     27static struct adb_request *last_req;
     28static unsigned int autopoll_devs;
     29static u8 autopoll_addr;
     30
     31static enum adb_iop_state {
     32	idle,
     33	sending,
     34	awaiting_reply
     35} adb_iop_state;
     36
     37static void adb_iop_start(void);
     38static int adb_iop_probe(void);
     39static int adb_iop_init(void);
     40static int adb_iop_send_request(struct adb_request *, int);
     41static int adb_iop_write(struct adb_request *);
     42static int adb_iop_autopoll(int);
     43static void adb_iop_poll(void);
     44static int adb_iop_reset_bus(void);
     45
     46/* ADB command byte structure */
     47#define ADDR_MASK       0xF0
     48#define OP_MASK         0x0C
     49#define TALK            0x0C
     50
     51struct adb_driver adb_iop_driver = {
     52	.name         = "ISM IOP",
     53	.probe        = adb_iop_probe,
     54	.init         = adb_iop_init,
     55	.send_request = adb_iop_send_request,
     56	.autopoll     = adb_iop_autopoll,
     57	.poll         = adb_iop_poll,
     58	.reset_bus    = adb_iop_reset_bus
     59};
     60
     61static void adb_iop_done(void)
     62{
     63	struct adb_request *req = current_req;
     64
     65	adb_iop_state = idle;
     66
     67	req->complete = 1;
     68	current_req = req->next;
     69	if (req->done)
     70		(*req->done)(req);
     71
     72	if (adb_iop_state == idle)
     73		adb_iop_start();
     74}
     75
     76/*
     77 * Completion routine for ADB commands sent to the IOP.
     78 *
     79 * This will be called when a packet has been successfully sent.
     80 */
     81
     82static void adb_iop_complete(struct iop_msg *msg)
     83{
     84	unsigned long flags;
     85
     86	local_irq_save(flags);
     87
     88	adb_iop_state = awaiting_reply;
     89
     90	local_irq_restore(flags);
     91}
     92
     93/*
     94 * Listen for ADB messages from the IOP.
     95 *
     96 * This will be called when unsolicited IOP messages are received.
     97 * These IOP messages can carry ADB autopoll responses and also occur
     98 * after explicit ADB commands.
     99 */
    100
    101static void adb_iop_listen(struct iop_msg *msg)
    102{
    103	struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
    104	u8 addr = (amsg->cmd & ADDR_MASK) >> 4;
    105	u8 op = amsg->cmd & OP_MASK;
    106	unsigned long flags;
    107	bool req_done = false;
    108
    109	local_irq_save(flags);
    110
    111	/* Responses to Talk commands may be unsolicited as they are
    112	 * produced when the IOP polls devices. They are mostly timeouts.
    113	 */
    114	if (op == TALK && ((1 << addr) & autopoll_devs))
    115		autopoll_addr = addr;
    116
    117	switch (amsg->flags & (ADB_IOP_EXPLICIT |
    118			       ADB_IOP_AUTOPOLL |
    119			       ADB_IOP_TIMEOUT)) {
    120	case ADB_IOP_EXPLICIT:
    121	case ADB_IOP_EXPLICIT | ADB_IOP_TIMEOUT:
    122		if (adb_iop_state == awaiting_reply) {
    123			struct adb_request *req = current_req;
    124
    125			if (req->reply_expected) {
    126				req->reply_len = amsg->count + 1;
    127				memcpy(req->reply, &amsg->cmd, req->reply_len);
    128			}
    129
    130			req_done = true;
    131		}
    132		break;
    133	case ADB_IOP_AUTOPOLL:
    134		if (((1 << addr) & autopoll_devs) &&
    135		    amsg->cmd == ADB_READREG(addr, 0))
    136			adb_input(&amsg->cmd, amsg->count + 1, 1);
    137		break;
    138	}
    139	msg->reply[0] = autopoll_addr ? ADB_IOP_AUTOPOLL : 0;
    140	msg->reply[1] = 0;
    141	msg->reply[2] = autopoll_addr ? ADB_READREG(autopoll_addr, 0) : 0;
    142	iop_complete_message(msg);
    143
    144	if (req_done)
    145		adb_iop_done();
    146
    147	local_irq_restore(flags);
    148}
    149
    150/*
    151 * Start sending an ADB packet, IOP style
    152 *
    153 * There isn't much to do other than hand the packet over to the IOP
    154 * after encapsulating it in an adb_iopmsg.
    155 */
    156
    157static void adb_iop_start(void)
    158{
    159	struct adb_request *req;
    160	struct adb_iopmsg amsg;
    161
    162	/* get the packet to send */
    163	req = current_req;
    164	if (!req)
    165		return;
    166
    167	/* The IOP takes MacII-style packets, so strip the initial
    168	 * ADB_PACKET byte.
    169	 */
    170	amsg.flags = ADB_IOP_EXPLICIT;
    171	amsg.count = req->nbytes - 2;
    172
    173	/* amsg.data immediately follows amsg.cmd, effectively making
    174	 * &amsg.cmd a pointer to the beginning of a full ADB packet.
    175	 */
    176	memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
    177
    178	req->sent = 1;
    179	adb_iop_state = sending;
    180
    181	/* Now send it. The IOP manager will call adb_iop_complete
    182	 * when the message has been sent.
    183	 */
    184	iop_send_message(ADB_IOP, ADB_CHAN, req, sizeof(amsg), (__u8 *)&amsg,
    185			 adb_iop_complete);
    186}
    187
    188static int adb_iop_probe(void)
    189{
    190	if (!iop_ism_present)
    191		return -ENODEV;
    192	return 0;
    193}
    194
    195static int adb_iop_init(void)
    196{
    197	pr_info("adb: IOP ISM driver v0.4 for Unified ADB\n");
    198	iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
    199	return 0;
    200}
    201
    202static int adb_iop_send_request(struct adb_request *req, int sync)
    203{
    204	int err;
    205
    206	err = adb_iop_write(req);
    207	if (err)
    208		return err;
    209
    210	if (sync) {
    211		while (!req->complete)
    212			adb_iop_poll();
    213	}
    214	return 0;
    215}
    216
    217static int adb_iop_write(struct adb_request *req)
    218{
    219	unsigned long flags;
    220
    221	if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
    222		req->complete = 1;
    223		return -EINVAL;
    224	}
    225
    226	req->next = NULL;
    227	req->sent = 0;
    228	req->complete = 0;
    229	req->reply_len = 0;
    230
    231	local_irq_save(flags);
    232
    233	if (current_req) {
    234		last_req->next = req;
    235		last_req = req;
    236	} else {
    237		current_req = req;
    238		last_req = req;
    239	}
    240
    241	if (adb_iop_state == idle)
    242		adb_iop_start();
    243
    244	local_irq_restore(flags);
    245
    246	return 0;
    247}
    248
    249static void adb_iop_set_ap_complete(struct iop_msg *msg)
    250{
    251	struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
    252
    253	autopoll_devs = get_unaligned_be16(amsg->data);
    254	if (autopoll_devs & (1 << autopoll_addr))
    255		return;
    256	autopoll_addr = autopoll_devs ? (ffs(autopoll_devs) - 1) : 0;
    257}
    258
    259static int adb_iop_autopoll(int devs)
    260{
    261	struct adb_iopmsg amsg;
    262	unsigned long flags;
    263	unsigned int mask = (unsigned int)devs & 0xFFFE;
    264
    265	local_irq_save(flags);
    266
    267	amsg.flags = ADB_IOP_SET_AUTOPOLL | (mask ? ADB_IOP_AUTOPOLL : 0);
    268	amsg.count = 2;
    269	amsg.cmd = 0;
    270	put_unaligned_be16(mask, amsg.data);
    271
    272	iop_send_message(ADB_IOP, ADB_CHAN, NULL, sizeof(amsg), (__u8 *)&amsg,
    273			 adb_iop_set_ap_complete);
    274
    275	local_irq_restore(flags);
    276
    277	return 0;
    278}
    279
    280static void adb_iop_poll(void)
    281{
    282	iop_ism_irq_poll(ADB_IOP);
    283}
    284
    285static int adb_iop_reset_bus(void)
    286{
    287	struct adb_request req;
    288
    289	/* Command = 0, Address = ignored */
    290	adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
    291	adb_iop_send_request(&req, 1);
    292
    293	/* Don't want any more requests during the Global Reset low time. */
    294	mdelay(3);
    295
    296	return 0;
    297}