summaryrefslogtreecommitdiffstats
path: root/drivers/rapidio/rio-access.c
blob: 8b56bbdd011ec0d5bf9870ca36abeda25caff49e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * RapidIO configuration space access support
 *
 * Copyright 2005 MontaVista Software, Inc.
 * Matt Porter <mporter@kernel.crashing.org>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */

#include <linux/rio.h>
#include <linux/module.h>

/*
 * These interrupt-safe spinlocks protect all accesses to RIO
 * configuration space and doorbell access.
 */
static DEFINE_SPINLOCK(rio_config_lock);
static DEFINE_SPINLOCK(rio_doorbell_lock);

/*
 *  Wrappers for all RIO configuration access functions.  They just check
 *  alignment, do locking and call the low-level functions pointed to
 *  by rio_mport->ops.
 */

#define RIO_8_BAD 0
#define RIO_16_BAD (offset & 1)
#define RIO_32_BAD (offset & 3)

/**
 * RIO_LOP_READ - Generate rio_local_read_config_* functions
 * @size: Size of configuration space read (8, 16, 32 bits)
 * @type: C type of value argument
 * @len: Length of configuration space read (1, 2, 4 bytes)
 *
 * Generates rio_local_read_config_* functions used to access
 * configuration space registers on the local device.
 */
#define RIO_LOP_READ(size,type,len) \
int __rio_local_read_config_##size \
	(struct rio_mport *mport, u32 offset, type *value)		\
{									\
	int res;							\
	unsigned long flags;						\
	u32 data = 0;							\
	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
	spin_lock_irqsave(&rio_config_lock, flags);			\
	res = mport->ops->lcread(mport->id, offset, len, &data);	\
	*value = (type)data;						\
	spin_unlock_irqrestore(&rio_config_lock, flags);		\
	return res;							\
}

/**
 * RIO_LOP_WRITE - Generate rio_local_write_config_* functions
 * @size: Size of configuration space write (8, 16, 32 bits)
 * @type: C type of value argument
 * @len: Length of configuration space write (1, 2, 4 bytes)
 *
 * Generates rio_local_write_config_* functions used to access
 * configuration space registers on the local device.
 */
#define RIO_LOP_WRITE(size,type,len) \
int __rio_local_write_config_##size \
	(struct rio_mport *mport, u32 offset, type value)		\
{									\
	int res;							\
	unsigned long flags;						\
	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
	spin_lock_irqsave(&rio_config_lock, flags);			\
	res = mport->ops->lcwrite(mport->id, offset, len, value);	\
	spin_unlock_irqrestore(&rio_config_lock, flags);		\
	return res;							\
}

RIO_LOP_READ(8, u8, 1)
RIO_LOP_READ(16, u16, 2)
RIO_LOP_READ(32, u32, 4)
RIO_LOP_WRITE(8, u8, 1)
RIO_LOP_WRITE(16, u16, 2)
RIO_LOP_WRITE(32, u32, 4)

EXPORT_SYMBOL_GPL(__rio_local_read_config_8);
EXPORT_SYMBOL_GPL(__rio_local_read_config_16);
EXPORT_SYMBOL_GPL(__rio_local_read_config_32);
EXPORT_SYMBOL_GPL(__rio_local_write_config_8);
EXPORT_SYMBOL_GPL(__rio_local_write_config_16);
EXPORT_SYMBOL_GPL(__rio_local_write_config_32);

/**
 * RIO_OP_READ - Generate rio_mport_read_config_* functions
 * @size: Size of configuration space read (8, 16, 32 bits)
 * @type: C type of value argument
 * @len: Length of configuration space read (1, 2, 4 bytes)
 *
 * Generates rio_mport_read_config_* functions used to access
 * configuration space registers on the local device.
 */
#define RIO_OP_READ(size,type,len) \
int rio_mport_read_config_##size \
	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *value)	\
{									\
	int res;							\
	unsigned long flags;						\
	u32 data = 0;							\
	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
	spin_lock_irqsave(&rio_config_lock, flags);			\
	res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \
	*value = (type)data;						\
	spin_unlock_irqrestore(&rio_config_lock, flags);		\
	return res;							\
}

/**
 * RIO_OP_WRITE - Generate rio_mport_write_config_* functions
 * @size: Size of configuration space write (8, 16, 32 bits)
 * @type: C type of value argument
 * @len: Length of configuration space write (1, 2, 4 bytes)
 *
 * Generates rio_mport_write_config_* functions used to access
 * configuration space registers on the local device.
 */
#define RIO_OP_WRITE(size,type,len) \
int rio_mport_write_config_##size \
	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value)	\
{									\
	int res;							\
	unsigned long flags;						\
	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
	spin_lock_irqsave(&rio_config_lock, flags);			\
	res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \
	spin_unlock_irqrestore(&rio_config_lock, flags);		\
	return res;							\
}

RIO_OP_READ(8, u8, 1)
RIO_OP_READ(16, u16, 2)
RIO_OP_READ(32, u32, 4)
RIO_OP_WRITE(8, u8, 1)
RIO_OP_WRITE(16, u16, 2)
RIO_OP_WRITE(32, u32, 4)

EXPORT_SYMBOL_GPL(rio_mport_read_config_8);
EXPORT_SYMBOL_GPL(rio_mport_read_config_16);
EXPORT_SYMBOL_GPL(rio_mport_read_config_32);
EXPORT_SYMBOL_GPL(rio_mport_write_config_8);
EXPORT_SYMBOL_GPL(rio_mport_write_config_16);
EXPORT_SYMBOL_GPL(rio_mport_write_config_32);

/**
 * rio_mport_send_doorbell - Send a doorbell message
 *
 * @mport: RIO master port
 * @destid: RIO device destination ID
 * @data: Doorbell message data
 *
 * Send a doorbell message to a RIO device. The doorbell message
 * has a 16-bit info field provided by the data argument.
 */
int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
{
	int res;
	unsigned long flags;

	spin_lock_irqsave(&rio_doorbell_lock, flags);
	res = mport->ops->dsend(mport->id, destid, data);
	spin_unlock_irqrestore(&rio_doorbell_lock, flags);

	return res;
}

EXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
OpenPOWER on IntegriCloud