/* * sysmgr.c * * Implementation of System manager. * * Copyright (C) 2009 Texas Instruments, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE. */ /* Standard headers */ #include <linux/types.h> #include <linux/module.h> #include <syslink/atomic_linux.h> /* Module headers */ #include <multiproc.h> #include <sysmemmgr.h> #include <sysmgr.h> #include <_sysmgr.h> #include <platform.h> #include <platform_mem.h> #include <gatepeterson.h> #include <sharedregion.h> #include <listmp.h> #include <messageq.h> #include <messageq_transportshm.h> #include <notify.h> /*#include <notify_driver.h>*/ #include <notify_ducatidriver.h> #include <nameserver.h> #include <nameserver_remote.h> #include <nameserver_remotenotify.h> #include <procmgr.h> #include <heap.h> #include <heapbuf.h> /* ============================================================================= * Macros * ============================================================================= */ /*! * @def BOOTLOADPAGESIZE * @brief Error code base for System manager. */ #define BOOTLOADPAGESIZE (0x1000) /* 4K page size */ /*! * @def SYSMGR_ENTRYVALIDITYSTAMP * @brief Validity stamp for boot load page entries. */ #define SYSMGR_ENTRYVALIDITYSTAMP (0xBABAC0C0) /*! * @def SYSMGR_ENTRYVALIDSTAMP * @brief Validity stamp for boot load page entries. */ #define SYSMGR_ENTRYVALIDSTAMP (0xBABAC0C0) /*! * @def SYSMGR_SCALABILITYHANDSHAKESTAMP * @brief scalability configuration handshake value. */ #define SYSMGR_SCALABILITYHANDSHAKESTAMP (0xBEEF0000) /*! * @def SYSMGR_SETUPHANDSHAKESTAMP * @brief Platform configured handshake value. */ #define SYSMGR_SETUPHANDSHAKESTAMP (0xBEEF0001) /*! * @def SYSMGR_DESTROYHANDSHAKESTAMP * @brief Destroy handshake value. */ #define SYSMGR_DESTROYHANDSHAKESTAMP (0xBEEF0002) /*! * @def SYSMGR_BOOTLOADPAGESIZE * @brief Boot load page size. */ #define SYSMGR_BOOTLOADPAGESIZE (0x00001000) /* Macro to make a correct module magic number with ref_count */ #define SYSMGR_MAKE_MAGICSTAMP(x) ((SYSMGR_MODULEID << 12) | (x)) /* ============================================================================= * Structures & Enums * ============================================================================= */ /*! @brief structure for System manager boot load page entry */ struct sysmgr_bootload_page_entry { VOLATILE u32 offset; /* Offset of next entry (-1 if not present) */ VOLATILE u32 valid; /* Validity of the entry */ VOLATILE u32 size; /* Size of the entry data */ VOLATILE u32 cmd_id; /* Command ID */ }; /*! @brief structure containg system manager state object */ struct sysmgr_boot_load_page { VOLATILE struct sysmgr_bootload_page_entry host_config; /* First entry, host specific configuration in the boot load page */ u8 padding1[(BOOTLOADPAGESIZE/2) - \ sizeof(struct sysmgr_bootload_page_entry)]; /* Padding1 */ VOLATILE u32 handshake; /* Handshake variable, wrote by slave to indicate configuration done. */ VOLATILE struct sysmgr_bootload_page_entry slave_config; /* First entry, slave specific configuration in the boot load page */ u8 padding2[(BOOTLOADPAGESIZE/2) - \ sizeof(struct sysmgr_bootload_page_entry) - \ sizeof(u32)]; /* Padding2 */ }; /*! @brief structure for System manager module state */ struct sysmgr_module_object { atomic_t ref_count; /* Reference count */ struct sysmgr_config config; /* Overall system configuration */ struct sysmgr_boot_load_page *boot_load_page[MULTIPROC_MAXPROCESSORS]; /* Boot load page of the slaves */ bool multiproc_init_flag; /* Multiproc Initialize flag */ bool gatepeterson_init_flag; /* Gatepeterson Initialize flag */ bool sharedregion_init_flag; /* Sharedregion Initialize flag */ bool listmp_init_flag; /* Listmp Initialize flag */ bool messageq_init_flag; /* Messageq Initialize flag */ bool notify_init_flag; /* Notify Initialize flag */ bool proc_mgr_init_flag; /* Processor manager Initialize flag */ bool heapbuf_init_flag; /* Heapbuf Initialize flag */ bool nameserver_init_flag; /* Nameserver_remotenotify Initialize flag */ bool listmp_sharedmemory_init_flag; /* Listmp_sharedmemory Initialize flag */ bool messageq_transportshm_init_flag; /* Messageq_transportshm Initialize flag */ bool notify_ducatidrv_init_flag; /* notify_ducatidrv Initialize flag */ bool nameserver_remotenotify_init_flag; /* nameserver_remotenotify Initialize flag */ bool platform_init_flag; /* Flag to indicate platform initialization status */ }; /* ============================================================================= * Globals * ============================================================================= */ /*! * @var sysmgr_state * * @brief Variable holding state of system manager. */ static struct sysmgr_module_object sysmgr_state; /* ============================================================================= * APIS * ============================================================================= */ /* * ======== sysmgr_get_config ======== * Purpose: * Function to get the default values for configuration. */ void sysmgr_get_config(struct sysmgr_config *config) { s32 status = 0; if (WARN_ON(config == NULL)) { status = -EINVAL; printk(KERN_ALERT "sysmgr_get_config [0x%x] : Argument of type" " (sysmgr_get_config *) passed is null!", status); return; } /* Get the gatepeterson default config */ multiproc_get_config(&config->multiproc_cfg); /* Get the gatepeterson default config */ gatepeterson_get_config(&config->gatepeterson_cfg); /* Get the sharedregion default config */ sharedregion_get_config(&config->sharedregion_cfg); /* Get the messageq default config */ messageq_get_config(&config->messageq_cfg); /* Get the notify default config */ notify_get_config(&config->notify_cfg); /* Get the proc_mgr default config */ proc_mgr_get_config(&config->proc_mgr_cfg); /* Get the heapbuf default config */ heapbuf_get_config(&config->heapbuf_cfg); /* Get the listmp_sharedmemory default config */ listmp_sharedmemory_get_config(&config->listmp_sharedmemory_cfg); /* Get the messageq_transportshm default config */ messageq_transportshm_get_config(&config->messageq_transportshm_cfg); /* Get the notify_ducati driver default config */ notify_ducatidrv_getconfig(&config->notify_ducatidrv_cfg); /* Get the nameserver_remotenotify default config */ nameserver_remotenotify_get_config( &config->nameserver_remotenotify_cfg); } EXPORT_SYMBOL(sysmgr_get_config); /* * ======== sysmgr_get_object_config ======== * Purpose: * Function to get the SysMgr Object configuration from Slave. */ u32 sysmgr_get_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size) { struct sysmgr_bootload_page_entry *entry = NULL; u32 offset = 0; u32 ret = 0; struct sysmgr_boot_load_page *blp = NULL; blp = (struct sysmgr_boot_load_page *) sysmgr_state.boot_load_page[proc_id]; entry = (struct sysmgr_bootload_page_entry *) &blp->slave_config; while (entry->valid == SYSMGR_ENTRYVALIDSTAMP) { if (entry->cmd_id == cmd_id) { if (size == entry->size) { memcpy(config, (void *)((u32)entry + \ sizeof(struct sysmgr_bootload_page_entry)), size); ret = size; break; } } if (entry->offset != -1) { offset += entry->offset; entry = (struct sysmgr_bootload_page_entry *) ((u32) &blp->slave_config + entry->offset); } else { break; } } /* return number of bytes wrote to the boot load page */ return ret; } /* * ======== sysmgr_put_object_config ======== * Purpose: * Function to put the SysMgr Object configuration to Slave. */ u32 sysmgr_put_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size) { struct sysmgr_bootload_page_entry *entry = NULL; struct sysmgr_bootload_page_entry *prev = NULL; u32 offset = 0; struct sysmgr_boot_load_page *blp = NULL; /* Get the boot load page pointer */ blp = sysmgr_state.boot_load_page[proc_id]; /* Put the entry at the end of list */ entry = (struct sysmgr_bootload_page_entry *) &blp->host_config; while (entry->valid == SYSMGR_ENTRYVALIDSTAMP) { prev = entry; if (entry->offset != -1) { offset += entry->offset; entry = (struct sysmgr_bootload_page_entry *) ((u32) &blp->slave_config + entry->offset); } else { break; } } /* First entry has prev set to NULL */ if (prev == NULL) { entry->offset = -1; entry->cmd_id = cmd_id; entry->size = size; memcpy((void *)((u32)entry + \ sizeof(struct sysmgr_bootload_page_entry)), config, size); entry->valid = SYSMGR_ENTRYVALIDSTAMP; } else { entry = (struct sysmgr_bootload_page_entry *)((u32)entry + \ sizeof(struct sysmgr_bootload_page_entry) + \ entry->size); entry->offset = -1; entry->cmd_id = cmd_id; entry->size = size; memcpy((void *)((u32)entry + \ sizeof(struct sysmgr_bootload_page_entry)), config, size); entry->valid = SYSMGR_ENTRYVALIDSTAMP; /* Attach the new created entry */ prev->offset = ((u32) entry - (u32) &blp->slave_config); } /* return number of bytes wrote to the boot load page */ return size; } /* * ======== sysmgr_setup ======== * Purpose: * Function to setup the System. */ s32 sysmgr_setup(const struct sysmgr_config *cfg) { s32 status = 0; struct sysmgr_config *config = NULL; /* This sets the ref_count variable is not initialized, upper 16 bits is * written with module Id to ensure correctness of ref_count variable. */ atomic_cmpmask_and_set(&sysmgr_state.ref_count, SYSMGR_MAKE_MAGICSTAMP(0), SYSMGR_MAKE_MAGICSTAMP(0)); if (atomic_inc_return(&sysmgr_state.ref_count) != SYSMGR_MAKE_MAGICSTAMP(1)) { status = 1; goto exit; } if (cfg == NULL) { sysmgr_get_config(&sysmgr_state.config); config = &sysmgr_state.config; } else { memcpy((void *) (&sysmgr_state.config), (void *) cfg, sizeof(struct sysmgr_config)); config = (struct sysmgr_config *) cfg; } /* Initialize PlatformMem */ status = platform_mem_setup(); if (status < 0) { printk(KERN_ERR "sysmgr_setup : platform_mem_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "platform_mem_setup_setup : status [0x%x]\n" , status); } /* Override the platform specific configuration */ platform_override_config(config); status = multiproc_setup(&(config->multiproc_cfg)); if (status < 0) { printk(KERN_ERR "sysmgr_setup : multiproc_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "sysmgr_setup : status [0x%x]\n" , status); sysmgr_state.multiproc_init_flag = true; } /* Initialize ProcMgr */ if (status >= 0) { status = proc_mgr_setup(&(config->proc_mgr_cfg)); if (status < 0) { printk(KERN_ERR "sysmgr_setup : proc_mgr_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "proc_mgr_setup : status [0x%x]\n" , status); sysmgr_state.proc_mgr_init_flag = true; } } /* Initialize SharedRegion */ if (status >= 0) { status = sharedregion_setup(&config->sharedregion_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : sharedregion_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "sharedregion_setup : status [0x%x]\n" , status); sysmgr_state.sharedregion_init_flag = true; } } /* Initialize Notify */ if (status >= 0) { status = notify_setup(&config->notify_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : notify_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "notify_setup : status [0x%x]\n" , status); sysmgr_state.notify_init_flag = true; } } /* Initialize NameServer */ if (status >= 0) { status = nameserver_setup(); if (status < 0) { printk(KERN_ERR "sysmgr_setup : nameserver_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "nameserver_setup : status [0x%x]\n" , status); sysmgr_state.nameserver_init_flag = true; } } /* Initialize GatePeterson */ if (status >= 0) { status = gatepeterson_setup(&config->gatepeterson_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : gatepeterson_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "gatepeterson_setup : status [0x%x]\n" , status); sysmgr_state.gatepeterson_init_flag = true; } } /* Intialize MessageQ */ if (status >= 0) { status = messageq_setup(&config->messageq_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : messageq_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "messageq_setup : status [0x%x]\n" , status); sysmgr_state.messageq_init_flag = true; } } /* Intialize HeapBuf */ if (status >= 0) { status = heapbuf_setup(&config->heapbuf_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : heapbuf_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "heapbuf_setup : status [0x%x]\n" , status); sysmgr_state.heapbuf_init_flag = true; } } /* Initialize ListMPSharedMemory */ if (status >= 0) { status = listmp_sharedmemory_setup( &config->listmp_sharedmemory_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : " "listmp_sharedmemory_setup failed [0x%x]\n", status); } else { printk(KERN_ERR "listmp_sharedmemory_setup : " "status [0x%x]\n" , status); sysmgr_state.listmp_sharedmemory_init_flag = true; } } /* Initialize MessageQTransportShm */ if (status >= 0) { status = messageq_transportshm_setup( &config->messageq_transportshm_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : " "messageq_transportshm_setup failed [0x%x]\n", status); } else { printk(KERN_ERR "messageq_transportshm_setup : " "status [0x%x]\n", status); sysmgr_state.messageq_transportshm_init_flag = true; } } /* Initialize Notify DucatiDriver */ if (status >= 0) { status = notify_ducatidrv_setup(&config->notify_ducatidrv_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : " "notify_ducatidrv_setup failed [0x%x]\n", status); } else { printk(KERN_ERR "notify_ducatidrv_setup : " "status [0x%x]\n" , status); sysmgr_state.notify_ducatidrv_init_flag = true; } } /* Initialize NameServerRemoteNotify */ if (status >= 0) { status = nameserver_remotenotify_setup( &config->nameserver_remotenotify_cfg); if (status < 0) { printk(KERN_ERR "sysmgr_setup : " "nameserver_remotenotify_setup failed [0x%x]\n", status); } else { printk(KERN_ERR "nameserver_remotenotify_setup : " "status [0x%x]\n" , status); sysmgr_state.nameserver_remotenotify_init_flag = true; } } if (status >= 0) { /* Call platform setup function */ status = platform_setup(config); if (status < 0) { printk(KERN_ERR "sysmgr_setup : platform_setup " "failed [0x%x]\n", status); } else { printk(KERN_ERR "platform_setup : status [0x%x]\n" , status); sysmgr_state.platform_init_flag = true; } } exit: if (status < 0) atomic_set(&sysmgr_state.ref_count, SYSMGR_MAKE_MAGICSTAMP(0)); return status; } EXPORT_SYMBOL(sysmgr_setup); /* * ======== sysmgr_setup ======== * Purpose: * Function to finalize the System. */ s32 sysmgr_destroy(void) { s32 status = 0; if (atomic_cmpmask_and_lt(&(sysmgr_state.ref_count), SYSMGR_MAKE_MAGICSTAMP(0), SYSMGR_MAKE_MAGICSTAMP(1)) != false) { /*! @retval SYSMGR_E_INVALIDSTATE Module was not initialized */ status = SYSMGR_E_INVALIDSTATE; goto exit; } if (atomic_dec_return(&sysmgr_state.ref_count) != SYSMGR_MAKE_MAGICSTAMP(0)) { status = 1; goto exit; } /* Finalize Platform module*/ if (sysmgr_state.platform_init_flag == true) { status = platform_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : platform_destroy " "failed [0x%x]", status); } else { sysmgr_state.platform_init_flag = false; } } /* Finalize NameServerRemoteNotify module */ if (sysmgr_state.nameserver_remotenotify_init_flag == true) { status = nameserver_remotenotify_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "nameserver_remotenotify_destroy failed [0x%x]", status); } else { sysmgr_state.nameserver_remotenotify_init_flag \ = false; } } /* Finalize Notify Ducati Driver module */ if (sysmgr_state.notify_ducatidrv_init_flag == true) { status = notify_ducatidrv_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "notify_ducatidrv_destroy failed [0x%x]", status); } else { sysmgr_state.notify_ducatidrv_init_flag = false; } } /* Finalize MessageQTransportShm module */ if (sysmgr_state.messageq_transportshm_init_flag == true) { status = messageq_transportshm_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "messageq_transportshm_destroy failed [0x%x]", status); } else { sysmgr_state.messageq_transportshm_init_flag = \ false; } } /* Finalize ListMPSharedMemory module */ if (sysmgr_state.listmp_sharedmemory_init_flag == true) { status = listmp_sharedmemory_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "listmp_sharedmemory_destroy failed [0x%x]", status); } else { sysmgr_state.listmp_sharedmemory_init_flag = \ false; } } /* Finalize HeapBuf module */ if (sysmgr_state.heapbuf_init_flag == true) { status = heapbuf_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : heapbuf_destroy " "failed [0x%x]", status); } else { sysmgr_state.heapbuf_init_flag = false; } } /* Finalize MessageQ module */ if (sysmgr_state.messageq_init_flag == true) { status = messageq_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : messageq_destroy " "failed [0x%x]", status); } else { sysmgr_state.messageq_init_flag = false; } } /* Finalize GatePeterson module */ if (sysmgr_state.gatepeterson_init_flag == true) { status = gatepeterson_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "gatepeterson_destroy failed [0x%x]", status); } else { sysmgr_state.gatepeterson_init_flag = false; } } /* Finalize NameServer module */ if (sysmgr_state.nameserver_init_flag == true) { status = nameserver_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : nameserver_destroy " "failed [0x%x]", status); } else { sysmgr_state.nameserver_init_flag = false; } } /* Finalize Notify module */ if (sysmgr_state.notify_init_flag == true) { status = notify_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : sysmgr_destroy " "failed [0x%x]", status); } else { sysmgr_state.notify_init_flag = false; } } /* Finalize SharedRegion module */ if (sysmgr_state.sharedregion_init_flag == true) { status = sharedregion_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : " "sharedregion_destroy failed [0x%x]", status); } else { sysmgr_state.sharedregion_init_flag = false; } } /* Finalize ProcMgr module */ if (sysmgr_state.proc_mgr_init_flag == true) { status = proc_mgr_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : proc_mgr_destroy " "failed [0x%x]", status); } else { sysmgr_state.proc_mgr_init_flag = false; } } /* Finalize MultiProc module */ if (sysmgr_state.multiproc_init_flag == true) { status = multiproc_destroy(); if (status < 0) { printk(KERN_ERR "sysmgr_destroy : multiproc_destroy " "failed [0x%x]", status); } else { sysmgr_state.proc_mgr_init_flag = false; } } atomic_set(&sysmgr_state.ref_count, SYSMGR_MAKE_MAGICSTAMP(0)); exit: if (status < 0) { printk(KERN_ERR "sysmgr_destroy : Module was not initialized " "status = 0x%x]", status); } return status; } EXPORT_SYMBOL(sysmgr_destroy); /* * ======== sysmgr_set_boot_load_page ======== * Purpose: * Function to set the boot load page address for a slave. */ void sysmgr_set_boot_load_page(u16 proc_id, u32 boot_load_page) { struct sysmgr_boot_load_page *temp = \ (struct sysmgr_boot_load_page *) boot_load_page; /* Initialize the host config area */ sysmgr_state.boot_load_page[proc_id] = temp; temp->host_config.offset = -1; temp->host_config.valid = 0; temp->handshake = 0; } /* * ======== sysmgr_wait_for_scalability_info ======== * Purpose: * Function to wait for scalability handshake value. */ void sysmgr_wait_for_scalability_info(u16 proc_id) { VOLATILE struct sysmgr_boot_load_page *temp = \ sysmgr_state.boot_load_page[proc_id]; printk(KERN_ERR "sysmgr_wait_for_scalability_info: BF while temp->handshake:%x\n", temp->handshake); while (temp->handshake != SYSMGR_SCALABILITYHANDSHAKESTAMP) ; printk(KERN_ERR "sysmgr_wait_for_scalability_info:AF while temp->handshake:%x\n", temp->handshake); } /* * ======== sysmgr_wait_for_slave_setup ======== * Purpose: * Function to wait for slave to complete setup. */ void sysmgr_wait_for_slave_setup(u16 proc_id) { VOLATILE struct sysmgr_boot_load_page *temp = \ sysmgr_state.boot_load_page[proc_id]; while (temp->handshake != SYSMGR_SETUPHANDSHAKESTAMP) ; }