1394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/*
2394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * RapidIO configuration space access support
3394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
4394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Copyright 2005 MontaVista Software, Inc.
5394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Matt Porter <mporter@kernel.crashing.org>
6394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
7394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * This program is free software; you can redistribute  it and/or modify it
8394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * under  the terms of  the GNU General  Public License as published by the
9394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Free Software Foundation;  either version 2 of the  License, or (at your
10394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * option) any later version.
11394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
12394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
13394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#include <linux/rio.h>
14394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#include <linux/module.h>
15394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
16394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/*
17394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * These interrupt-safe spinlocks protect all accesses to RIO
18394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * configuration space and doorbell access.
19394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
2034af946a22724c4e2b204957f2b24b22a0fb121cIngo Molnarstatic DEFINE_SPINLOCK(rio_config_lock);
2134af946a22724c4e2b204957f2b24b22a0fb121cIngo Molnarstatic DEFINE_SPINLOCK(rio_doorbell_lock);
22394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
23394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/*
24394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *  Wrappers for all RIO configuration access functions.  They just check
25394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *  alignment, do locking and call the low-level functions pointed to
26394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *  by rio_mport->ops.
27394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
28394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
29394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_8_BAD 0
30394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_16_BAD (offset & 1)
31394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_32_BAD (offset & 3)
32394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
33394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/**
34394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * RIO_LOP_READ - Generate rio_local_read_config_* functions
35394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @size: Size of configuration space read (8, 16, 32 bits)
36394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @type: C type of value argument
37394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @len: Length of configuration space read (1, 2, 4 bytes)
38394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
39394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Generates rio_local_read_config_* functions used to access
40394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * configuration space registers on the local device.
41394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
42394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_LOP_READ(size,type,len) \
43394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porterint __rio_local_read_config_##size \
44394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	(struct rio_mport *mport, u32 offset, type *value)		\
45394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter{									\
46394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	int res;							\
47394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	unsigned long flags;						\
48394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	u32 data = 0;							\
49394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
50394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_lock_irqsave(&rio_config_lock, flags);			\
51ad1e9380b17addf112f89ce5a57d4d0bee129b7aZhang Wei	res = mport->ops->lcread(mport, mport->id, offset, len, &data);	\
52394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	*value = (type)data;						\
53394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_unlock_irqrestore(&rio_config_lock, flags);		\
54394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	return res;							\
55394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter}
56394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
57394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/**
58394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * RIO_LOP_WRITE - Generate rio_local_write_config_* functions
59394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @size: Size of configuration space write (8, 16, 32 bits)
60394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @type: C type of value argument
61394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @len: Length of configuration space write (1, 2, 4 bytes)
62394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
63394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Generates rio_local_write_config_* functions used to access
64394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * configuration space registers on the local device.
65394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
66394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_LOP_WRITE(size,type,len) \
67394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porterint __rio_local_write_config_##size \
68394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	(struct rio_mport *mport, u32 offset, type value)		\
69394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter{									\
70394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	int res;							\
71394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	unsigned long flags;						\
72394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
73394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_lock_irqsave(&rio_config_lock, flags);			\
74ad1e9380b17addf112f89ce5a57d4d0bee129b7aZhang Wei	res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\
75394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_unlock_irqrestore(&rio_config_lock, flags);		\
76394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	return res;							\
77394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter}
78394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
79394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_READ(8, u8, 1)
80394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_READ(16, u16, 2)
81394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_READ(32, u32, 4)
82394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_WRITE(8, u8, 1)
83394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_WRITE(16, u16, 2)
84394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_LOP_WRITE(32, u32, 4)
85394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
86394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_read_config_8);
87394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_read_config_16);
88394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_read_config_32);
89394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_write_config_8);
90394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_write_config_16);
91394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(__rio_local_write_config_32);
92394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
93394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/**
94394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * RIO_OP_READ - Generate rio_mport_read_config_* functions
95394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @size: Size of configuration space read (8, 16, 32 bits)
96394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @type: C type of value argument
97394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @len: Length of configuration space read (1, 2, 4 bytes)
98394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
99394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Generates rio_mport_read_config_* functions used to access
100394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * configuration space registers on the local device.
101394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
102394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_OP_READ(size,type,len) \
103394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porterint rio_mport_read_config_##size \
104394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *value)	\
105394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter{									\
106394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	int res;							\
107394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	unsigned long flags;						\
108394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	u32 data = 0;							\
109394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
110394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_lock_irqsave(&rio_config_lock, flags);			\
111ad1e9380b17addf112f89ce5a57d4d0bee129b7aZhang Wei	res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \
112394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	*value = (type)data;						\
113394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_unlock_irqrestore(&rio_config_lock, flags);		\
114394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	return res;							\
115394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter}
116394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
117394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/**
118394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * RIO_OP_WRITE - Generate rio_mport_write_config_* functions
119394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @size: Size of configuration space write (8, 16, 32 bits)
120394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @type: C type of value argument
121394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @len: Length of configuration space write (1, 2, 4 bytes)
122394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
123394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Generates rio_mport_write_config_* functions used to access
124394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * configuration space registers on the local device.
125394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
126394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter#define RIO_OP_WRITE(size,type,len) \
127394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porterint rio_mport_write_config_##size \
128394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value)	\
129394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter{									\
130394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	int res;							\
131394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	unsigned long flags;						\
132394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
133394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_lock_irqsave(&rio_config_lock, flags);			\
134ad1e9380b17addf112f89ce5a57d4d0bee129b7aZhang Wei	res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \
135394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_unlock_irqrestore(&rio_config_lock, flags);		\
136394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	return res;							\
137394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter}
138394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
139394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_READ(8, u8, 1)
140394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_READ(16, u16, 2)
141394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_READ(32, u32, 4)
142394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_WRITE(8, u8, 1)
143394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_WRITE(16, u16, 2)
144394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterRIO_OP_WRITE(32, u32, 4)
145394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
146394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_read_config_8);
147394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_read_config_16);
148394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_read_config_32);
149394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_write_config_8);
150394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_write_config_16);
151394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_write_config_32);
152394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
153394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter/**
154394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * rio_mport_send_doorbell - Send a doorbell message
155394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
156394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @mport: RIO master port
157394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @destid: RIO device destination ID
158394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * @data: Doorbell message data
159394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter *
160394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * Send a doorbell message to a RIO device. The doorbell message
161394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter * has a 16-bit info field provided by the data argument.
162394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter */
163394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porterint rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
164394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter{
165394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	int res;
166394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	unsigned long flags;
167394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
168394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_lock_irqsave(&rio_doorbell_lock, flags);
169ad1e9380b17addf112f89ce5a57d4d0bee129b7aZhang Wei	res = mport->ops->dsend(mport, mport->id, destid, data);
170394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	spin_unlock_irqrestore(&rio_doorbell_lock, flags);
171394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
172394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter	return res;
173394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter}
174394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt Porter
175394b701ce4fbfde919a9bcbf84cb4820a7c6d47cMatt PorterEXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
176