You need to sign in or sign up before continuing.
rio-access.c 5.5 KB
Newer Older
M
Matt Porter 已提交
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 spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED;

/*
 *  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);