Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f62f2fdd authored by Stephen Neuendorffer's avatar Stephen Neuendorffer Committed by Josh Boyer
Browse files

[POWERPC] Xilinx: hwicap cleanup



This fixes various items pointed out during a review of the hwicap driver.
Primarily, reversed memcpy calls, re-entrancy issues, and mutex conversion
have been addressed.  There are also fixes to comments to use the kerneldoc
format, as well as some sparse annotations.

Signed-off-by: default avatarStephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: default avatarGrant Likely <grant.likely@secretlab.ca>
Signed-off-by: default avatarJosh Boyer <jwboyer@linux.vnet.ibm.com>
parent fe57e8be
Loading
Loading
Loading
Loading
+40 −40
Original line number Original line Diff line number Diff line
@@ -73,8 +73,8 @@
#define XHI_BUFFER_START 0
#define XHI_BUFFER_START 0


/**
/**
 * buffer_icap_get_status: Get the contents of the status register.
 * buffer_icap_get_status - Get the contents of the status register.
 * @parameter base_address: is the base address of the device
 * @base_address: is the base address of the device
 *
 *
 * The status register contains the ICAP status and the done bit.
 * The status register contains the ICAP status and the done bit.
 *
 *
@@ -94,9 +94,9 @@ static inline u32 buffer_icap_get_status(void __iomem *base_address)
}
}


/**
/**
 * buffer_icap_get_bram: Reads data from the storage buffer bram.
 * buffer_icap_get_bram - Reads data from the storage buffer bram.
 * @parameter base_address: contains the base address of the component.
 * @base_address: contains the base address of the component.
 * @parameter offset: The word offset from which the data should be read.
 * @offset: The word offset from which the data should be read.
 *
 *
 * A bram is used as a configuration memory cache.  One frame of data can
 * A bram is used as a configuration memory cache.  One frame of data can
 * be stored in this "storage buffer".
 * be stored in this "storage buffer".
@@ -108,8 +108,8 @@ static inline u32 buffer_icap_get_bram(void __iomem *base_address,
}
}


/**
/**
 * buffer_icap_busy: Return true if the icap device is busy
 * buffer_icap_busy - Return true if the icap device is busy
 * @parameter base_address: is the base address of the device
 * @base_address: is the base address of the device
 *
 *
 * The queries the low order bit of the status register, which
 * The queries the low order bit of the status register, which
 * indicates whether the current configuration or readback operation
 * indicates whether the current configuration or readback operation
@@ -121,8 +121,8 @@ static inline bool buffer_icap_busy(void __iomem *base_address)
}
}


/**
/**
 * buffer_icap_busy: Return true if the icap device is not busy
 * buffer_icap_busy - Return true if the icap device is not busy
 * @parameter base_address: is the base address of the device
 * @base_address: is the base address of the device
 *
 *
 * The queries the low order bit of the status register, which
 * The queries the low order bit of the status register, which
 * indicates whether the current configuration or readback operation
 * indicates whether the current configuration or readback operation
@@ -134,9 +134,9 @@ static inline bool buffer_icap_done(void __iomem *base_address)
}
}


/**
/**
 * buffer_icap_set_size: Set the size register.
 * buffer_icap_set_size - Set the size register.
 * @parameter base_address: is the base address of the device
 * @base_address: is the base address of the device
 * @parameter data: The size in bytes.
 * @data: The size in bytes.
 *
 *
 * The size register holds the number of 8 bit bytes to transfer between
 * The size register holds the number of 8 bit bytes to transfer between
 * bram and the icap (or icap to bram).
 * bram and the icap (or icap to bram).
@@ -148,9 +148,9 @@ static inline void buffer_icap_set_size(void __iomem *base_address,
}
}


/**
/**
 * buffer_icap_mSetoffsetReg: Set the bram offset register.
 * buffer_icap_set_offset - Set the bram offset register.
 * @parameter base_address: contains the base address of the device.
 * @base_address: contains the base address of the device.
 * @parameter data: is the value to be written to the data register.
 * @data: is the value to be written to the data register.
 *
 *
 * The bram offset register holds the starting bram address to transfer
 * The bram offset register holds the starting bram address to transfer
 * data from during configuration or write data to during readback.
 * data from during configuration or write data to during readback.
@@ -162,9 +162,9 @@ static inline void buffer_icap_set_offset(void __iomem *base_address,
}
}


/**
/**
 * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
 * buffer_icap_set_rnc - Set the RNC (Readback not Configure) register.
 * @parameter base_address: contains the base address of the device.
 * @base_address: contains the base address of the device.
 * @parameter data: is the value to be written to the data register.
 * @data: is the value to be written to the data register.
 *
 *
 * The RNC register determines the direction of the data transfer.  It
 * The RNC register determines the direction of the data transfer.  It
 * controls whether a configuration or readback take place.  Writing to
 * controls whether a configuration or readback take place.  Writing to
@@ -178,10 +178,10 @@ static inline void buffer_icap_set_rnc(void __iomem *base_address,
}
}


/**
/**
 * buffer_icap_set_bram: Write data to the storage buffer bram.
 * buffer_icap_set_bram - Write data to the storage buffer bram.
 * @parameter base_address: contains the base address of the component.
 * @base_address: contains the base address of the component.
 * @parameter offset: The word offset at which the data should be written.
 * @offset: The word offset at which the data should be written.
 * @parameter data: The value to be written to the bram offset.
 * @data: The value to be written to the bram offset.
 *
 *
 * A bram is used as a configuration memory cache.  One frame of data can
 * A bram is used as a configuration memory cache.  One frame of data can
 * be stored in this "storage buffer".
 * be stored in this "storage buffer".
@@ -193,10 +193,10 @@ static inline void buffer_icap_set_bram(void __iomem *base_address,
}
}


/**
/**
 * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
 * buffer_icap_device_read - Transfer bytes from ICAP to the storage buffer.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter offset: The storage buffer start address.
 * @offset: The storage buffer start address.
 * @parameter count: The number of words (32 bit) to read from the
 * @count: The number of words (32 bit) to read from the
 *           device (ICAP).
 *           device (ICAP).
 **/
 **/
static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
@@ -227,10 +227,10 @@ static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
};
};


/**
/**
 * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
 * buffer_icap_device_write - Transfer bytes from ICAP to the storage buffer.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter offset: The storage buffer start address.
 * @offset: The storage buffer start address.
 * @parameter count: The number of words (32 bit) to read from the
 * @count: The number of words (32 bit) to read from the
 *           device (ICAP).
 *           device (ICAP).
 **/
 **/
static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
@@ -261,8 +261,8 @@ static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
};
};


/**
/**
 * buffer_icap_reset: Reset the logic of the icap device.
 * buffer_icap_reset - Reset the logic of the icap device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * Writing to the status register resets the ICAP logic in an internal
 * Writing to the status register resets the ICAP logic in an internal
 * version of the core.  For the version of the core published in EDK,
 * version of the core.  For the version of the core published in EDK,
@@ -274,10 +274,10 @@ void buffer_icap_reset(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * buffer_icap_set_configuration: Load a partial bitstream from system memory.
 * buffer_icap_set_configuration - Load a partial bitstream from system memory.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter data: Kernel address of the partial bitstream.
 * @data: Kernel address of the partial bitstream.
 * @parameter size: the size of the partial bitstream in 32 bit words.
 * @size: the size of the partial bitstream in 32 bit words.
 **/
 **/
int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
			     u32 size)
			     u32 size)
@@ -333,10 +333,10 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
};
};


/**
/**
 * buffer_icap_get_configuration: Read configuration data from the device.
 * buffer_icap_get_configuration - Read configuration data from the device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter data: Address of the data representing the partial bitstream
 * @data: Address of the data representing the partial bitstream
 * @parameter size: the size of the partial bitstream in 32 bit words.
 * @size: the size of the partial bitstream in 32 bit words.
 **/
 **/
int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
			     u32 size)
			     u32 size)
+30 −30
Original line number Original line Diff line number Diff line
@@ -94,9 +94,9 @@




/**
/**
 * fifo_icap_fifo_write: Write data to the write FIFO.
 * fifo_icap_fifo_write - Write data to the write FIFO.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter data: the 32-bit value to be written to the FIFO.
 * @data: the 32-bit value to be written to the FIFO.
 *
 *
 * This function will silently fail if the fifo is full.
 * This function will silently fail if the fifo is full.
 **/
 **/
@@ -108,8 +108,8 @@ static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
}
}


/**
/**
 * fifo_icap_fifo_read: Read data from the Read FIFO.
 * fifo_icap_fifo_read - Read data from the Read FIFO.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * This function will silently fail if the fifo is empty.
 * This function will silently fail if the fifo is empty.
 **/
 **/
@@ -121,9 +121,9 @@ static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * fifo_icap_set_read_size: Set the the size register.
 * fifo_icap_set_read_size - Set the the size register.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter data: the size of the following read transaction, in words.
 * @data: the size of the following read transaction, in words.
 **/
 **/
static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
		u32 data)
		u32 data)
@@ -132,8 +132,8 @@ static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
}
}


/**
/**
 * fifo_icap_start_config: Initiate a configuration (write) to the device.
 * fifo_icap_start_config - Initiate a configuration (write) to the device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 **/
 **/
static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
{
{
@@ -142,8 +142,8 @@ static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * fifo_icap_start_readback: Initiate a readback from the device.
 * fifo_icap_start_readback - Initiate a readback from the device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 **/
 **/
static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
{
{
@@ -152,8 +152,8 @@ static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * fifo_icap_busy: Return true if the ICAP is still processing a transaction.
 * fifo_icap_busy - Return true if the ICAP is still processing a transaction.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 **/
 **/
static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
{
{
@@ -163,8 +163,8 @@ static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * fifo_icap_write_fifo_vacancy: Query the write fifo available space.
 * fifo_icap_write_fifo_vacancy - Query the write fifo available space.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * Return the number of words that can be safely pushed into the write fifo.
 * Return the number of words that can be safely pushed into the write fifo.
 **/
 **/
@@ -175,8 +175,8 @@ static inline u32 fifo_icap_write_fifo_vacancy(
}
}


/**
/**
 * fifo_icap_read_fifo_occupancy: Query the read fifo available data.
 * fifo_icap_read_fifo_occupancy - Query the read fifo available data.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * Return the number of words that can be safely read from the read fifo.
 * Return the number of words that can be safely read from the read fifo.
 **/
 **/
@@ -187,11 +187,11 @@ static inline u32 fifo_icap_read_fifo_occupancy(
}
}


/**
/**
 * fifo_icap_set_configuration: Send configuration data to the ICAP.
 * fifo_icap_set_configuration - Send configuration data to the ICAP.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter frame_buffer: a pointer to the data to be written to the
 * @frame_buffer: a pointer to the data to be written to the
 *		ICAP device.
 *		ICAP device.
 * @parameter num_words: the number of words (32 bit) to write to the ICAP
 * @num_words: the number of words (32 bit) to write to the ICAP
 *		device.
 *		device.


 * This function writes the given user data to the Write FIFO in
 * This function writes the given user data to the Write FIFO in
@@ -266,10 +266,10 @@ int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
}
}


/**
/**
 * fifo_icap_get_configuration: Read configuration data from the device.
 * fifo_icap_get_configuration - Read configuration data from the device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 * @parameter data: Address of the data representing the partial bitstream
 * @data: Address of the data representing the partial bitstream
 * @parameter size: the size of the partial bitstream in 32 bit words.
 * @size: the size of the partial bitstream in 32 bit words.
 *
 *
 * This function reads the specified number of words from the ICAP device in
 * This function reads the specified number of words from the ICAP device in
 * the polled mode.
 * the polled mode.
@@ -335,8 +335,8 @@ int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
}
}


/**
/**
 * buffer_icap_reset: Reset the logic of the icap device.
 * buffer_icap_reset - Reset the logic of the icap device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * This function forces the software reset of the complete HWICAP device.
 * This function forces the software reset of the complete HWICAP device.
 * All the registers will return to the default value and the FIFO is also
 * All the registers will return to the default value and the FIFO is also
@@ -360,8 +360,8 @@ void fifo_icap_reset(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * fifo_icap_flush_fifo: This function flushes the FIFOs in the device.
 * fifo_icap_flush_fifo - This function flushes the FIFOs in the device.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 */
 */
void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
{
{
+62 −76
Original line number Original line Diff line number Diff line
@@ -84,7 +84,7 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <asm/semaphore.h>
#include <linux/mutex.h>
#include <linux/sysctl.h>
#include <linux/sysctl.h>
#include <linux/version.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/fs.h>
@@ -119,6 +119,7 @@ module_param(xhwicap_minor, int, S_IRUGO);


/* An array, which is set to true when the device is registered. */
/* An array, which is set to true when the device is registered. */
static bool probed_devices[HWICAP_DEVICES];
static bool probed_devices[HWICAP_DEVICES];
static struct mutex icap_sem;


static struct class *icap_class;
static struct class *icap_class;


@@ -199,14 +200,14 @@ static const struct config_registers v5_config_registers = {
};
};


/**
/**
 * hwicap_command_desync: Send a DESYNC command to the ICAP port.
 * hwicap_command_desync - Send a DESYNC command to the ICAP port.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 *
 * This command desynchronizes the ICAP After this command, a
 * This command desynchronizes the ICAP After this command, a
 * bitstream containing a NULL packet, followed by a SYNCH packet is
 * bitstream containing a NULL packet, followed by a SYNCH packet is
 * required before the ICAP will recognize commands.
 * required before the ICAP will recognize commands.
 */
 */
int hwicap_command_desync(struct hwicap_drvdata *drvdata)
static int hwicap_command_desync(struct hwicap_drvdata *drvdata)
{
{
	u32 buffer[4];
	u32 buffer[4];
	u32 index = 0;
	u32 index = 0;
@@ -228,51 +229,18 @@ int hwicap_command_desync(struct hwicap_drvdata *drvdata)
}
}


/**
/**
 * hwicap_command_capture: Send a CAPTURE command to the ICAP port.
 * hwicap_get_configuration_register - Query a configuration register.
 * @parameter drvdata: a pointer to the drvdata.
 * @drvdata: a pointer to the drvdata.
 *
 * @reg: a constant which represents the configuration
 * This command captures all of the flip flop states so they will be
 * available during readback.  One can use this command instead of
 * enabling the CAPTURE block in the design.
 */
int hwicap_command_capture(struct hwicap_drvdata *drvdata)
{
	u32 buffer[7];
	u32 index = 0;

	/*
	 * Create the data to be written to the ICAP.
	 */
	buffer[index++] = XHI_DUMMY_PACKET;
	buffer[index++] = XHI_SYNC_PACKET;
	buffer[index++] = XHI_NOOP_PACKET;
	buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
	buffer[index++] = XHI_CMD_GCAPTURE;
	buffer[index++] = XHI_DUMMY_PACKET;
	buffer[index++] = XHI_DUMMY_PACKET;

	/*
	 * Write the data to the FIFO and intiate the transfer of data
	 * present in the FIFO to the ICAP device.
	 */
	return drvdata->config->set_configuration(drvdata,
			&buffer[0], index);

}

/**
 * hwicap_get_configuration_register: Query a configuration register.
 * @parameter drvdata: a pointer to the drvdata.
 * @parameter reg: a constant which represents the configuration
 *		register value to be returned.
 *		register value to be returned.
 * 		Examples:  XHI_IDCODE, XHI_FLR.
 * 		Examples:  XHI_IDCODE, XHI_FLR.
 * @parameter RegData: returns the value of the register.
 * @reg_data: returns the value of the register.
 *
 *
 * Sends a query packet to the ICAP and then receives the response.
 * Sends a query packet to the ICAP and then receives the response.
 * The icap is left in Synched state.
 * The icap is left in Synched state.
 */
 */
int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
static int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
		u32 reg, u32 *RegData)
		u32 reg, u32 *reg_data)
{
{
	int status;
	int status;
	u32 buffer[6];
	u32 buffer[6];
@@ -300,14 +268,14 @@ int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
	/*
	/*
	 * Read the configuration register
	 * Read the configuration register
	 */
	 */
	status = drvdata->config->get_configuration(drvdata, RegData, 1);
	status = drvdata->config->get_configuration(drvdata, reg_data, 1);
	if (status)
	if (status)
		return status;
		return status;


	return 0;
	return 0;
}
}


int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
static int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
{
{
	int status;
	int status;
	u32 idcode;
	u32 idcode;
@@ -344,7 +312,7 @@ int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
}
}


static ssize_t
static ssize_t
hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
hwicap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
{
	struct hwicap_drvdata *drvdata = file->private_data;
	struct hwicap_drvdata *drvdata = file->private_data;
	ssize_t bytes_to_read = 0;
	ssize_t bytes_to_read = 0;
@@ -353,8 +321,9 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
	u32 bytes_remaining;
	u32 bytes_remaining;
	int status;
	int status;


	if (down_interruptible(&drvdata->sem))
	status = mutex_lock_interruptible(&drvdata->sem);
		return -ERESTARTSYS;
	if (status)
		return status;


	if (drvdata->read_buffer_in_use) {
	if (drvdata->read_buffer_in_use) {
		/* If there are leftover bytes in the buffer, just */
		/* If there are leftover bytes in the buffer, just */
@@ -370,8 +339,9 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
			goto error;
			goto error;
		}
		}
		drvdata->read_buffer_in_use -= bytes_to_read;
		drvdata->read_buffer_in_use -= bytes_to_read;
		memcpy(drvdata->read_buffer + bytes_to_read,
		memmove(drvdata->read_buffer,
				drvdata->read_buffer, 4 - bytes_to_read);
		       drvdata->read_buffer + bytes_to_read,
		       4 - bytes_to_read);
	} else {
	} else {
		/* Get new data from the ICAP, and return was was requested. */
		/* Get new data from the ICAP, and return was was requested. */
		kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
		kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
@@ -414,18 +384,20 @@ hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
			status = -EFAULT;
			status = -EFAULT;
			goto error;
			goto error;
		}
		}
		memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
		memcpy(drvdata->read_buffer,
		       kbuf,
		       bytes_remaining);
		drvdata->read_buffer_in_use = bytes_remaining;
		drvdata->read_buffer_in_use = bytes_remaining;
		free_page((unsigned long)kbuf);
		free_page((unsigned long)kbuf);
	}
	}
	status = bytes_to_read;
	status = bytes_to_read;
 error:
 error:
	up(&drvdata->sem);
	mutex_unlock(&drvdata->sem);
	return status;
	return status;
}
}


static ssize_t
static ssize_t
hwicap_write(struct file *file, const char *buf,
hwicap_write(struct file *file, const char __user *buf,
		size_t count, loff_t *ppos)
		size_t count, loff_t *ppos)
{
{
	struct hwicap_drvdata *drvdata = file->private_data;
	struct hwicap_drvdata *drvdata = file->private_data;
@@ -435,8 +407,9 @@ hwicap_write(struct file *file, const char *buf,
	ssize_t len;
	ssize_t len;
	ssize_t status;
	ssize_t status;


	if (down_interruptible(&drvdata->sem))
	status = mutex_lock_interruptible(&drvdata->sem);
		return -ERESTARTSYS;
	if (status)
		return status;


	left += drvdata->write_buffer_in_use;
	left += drvdata->write_buffer_in_use;


@@ -465,7 +438,7 @@ hwicap_write(struct file *file, const char *buf,
			memcpy(kbuf, drvdata->write_buffer,
			memcpy(kbuf, drvdata->write_buffer,
					drvdata->write_buffer_in_use);
					drvdata->write_buffer_in_use);
			if (copy_from_user(
			if (copy_from_user(
			    (((char *)kbuf) + (drvdata->write_buffer_in_use)),
			    (((char *)kbuf) + drvdata->write_buffer_in_use),
			    buf + written,
			    buf + written,
			    len - (drvdata->write_buffer_in_use))) {
			    len - (drvdata->write_buffer_in_use))) {
				free_page((unsigned long)kbuf);
				free_page((unsigned long)kbuf);
@@ -508,7 +481,7 @@ hwicap_write(struct file *file, const char *buf,
	free_page((unsigned long)kbuf);
	free_page((unsigned long)kbuf);
	status = written;
	status = written;
 error:
 error:
	up(&drvdata->sem);
	mutex_unlock(&drvdata->sem);
	return status;
	return status;
}
}


@@ -519,8 +492,9 @@ static int hwicap_open(struct inode *inode, struct file *file)


	drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
	drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);


	if (down_interruptible(&drvdata->sem))
	status = mutex_lock_interruptible(&drvdata->sem);
		return -ERESTARTSYS;
	if (status)
		return status;


	if (drvdata->is_open) {
	if (drvdata->is_open) {
		status = -EBUSY;
		status = -EBUSY;
@@ -539,7 +513,7 @@ static int hwicap_open(struct inode *inode, struct file *file)
	drvdata->is_open = 1;
	drvdata->is_open = 1;


 error:
 error:
	up(&drvdata->sem);
	mutex_unlock(&drvdata->sem);
	return status;
	return status;
}
}


@@ -549,8 +523,7 @@ static int hwicap_release(struct inode *inode, struct file *file)
	int i;
	int i;
	int status = 0;
	int status = 0;


	if (down_interruptible(&drvdata->sem))
	mutex_lock(&drvdata->sem);
		return -ERESTARTSYS;


	if (drvdata->write_buffer_in_use) {
	if (drvdata->write_buffer_in_use) {
		/* Flush write buffer. */
		/* Flush write buffer. */
@@ -569,7 +542,7 @@ static int hwicap_release(struct inode *inode, struct file *file)


 error:
 error:
	drvdata->is_open = 0;
	drvdata->is_open = 0;
	up(&drvdata->sem);
	mutex_unlock(&drvdata->sem);
	return status;
	return status;
}
}


@@ -592,31 +565,36 @@ static int __devinit hwicap_setup(struct device *dev, int id,


	dev_info(dev, "Xilinx icap port driver\n");
	dev_info(dev, "Xilinx icap port driver\n");


	mutex_lock(&icap_sem);

	if (id < 0) {
	if (id < 0) {
		for (id = 0; id < HWICAP_DEVICES; id++)
		for (id = 0; id < HWICAP_DEVICES; id++)
			if (!probed_devices[id])
			if (!probed_devices[id])
				break;
				break;
	}
	}
	if (id < 0 || id >= HWICAP_DEVICES) {
	if (id < 0 || id >= HWICAP_DEVICES) {
		mutex_unlock(&icap_sem);
		dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
		dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
		return -EINVAL;
		return -EINVAL;
	}
	}
	if (probed_devices[id]) {
	if (probed_devices[id]) {
		mutex_unlock(&icap_sem);
		dev_err(dev, "cannot assign to %s%i; it is already in use\n",
		dev_err(dev, "cannot assign to %s%i; it is already in use\n",
			DRIVER_NAME, id);
			DRIVER_NAME, id);
		return -EBUSY;
		return -EBUSY;
	}
	}


	probed_devices[id] = 1;
	probed_devices[id] = 1;
	mutex_unlock(&icap_sem);


	devt = MKDEV(xhwicap_major, xhwicap_minor + id);
	devt = MKDEV(xhwicap_major, xhwicap_minor + id);


	drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
	drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
	if (!drvdata) {
	if (!drvdata) {
		dev_err(dev, "Couldn't allocate device private record\n");
		dev_err(dev, "Couldn't allocate device private record\n");
		return -ENOMEM;
		retval = -ENOMEM;
		goto failed0;
	}
	}
	memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));
	dev_set_drvdata(dev, (void *)drvdata);
	dev_set_drvdata(dev, (void *)drvdata);


	if (!regs_res) {
	if (!regs_res) {
@@ -648,7 +626,7 @@ static int __devinit hwicap_setup(struct device *dev, int id,
	drvdata->config = config;
	drvdata->config = config;
	drvdata->config_regs = config_regs;
	drvdata->config_regs = config_regs;


	init_MUTEX(&drvdata->sem);
	mutex_init(&drvdata->sem);
	drvdata->is_open = 0;
	drvdata->is_open = 0;


	dev_info(dev, "ioremap %lx to %p with size %x\n",
	dev_info(dev, "ioremap %lx to %p with size %x\n",
@@ -663,7 +641,7 @@ static int __devinit hwicap_setup(struct device *dev, int id,
		goto failed3;
		goto failed3;
	}
	}
	/*  devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
	/*  devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
	class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
	device_create(icap_class, dev, devt, "%s%d", DRIVER_NAME, id);
	return 0;		/* success */
	return 0;		/* success */


 failed3:
 failed3:
@@ -675,6 +653,11 @@ static int __devinit hwicap_setup(struct device *dev, int id,
 failed1:
 failed1:
	kfree(drvdata);
	kfree(drvdata);


 failed0:
	mutex_lock(&icap_sem);
	probed_devices[id] = 0;
	mutex_unlock(&icap_sem);

	return retval;
	return retval;
}
}


@@ -699,14 +682,16 @@ static int __devexit hwicap_remove(struct device *dev)
	if (!drvdata)
	if (!drvdata)
		return 0;
		return 0;


	class_device_destroy(icap_class, drvdata->devt);
	device_destroy(icap_class, drvdata->devt);
	cdev_del(&drvdata->cdev);
	cdev_del(&drvdata->cdev);
	iounmap(drvdata->base_address);
	iounmap(drvdata->base_address);
	release_mem_region(drvdata->mem_start, drvdata->mem_size);
	release_mem_region(drvdata->mem_start, drvdata->mem_size);
	kfree(drvdata);
	kfree(drvdata);
	dev_set_drvdata(dev, NULL);
	dev_set_drvdata(dev, NULL);
	probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;


	mutex_lock(&icap_sem);
	probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;
	mutex_unlock(&icap_sem);
	return 0;		/* success */
	return 0;		/* success */
}
}


@@ -821,28 +806,29 @@ static struct of_platform_driver hwicap_of_driver = {
};
};


/* Registration helpers to keep the number of #ifdefs to a minimum */
/* Registration helpers to keep the number of #ifdefs to a minimum */
static inline int __devinit hwicap_of_register(void)
static inline int __init hwicap_of_register(void)
{
{
	pr_debug("hwicap: calling of_register_platform_driver()\n");
	pr_debug("hwicap: calling of_register_platform_driver()\n");
	return of_register_platform_driver(&hwicap_of_driver);
	return of_register_platform_driver(&hwicap_of_driver);
}
}


static inline void __devexit hwicap_of_unregister(void)
static inline void __exit hwicap_of_unregister(void)
{
{
	of_unregister_platform_driver(&hwicap_of_driver);
	of_unregister_platform_driver(&hwicap_of_driver);
}
}
#else /* CONFIG_OF */
#else /* CONFIG_OF */
/* CONFIG_OF not enabled; do nothing helpers */
/* CONFIG_OF not enabled; do nothing helpers */
static inline int __devinit hwicap_of_register(void) { return 0; }
static inline int __init hwicap_of_register(void) { return 0; }
static inline void __devexit hwicap_of_unregister(void) { }
static inline void __exit hwicap_of_unregister(void) { }
#endif /* CONFIG_OF */
#endif /* CONFIG_OF */


static int __devinit hwicap_module_init(void)
static int __init hwicap_module_init(void)
{
{
	dev_t devt;
	dev_t devt;
	int retval;
	int retval;


	icap_class = class_create(THIS_MODULE, "xilinx_config");
	icap_class = class_create(THIS_MODULE, "xilinx_config");
	mutex_init(&icap_sem);


	if (xhwicap_major) {
	if (xhwicap_major) {
		devt = MKDEV(xhwicap_major, xhwicap_minor);
		devt = MKDEV(xhwicap_major, xhwicap_minor);
@@ -883,7 +869,7 @@ static int __devinit hwicap_module_init(void)
	return retval;
	return retval;
}
}


static void __devexit hwicap_module_cleanup(void)
static void __exit hwicap_module_cleanup(void)
{
{
	dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
	dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);


+12 −12
Original line number Original line Diff line number Diff line
@@ -48,9 +48,9 @@ struct hwicap_drvdata {
	u8 write_buffer[4];
	u8 write_buffer[4];
	u32 read_buffer_in_use;	  /* Always in [0,3] */
	u32 read_buffer_in_use;	  /* Always in [0,3] */
	u8 read_buffer[4];
	u8 read_buffer[4];
	u32 mem_start;		  /* phys. address of the control registers */
	resource_size_t mem_start;/* phys. address of the control registers */
	u32 mem_end;		  /* phys. address of the control registers */
	resource_size_t mem_end;  /* phys. address of the control registers */
	u32 mem_size;
	resource_size_t mem_size;
	void __iomem *base_address;/* virt. address of the control registers */
	void __iomem *base_address;/* virt. address of the control registers */


	struct device *dev;
	struct device *dev;
@@ -61,7 +61,7 @@ struct hwicap_drvdata {
	const struct config_registers *config_regs;
	const struct config_registers *config_regs;
	void *private_data;
	void *private_data;
	bool is_open;
	bool is_open;
	struct semaphore sem;
	struct mutex sem;
};
};


struct hwicap_driver_config {
struct hwicap_driver_config {
@@ -164,29 +164,29 @@ struct config_registers {
#define XHI_DISABLED_AUTO_CRC       0x0000DEFCUL
#define XHI_DISABLED_AUTO_CRC       0x0000DEFCUL


/**
/**
 * hwicap_type_1_read: Generates a Type 1 read packet header.
 * hwicap_type_1_read - Generates a Type 1 read packet header.
 * @parameter: Register is the address of the register to be read back.
 * @reg: is the address of the register to be read back.
 *
 *
 * Generates a Type 1 read packet header, which is used to indirectly
 * Generates a Type 1 read packet header, which is used to indirectly
 * read registers in the configuration logic.  This packet must then
 * read registers in the configuration logic.  This packet must then
 * be sent through the icap device, and a return packet received with
 * be sent through the icap device, and a return packet received with
 * the information.
 * the information.
 **/
 **/
static inline u32 hwicap_type_1_read(u32 Register)
static inline u32 hwicap_type_1_read(u32 reg)
{
{
	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
		(Register << XHI_REGISTER_SHIFT) |
		(reg << XHI_REGISTER_SHIFT) |
		(XHI_OP_READ << XHI_OP_SHIFT);
		(XHI_OP_READ << XHI_OP_SHIFT);
}
}


/**
/**
 * hwicap_type_1_write: Generates a Type 1 write packet header
 * hwicap_type_1_write - Generates a Type 1 write packet header
 * @parameter: Register is the address of the register to be read back.
 * @reg: is the address of the register to be read back.
 **/
 **/
static inline u32 hwicap_type_1_write(u32 Register)
static inline u32 hwicap_type_1_write(u32 reg)
{
{
	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
		(Register << XHI_REGISTER_SHIFT) |
		(reg << XHI_REGISTER_SHIFT) |
		(XHI_OP_WRITE << XHI_OP_SHIFT);
		(XHI_OP_WRITE << XHI_OP_SHIFT);
}
}