174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/* 274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * PS3 virtual uart 374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Copyright (C) 2006 Sony Computer Entertainment Inc. 574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Copyright 2006 Sony Corp. 674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * This program is free software; you can redistribute it and/or modify 874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * it under the terms of the GNU General Public License as published by 974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * the Free Software Foundation; version 2 of the License. 1074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 1174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * This program is distributed in the hope that it will be useful, 1274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * but WITHOUT ANY WARRANTY; without even the implied warranty of 1374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * GNU General Public License for more details. 1574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 1674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * You should have received a copy of the GNU General Public License 1774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * along with this program; if not, write to the Free Software 1874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 2074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include <linux/kernel.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 2374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include <linux/module.h> 2474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include <linux/interrupt.h> 25ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand#include <linux/workqueue.h> 261977f032722c27ee3730284582fd3991ad9ac81bJiri Slaby#include <linux/bitops.h> 2774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include <asm/ps3.h> 2874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2975c86e7422751c5be3caaf448d802839ec685725Geoff Levand#include <asm/firmware.h> 3074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include <asm/lv1call.h> 3174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#include "vuart.h" 3374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff LevandMODULE_AUTHOR("Sony Corporation"); 3574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff LevandMODULE_LICENSE("GPL v2"); 3675c86e7422751c5be3caaf448d802839ec685725Geoff LevandMODULE_DESCRIPTION("PS3 vuart"); 3774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 3974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * vuart - An inter-partition data link service. 4074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * port 0: PS3 AV Settings. 4174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * port 2: PS3 System Manager. 4274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 4374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * The vuart provides a bi-directional byte stream data link between logical 4474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * partitions. Its primary role is as a communications link between the guest 4574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * OS and the system policy module. The current HV does not support any 4674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * connections other than those listed. 4774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 4874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 4974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandenum {PORT_COUNT = 3,}; 5074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 5174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandenum vuart_param { 5274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_TX_TRIGGER = 0, 5374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_TRIGGER = 1, 5474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_INTERRUPT_MASK = 2, 5574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_BUF_SIZE = 3, /* read only */ 5674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_BYTES = 4, /* read only */ 5774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_TX_BUF_SIZE = 5, /* read only */ 5874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_TX_BYTES = 6, /* read only */ 5974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_INTERRUPT_STATUS = 7, /* read only */ 6074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand}; 6174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandenum vuart_interrupt_bit { 6374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_BIT_TX = 0, 6474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_BIT_RX = 1, 6574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_BIT_DISCONNECT = 2, 6674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand}; 6774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandenum vuart_interrupt_mask { 6974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_MASK_TX = 1, 7074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_MASK_RX = 2, 7174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand INTERRUPT_MASK_DISCONNECT = 4, 7274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand}; 7374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 7474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * struct ps3_vuart_port_priv - private vuart device data. 767626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 777626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 787626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstruct ps3_vuart_port_priv { 797626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand u64 interrupt_mask; 807626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 817626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct { 827626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spinlock_t lock; 837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct list_head head; 847626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } tx_list; 857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct { 867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_work work; 877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand unsigned long bytes_held; 887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spinlock_t lock; 897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct list_head head; 907626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } rx_list; 917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_stats stats; 927626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand}; 937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 947626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic struct ps3_vuart_port_priv *to_port_priv( 957626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_system_bus_device *dev) 967626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 977626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!dev); 987626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!dev->driver_priv); 997626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (struct ps3_vuart_port_priv *)dev->driver_priv; 1007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 1017626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 1027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 10374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * struct ports_bmp - bitmap indicating ports needing service. 10474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 10574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * A 256 bit read only bitmap indicating ports needing service. Do not write 10674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * to these bits. Must not cross a page boundary. 10774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 10874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandstruct ports_bmp { 11074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand u64 status; 11174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand u64 unused[3]; 112d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven} __attribute__((aligned(32))); 11374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__) 115848cfdc5c1cd2163ba0c9a6490d9adcb7a7c3518Geoff Levandstatic void __maybe_unused _dump_ports_bmp( 116d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven const struct ports_bmp *bmp, const char *func, int line) 11774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 118a9dad6e598155e2a548142336cd833e5360335d1Stephen Rothwell pr_debug("%s:%d: ports_bmp: %016llxh\n", func, line, bmp->status); 11974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 12074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__) 122848cfdc5c1cd2163ba0c9a6490d9adcb7a7c3518Geoff Levandstatic void __maybe_unused _dump_port_params(unsigned int port_number, 123d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven const char *func, int line) 12474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 12574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#if defined(DEBUG) 12674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand static const char *strings[] = { 12774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "tx_trigger ", 12874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "rx_trigger ", 12974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "interrupt_mask ", 13074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "rx_buf_size ", 13174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "rx_bytes ", 13274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "tx_buf_size ", 13374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "tx_bytes ", 13474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "interrupt_status", 13574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand }; 13674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 13774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int i; 13874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand u64 value; 13974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 14074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand for (i = 0; i < ARRAY_SIZE(strings); i++) { 14174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = lv1_get_virtual_uart_param(port_number, i, &value); 14274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 14374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 14474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand pr_debug("%s:%d: port_%u: %s failed: %s\n", func, line, 14574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand port_number, strings[i], ps3_result(result)); 14674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand continue; 14774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 14874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand pr_debug("%s:%d: port_%u: %s = %lxh\n", 14974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand func, line, port_number, strings[i], value); 15074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 15174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand#endif 15274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 15374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 15474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandstruct vuart_triggers { 15574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long rx; 15674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long tx; 15774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand}; 15874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1597626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_get_triggers(struct ps3_system_bus_device *dev, 16074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand struct vuart_triggers *trig) 16174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 16274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 163b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 size; 164b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 val; 165b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 tx; 16674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1677626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 168b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell PARAM_TX_TRIGGER, &tx); 169b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell trig->tx = tx; 17074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 17174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 17274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n", 17374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 17474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 17574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 17674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1777626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 17874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_BUF_SIZE, &size); 17974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 18074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 18174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n", 18274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 18374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 18474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 18574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 18774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_TRIGGER, &val); 18874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 18974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 19074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n", 19174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 19274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 19374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 19474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 19574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand trig->rx = size - val; 19674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 19774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx %lxh, rx %lxh\n", __func__, __LINE__, 19874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand trig->tx, trig->rx); 19974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 20074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 20174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 20274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2037626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx, 20474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int rx) 20574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 20674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 207b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 size; 20874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_set_virtual_uart_param(dev->port_number, 21074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_TX_TRIGGER, tx); 21174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 21274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 21374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n", 21474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 21574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 21674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 21774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 21974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_BUF_SIZE, &size); 22074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 22174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 22274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx_buf_size failed: %s\n", 22374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 22474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 22574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 22674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_set_virtual_uart_param(dev->port_number, 22874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_TRIGGER, size - rx); 22974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 23074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 23174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: rx_trigger failed: %s\n", 23274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 23374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 23474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 23574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 23674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: tx %xh, rx %xh\n", __func__, __LINE__, 23774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand tx, rx); 23874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 23974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 24074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 24174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2427626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev, 24375c86e7422751c5be3caaf448d802839ec685725Geoff Levand u64 *bytes_waiting) 24474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 2457626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand int result; 2467626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 2477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 24874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand PARAM_RX_BYTES, bytes_waiting); 24974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 25074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 25174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n", 25274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 25374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 254a9dad6e598155e2a548142336cd833e5360335d1Stephen Rothwell dev_dbg(&dev->core, "%s:%d: %llxh\n", __func__, __LINE__, 25574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand *bytes_waiting); 25674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 25774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 25874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2597626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 2607626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources. 2617626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 2627626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables. 2637626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 2647626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 2657626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev, 26674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long mask) 26774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 26874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 2697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 27074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 27174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask); 27274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2737626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->interrupt_mask = mask; 27474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_set_virtual_uart_param(dev->port_number, 2767626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand PARAM_INTERRUPT_MASK, priv->interrupt_mask); 27774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 27874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 27974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n", 28074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 28174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 28274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 28374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 28474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev, 28674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long *status) 28774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 2887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand int result; 2897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 29075c86e7422751c5be3caaf448d802839ec685725Geoff Levand u64 tmp; 2917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 2927626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_get_virtual_uart_param(dev->port_number, 29375c86e7422751c5be3caaf448d802839ec685725Geoff Levand PARAM_INTERRUPT_STATUS, &tmp); 29474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 29574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 29674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n", 29774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 29874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 2997626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand *status = tmp & priv->interrupt_mask; 30075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 301a9dad6e598155e2a548142336cd833e5360335d1Stephen Rothwell dev_dbg(&dev->core, "%s:%d: m %llxh, s %llxh, m&s %lxh\n", 3027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, priv->interrupt_mask, tmp, *status); 30374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 30474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 30574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 30674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev) 30874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3117626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0 3127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 31374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand | INTERRUPT_MASK_TX); 31474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 31574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3167626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev) 31774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3197626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3207626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0 3217626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 32274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand | INTERRUPT_MASK_RX); 32374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 32474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev) 32674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3287626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3297626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0 3307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 33174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand | INTERRUPT_MASK_DISCONNECT); 33274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 33374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3347626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev) 33574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3367626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3387626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_TX) 3397626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 34074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand & ~INTERRUPT_MASK_TX) : 0; 34174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 34274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3437626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev) 34474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3457626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3467626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_RX) 3487626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 34974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand & ~INTERRUPT_MASK_RX) : 0; 35074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 35174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev) 35374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 3547626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 3557626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 3567626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) 3577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask 35874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand & ~INTERRUPT_MASK_DISCONNECT) : 0; 35974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 36074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 36174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 36274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_raw_write - Low level write helper. 3637626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 36474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 36574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Do not call ps3_vuart_raw_write directly, use ps3_vuart_write. 36674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 36774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3687626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_raw_write(struct ps3_system_bus_device *dev, 369b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell const void *buf, unsigned int bytes, u64 *bytes_written) 37074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 37174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 3727626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 37374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3747626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_write_virtual_uart(dev->port_number, 37574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written); 37674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 37774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 37874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: lv1_write_virtual_uart failed: " 37974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "%s\n", __func__, __LINE__, ps3_result(result)); 38074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 38174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 38274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.bytes_written += *bytes_written; 38474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 385b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell dev_dbg(&dev->core, "%s:%d: wrote %llxh/%xh=>%lxh\n", __func__, __LINE__, 3867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand *bytes_written, bytes, priv->stats.bytes_written); 38774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 38874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 38974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 39074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 39174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 39274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_raw_read - Low level read helper. 3937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 39474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 39574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Do not call ps3_vuart_raw_read directly, use ps3_vuart_read. 39674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 39774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 3987626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf, 399b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell unsigned int bytes, u64 *bytes_read) 40074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 40174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 4027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 40374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 40474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes); 40574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 4067626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = lv1_read_virtual_uart(dev->port_number, 40774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read); 40874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 40974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 41074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: lv1_read_virtual_uart failed: %s\n", 41174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, ps3_result(result)); 41274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 41374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 41474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 4157626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.bytes_read += *bytes_read; 41674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 417b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell dev_dbg(&dev->core, "%s:%d: read %llxh/%xh=>%lxh\n", __func__, __LINE__, 4187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand *bytes_read, bytes, priv->stats.bytes_read); 41974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 42074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 42174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 42274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 42374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 42475c86e7422751c5be3caaf448d802839ec685725Geoff Levand * ps3_vuart_clear_rx_bytes - Discard bytes received. 4257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 42675c86e7422751c5be3caaf448d802839ec685725Geoff Levand * @bytes: Max byte count to discard, zero = all pending. 42775c86e7422751c5be3caaf448d802839ec685725Geoff Levand * 42875c86e7422751c5be3caaf448d802839ec685725Geoff Levand * Used to clear pending rx interrupt source. Will not block. 42975c86e7422751c5be3caaf448d802839ec685725Geoff Levand */ 43075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 4317626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandvoid ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev, 43275c86e7422751c5be3caaf448d802839ec685725Geoff Levand unsigned int bytes) 43375c86e7422751c5be3caaf448d802839ec685725Geoff Levand{ 43475c86e7422751c5be3caaf448d802839ec685725Geoff Levand int result; 4357626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 43675c86e7422751c5be3caaf448d802839ec685725Geoff Levand u64 bytes_waiting; 437d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven void *tmp; 43875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 43975c86e7422751c5be3caaf448d802839ec685725Geoff Levand result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting); 44075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 44175c86e7422751c5be3caaf448d802839ec685725Geoff Levand BUG_ON(result); 44275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 44375c86e7422751c5be3caaf448d802839ec685725Geoff Levand bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting; 44475c86e7422751c5be3caaf448d802839ec685725Geoff Levand 44575c86e7422751c5be3caaf448d802839ec685725Geoff Levand dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes); 44675c86e7422751c5be3caaf448d802839ec685725Geoff Levand 44775c86e7422751c5be3caaf448d802839ec685725Geoff Levand if (!bytes) 44875c86e7422751c5be3caaf448d802839ec685725Geoff Levand return; 44975c86e7422751c5be3caaf448d802839ec685725Geoff Levand 45075c86e7422751c5be3caaf448d802839ec685725Geoff Levand /* Add some extra space for recently arrived data. */ 45175c86e7422751c5be3caaf448d802839ec685725Geoff Levand 45275c86e7422751c5be3caaf448d802839ec685725Geoff Levand bytes += 128; 45375c86e7422751c5be3caaf448d802839ec685725Geoff Levand 45475c86e7422751c5be3caaf448d802839ec685725Geoff Levand tmp = kmalloc(bytes, GFP_KERNEL); 45575c86e7422751c5be3caaf448d802839ec685725Geoff Levand 45675c86e7422751c5be3caaf448d802839ec685725Geoff Levand if (!tmp) 45775c86e7422751c5be3caaf448d802839ec685725Geoff Levand return; 45875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 45975c86e7422751c5be3caaf448d802839ec685725Geoff Levand ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting); 46075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 46175c86e7422751c5be3caaf448d802839ec685725Geoff Levand kfree(tmp); 46275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 46375c86e7422751c5be3caaf448d802839ec685725Geoff Levand /* Don't include these bytes in the stats. */ 46475c86e7422751c5be3caaf448d802839ec685725Geoff Levand 4657626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.bytes_read -= bytes_waiting; 46675c86e7422751c5be3caaf448d802839ec685725Geoff Levand} 4677626e78d29651d3075e88f233c0632867ea6a35cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes); 46875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 46975c86e7422751c5be3caaf448d802839ec685725Geoff Levand/** 47074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * struct list_buffer - An element for a port device fifo buffer list. 47174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 47274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 47374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandstruct list_buffer { 47474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand struct list_head link; 47574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand const unsigned char *head; 47674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand const unsigned char *tail; 47774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long dbg_number; 47874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned char data[]; 47974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand}; 48074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 48174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 48274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_write - the entry point for writing data to a port 4837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 48474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 48574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * If the port is idle on entry as much of the incoming data is written to 48674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * the port as the port will accept. Otherwise a list buffer is created 48774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * and any remaning incoming data is copied to that buffer. The buffer is 48874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * then enqueued for transmision via the transmit interrupt. 48974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 49074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 4917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, 49274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int bytes) 49374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 49474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand static unsigned long dbg_number; 49574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 4967626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 49774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long flags; 49874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand struct list_buffer *lb; 49974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 50074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, 50174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes, bytes); 50274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 5037626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->tx_list.lock, flags); 50474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 5057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (list_empty(&priv->tx_list.head)) { 506b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 bytes_written; 50774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 50874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written); 50974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 5107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->tx_list.lock, flags); 51174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 51274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 51374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, 51474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "%s:%d: ps3_vuart_raw_write failed\n", 51574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__); 51674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 51774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 51874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 51974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (bytes_written == bytes) { 52074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: wrote %xh bytes\n", 52174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, bytes); 52274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 52374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 52474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 52574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes -= bytes_written; 52674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand buf += bytes_written; 52774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } else 5287626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->tx_list.lock, flags); 52974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 53074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL); 53174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 532d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven if (!lb) 53374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return -ENOMEM; 53474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 53574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand memcpy(lb->data, buf, bytes); 53674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->head = lb->data; 53774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->tail = lb->data + bytes; 53874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->dbg_number = ++dbg_number; 53974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 5407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->tx_list.lock, flags); 5417626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand list_add_tail(&lb->link, &priv->tx_list.head); 54274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_enable_interrupt_tx(dev); 5437626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->tx_list.lock, flags); 54474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 54574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n", 54674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, lb->dbg_number, bytes); 54774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 54874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 54974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 5507626e78d29651d3075e88f233c0632867ea6a35cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_write); 5517626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 5537626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list. 5547626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 5557626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @bytes_queued: Number of bytes queued to the buffer list. 5567626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * 5577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * Must be called with priv->rx_list.lock held. 5587626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 5597626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5607626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev, 5617626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand u64 *bytes_queued) 5627626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 5637626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand static unsigned long dbg_number; 5647626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand int result; 5657626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 5667626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct list_buffer *lb; 5677626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand u64 bytes; 5687626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand *bytes_queued = 0; 5707626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5717626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes); 5727626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(result); 5737626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5747626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result) 5757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return -EIO; 5767626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5777626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!bytes) 5787626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 5797626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5807626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand /* Add some extra space for recently arrived data. */ 5817626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5827626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand bytes += 128; 5837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5847626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC); 5857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!lb) 5877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return -ENOMEM; 5887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_raw_read(dev, lb->data, bytes, &bytes); 5907626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand lb->head = lb->data; 5927626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand lb->tail = lb->data + bytes; 5937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand lb->dbg_number = ++dbg_number; 5947626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 5957626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand list_add_tail(&lb->link, &priv->rx_list.head); 5967626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.bytes_held += bytes; 5977626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 598a9dad6e598155e2a548142336cd833e5360335d1Stephen Rothwell dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %llxh bytes\n", 5997626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, lb->dbg_number, bytes); 6007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6017626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand *bytes_queued = bytes; 6027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6037626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 6047626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 60574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 60674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 6077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_read - The entry point for reading data from a port. 60874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 6097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * Queue data waiting at the port, and if enough bytes to satisfy the request 6107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * are held in the buffer list those bytes are dequeued and copied to the 6117626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * caller's buffer. Emptied list buffers are retiered. If the request cannot 6127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * be statified by bytes held in the list buffers -EAGAIN is returned. 61374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 61474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6157626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf, 61674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int bytes) 61774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 6187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand int result; 6197626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 62074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long flags; 62174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand struct list_buffer *lb, *n; 62274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long bytes_read; 62374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 62474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__, 62574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes, bytes); 62674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->rx_list.lock, flags); 62874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6297626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand /* Queue rx bytes here for polled reads. */ 6307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6317626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand while (priv->rx_list.bytes_held < bytes) { 6327626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand u64 tmp; 6337626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6347626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_vuart_queue_rx_bytes(dev, &tmp); 6357626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result || !tmp) { 6367626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n", 6377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, 6387626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand bytes - priv->rx_list.bytes_held); 6397626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 6407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return -EAGAIN; 6417626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 64274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 64374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6447626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) { 64574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes_read = min((unsigned int)(lb->tail - lb->head), bytes); 64674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 64774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand memcpy(buf, lb->head, bytes_read); 64874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand buf += bytes_read; 64974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes -= bytes_read; 6507626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.bytes_held -= bytes_read; 65174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 65274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (bytes_read < lb->tail - lb->head) { 65374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->head += bytes_read; 65475c86e7422751c5be3caaf448d802839ec685725Geoff Levand dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh " 65575c86e7422751c5be3caaf448d802839ec685725Geoff Levand "bytes\n", __func__, __LINE__, lb->dbg_number, 65675c86e7422751c5be3caaf448d802839ec685725Geoff Levand bytes_read); 6577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 65874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 65974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 66074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 66175c86e7422751c5be3caaf448d802839ec685725Geoff Levand dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh " 66275c86e7422751c5be3caaf448d802839ec685725Geoff Levand "bytes\n", __func__, __LINE__, lb->dbg_number, 66375c86e7422751c5be3caaf448d802839ec685725Geoff Levand bytes_read); 66474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 66574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand list_del(&lb->link); 66674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand kfree(lb); 66774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 66874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 67074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 67174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 6727626e78d29651d3075e88f233c0632867ea6a35cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_read); 67374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 6747626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 6757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_work - Asynchronous read handler. 6767626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 6777626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6787626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic void ps3_vuart_work(struct work_struct *work) 6797626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 6807626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_system_bus_device *dev = 6817626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_work_to_system_bus_dev(work); 6827626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_driver *drv = 6837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_system_bus_dev_to_vuart_drv(dev); 6847626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!drv); 6867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->work(dev); 6877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 6887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 6897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandint ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes) 690ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand{ 6917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 692ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand unsigned long flags; 693ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 6947626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (priv->rx_list.work.trigger) { 695ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n", 696ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand __func__, __LINE__); 697ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand return -EAGAIN; 698ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand } 699ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 700ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand BUG_ON(!bytes); 701ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 7027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work); 703ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 7047626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->rx_list.lock, flags); 7057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (priv->rx_list.bytes_held >= bytes) { 706ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n", 707ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand __func__, __LINE__, bytes); 7087626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand schedule_work(&priv->rx_list.work.work); 7097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 710ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand return 0; 711ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand } 712ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 7137626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.work.trigger = bytes; 7147626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 715ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 716ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__, 717ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand __LINE__, bytes, bytes); 718ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 719ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand return 0; 720ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand} 7217626e78d29651d3075e88f233c0632867ea6a35cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_read_async); 722ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 7237626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandvoid ps3_vuart_cancel_async(struct ps3_system_bus_device *dev) 724ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand{ 7257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand to_port_priv(dev)->rx_list.work.trigger = 0; 726ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand} 7277626e78d29651d3075e88f233c0632867ea6a35cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_cancel_async); 728ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 72974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 73074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler 73174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 73274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Services the transmit interrupt for the port. Writes as much data from the 73374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * buffer list as the port will accept. Retires any emptied list buffers and 73474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * adjusts the final list buffer state for a partial write. 73574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 73674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 7377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev) 73874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 73974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result = 0; 7407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 74174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long flags; 74274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand struct list_buffer *lb, *n; 74374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long bytes_total = 0; 74474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 74574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 74674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 7477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->tx_list.lock, flags); 74874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 7497626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) { 75074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 751b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell u64 bytes_written; 75274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 75374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head, 75474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand &bytes_written); 75574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 75674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 75774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, 75874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand "%s:%d: ps3_vuart_raw_write failed\n", 75974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__); 76074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand break; 76174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 76274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 76374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes_total += bytes_written; 76474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 76574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (bytes_written < lb->tail - lb->head) { 76674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->head += bytes_written; 76774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, 768b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell "%s:%d cleared buf_%lu, %llxh bytes\n", 76974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, lb->dbg_number, 77074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand bytes_written); 77174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand goto port_full; 77274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 77374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 77474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__, 77574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand lb->dbg_number); 77674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 77774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand list_del(&lb->link); 77874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand kfree(lb); 77974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 78074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 78174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_disable_interrupt_tx(dev); 78274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandport_full: 7837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->tx_list.lock, flags); 78474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n", 78574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__, bytes_total); 78674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 78774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 78874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 78974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 79074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_handle_interrupt_rx - third stage receive interrupt handler 79174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 79274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Services the receive interrupt for the port. Creates a list buffer and 79374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * copies all waiting port data to that buffer and enqueues the buffer in the 79474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * buffer list. Buffer list data is dequeued via ps3_vuart_read. 79574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 79674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 7977626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev) 79874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 7997626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand int result; 8007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 80174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long flags; 8027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand u64 bytes; 80374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 80474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 80574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 8067626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_irqsave(&priv->rx_list.lock, flags); 8077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_vuart_queue_rx_bytes(dev, &bytes); 80874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 8097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result) { 8107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 8117626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return result; 8127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 81374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 8147626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (priv->rx_list.work.trigger && priv->rx_list.bytes_held 8157626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand >= priv->rx_list.work.trigger) { 816ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n", 8177626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, priv->rx_list.work.trigger); 8187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.work.trigger = 0; 8197626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand schedule_work(&priv->rx_list.work.work); 820ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand } 8217626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 8227626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_unlock_irqrestore(&priv->rx_list.lock, flags); 8237626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return result; 82474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 82574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 82674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandstatic int ps3_vuart_handle_interrupt_disconnect( 8277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_system_bus_device *dev) 82874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 82974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 83074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand BUG_ON("no support"); 83174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return -1; 83274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 83374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 83474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 83574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_handle_port_interrupt - second stage interrupt handler 83674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 83774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Services any pending interrupt types for the port. Passes control to the 83874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * third stage type specific interrupt handler. Returns control to the first 83974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * stage handler after one iteration. 84074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 84174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 8427626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev) 84374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 84474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 8457626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 84674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned long status; 84774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 84875c86e7422751c5be3caaf448d802839ec685725Geoff Levand result = ps3_vuart_get_interrupt_status(dev, &status); 84974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 85074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 85174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 85274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 85374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: status: %lxh\n", __func__, __LINE__, 85474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand status); 85574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 85674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (status & INTERRUPT_MASK_DISCONNECT) { 8577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.disconnect_interrupts++; 85874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = ps3_vuart_handle_interrupt_disconnect(dev); 85974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 86074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_disable_interrupt_disconnect(dev); 86174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 86274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 86374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (status & INTERRUPT_MASK_TX) { 8647626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.tx_interrupts++; 86574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = ps3_vuart_handle_interrupt_tx(dev); 86674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 86774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_disable_interrupt_tx(dev); 86874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 86974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 87074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (status & INTERRUPT_MASK_RX) { 8717626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->stats.rx_interrupts++; 87274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = ps3_vuart_handle_interrupt_rx(dev); 87374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) 87474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_disable_interrupt_rx(dev); 87574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 87674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 87774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 87874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 87974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 88075c86e7422751c5be3caaf448d802839ec685725Geoff Levandstruct vuart_bus_priv { 8817626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ports_bmp *bmp; 88274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int virq; 883c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand struct mutex probe_mutex; 88475c86e7422751c5be3caaf448d802839ec685725Geoff Levand int use_count; 8857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_system_bus_device *devices[PORT_COUNT]; 88675c86e7422751c5be3caaf448d802839ec685725Geoff Levand} static vuart_bus_priv; 88774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 88874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 88974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_irq_handler - first stage interrupt handler 89074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 89174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Loops finding any interrupting port and its associated instance data. 89274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * Passes control to the second stage port specific interrupt handler. Loops 89374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * until all outstanding interrupts are serviced. 89474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 89574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 89674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandstatic irqreturn_t ps3_vuart_irq_handler(int irq, void *_private) 89774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 8987626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct vuart_bus_priv *bus_priv = _private; 89974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!bus_priv); 90174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 90274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand while (1) { 90374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand unsigned int port; 90474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dump_ports_bmp(bus_priv->bmp); 90674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status); 90874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 90974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (port == BITS_PER_LONG) 91074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand break; 91174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 91274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand BUG_ON(port >= PORT_COUNT); 91375c86e7422751c5be3caaf448d802839ec685725Geoff Levand BUG_ON(!bus_priv->devices[port]); 91474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 91575c86e7422751c5be3caaf448d802839ec685725Geoff Levand ps3_vuart_handle_port_interrupt(bus_priv->devices[port]); 91674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 91774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 91874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return IRQ_HANDLED; 91974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 92074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9217626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_bus_interrupt_get(void) 92274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 92374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 92474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug(" -> %s:%d\n", __func__, __LINE__); 9267626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.use_count++; 9287626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9297626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(vuart_bus_priv.use_count > 2); 9307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 931d0e5c2185e1c6508894e1ee1a8e9bf79e009e427Geert Uytterhoeven if (vuart_bus_priv.use_count != 1) 9327626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 9337626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9347626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(vuart_bus_priv.bmp); 9357626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9367626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL); 9377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9387626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!vuart_bus_priv.bmp) { 9397626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__); 9407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = -ENOMEM; 9417626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_bmp_malloc; 9427626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 9437626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9447626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp, 9457626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand &vuart_bus_priv.virq); 9467626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result) { 9487626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n", 9497626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, result); 9507626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = -EPERM; 9517626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_alloc_irq; 9527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 9537626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9547626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, 9556ea741a13690da9dbbac76175db8e313b0c4b817Yong Zhang 0, "vuart", &vuart_bus_priv); 95674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result) { 9587626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d: request_irq failed (%d)\n", 9597626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__, result); 9607626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_request_irq; 9617626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 96274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 9637626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug(" <- %s:%d: ok\n", __func__, __LINE__); 96474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 9657626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9667626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_request_irq: 9677626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_irq_destroy(vuart_bus_priv.virq); 9687626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.virq = NO_IRQ; 9697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_alloc_irq: 9707626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand kfree(vuart_bus_priv.bmp); 9717626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.bmp = NULL; 9727626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_bmp_malloc: 9737626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.use_count--; 9747626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); 9757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return result; 9767626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 9777626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9787626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_bus_interrupt_put(void) 9797626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 9807626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug(" -> %s:%d\n", __func__, __LINE__); 9817626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9827626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.use_count--; 9837626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9847626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(vuart_bus_priv.use_count < 0); 9857626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (vuart_bus_priv.use_count != 0) 9877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 9887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand free_irq(vuart_bus_priv.virq, &vuart_bus_priv); 9907626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_irq_destroy(vuart_bus_priv.virq); 9927626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.virq = NO_IRQ; 9937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9947626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand kfree(vuart_bus_priv.bmp); 9957626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.bmp = NULL; 9967626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 9977626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug(" <- %s:%d\n", __func__, __LINE__); 9987626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 99974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 100074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10017626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_probe(struct ps3_system_bus_device *dev) 100274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 100374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 10047626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_driver *drv; 10057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = NULL; 100674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 100774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 100874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv = ps3_system_bus_dev_to_vuart_drv(dev); 10107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 10117626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__, 10127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->core.core.name); 10137626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 101474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand BUG_ON(!drv); 101574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10167626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (dev->port_number >= PORT_COUNT) { 10177626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG(); 10187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return -EINVAL; 10197626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 102075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 1021c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_lock(&vuart_bus_priv.probe_mutex); 102275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10237626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_vuart_bus_interrupt_get(); 102474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (result) 10267626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_setup_interrupt; 102774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10287626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (vuart_bus_priv.devices[dev->port_number]) { 102974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__, 10307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __LINE__, dev->port_number); 103174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = -EBUSY; 10327626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_busy; 103374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 103474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10357626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.devices[dev->port_number] = dev; 103675c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand /* Setup dev->driver_priv. */ 103875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10397626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv), 10407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand GFP_KERNEL); 104175c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10427626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!dev->driver_priv) { 104375c86e7422751c5be3caaf448d802839ec685725Geoff Levand result = -ENOMEM; 10447626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand goto fail_dev_malloc; 104575c86e7422751c5be3caaf448d802839ec685725Geoff Levand } 104675c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv = to_port_priv(dev); 104875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10497626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand INIT_LIST_HEAD(&priv->tx_list.head); 10507626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_init(&priv->tx_list.lock); 105175c86e7422751c5be3caaf448d802839ec685725Geoff Levand 10527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand INIT_LIST_HEAD(&priv->rx_list.head); 10537626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand spin_lock_init(&priv->rx_list.lock); 1054ea1547d31153f8c3bdd32646f17d096d3108c838Geoff Levand 10557626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand INIT_WORK(&priv->rx_list.work.work, NULL); 10567626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.work.trigger = 0; 10577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv->rx_list.work.dev = dev; 105874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 105974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand /* clear stale pending interrupts */ 106075c86e7422751c5be3caaf448d802839ec685725Geoff Levand 106175c86e7422751c5be3caaf448d802839ec685725Geoff Levand ps3_vuart_clear_rx_bytes(dev, 0); 106275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 106375c86e7422751c5be3caaf448d802839ec685725Geoff Levand ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX); 106474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 106574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand ps3_vuart_set_triggers(dev, 1, 1); 106674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 106774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (drv->probe) 106874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = drv->probe(dev); 106974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand else { 107074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand result = 0; 107174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_info(&dev->core, "%s:%d: no probe method\n", __func__, 107274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __LINE__); 107374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 107474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 107574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand if (result) { 107674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand dev_dbg(&dev->core, "%s:%d: drv->probe failed\n", 107774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand __func__, __LINE__); 107874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand goto fail_probe; 107974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 108074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1081c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 108275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 108374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 108474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 108574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandfail_probe: 108675c86e7422751c5be3caaf448d802839ec685725Geoff Levand ps3_vuart_set_interrupt_mask(dev, 0); 10877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand kfree(dev->driver_priv); 10887626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev->driver_priv = NULL; 10897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_dev_malloc: 10907626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.devices[dev->port_number] = NULL; 10917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_busy: 10927626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_bus_interrupt_put(); 10937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandfail_setup_interrupt: 1094c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 10957626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__); 109674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 109774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 109874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 10997626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 11007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_cleanup - common cleanup helper. 11017626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 11027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * 11037626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * Cleans interrupts and HV resources. Must be called with 11047626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * vuart_bus_priv.probe_mutex held. Used by ps3_vuart_remove and 11057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_shutdown. After this call, polled reading will still work. 11067626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 11077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11087626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_cleanup(struct ps3_system_bus_device *dev) 110974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 11107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__); 11117626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_cancel_async(dev); 11137626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_set_interrupt_mask(dev, 0); 11147626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_bus_interrupt_put(); 11157626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 11167626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 11177626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11187626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand/** 11197626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_remove - Completely clean the device instance. 11207626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 11217626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * 11227626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * Cleans all memory, interrupts and HV resources. After this call the 11237626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * device can no longer be used. 11247626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand */ 11257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11267626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_remove(struct ps3_system_bus_device *dev) 11277626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 11287626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_priv *priv = to_port_priv(dev); 11297626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_driver *drv; 11307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11317626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!dev); 113274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1133c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_lock(&vuart_bus_priv.probe_mutex); 113475c86e7422751c5be3caaf448d802839ec685725Geoff Levand 11357626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, 11367626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev->match_id); 113774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11387626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!dev->core.driver) { 11397626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, 11407626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __LINE__); 1141c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 11427626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 11437626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 114474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11457626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv = ps3_system_bus_dev_to_vuart_drv(dev); 114674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11477626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!drv); 114874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11497626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (drv->remove) { 11507626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->remove(dev); 11517626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } else { 11527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__, 11537626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __LINE__); 115475c86e7422751c5be3caaf448d802839ec685725Geoff Levand BUG(); 115574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand } 115675c86e7422751c5be3caaf448d802839ec685725Geoff Levand 11577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_cleanup(dev); 11587626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 11597626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand vuart_bus_priv.devices[dev->port_number] = NULL; 11607626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand kfree(priv); 11617626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand priv = NULL; 116275c86e7422751c5be3caaf448d802839ec685725Geoff Levand 11637626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 1164c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 116574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return 0; 116674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 116774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 116874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 11697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * ps3_vuart_shutdown - Cleans interrupts and HV resources. 11707626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * @dev: The struct ps3_system_bus_device instance. 117174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * 11727626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * Cleans interrupts and HV resources. After this call the 11737626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * device can still be used in polling mode. This behavior required 11747626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * by sys-manager to be able to complete the device power operation 11757626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand * sequence. 117674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 117774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11787626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int ps3_vuart_shutdown(struct ps3_system_bus_device *dev) 117974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 11807626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand struct ps3_vuart_port_driver *drv; 118174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11827626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!dev); 118375c86e7422751c5be3caaf448d802839ec685725Geoff Levand 1184c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_lock(&vuart_bus_priv.probe_mutex); 118575c86e7422751c5be3caaf448d802839ec685725Geoff Levand 11867626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, 11877626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev->match_id); 118875c86e7422751c5be3caaf448d802839ec685725Geoff Levand 11897626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!dev->core.driver) { 11907626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, 11917626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __LINE__); 1192c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 11937626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 11947626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 119574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11967626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv = ps3_system_bus_dev_to_vuart_drv(dev); 119774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 11987626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!drv); 119974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12007626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (drv->shutdown) 12017626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->shutdown(dev); 12027626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand else if (drv->remove) { 12037626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n", 12047626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __func__, __LINE__); 12057626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->remove(dev); 12067626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } else { 12077626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__, 12087626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand __LINE__); 12097626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG(); 12107626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand } 121174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12127626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_vuart_cleanup(dev); 121375c86e7422751c5be3caaf448d802839ec685725Geoff Levand 12147626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 121575c86e7422751c5be3caaf448d802839ec685725Geoff Levand 1216c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_unlock(&vuart_bus_priv.probe_mutex); 12177626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 121874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 121974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12207626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic int __init ps3_vuart_bus_init(void) 122174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 12227626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d:\n", __func__, __LINE__); 122375c86e7422751c5be3caaf448d802839ec685725Geoff Levand 12247626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) 12257626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return -ENODEV; 122674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 1227c4e6752dd4f249d6797146d655973bc0bde4c26eGeoff Levand mutex_init(&vuart_bus_priv.probe_mutex); 122874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12297626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand return 0; 12307626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand} 123174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12327626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandstatic void __exit ps3_vuart_bus_exit(void) 12337626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand{ 12347626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d:\n", __func__, __LINE__); 123574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 123674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12377626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandcore_initcall(ps3_vuart_bus_init); 12387626e78d29651d3075e88f233c0632867ea6a35cGeoff Levandmodule_exit(ps3_vuart_bus_exit); 123974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 124074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 124174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_port_driver_register - Add a vuart port device driver. 124274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 124374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 124474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandint ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv) 124574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 124674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand int result; 124774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 12487626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); 12497626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 12507626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!drv->core.match_id); 12517626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand BUG_ON(!drv->core.core.name); 12527626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 12537626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->core.probe = ps3_vuart_probe; 12547626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->core.remove = ps3_vuart_remove; 12557626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand drv->core.shutdown = ps3_vuart_shutdown; 12567626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand 12577626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand result = ps3_system_bus_driver_register(&drv->core); 125874e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand return result; 125974e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 126074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register); 126174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 126274e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand/** 126374e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand * ps3_vuart_port_driver_unregister - Remove a vuart port device driver. 126474e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand */ 126574e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand 126674e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levandvoid ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv) 126774e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand{ 12687626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name); 12697626e78d29651d3075e88f233c0632867ea6a35cGeoff Levand ps3_system_bus_driver_unregister(&drv->core); 127074e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff Levand} 127174e95d5de9d8eb243cda68b546bdb29f6ef0f01cGeoff LevandEXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister); 1272