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

Commit 433e63c6 authored by Mark Allyn's avatar Mark Allyn Committed by Greg Kroah-Hartman
Browse files

Staging: rar_register: fix checkpatch errors and debug program file

parent 9cedb392
Loading
Loading
Loading
Loading
+445 −283
Original line number Diff line number Diff line
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/semaphore.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/ioctl.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
/*
 *  rar_register.c - An Intel Restricted Access Region register driver
 *
 *  Copyright(c) 2009 Intel Corporation. All rights reserved.
 *
 *  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.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 *  02111-1307, USA.
 *
 * -------------------------------------------------------------------
 *  20091204 Mark Allyn <mark.a.allyn@intel.com>
 *	     Ossama Othman <ossama.othman@intel.com>
 *	Cleanup per feedback from Alan Cox and Arjan Van De Ven
 *
 *  20090806 Ossama Othman <ossama.othman@intel.com>
 *      Return zero high address if upper 22 bits is zero.
 *      Cleaned up checkpatch errors.
 *      Clarified that driver is dealing with bus addresses.
 *
 *  20090702 Ossama Othman <ossama.othman@intel.com>
 *      Removed unnecessary include directives
 *      Cleaned up spinlocks.
 *      Cleaned up logging.
 *      Improved invalid parameter checks.
 *      Fixed and simplified RAR address retrieval and RAR locking
 *      code.
 *
 *  20090626 Mark Allyn <mark.a.allyn@intel.com>
 *      Initial publish
 */

#define DEBUG 1

#include "rar_register.h"

/* The following defines are for the IPC process to retrieve RAR in */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/kernel.h>

/* === Lincroft Message Bus Interface === */
/* Message Control Register */
#define LNC_MCR_OFFSET 0xD0

/* Maximum number of clients (other drivers using this driver) */
#define MAX_RAR_CLIENTS 10

/* Message Data Register */
#define LNC_MDR_OFFSET 0xD4

@@ -46,50 +80,64 @@
#define LNC_BRAR2L 0x14
#define LNC_BRAR2H 0x15


/* This structure is only used during module initialization. */
struct RAR_offsets {
	int low; /* Register offset for low RAR physical address. */
	int high; /* Register offset for high RAR physical address. */
};

struct pci_dev *rar_dev;
static uint32_t registered;

/* Moorestown supports three restricted access regions. */
#define MRST_NUM_RAR 3

struct RAR_address_struct rar_addr[MRST_NUM_RAR];

/* prototype for init */
static int __init rar_init_handler(void);
static void __exit rar_exit_handler(void);
/* RAR Bus Address Range */
struct RAR_address_range {
	dma_addr_t low;
	dma_addr_t high;
};

/*
  function that is activated on the successfull probe of the RAR device
*/
static int __devinit rar_probe(struct pci_dev *pdev,
			       const struct pci_device_id *ent);
/* Structure containing low and high RAR register offsets. */
struct RAR_offsets {
	u32 low;  /* Register offset for low  RAR bus address. */
	u32 high; /* Register offset for high RAR bus address. */
};

static const struct pci_device_id rar_pci_id_tbl[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4110) },
	{ 0 }
struct client {
	int (*client_callback)(void *client_data);
	void *customer_data;
	int client_called;
	};

MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
static DEFINE_MUTEX(rar_mutex);
static DEFINE_MUTEX(lnc_reg_mutex);

/* field for registering driver to PCI device */
static struct pci_driver rar_pci_driver = {
	.name = "rar_driver",
	.id_table = rar_pci_id_tbl,
	.probe = rar_probe
struct RAR_device {
	struct RAR_offsets const rar_offsets[MRST_NUM_RAR];
	struct RAR_address_range rar_addr[MRST_NUM_RAR];
	struct pci_dev *rar_dev;
	bool registered;
	};

/* this platform has only one rar_device for 3 rar regions */
static struct RAR_device my_rar_device = {
	.rar_offsets = {
		[0].low = LNC_BRAR0L,
		[0].high = LNC_BRAR0H,
		[1].low = LNC_BRAR1L,
		[1].high = LNC_BRAR1H,
		[2].low = LNC_BRAR2L,
		[2].high = LNC_BRAR2H
	}
};

/* This function is used to retrieved RAR info using the IPC message
   bus interface */
static int memrar_get_rar_addr(struct pci_dev *pdev,
/* this data is for handling requests from other drivers which arrive
 * prior to this driver initializing
 */

static struct client clients[MAX_RAR_CLIENTS];
static int num_clients;

/*
 * This function is used to retrieved RAR info using the Lincroft
 * message bus interface.
 */
static int retrieve_rar_addr(struct pci_dev *pdev,
	int offset,
			       u32 *addr)
	dma_addr_t *addr)
{
	/*
	 * ======== The Lincroft Message Bus Interface ========
@@ -133,7 +181,8 @@ static int memrar_get_rar_addr(struct pci_dev *pdev,
	 *  register.
	*/

	int result = 0; /* result */
	int result;

	/* Construct control message */
	u32 const message =
		 (LNC_MESSAGE_READ_OPCODE << 24)
@@ -141,233 +190,401 @@ static int memrar_get_rar_addr(struct pci_dev *pdev,
		 | (offset << 8)
		 | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);

	printk(KERN_WARNING "rar- offset to LNC MSG is %x\n", offset);
	dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);

	if (addr == 0)
	if (addr == 0) {
		WARN_ON(1);
		return -EINVAL;
	}

	/*
	* We synchronize access to the Lincroft MCR and MDR registers
	* until BOTH the command is issued through the MCR register
	* and the corresponding data is read from the MDR register.
	* Otherwise a race condition would exist between accesses to
	* both registers.
	*/

	mutex_lock(&lnc_reg_mutex);

	/* Send the control message */
	result = pci_write_config_dword(pdev,
					LNC_MCR_OFFSET,
					message);
	result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);

	printk(KERN_WARNING "rar- result from send ctl register is %x\n",
	       result);
	dev_dbg(&pdev->dev, "Result from send ctl register is %x\n", result);

	if (!result)
		result = pci_read_config_dword(pdev,
					       LNC_MDR_OFFSET,
					       addr);
	if (!result) {
		result = pci_read_config_dword(pdev, LNC_MDR_OFFSET,
			(u32 *)addr);
		dev_dbg(&pdev->dev,
			"Result from read data register is %x\n", result);

	printk(KERN_WARNING "rar- result from read data register is %x\n",
	       result);
		dev_dbg(&pdev->dev,
			"Value read from data register is %lx\n",
			 (unsigned long)*addr);
	}

	printk(KERN_WARNING "rar- value read from data register is %x\n",
	       *addr);
	mutex_unlock(&lnc_reg_mutex);

	if (result)
		return -1;
	else
		return 0;
	return result;
}

static int memrar_set_rar_addr(struct pci_dev *pdev,
static int set_rar_address(struct pci_dev *pdev,
	int offset,
			       u32 addr)
	dma_addr_t addr)
{
	/*
	 * ======== The Lincroft Message Bus Interface ========
	 * Lincroft registers may be obtained from the PCI
	 * (the Host Bridge) using the Lincroft Message Bus
	 * Interface.  That message bus interface is generally
	 * comprised of two registers: a control register (MCR, 0xDO)
	 * and a data register (MDR, 0xD4).
	 *
	 * The MCR (message control register) format is the following:
	 *   1.  [31:24]: Opcode
	 *   2.  [23:16]: Port
	 *   3.  [15:8]: Register Offset
	 *   4.  [7:4]: Byte Enables (use 0xF to set all of these bits
	 *              to 1)
	 *   5.  [3:0]: reserved
	 *
	 *  Read (0xD0) and write (0xE0) opcodes are written to the
	 *  control register when reading and writing to Lincroft
	 *  registers, respectively.
	 *
	 *  We're interested in registers found in the Lincroft
	 *  B-unit.  The B-unit port is 0x3.
	 *
	 *  The six B-unit RAR register offsets we use are listed
	 *  earlier in this file.
	 *
	 *  Lastly writing to the MCR register requires the "Byte
	 *  enables" bits to be set to 1.  This may be achieved by
	 *  writing 0xF at bit 4.
	 *
	 * The MDR (message data register) format is the following:
	 *   1. [31:0]: Read/Write Data
	 *
	 *  Data being read from this register is only available after
	 *  writing the appropriate control message to the MCR
	 *  register.
	 *
	* Data being written to this register must be written before
	* writing the appropriate control message to the MCR
	* register.
	* @note See rar_get_address() for a description of the
	* message bus interface being used here.
	*/

	int result = 0; /* result */
	int result = 0;

	/* Construct control message */
	u32 const message =
	       (LNC_MESSAGE_WRITE_OPCODE << 24)
	u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
		| (LNC_BUNIT_PORT << 16)
		| (offset << 8)
		| (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);

	printk(KERN_WARNING "rar- offset to LNC MSG is %x\n", offset);

	if (addr == 0)
	if (addr == 0) {
		WARN_ON(1);
		return -EINVAL;
	}

	dev_dbg(&pdev->dev, "Offset for 'set' LNC MSG is %x\n", offset);

	/*
	* We synchronize access to the Lincroft MCR and MDR registers
	* until BOTH the command is issued through the MCR register
	* and the corresponding data is read from the MDR register.
	* Otherwise a race condition would exist between accesses to
	* both registers.
	*/

	mutex_lock(&lnc_reg_mutex);

	/* Send the control message */
	result = pci_write_config_dword(pdev,
					LNC_MDR_OFFSET,
					addr);
	result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);

	printk(KERN_WARNING "rar- result from send ctl register is %x\n",
	       result);
	dev_dbg(&pdev->dev, "Result from write data register is %x\n", result);

	if (!result) {
		dev_dbg(&pdev->dev,
			"Value written to data register is %lx\n",
			 (unsigned long)addr);

	if (!result)
		result = pci_write_config_dword(pdev,
						LNC_MCR_OFFSET,
						message);
		result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);

	printk(KERN_WARNING "rar- result from write data register is %x\n",
		dev_dbg(&pdev->dev, "Result from send ctl register is %x\n",
			result);
	}

	printk(KERN_WARNING "rar- value read to data register is %x\n",
	       addr);
	mutex_unlock(&lnc_reg_mutex);

	if (result)
		return -1;
	else
		return 0;
	return result;
}

/*

 * Initialize RAR parameters, such as physical addresses, etc.

* Initialize RAR parameters, such as bus addresses, etc.
*/
static int memrar_init_rar_params(struct pci_dev *pdev)
static int init_rar_params(struct pci_dev *pdev)
{
	struct RAR_offsets const offsets[] = {
	       { LNC_BRAR0L, LNC_BRAR0H },
	       { LNC_BRAR1L, LNC_BRAR1H },
	       { LNC_BRAR2L, LNC_BRAR2H }
	};

	size_t const num_offsets = sizeof(offsets) / sizeof(offsets[0]);
	struct RAR_offsets const *end = offsets + num_offsets;
	struct RAR_offsets const *i;
	unsigned int n = 0;
	unsigned int i;
	int result = 0;

	/* Retrieve RAR start and end physical addresses. */

	/*
	/* Retrieve RAR start and end bus addresses.
	* Access the RAR registers through the Lincroft Message Bus
	* Interface on PCI device: 00:00.0 Host bridge.
	*/

	/* struct pci_dev *pdev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); */

	if (pdev == NULL)
		return -ENODEV;
	for (i = 0; i < MRST_NUM_RAR; ++i) {
		struct RAR_offsets const *offset =
			&my_rar_device.rar_offsets[i];
		struct RAR_address_range *addr = &my_rar_device.rar_addr[i];

	for (i = offsets; i != end; ++i, ++n) {
		if (memrar_get_rar_addr(pdev,
					(*i).low,
					&(rar_addr[n].low)) != 0
		    || memrar_get_rar_addr(pdev,
					   (*i).high,
					   &(rar_addr[n].high)) != 0) {
	if ((retrieve_rar_addr(pdev, offset->low, &addr->low) != 0)
		|| (retrieve_rar_addr(pdev, offset->high, &addr->high) != 0)) {
		result = -1;
		break;
		}
	}

		/*
		* Only the upper 22 bits of the RAR addresses are
		* stored in their corresponding RAR registers so we
		* must set the lower 10 bits accordingly.

		* The low address has its lower 10 bits cleared, and
		* the high address has all its lower 10 bits set,
		* e.g.:
		* low = 0x2ffffc00
		*/

		addr->low &= (dma_addr_t)0xfffffc00u;

		/*
		* Set bits 9:0 on uppser address if bits 31:10 are non
		* zero; otherwize clear all bits
		*/

		if ((addr->high & 0xfffffc00u) == 0)
			addr->high = 0;
		else
			addr->high |= 0x3ffu;
	}
	/* Done accessing the device. */
	/* pci_dev_put(pdev); */

	if (result == 0) {
		if (1) {
			size_t z;
		int z;
		for (z = 0; z != MRST_NUM_RAR; ++z) {
				printk(KERN_WARNING
				       "rar - BRAR[%Zd] physical address low\n"
				       "\tlow:  0x%08x\n"
				       "\thigh: 0x%08x\n",
				       z,
				       rar_addr[z].low,
				       rar_addr[z].high);
			/*
			* "BRAR" refers to the RAR registers in the
			* Lincroft B-unit.
			*/
			dev_info(&pdev->dev, "BRAR[%u] bus address range = "
			  "[%lx, %lx]\n", z,
			  (unsigned long)my_rar_device.rar_addr[z].low,
			  (unsigned long)my_rar_device.rar_addr[z].high);
		}
	}

	return result;
}

/*
 * The rar_get_address function is used by other device drivers
 * to obtain RAR address information on a RAR. It takes three
 * parameters:
 *
 * int rar_index
 * The rar_index is an index to the rar for which you wish to retrieve
 * the address information.
 * Values can be 0,1, or 2.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
int rar_get_address(int rar_index,
	dma_addr_t *start_address,
	dma_addr_t *end_address)
{
	int result = -ENODEV;

	if (my_rar_device.registered) {
		if (start_address == 0 || end_address == 0
			|| rar_index >= MRST_NUM_RAR || rar_index < 0) {
			result = -EINVAL;
		} else {
			*start_address =
				my_rar_device.rar_addr[rar_index].low;
			*end_address =
				my_rar_device.rar_addr[rar_index].high;

			result = 0;
		}
	}

	return result;
}
EXPORT_SYMBOL(rar_get_address);

/*
  function that is activated on the successfull probe of the RAR device
 * The rar_lock function is ued by other device drivers to lock an RAR.
 * once an RAR is locked, it stays locked until the next system reboot.
 * The function takes one parameter:
 *
 * int rar_index
 * The rar_index is an index to the rar that you want to lock.
 * Values can be 0,1, or 2.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
static int __devinit rar_probe(struct pci_dev *pdev,
			       const struct pci_device_id *ent)
int rar_lock(int rar_index)
{
	/* error */
	int error;
	int result = -ENODEV;

	if (rar_index >= MRST_NUM_RAR || rar_index < 0) {
		result = -EINVAL;
		return result;
	}

	dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex locking\n");
	mutex_lock(&rar_mutex);

	if (my_rar_device.registered) {

		dma_addr_t low = my_rar_device.rar_addr[rar_index].low &
			0xfffffc00u;

		dma_addr_t high = my_rar_device.rar_addr[rar_index].high &
			0xfffffc00u;

		/*
		* Only allow I/O from the graphics and Langwell;
		* Not from the x96 processor
		*/
		if (rar_index == (int)RAR_TYPE_VIDEO) {
			low |= 0x00000009;
			high |= 0x00000015;
		}

		else if (rar_index == (int)RAR_TYPE_AUDIO) {
			/* Only allow I/O from Langwell; nothing from x86 */
			low |= 0x00000008;
			high |= 0x00000018;
		}

		else
			/* Read-only from all agents */
			high |= 0x00000018;

		/*
		* Now program the register using the Lincroft message
		* bus interface.
		*/
		result = set_rar_address(my_rar_device.rar_dev,
			my_rar_device.rar_offsets[rar_index].low,
			low);

		if (result == 0)
			result = set_rar_address(
			my_rar_device.rar_dev,
			my_rar_device.rar_offsets[rar_index].high,
			high);
	}

	dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex unlocking\n");
	mutex_unlock(&rar_mutex);
	return result;
}
EXPORT_SYMBOL(rar_lock);

/* The register_rar function is to used by other device drivers
 * to ensure that this driver is ready. As we cannot be sure of
 * the compile/execute order of dirvers in ther kernel, it is
 * best to give this driver a callback function to call when
 * it is ready to give out addresses. The callback function
 * would have those steps that continue the initialization of
 * a driver that do require a valid RAR address. One of those
 * steps would be to call rar_get_address()
 * This function return 0 on success an -1 on failure.
*/
int register_rar(int (*callback)(void *yourparameter), void *yourparameter)
{

	int result = -ENODEV;

	if (callback == NULL)
		return -EINVAL;

	mutex_lock(&rar_mutex);

	if (my_rar_device.registered) {

		mutex_unlock(&rar_mutex);
		/*
		* if the driver already registered, then we can simply
		* call the callback right now
		*/

		return (*callback)(yourparameter);
	}

	if (num_clients < MRST_NUM_RAR) {

		clients[num_clients].client_callback = callback;
		clients[num_clients].customer_data = yourparameter;
		num_clients += 1;
		result = 0;
	}

	/*------------------------
	CODE
	---------------------------*/
	mutex_unlock(&rar_mutex);
	return result;

}
EXPORT_SYMBOL(register_rar);

/*
 * This function registers the driver with the device subsystem (
 * either PCI, USB, etc).
 * Function that is activaed on the succesful probe of the RAR device
 * (Moorestown host controller).
 */
static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	int error;
	int counter;

	DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
	  "Rar pci probe starting\n");
	error = 0;
	dev_dbg(&dev->dev, "PCI probe starting\n");

	/* enable the device */
	error = pci_enable_device(pdev);
	error = pci_enable_device(dev);
	if (error) {
		DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
		  "error enabling pci device\n");
		dev_err(&dev->dev,
			"Error enabling RAR register PCI device\n");
		goto end_function;
	}

	rar_dev = pdev;
	registered = 1;

	/* Initialize the RAR parameters, which have to be retrieved */
	/* via the message bus service */
	error = memrar_init_rar_params(rar_dev);
	/* we have only one device; fill in the rar_device structure */
	my_rar_device.rar_dev = dev;

	/*
	* Initialize the RAR parameters, which have to be retrieved
	* via the message bus interface.
	*/
	error = init_rar_params(dev);
	if (error) {
		DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
		  "error getting RAR addresses device\n");
		registered = 0;
		pci_disable_device(dev);

		dev_err(&dev->dev,
			"Error retrieving RAR addresses\n");

		goto end_function;
	}

	dev_dbg(&dev->dev, "PCI probe locking\n");
	mutex_lock(&rar_mutex);
	my_rar_device.registered = 1;

	/* now call anyone who has registered (using callbacks) */
	for (counter = 0; counter < num_clients; counter += 1) {
		if (clients[counter].client_callback) {
			error = (*clients[counter].client_callback)(
				clients[counter].customer_data);
			/* set callback to NULL to indicate it has been done */
			clients[counter].client_callback = NULL;
				dev_dbg(&my_rar_device.rar_dev->dev,
				"Callback called for %d\n",
			counter);
		}
	}

	dev_dbg(&dev->dev, "PCI probe unlocking\n");
	mutex_unlock(&rar_mutex);

end_function:

	return error;
}

/*
  this function registers the driver to
  the device subsystem (either PCI, USB, etc)
*/
const struct pci_device_id rar_pci_id_tbl[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_RAR_DEVICE_ID) },
	{ 0 }
};

MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);

const struct pci_device_id *my_id_table = rar_pci_id_tbl;

/* field for registering driver to PCI device */
static struct pci_driver rar_pci_driver = {
	.name = "rar_register_driver",
	.id_table = rar_pci_id_tbl,
	.probe = rar_probe
};

static int __init rar_init_handler(void)
{
	return pci_register_driver(&rar_pci_driver);
@@ -382,59 +599,4 @@ module_init(rar_init_handler);
module_exit(rar_exit_handler);

MODULE_LICENSE("GPL");


/* The get_rar_address function is used by other device drivers
 * to obtain RAR address information on a RAR. It takes two
 * parameter:
 *
 * int rar_index
 * The rar_index is an index to the rar for which you wish to retrieve
 * the address information.
 * Values can be 0,1, or 2.
 *
 * struct RAR_address_struct is a pointer to a place to which the function
 * can return the address structure for the RAR.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
int get_rar_address(int rar_index, struct RAR_address_struct *addresses)
{
	if (registered && (rar_index < 3) && (rar_index >= 0)) {
		*addresses = rar_addr[rar_index];
		/* strip off lock bit information  */
		addresses->low = addresses->low & 0xfffffff0;
		addresses->high = addresses->high & 0xfffffff0;
		return 0;
	} else
		return -ENODEV;
}
EXPORT_SYMBOL(get_rar_address);

/* The lock_rar function is used by other device drivers to lock an RAR.
 * once an RAR is locked, it stays locked until the next system reboot.
 * The function takes one parameter:
 *
 * int rar_index
 * The rar_index is an index to the rar that you want to lock.
 * Values can be 0,1, or 2.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
int lock_rar(int rar_index)
{
	u32 working_addr;
	int result;

	if (registered && (rar_index < 3) && (rar_index >= 0)) {
		/* first make sure that lock bits are clear (this does lock) */
		working_addr = rar_addr[rar_index].low & 0xfffffff0;

		/* now send that value to the register using the IPC */
		result = memrar_set_rar_addr(rar_dev, rar_index, working_addr);
		return result;
	} else
		return -ENODEV;
}
MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");