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

command.c (4178B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2
      3/*
      4 * IBM ASM Service Processor Device Driver
      5 *
      6 * Copyright (C) IBM Corporation, 2004
      7 *
      8 * Author: Max Asböck <amax@us.ibm.com>
      9 */
     10
     11#include <linux/sched.h>
     12#include <linux/slab.h>
     13#include "ibmasm.h"
     14#include "lowlevel.h"
     15
     16static void exec_next_command(struct service_processor *sp);
     17
     18static atomic_t command_count = ATOMIC_INIT(0);
     19
     20struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
     21{
     22	struct command *cmd;
     23
     24	if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
     25		return NULL;
     26
     27	cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
     28	if (cmd == NULL)
     29		return NULL;
     30
     31
     32	cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
     33	if (cmd->buffer == NULL) {
     34		kfree(cmd);
     35		return NULL;
     36	}
     37	cmd->buffer_size = buffer_size;
     38
     39	kref_init(&cmd->kref);
     40	cmd->lock = &sp->lock;
     41
     42	cmd->status = IBMASM_CMD_PENDING;
     43	init_waitqueue_head(&cmd->wait);
     44	INIT_LIST_HEAD(&cmd->queue_node);
     45
     46	atomic_inc(&command_count);
     47	dbg("command count: %d\n", atomic_read(&command_count));
     48
     49	return cmd;
     50}
     51
     52void ibmasm_free_command(struct kref *kref)
     53{
     54	struct command *cmd = to_command(kref);
     55
     56	list_del(&cmd->queue_node);
     57	atomic_dec(&command_count);
     58	dbg("command count: %d\n", atomic_read(&command_count));
     59	kfree(cmd->buffer);
     60	kfree(cmd);
     61}
     62
     63static void enqueue_command(struct service_processor *sp, struct command *cmd)
     64{
     65	list_add_tail(&cmd->queue_node, &sp->command_queue);
     66}
     67
     68static struct command *dequeue_command(struct service_processor *sp)
     69{
     70	struct command *cmd;
     71	struct list_head *next;
     72
     73	if (list_empty(&sp->command_queue))
     74		return NULL;
     75
     76	next = sp->command_queue.next;
     77	list_del_init(next);
     78	cmd = list_entry(next, struct command, queue_node);
     79
     80	return cmd;
     81}
     82
     83static inline void do_exec_command(struct service_processor *sp)
     84{
     85	char tsbuf[32];
     86
     87	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
     88
     89	if (ibmasm_send_i2o_message(sp)) {
     90		sp->current_command->status = IBMASM_CMD_FAILED;
     91		wake_up(&sp->current_command->wait);
     92		command_put(sp->current_command);
     93		exec_next_command(sp);
     94	}
     95}
     96
     97/*
     98 * exec_command
     99 * send a command to a service processor
    100 * Commands are executed sequentially. One command (sp->current_command)
    101 * is sent to the service processor. Once the interrupt handler gets a
    102 * message of type command_response, the message is copied into
    103 * the current commands buffer,
    104 */
    105void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
    106{
    107	unsigned long flags;
    108	char tsbuf[32];
    109
    110	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
    111
    112	spin_lock_irqsave(&sp->lock, flags);
    113
    114	if (!sp->current_command) {
    115		sp->current_command = cmd;
    116		command_get(sp->current_command);
    117		spin_unlock_irqrestore(&sp->lock, flags);
    118		do_exec_command(sp);
    119	} else {
    120		enqueue_command(sp, cmd);
    121		spin_unlock_irqrestore(&sp->lock, flags);
    122	}
    123}
    124
    125static void exec_next_command(struct service_processor *sp)
    126{
    127	unsigned long flags;
    128	char tsbuf[32];
    129
    130	dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
    131
    132	spin_lock_irqsave(&sp->lock, flags);
    133	sp->current_command = dequeue_command(sp);
    134	if (sp->current_command) {
    135		command_get(sp->current_command);
    136		spin_unlock_irqrestore(&sp->lock, flags);
    137		do_exec_command(sp);
    138	} else {
    139		spin_unlock_irqrestore(&sp->lock, flags);
    140	}
    141}
    142
    143/*
    144 * Sleep until a command has failed or a response has been received
    145 * and the command status been updated by the interrupt handler.
    146 * (see receive_response).
    147 */
    148void ibmasm_wait_for_response(struct command *cmd, int timeout)
    149{
    150	wait_event_interruptible_timeout(cmd->wait,
    151				cmd->status == IBMASM_CMD_COMPLETE ||
    152				cmd->status == IBMASM_CMD_FAILED,
    153				timeout * HZ);
    154}
    155
    156/*
    157 * receive_command_response
    158 * called by the interrupt handler when a dot command of type command_response
    159 * was received.
    160 */
    161void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
    162{
    163	struct command *cmd = sp->current_command;
    164
    165	if (!sp->current_command)
    166		return;
    167
    168	memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
    169	cmd->status = IBMASM_CMD_COMPLETE;
    170	wake_up(&sp->current_command->wait);
    171	command_put(sp->current_command);
    172	exec_next_command(sp);
    173}