zynq7000 AMP双核IPC+SharedMem通信

27 篇文章 7 订阅

开始

接着上文,然后做双核通信,参考大佬
driver:

/*  dbox-ipc-dev.c - The simplest kernel module.

* Copyright (C) 2013 - 2016 Xilinx, Inc
*
*   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, see <http://www.gnu.org/licenses/>.

*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h> 
#include <linux/cdev.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>


#include <linux/of_irq.h>
#include <linux/fs.h>
#include <linux/fcntl.h> 
#include <../../arch/arm/mach-zynq/common.h>
#include <linux/irqchip/arm-gic.h> 

//extern int zynq_cpun_stop(int cpu);

/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
    ("Xilinx Inc.");
MODULE_DESCRIPTION
    ("dbox-ipc-dev - loadable module template generated by petalinux-create -t modules");

#define DRIVER_NAME "dbox-ipc-dev"
#define DRIVER_NUM 1

/* Simple example of how to receive command line parameters to your module.
   Delete if you don't need them */
unsigned myint = 0xdeadbeef;
char *mystr = "default";

module_param(myint, int, S_IRUGO);
module_param(mystr, charp, S_IRUGO);

#define StarCpu1			0x10000000
#define StopCpu1			0x20000000
#define KickCpu1			0x30000000

struct dbox_ipc_dev_local {
	int irq;
	int cpu0_to_cpu1_ipi;
	int cpu1_to_cpu0_ipi;
	unsigned long mem_start;
	unsigned long mem_end;
	void __iomem *base_addr;
};

struct dbox_ipc_dev 
{ 
	dev_t devid;                   /*  设备号  */ 
	struct cdev chdev;            	/* cdev 结构体  */ 
	struct class *class;         	/*  类  */ 
	struct device *device;     		/*  设备  */ 
	struct dbox_ipc_dev_local *param;
	struct fasync_struct *async_queue; 
};


static struct dbox_ipc_dev dbox_ipc_dev_;

static int dbox_ipc_dev_open(struct inode *inode, struct file *filp) 
{ 
	//cpu_up(1);
	printk("dbox_ipc_dev Dev: open success  \r\n"); 
					
	return 0; 
} 


static ssize_t dbox_ipc_dev_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt) 
{
	int ret; 
	
	ret = copy_from_user((unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)), buf, cnt);  
	
	if(0 > ret)
	{
		printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data from user space \r\n"); 
		return -EFAULT; 			
	}
	
	printk("dbox_ipc_dev_ Dev: write add: %08X  cnt: %d\r\n",(unsigned int)(dbox_ipc_dev_.param->base_addr + (*offt)),cnt); 
	
	*offt = *offt + cnt;
	
	return cnt;
}

static ssize_t dbox_ipc_dev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) 
{ 
	int ret = 0; 
	
	ret = copy_to_user(buf, (unsigned char*)(dbox_ipc_dev_.param->base_addr + (*offt)) , cnt); 
	
	if(ret < 0)
	{ 
		printk(KERN_ERR "dbox_ipc_dev_ Dev: Failed to copy data to user space \r\n"); 
	} 
	
	*offt = *offt + cnt;
	
	return cnt;  
}

static long dbox_ipc_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg) 
{
	int ret = 0; 
	printk("cmd %d \n" ,cmd);
	switch(cmd)
	{
	case StarCpu1:
		ret = cpu_down(1);
		if (ret && (ret != -EBUSY)) 
		{
			printk("Can't release cpu1 %d\n",ret);
			return ret;
		}
		//zynq_cpun_stop(1);
		zynq_cpun_start((u32)dbox_ipc_dev_.param->mem_start, 1);
		printk("StarCpu1\n");
		break;		
	case StopCpu1:	
		ret = cpu_up(1);
		if (ret)
		{
			printk("Can't power on cpu1 %d\n", ret);
		}
		printk("StopCpu1\n");
		break;
	case KickCpu1:
		gic_raise_softirq(cpumask_of(1), dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
		printk("KickCpu %d  %d \n",1,dbox_ipc_dev_.param->cpu0_to_cpu1_ipi);
		break;		
	}
	return 0;
}
/*********************************************************************
*
*
*
**********************************************************************/
loff_t dbox_ipc_dev_llseek(struct file *filp, loff_t off, int whence)
{
	loff_t newpos;
	switch(whence)
	{
	case 0: /* SEEK_SET */
		newpos = off;    
		break;
	case 1: /* SEEK_CUR */
	    newpos = filp->f_pos + off;
	    break;
	case 2: /* SEEK_END */
		if(whence>0)
			newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start);
		else
			newpos = (dbox_ipc_dev_.param->mem_end - dbox_ipc_dev_.param->mem_start)+ whence;		
	    break;
	default: /* can't happen */
	    return -EINVAL;
	}

	if (newpos < 0)
	    return -EINVAL;
	
	filp->f_pos = newpos;

	return newpos;
}
/*********************************************************************
*
*
*
**********************************************************************/
static int dbox_ipc_dev_fasync(int fd, struct file *filp, int on) 
{
	return fasync_helper(fd, filp, on, &dbox_ipc_dev_.async_queue); 
}
/*********************************************************************
*
*
*
**********************************************************************/
static int dbox_ipc_dev_fasync_release(struct inode *inode, struct file *filp) 
{
	return dbox_ipc_dev_fasync(-1, filp, 0); 
}
/*********************************************************************
*
*
*
**********************************************************************/
static struct file_operations dbox_ipc_dev_fops = 
{ 
	.owner = THIS_MODULE, 
	.open = dbox_ipc_dev_open, 
	.write = dbox_ipc_dev_write, 
	.read = dbox_ipc_dev_read, 
	.unlocked_ioctl = dbox_ipc_dev_ioctl, 
	.llseek = dbox_ipc_dev_llseek, 
	.fasync = dbox_ipc_dev_fasync, 
	.release = dbox_ipc_dev_fasync_release, 
 }; 
/*********************************************************************
*
*
*
**********************************************************************/
static int dbox_ipc_dev_param_init(struct dbox_ipc_dev_local *nd) 
{ 
	dbox_ipc_dev_.param = nd;	
	cpu_down(1);
	return 0;
}
/*********************************************************************
*
*IPI 中断通知Linux CPU0 有信息要处理
*
**********************************************************************/
static void cpu1_to_cpu0_ipi_kick(void)
{
	//printk("[dbox]-->>ipi %d \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
	if(dbox_ipc_dev_.async_queue) 
	{
		printk("ipi %d  kick SIGIO \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
		kill_fasync(&dbox_ipc_dev_.async_queue, SIGIO, POLL_IN); 
	}
	else
	{
		printk("ipi %d kick but async_queue is null \n",dbox_ipc_dev_.param->cpu1_to_cpu0_ipi);
	}
}

static irqreturn_t dbox_ipc_dev_irq(int irq, void *lp)
{
	printk("dbox-ipc-dev interrupt\n");
	return IRQ_HANDLED;
}

static int dbox_ipc_dev_probe(struct platform_device *pdev)
{
	struct resource *r_irq; /* Interrupt resources */
	struct resource *r_mem; /* IO mem resources */
	struct device *dev = &pdev->dev;
	struct dbox_ipc_dev_local *lp = NULL;

	int rc = 0;
	dev_info(dev, "Device Tree Probing\n");
	printk("---->>>>>dbox ipc dev Device Tree Probing\n");
	/* Get iospace for the device */
	r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!r_mem) {
		dev_err(dev, "invalid address\n");
		return -ENODEV;
	}
	lp = (struct dbox_ipc_dev_local *) kmalloc(sizeof(struct dbox_ipc_dev_local), GFP_KERNEL);
	if (!lp) {
		dev_err(dev, "Cound not allocate dbox-ipc-dev device\n");
		return -ENOMEM;
	}
	dev_set_drvdata(dev, lp);
	lp->mem_start = r_mem->start;
	lp->mem_end = r_mem->end;

	if (!request_mem_region(lp->mem_start,
				lp->mem_end - lp->mem_start + 1,
				DRIVER_NAME)) {
		dev_err(dev, "Couldn't lock memory region at %p\n",
			(void *)lp->mem_start);
		rc = -EBUSY;
		goto error1;
	}

	lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
	if (!lp->base_addr) {
		dev_err(dev, "dbox-ipc-dev: Could not allocate iomem\n");
		rc = -EIO;
		goto error2;
	}

	lp->cpu0_to_cpu1_ipi = 12;
	lp->cpu1_to_cpu0_ipi = 13;//默认值

	/* Read ipi12 ipi number 用于 ucos 通知 linux */
	rc = of_property_read_u32(pdev->dev.of_node, "ipi12",&lp->cpu1_to_cpu0_ipi);
	if (rc < 0) 
	{
		dev_err(&pdev->dev, "unable to read property ipi 12");
		goto error3;
	}
	rc = set_ipi_handler(lp->cpu1_to_cpu0_ipi, cpu1_to_cpu0_ipi_kick,"cpu 1 kick cpu0");
	if (rc) 
	{
		dev_err(&pdev->dev, "IPI 12 handler already registered\n");
		goto error3;
	}
	/* Read ipi13 ipi number 用于 linux 通知 ucos */
	rc = of_property_read_u32(pdev->dev.of_node, "ipi13",&lp->cpu0_to_cpu1_ipi);
	if (rc < 0) 
	{
		dev_err(&pdev->dev, "unable to read property ipi 13");
		goto error3;
	}
	printk("dbox_ipc_dev_device at 0x%08x mapped to 0x%08x len= %08X , ipi= %d\n",
		(unsigned int __force)lp->mem_start,
		(unsigned int __force)lp->base_addr,
		(unsigned int __force)(lp->mem_end - lp->mem_start+1),
		lp->cpu0_to_cpu1_ipi);

	//dev_info(dev,"dbox-ipc-dev at 0x%08x mapped to 0x%08x, irq=%d\n",
	//	(unsigned int __force)lp->mem_start,
	//	(unsigned int __force)lp->base_addr,
	//	lp->irq);
		
	
	dbox_ipc_dev_param_init(lp); 
	
	rc = alloc_chrdev_region(&dbox_ipc_dev_.devid, 0, DRIVER_NUM, DRIVER_NAME); 
	if(rc)
	{
		dev_err(&pdev->dev, "unable to alloc_chrdev_region ");
	}
	
	dbox_ipc_dev_.chdev.owner = THIS_MODULE; 
	cdev_init(&dbox_ipc_dev_.chdev, &dbox_ipc_dev_fops); 
	
	rc = cdev_add(&dbox_ipc_dev_.chdev, dbox_ipc_dev_.devid, 1); 
	if(rc)
	{
		dev_err(&pdev->dev, "unable to cdev_add ");
	}	
	
	dbox_ipc_dev_.class = class_create(THIS_MODULE, DRIVER_NAME); 
	if (IS_ERR(dbox_ipc_dev_.class)) 
	{ 
		dev_err(&pdev->dev, "unable to class_create ");
	} 	
	
	dbox_ipc_dev_.device = device_create(dbox_ipc_dev_.class, &pdev->dev,dbox_ipc_dev_.devid, NULL, DRIVER_NAME); 
	if (IS_ERR(dbox_ipc_dev_.device)) 
	{ 
		dev_err(&pdev->dev, "unable to device_create ");
	}
	

	/* Get IRQ for the device */
	/*
	r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!r_irq) {
		dev_info(dev, "no IRQ found\n");
		dev_info(dev, "dbox-ipc-dev at 0x%08x mapped to 0x%08x\n",
			(unsigned int __force)lp->mem_start,
			(unsigned int __force)lp->base_addr);
		return 0;
	}
	lp->irq = r_irq->start;
	rc = request_irq(lp->irq, &dbox_ipc_dev_irq, 0, DRIVER_NAME, lp);
	if (rc) {
		dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
			lp->irq);
		goto error3;
	}*/
	return 0;
error3:
	clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
	//free_irq(lp->irq, lp);
error2:
	release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
	kfree(lp);
	dev_set_drvdata(dev, NULL);
	return rc;
}

static int dbox_ipc_dev_remove(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct dbox_ipc_dev_local *lp = dev_get_drvdata(dev);
	//free_irq(lp->irq, lp);
	device_destroy(dbox_ipc_dev_.class, dbox_ipc_dev_.devid); 
	class_destroy(dbox_ipc_dev_.class); 	
	cdev_del(&dbox_ipc_dev_.chdev); 	
	unregister_chrdev_region(dbox_ipc_dev_.devid, DRIVER_NUM); 	
	clear_ipi_handler(lp->cpu0_to_cpu1_ipi);
	iounmap(lp->base_addr);
	release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
	kfree(lp);
	dev_set_drvdata(dev, NULL);
	return 0;
}

//#ifdef CONFIG_OF
static struct of_device_id dbox_ipc_dev_of_match[] = {
	{ .compatible = "dbox,dbox-ipc-dev", },
	{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, dbox_ipc_dev_of_match);
//#else
//# define dbox_ipc_dev_of_match
//#endif


static struct platform_driver dbox_ipc_dev_driver = {
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table	= dbox_ipc_dev_of_match,
	},
	.probe		= dbox_ipc_dev_probe,
	.remove		= dbox_ipc_dev_remove,
};

static int __init dbox_ipc_dev_init(void)
{
	printk("<1>Hello module world.\n");
	printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,
	       mystr);

	return platform_driver_register(&dbox_ipc_dev_driver);
}


static void __exit dbox_ipc_dev_exit(void)
{
	platform_driver_unregister(&dbox_ipc_dev_driver);
	printk(KERN_ALERT "Goodbye module world.\n");
}

module_init(dbox_ipc_dev_init);
module_exit(dbox_ipc_dev_exit);

设备树

	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;
		
		reserved: buffer@0x10000000 {
			no-map;
			reg = <0x10000000 0x10000000>;		
		};	
	};

	reserved-driver@0 {
		compatible = "xlnx,reserved-memory";
      	memory-region = <&reserved>;
	};
	   
	dbox_ipc_dev_instance: dbox_ipc_dev@0 {
		compatible = "dbox,dbox-ipc-dev";
		reg = <0x10000000 0x0f000000>;
		ipi12 = <12>;
		ipi13 = <13>;	
	};

裸机代码:

/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include <sleep.h>
#include  <stdio.h>
#include <xil_cache.h>
#include "xgpiops.h"
#include "xil_io.h"
#include "xscugic.h"
#define  SGI0_INTR_ID  0
#define  SGI1_INTR_ID  1
#define  SGI2_INTR_ID  2
#define  SGI3_INTR_ID  3
#define  SGI4_INTR_ID  4
#define  SGI5_INTR_ID  5
#define  SGI6_INTR_ID  6
#define  SGI7_INTR_ID  7
#define  SGI8_INTR_ID  8
#define  SGI9_INTR_ID  9
#define  SGI10_INTR_ID  10
#define  SGI11_INTR_ID  11
#define  SGI12_INTR_ID  12
#define  SGI13_INTR_ID  13
#define  SGI14_INTR_ID  14
#define  SGI15_INTR_ID  15

#define  ICDSGIR  0xF8F01F00
#define  ICDIPTR  0xF8F01800

#define  INTC_DEVICE_ID   XPAR_PS7_SCUGIC_0_DEVICE_ID
XScuGic InterruptController; /* Instance of the Interrupt Controller */
u32 SGI_INTR;

int SGI_trigered;
void  SGI0_INTR_ID_ISR (void);

#define SHARD_MEM_START_ADDR  0x10000000
static void* get_shared_mem_data_ptr(int offset)
{
	//Xil_DCacheFlushRange(SHARD_MEM_START_ADDR, 0x00100000);
	Xil_DCacheInvalidateRange((u32)SHARD_MEM_START_ADDR, 0x0f000000);
	return (void *)SHARD_MEM_START_ADDR;
}

u32 SetupSGIIntrSystem(XScuGic *IntcInstancePtr,Xil_InterruptHandler Handler, u32 DeveiceId, u32 SgiIntr, u32 CpuNo)
{
    int Status;
    XScuGic_Config *IntcConfig;
	IntcConfig =  XScuGic_LookupConfig(DeveiceId);
    if (NULL  == IntcConfig)
    {
        return XST_FAILURE;
    }
    Status =  XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,IntcConfig->CpuBaseAddress);
    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }
    XScuGic_SetPriorityTriggerType(IntcInstancePtr, SgiIntr,0xd0, 0x3);
    Status =  XScuGic_Connect(IntcInstancePtr, SgiIntr, (Xil_ExceptionHandler)Handler,0);
    if (Status != XST_SUCCESS)
    {
        return XST_FAILURE;
    }
    XScuGic_Enable(IntcInstancePtr, SgiIntr);
    XScuGic_InterruptMaptoCpu(IntcInstancePtr,CpuNo,SgiIntr);
    return XST_SUCCESS;
}

void  ExceptionSetup(XScuGic *IntcInstancePtr)
{
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,IntcInstancePtr);
    Xil_ExceptionEnable();
}

void  SGI1_INTR_ID_ISR (void* data)
{
	xil_printf("CPU0---->CPU1: The software interrupt0 has been triggered-->>\n\r");
	char* mem = (char *)get_shared_mem_data_ptr(0);
	xil_printf("\tdata-> %d, %d, %d, %d\n\r", mem[0], mem[1], mem[2], mem[3]);
    SGI_trigered=1;
}

int main()
{
    init_platform();
    Xil_DCacheDisable();
    int index = 10;
    while (--index) {
    	xil_printf("--->>>Hello main wait cpu0-->>>>>\n\r");
    	sleep(1);
    }
    int Status;
    SGI_INTR=SGI13_INTR_ID;
    SGI_trigered=0;
    Status =  SetupSGIIntrSystem(&InterruptController,(Xil_ExceptionHandler)SGI1_INTR_ID_ISR,INTC_DEVICE_ID, SGI_INTR,CPU_NO1);
    if (Status != XST_SUCCESS)
    {
    	xil_printf("FAILED Xil_ExceptionHandler \n\r");
    }
    ExceptionSetup(&InterruptController);
    while (1) {
    	sleep(3);
    	XScuGic_SoftwareIntr(&InterruptController, SGI12_INTR_ID, 0x1 << CPU_NO0);
    	xil_printf("--->>>echo ipi to cpu0-->>>>> %d\n\r", ++index);
    }

    cleanup_platform();
    return 0;
}

app

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值