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

motu-transaction.c (3598B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * motu-transaction.c - a part of driver for MOTU FireWire series
      4 *
      5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
      6 */
      7
      8
      9#include "motu.h"
     10
     11#define SND_MOTU_ADDR_BASE	0xfffff0000000ULL
     12#define ASYNC_ADDR_HI  0x0b04
     13#define ASYNC_ADDR_LO  0x0b08
     14
     15int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
     16			      size_t size)
     17{
     18	int tcode;
     19
     20	if (size % sizeof(__be32) > 0 || size <= 0)
     21		return -EINVAL;
     22	if (size == sizeof(__be32))
     23		tcode = TCODE_READ_QUADLET_REQUEST;
     24	else
     25		tcode = TCODE_READ_BLOCK_REQUEST;
     26
     27	return snd_fw_transaction(motu->unit, tcode,
     28				  SND_MOTU_ADDR_BASE + offset, reg, size, 0);
     29}
     30
     31int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
     32			       size_t size)
     33{
     34	int tcode;
     35
     36	if (size % sizeof(__be32) > 0 || size <= 0)
     37		return -EINVAL;
     38	if (size == sizeof(__be32))
     39		tcode = TCODE_WRITE_QUADLET_REQUEST;
     40	else
     41		tcode = TCODE_WRITE_BLOCK_REQUEST;
     42
     43	return snd_fw_transaction(motu->unit, tcode,
     44				  SND_MOTU_ADDR_BASE + offset, reg, size, 0);
     45}
     46
     47static void handle_message(struct fw_card *card, struct fw_request *request,
     48			   int tcode, int destination, int source,
     49			   int generation, unsigned long long offset,
     50			   void *data, size_t length, void *callback_data)
     51{
     52	struct snd_motu *motu = callback_data;
     53	__be32 *buf = (__be32 *)data;
     54	unsigned long flags;
     55
     56	if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
     57		fw_send_response(card, request, RCODE_COMPLETE);
     58		return;
     59	}
     60
     61	if (offset != motu->async_handler.offset || length != 4) {
     62		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
     63		return;
     64	}
     65
     66	spin_lock_irqsave(&motu->lock, flags);
     67	motu->msg = be32_to_cpu(*buf);
     68	spin_unlock_irqrestore(&motu->lock, flags);
     69
     70	fw_send_response(card, request, RCODE_COMPLETE);
     71
     72	wake_up(&motu->hwdep_wait);
     73}
     74
     75int snd_motu_transaction_reregister(struct snd_motu *motu)
     76{
     77	struct fw_device *device = fw_parent_device(motu->unit);
     78	__be32 data;
     79	int err;
     80
     81	if (motu->async_handler.callback_data == NULL)
     82		return -EINVAL;
     83
     84	/* Register messaging address. Block transaction is not allowed. */
     85	data = cpu_to_be32((device->card->node_id << 16) |
     86			   (motu->async_handler.offset >> 32));
     87	err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
     88					 sizeof(data));
     89	if (err < 0)
     90		return err;
     91
     92	data = cpu_to_be32(motu->async_handler.offset);
     93	return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
     94					  sizeof(data));
     95}
     96
     97int snd_motu_transaction_register(struct snd_motu *motu)
     98{
     99	static const struct fw_address_region resp_register_region = {
    100		.start	= 0xffffe0000000ull,
    101		.end	= 0xffffe000ffffull,
    102	};
    103	int err;
    104
    105	/* Perhaps, 4 byte messages are transferred. */
    106	motu->async_handler.length = 4;
    107	motu->async_handler.address_callback = handle_message;
    108	motu->async_handler.callback_data = motu;
    109
    110	err = fw_core_add_address_handler(&motu->async_handler,
    111					  &resp_register_region);
    112	if (err < 0)
    113		return err;
    114
    115	err = snd_motu_transaction_reregister(motu);
    116	if (err < 0) {
    117		fw_core_remove_address_handler(&motu->async_handler);
    118		motu->async_handler.address_callback = NULL;
    119	}
    120
    121	return err;
    122}
    123
    124void snd_motu_transaction_unregister(struct snd_motu *motu)
    125{
    126	__be32 data;
    127
    128	if (motu->async_handler.address_callback != NULL)
    129		fw_core_remove_address_handler(&motu->async_handler);
    130	motu->async_handler.address_callback = NULL;
    131
    132	/* Unregister the address. */
    133	data = cpu_to_be32(0x00000000);
    134	snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
    135	snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
    136}