/*
* PS3 virtual uart
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#include <asm/ps3.h>
#include <asm/firmware.h>
#include <asm/lv1call.h>
#include "vuart.h"
MODULE_AUTHOR("Sony Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("PS3 vuart");
/**
* vuart - An inter-partition data link service.
* port 0: PS3 AV Settings.
* port 2: PS3 System Manager.
*
* The vuart provides a bi-directional byte stream data link between logical
* partitions. Its primary role is as a communications link between the guest
* OS and the system policy module. The current HV does not support any
* connections other than those listed.
*/
enum {PORT_COUNT = 3,};
enum vuart_param {
PARAM_TX_TRIGGER = 0,
PARAM_RX_TRIGGER = 1,
PARAM_INTERRUPT_MASK = 2,
PARAM_RX_BUF_SIZE = 3, /* read only */
PARAM_RX_BYTES = 4, /* read only */
PARAM_TX_BUF_SIZE = 5, /* read only */
PARAM_TX_BYTES = 6, /* read only */
PARAM_INTERRUPT_STATUS = 7, /* read only */
};
enum vuart_interrupt_bit {
INTERRUPT_BIT_TX = 0,
INTERRUPT_BIT_RX = 1,
INTERRUPT_BIT_DISCONNECT = 2,
};
enum vuart_interrupt_mask {
INTERRUPT_MASK_TX = 1,
INTERRUPT_MASK_RX = 2,
INTERRUPT_MASK_DISCONNECT = 4,
};
/**
* struct ps3_vuart_port_priv - private vuart device data.
*/
struct ps3_vuart_port_priv {
u64 interrupt_mask;
struct {
spinlock_t lock;
struct list_head head;
} tx_list;
struct {
struct ps3_vuart_work work;
unsigned long bytes_held;
spinlock_t lock;
struct list_head head;
} rx_list;
struct ps3_vuart_stats stats;
};
static struct ps3_vuart_port_priv *to_port_priv(
struct ps3_system_bus_device *dev)
{
BUG_ON(!dev);
BUG_ON(!dev->driver_priv);
return (struct ps3_vuart_port_priv *)dev->driver_priv;
}
/**
* struct ports_bmp - bitmap indicating ports needing service.
*
* A 256 bit read only bitmap indicating ports needing service. Do not write
* to these bits. Must not cross a page boundary.
*/
struct ports_bmp {
u64 status;
u64 unused[3];
} __attribute__((aligned(32)));
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
static void __maybe_unused _dump_ports_bmp(
const struct ports_bmp *bmp, const char *func, int line)
{
pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
}
#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
static void __maybe_unused _dump_port_params(unsigned int port_number,
const