Commit c8c90ab1 authored by Ryan S. Arnold's avatar Ryan S. Arnold Committed by Linus Torvalds

[PATCH] HVCS fixes

Here are a set of HVCS (drivers/char/hvcs.c) fixes that were suggested by Jeff
Garzik on July 29th in his review of this driver as well as some other fixes
for problems I found while reviewing the driver.  These are all relatively
minor, but necessary.

- Cleaned up curly braces on single line conditional blocks.

- Replaced debug memset(...,0x3F,...) with memset(...,0x00,...).

- Removed explicit '= 0' after static int declarations since these default
  to zero.

- Removed list_for_each_safe() instances and replaced with
  list_for_each_entry() which cut down on amt of code.  The 'safe' version is
  un-needed now that the driver is using spinlocks.

- Changed spin_lock_irqsave() to spin_lock() when locking hvcs_structs_lock
  and hvcs_pi_lock since these are not touched in an int handler.

- changed spin_lock_irqsave() to spin_lock() in interrupt handler.

- Initialized hvcs_structs_lock and hvcs_pi_lock to SPIN_LOCK_UNLOCKED at
  declaration tiem rather than in hvcs_module_init().

- Added spin_lock around list_del() in destroy_hvcs_struct() to protect the
  list traversal from deletion.  The original omission was an oversight.

- Removed '= NULL' from pointer declarations since they are initialized NULL
  by default.

- Removed wmb() instance from hvcs_try_write().  They probably aren't needed
  with locking in place.

- Added check and cleanup for hvcs_pi_buff = kmalloc() in
  hvcs_module_init().

- Exposed hvcs_struct.index via a sysfs attribute so that the coupling
  between /dev/hvcs* and a vty-server can be systematically determined.

- Moved kobject_put() in hvcs_open() outside of the
  spin_unlock_irqrestore().

- In hvcs_probe() changed kmalloc(sizeof(*hvcsd),...) to
  kmalloc(sizeof(struct hvcs_struct)) because hvcsd references a NULL pointer
  at the time of kmalloc.

- Incremented the HVCS_DRIVER_VERSION to 1.3.1

arch/ppc64/kernel/hvcserver.c:

- Changed function documentation of EXPORTed functions to comply with proper
  kernel-doc documentation style.

- Changed 'unsigned int' types to 'uint32_t' to comply with how unit
  addresses and partition IDs are handled in other arch/ppc64 vterm code.

- Cleaned up curly braces on single line conditional blocks.

include/asm-ppc64/hvcserver.h:

- Added kernel-doc style documentation for hvcs_partner_info struct.

- changed 'unsigned int' types to 'uint32_t' to comply with how unit
  addresses and partition IDs are handled in other arch/ppc64 vterm code.
Signed-off-by: default avatarRyan S. Arnold <rsa@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0463210d
...@@ -61,14 +61,21 @@ int hvcs_convert(long to_convert) ...@@ -61,14 +61,21 @@ int hvcs_convert(long to_convert)
} }
} }
/**
* hvcs_free_partner_info - free pi allocated by hvcs_get_partner_info
* @head: list_head pointer for an allocated list of partner info structs to
* free.
*
* This function is used to free the partner info list that was returned by
* calling hvcs_get_partner_info().
*/
int hvcs_free_partner_info(struct list_head *head) int hvcs_free_partner_info(struct list_head *head)
{ {
struct hvcs_partner_info *pi; struct hvcs_partner_info *pi;
struct list_head *element; struct list_head *element;
if (!head) { if (!head)
return -EINVAL; return -EINVAL;
}
while (!list_empty(head)) { while (!list_empty(head)) {
element = head->next; element = head->next;
...@@ -82,7 +89,7 @@ int hvcs_free_partner_info(struct list_head *head) ...@@ -82,7 +89,7 @@ int hvcs_free_partner_info(struct list_head *head)
EXPORT_SYMBOL(hvcs_free_partner_info); EXPORT_SYMBOL(hvcs_free_partner_info);
/* Helper function for hvcs_get_partner_info */ /* Helper function for hvcs_get_partner_info */
int hvcs_next_partner(unsigned int unit_address, int hvcs_next_partner(uint32_t unit_address,
unsigned long last_p_partition_ID, unsigned long last_p_partition_ID,
unsigned long last_p_unit_address, unsigned long *pi_buff) unsigned long last_p_unit_address, unsigned long *pi_buff)
...@@ -94,25 +101,37 @@ int hvcs_next_partner(unsigned int unit_address, ...@@ -94,25 +101,37 @@ int hvcs_next_partner(unsigned int unit_address,
return hvcs_convert(retval); return hvcs_convert(retval);
} }
/* /**
* The unit_address parameter is the unit address of the vty-server vdevice * hvcs_get_partner_info - Get all of the partner info for a vty-server adapter
* in whose partner information the caller is interested. This function * @unit_address: The unit_address of the vty-server adapter for which this
* uses a pointer to a list_head instance in which to store the partner info. * function is fetching partner info.
* @head: An initialized list_head pointer to an empty list to use to return the
* list of partner info fetched from the hypervisor to the caller.
* @pi_buff: A page sized buffer pre-allocated prior to calling this function
* that is to be used to be used by firmware as an iterator to keep track
* of the partner info retrieval.
*
* This function returns non-zero on success, or if there is no partner info. * This function returns non-zero on success, or if there is no partner info.
* *
* The pi_buff is pre-allocated prior to calling this function because this
* function may be called with a spin_lock held and kmalloc of a page is not
* recommended as GFP_ATOMIC.
*
* The first long of this buffer is used to store a partner unit address. The
* second long is used to store a partner partition ID and starting at
* pi_buff[2] is the 79 character Converged Location Code (diff size than the
* unsigned longs, hence the casting mumbo jumbo you see later).
*
* Invocation of this function should always be followed by an invocation of * Invocation of this function should always be followed by an invocation of
* hvcs_free_partner_info() using a pointer to the SAME list head instance * hvcs_free_partner_info() using a pointer to the SAME list head instance
* that was used to store the partner_info list. * that was passed as a parameter to this function.
*/ */
int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head,
unsigned long *pi_buff) unsigned long *pi_buff)
{ {
/* /*
* This is a page sized buffer to be passed to hvcall per invocation. * Dealt with as longs because of the hcall interface even though the
* NOTE: the first long returned is unit_address. The second long * values are uint32_t.
* returned is the partition ID and starting with pi_buff[2] are
* HVCS_CLC_LENGTH characters, which are diff size than the unsigned
* long, hence the casting mumbojumbo you see later.
*/ */
unsigned long last_p_partition_ID; unsigned long last_p_partition_ID;
unsigned long last_p_unit_address; unsigned long last_p_unit_address;
...@@ -122,15 +141,12 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, ...@@ -122,15 +141,12 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head,
memset(pi_buff, 0x00, PAGE_SIZE); memset(pi_buff, 0x00, PAGE_SIZE);
/* invalid parameters */ /* invalid parameters */
if (!head) if (!head || !pi_buff)
return -EINVAL; return -EINVAL;
last_p_partition_ID = last_p_unit_address = ~0UL; last_p_partition_ID = last_p_unit_address = ~0UL;
INIT_LIST_HEAD(head); INIT_LIST_HEAD(head);
if (!pi_buff)
return -ENOMEM;
do { do {
retval = hvcs_next_partner(unit_address, last_p_partition_ID, retval = hvcs_next_partner(unit_address, last_p_partition_ID,
last_p_unit_address, pi_buff); last_p_unit_address, pi_buff);
...@@ -183,21 +199,29 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head, ...@@ -183,21 +199,29 @@ int hvcs_get_partner_info(unsigned int unit_address, struct list_head *head,
} }
EXPORT_SYMBOL(hvcs_get_partner_info); EXPORT_SYMBOL(hvcs_get_partner_info);
/* /**
* hvcs_register_connection - establish a connection between this vty-server and
* a vty.
* @unit_address: The unit address of the vty-server adapter that is to be
* establish a connection.
* @p_partition_ID: The partition ID of the vty adapter that is to be connected.
* @p_unit_address: The unit address of the vty adapter to which the vty-server
* is to be connected.
*
* If this function is called once and -EINVAL is returned it may * If this function is called once and -EINVAL is returned it may
* indicate that the partner info needs to be refreshed for the * indicate that the partner info needs to be refreshed for the
* target unit address at which point the caller must invoke * target unit address at which point the caller must invoke
* hvcs_get_partner_info() and then call this function again. If, * hvcs_get_partner_info() and then call this function again. If,
* for a second time, -EINVAL is returned then it indicates that * for a second time, -EINVAL is returned then it indicates that
* there is probably already a partner connection registered to a * there is probably already a partner connection registered to a
* different vty-server@ vdevice. It is also possible that a second * different vty-server adapter. It is also possible that a second
* -EINVAL may indicate that one of the parms is not valid, for * -EINVAL may indicate that one of the parms is not valid, for
* instance if the link was removed between the vty-server@ vdevice * instance if the link was removed between the vty-server adapter
* and the vty@ vdevice that you are trying to open. Don't shoot the * and the vty adapter that you are trying to open. Don't shoot the
* messenger. Firmware implemented it this way. * messenger. Firmware implemented it this way.
*/ */
int hvcs_register_connection( unsigned int unit_address, int hvcs_register_connection( uint32_t unit_address,
unsigned int p_partition_ID, unsigned int p_unit_address) uint32_t p_partition_ID, uint32_t p_unit_address)
{ {
long retval; long retval;
retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address, retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address,
...@@ -206,11 +230,17 @@ int hvcs_register_connection( unsigned int unit_address, ...@@ -206,11 +230,17 @@ int hvcs_register_connection( unsigned int unit_address,
} }
EXPORT_SYMBOL(hvcs_register_connection); EXPORT_SYMBOL(hvcs_register_connection);
/* /**
* If -EBUSY is returned continue to call this function * hvcs_free_connection - free the connection between a vty-server and vty
* until 0 is returned. * @unit_address: The unit address of the vty-server that is to have its
* connection severed.
*
* This function is used to free the partner connection between a vty-server
* adapter and a vty adapter.
*
* If -EBUSY is returned continue to call this function until 0 is returned.
*/ */
int hvcs_free_connection(unsigned int unit_address) int hvcs_free_connection(uint32_t unit_address)
{ {
long retval; long retval;
retval = plpar_hcall_norets(H_FREE_VTERM, unit_address); retval = plpar_hcall_norets(H_FREE_VTERM, unit_address);
......
This diff is collapsed.
...@@ -27,18 +27,31 @@ ...@@ -27,18 +27,31 @@
/* Converged Location Code length */ /* Converged Location Code length */
#define HVCS_CLC_LENGTH 79 #define HVCS_CLC_LENGTH 79
/**
* hvcs_partner_info - an element in a list of partner info
* @node: list_head denoting this partner_info struct's position in the list of
* partner info.
* @unit_address: The partner unit address of this entry.
* @partition_ID: The partner partition ID of this entry.
* @location_code: The converged location code of this entry + 1 char for the
* null-term.
*
* This structure outlines the format that partner info is presented to a caller
* of the hvcs partner info fetching functions. These are strung together into
* a list using linux kernel lists.
*/
struct hvcs_partner_info { struct hvcs_partner_info {
struct list_head node; struct list_head node;
unsigned int unit_address; uint32_t unit_address;
unsigned int partition_ID; uint32_t partition_ID;
char location_code[HVCS_CLC_LENGTH + 1]; /* CLC + 1 null-term char */ char location_code[HVCS_CLC_LENGTH + 1]; /* CLC + 1 null-term char */
}; };
extern int hvcs_free_partner_info(struct list_head *head); extern int hvcs_free_partner_info(struct list_head *head);
extern int hvcs_get_partner_info(unsigned int unit_address, extern int hvcs_get_partner_info(uint32_t unit_address,
struct list_head *head, unsigned long *pi_buff); struct list_head *head, unsigned long *pi_buff);
extern int hvcs_register_connection(unsigned int unit_address, extern int hvcs_register_connection(uint32_t unit_address,
unsigned int p_partition_ID, unsigned int p_unit_address); uint32_t p_partition_ID, uint32_t p_unit_address);
extern int hvcs_free_connection(unsigned int unit_address); extern int hvcs_free_connection(uint32_t unit_address);
#endif /* _PPC64_HVCSERVER_H */ #endif /* _PPC64_HVCSERVER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment