开始
接着上文,然后做双核通信,参考大佬
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