Help required for QNX PCI driver

:question:

I am writing a QNX driver for PCI device. I am using QNX 6.2.1A OS

my main function works as follows:

  1. attach pci server
  2. Detect and attach the device using pci_attach_device()
  3. Read the BAR0 offset using pci_read_config into a variable addr
  4. map the memory address addr to process address space . I tried allocation using both mmap and mmap_device_memory. The handle for address is stored in mem_hndl (pointer to void).
  5. try to read and write at various offsets from mem_hndl
  6. Unmap device memory
  7. detach device
  8. detach pci server

my problem is
when i read the device as in step 5:
I get 0xffffffff at any offset irrespective of what i read or write if memory has been mapped using mmap_devicce_memory
if i use mmap to map memory of device, i am able to read and write
but the problem is that I perform soft reset of device by writing to a bit of request register (mapped into memory) and this value stays same after reset.
I am not sure whether my map is correct when i using mmap and
I want to know what is the problem with mmap_device_memory return base because I cannot write to this map nor read from it? I use PROT_WRITE|PROT_READ|PROT_NOCACHE for protection pqrameter

Please help me in this regard

Regards
Moreshwar

As always, the devil is in the details. Post the actual code you are using and I am sure someone will point out any problems with it.

Also check to make sure the results from the pci_*() calls match what ‘pci -v’ shows for the values.

Rick…

Sorry forgot to attach code. The output matches pci -v. I posted this meesage to other forum as I need an urgent reply sory if that caused any inconvenience to anybody
The code is as follows:

#include <sys/neutrino.h>
#include <hw/pci.h>
#include <hw/pci_devices.h>
#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>

struct pci_dev_info inf;

#define HOTICE_CARD_DEVICE_ID 0x8478
#define HOTICE_CARD_VENDOR_ID 0x14f1
#define FUNC0_BAR_START ((void*)0x00900000)
int phndl;
void* hndl;
uint32_t addr;
void*mem_hndl;
uint32_t addr_hndl;
void pci_debug(struct pci_dev_info *inf);
void pci_give_command(uint16_t pci_command, struct pci_dev_info *inf);
int hdlc_detect_card(void);
void remove_card(struct pci_dev_info *inf);

//int main(int argc, char *argv)
int main(int argc, char *argv)
{
	hdlc_detect_card();
	remove_card(&inf);
	
	
}
void pci_debug(struct pci_dev_info *inf)
{
	uint32_t i;
fprintf(stdout,"\n device id=%x",inf->DeviceId);
fprintf(stdout,"\n Vendo id=%x",inf->VendorId);
fprintf(stdout,"\n BusNumber=%x",inf->BusNumber);
fprintf(stdout,"\n device function=%x",inf->DevFunc);
fprintf(stdout,"\n device class=%x",inf->Class);
fprintf(stdout,"\n device irq=%x",inf->Irq);
fprintf(stdout,"\n pcibase address =%x",(*(inf->CpuBaseAddress)));
//addr_hndl=(uint32_t*)(*(inf->CpuBaseAddress));
fprintf(stdout,"\n base address size=%x",(*(inf->BaseAddressSize)));
pci_read_config32(inf->BusNumber,inf->DevFunc,0x10,1,&i);
fprintf(stdout,"\n base address 0=%x",i);
pci_read_config32(inf->BusNumber,inf->DevFunc,0x14,1,&i);
fprintf(stdout,"\n base address 1=%x",i);
pci_read_config32(inf->BusNumber,inf->DevFunc,0x18,1,&i);
fprintf(stdout,"\n base address 2=%x",i);
pci_read_config32(inf->BusNumber,inf->DevFunc,0x1c,1,&i);
fprintf(stdout,"\n base address 3=%x",i);
pci_read_config32(inf->BusNumber,inf->DevFunc,0x20,1,&i);
fprintf(stdout,"\n base address 4=%x",i);
pci_read_config32(inf->BusNumber,inf->DevFunc,0x24,1,&i);
fprintf(stdout,"\n base address 5=%x",i);

}

void pci_give_command(uint16_t pci_command, struct pci_dev_info *inf)
{
uint16_t test_read;
//fprintf(stdout,"\n pci command register ip=%x",pci_command);
pci_write_config16(inf->BusNumber,inf->DevFunc,0x04,1,&pci_command);
pci_read_config16(inf->BusNumber,inf->DevFunc,0x06,1,&test_read);
fprintf(stdout,"\n pci command register ip=%x",pci_command);
fprintf(stdout,"\n pci command register op =%x",test_read);

}
int hdlc_detect_card(void)
{
	volatile uint32_t *x;
	volatile int status;
	volatile int pidx=0;
	int flg;
	unsigned device=HOTICE_CARD_DEVICE_ID;
	unsigned vendor=HOTICE_CARD_VENDOR_ID;
	unsigned index=1;
	unsigned bus;
	unsigned dev;
	unsigned func;
	unsigned dev_func;
	
	memset( &inf, 0, sizeof( inf ) );
	inf.VendorId= HOTICE_CARD_VENDOR_ID;
	inf.DeviceId= HOTICE_CARD_DEVICE_ID;
	ThreadCtl( _NTO_TCTL_IO, 0 );
	phndl=pci_attach(0);
	if (-1==phndl)
		fprintf(stderr,"\n unable to attach pci");
	else
	{
		status=pci_find_device( device,vendor,index,&bus,&dev_func );
		if (status!=PCI_SUCCESS)
		{
			fprintf(stderr,"\n device not found");
		}
		else
		{
			dev=(dev_func&0xf8)>>3;
			func=dev_func&0x07;
			fprintf(stdout,"\n BusNumber=%x",bus);
			fprintf(stdout,"\n device function=%x",func);
			fprintf(stdout,"\n device dev_function=%x",dev_func);
			fprintf(stdout,"\n device number=%x",dev);	
		}
		hndl=pci_attach_device(NULL,(PCI_SHARE|PCI_SEARCH_VENDEV|PCI_INIT_ALL),pidx,&inf);
//        hndl = pci_attach_device( NULL, (PCI_SEARCH_VENDEV|PCI_INIT_ALL), pidx, &inf );
		if(NULL==hndl)
		{
			fprintf(stderr,"\n Erro code %x, implies %s",errno,sys_errlist[errno]);
			return errno;
		}
		//pci_debug(&inf);
		status =pci_read_config32(inf.BusNumber,inf.DevFunc,0x10,1,&addr);
		if (PCI_SUCCESS!=status)
		{
			fprintf(stderr,"\n error reading config space 0 BAR2");
		}
		else
		{
		fprintf(stdout,"\n  reading config space 0 BAR2, addr is =%x",addr);
		addr_hndl=PCI_MEM_ADDR(addr);
		fprintf(stdout,"\n  config space 0 BAR2 addr is =%x",addr_hndl);
//		flg=(/*MAP_PRIVATE|*/MAP_ANON|MAP_PHYS);
	flg=0;
#if 0
		mem_hndl=mmap(/*FUNC0_BAR_START*/NULL,(*(inf.BaseAddressSize)),(PROT_READ|PROT_WRITE/*|PROT_NOCACHE*/),flg,NOFD,(uint64_t)addr_hndl);
#endif
#if 1
		mem_hndl=mmap_device_memory(/*FUNC0_BAR_START*/NULL,(*(inf.BaseAddressSize)),(PROT_READ|PROT_WRITE/*|PROT_NOCACHE*/),flg,(uint64_t)addr_hndl);
#endif		
//		|MAP_BELOW16M
		if (MAP_FAILED==mem_hndl)
		{
			fprintf(stderr, "mmap failed : %s\n",strerror(errno));
			remove_card(&inf);
			return;
		}
		fprintf(stdout,"\n  config space 0 BAR2 map addr is =%x",mem_hndl);
		pci_give_command(0x384, &inf);
		x=(uint32_t*)(mem_hndl+0x0600);		
		*x=0x00000010;
		fprintf(stdout,"\n  1.base read addr =%x",x);
		fprintf(stdout,"\n  1.value at base read addr =%x",*x);
		x=(uint32_t*)(mem_hndl+0x0008);		
//		x=(uint32_t*)addr_hndl;
		*x=0x00000100;
		fprintf(stdout,"\n 2. base read addr =%x",x);
		fprintf(stdout,"\n  2.value at base read addr =%x",*x);
		x=(uint32_t*)(mem_hndl+0x0600);		
//		*x=0x00000010;
		fprintf(stdout,"\n  3.base read addr =%x",x);
		fprintf(stdout,"\n  3.value at base read addr =%x",*x);
		x=(uint32_t*)(mem_hndl+0x0008);		
//		x=(uint32_t*)addr_hndl;
		*x=0x00000000;
		fprintf(stdout,"\n  4.base read addr =%x",x);
		fprintf(stdout,"\n  4.value at base read addr =%x",*x);
/*Interrupt Status Descriptor*/
		x=(uint32_t*)(mem_hndl+0x000C);		
		while (*x==0x00)
		{
			fprintf(stdout,"\n  5.base read addr =%x",x);
			fprintf(stdout,"\n  5.value at base read addr =%x",*x);
			}
		}
	}
}

void remove_card(struct pci_dev_info *inf)
{
	int status;
	if (MAP_FAILED!=mem_hndl)
	{
//		status = munmap(mem_hndl,(*(inf->BaseAddressSize)));
		status = munmap_device_memory(mem_hndl,(*(inf->BaseAddressSize)));
		if (-1==status)
		{
			fprintf(stderr, "munmap failed : %s\n",strerror(errno));
		}
	}
		status=pci_detach_device(hndl);
		if (PCI_SUCCESS!=status)
		{
			fprintf(stderr, "detach device failed status =%x : %s\n",status,strerror(errno));
		}
		status=pci_detach(phndl);
		if (PCI_SUCCESS!=status)
		{
			fprintf(stderr, "detach device failed status =%x : %s\n",status,strerror(errno));
		}

}

Wow, that code is hard to read when it is not formatted. Try wrapping it in {code] … {/code] tags (replace the { with [) and it should be easier next time.

Anyway, off the top of my head, it looks like you are using the size from BAR0 (*(inf.BaseAddressSize)) while mapping the BAR2 address?

It is a little hard to follow. If that isn’t the problem, post the matching output when you run as well so I can follow the code path.

Rick…

I am using BAR 0 indeed. I wanted to test this code with another device that has more registers with BAR 2 so code contains BAR2 but this never materialized :frowning: .
Anyway I am attaching my code again in image format hope this helps in understanding the code more easily till I get convesion from { to [ as mentioned. I am also attaching image of output . (the c source and output as text in zip attachment).
Hope it works in solving my problem. The code was written using ped and Workspace editor and compiled with qcc (or cc)
The outputs are two different. One for mmap_device_memory
and another for mmap.
for mmap_device_memory variable flgs is set to 0 and for mmap it is MAP_ANON|MAP_PHYS
when using mmap unampping is using munmap and with mmap_device_memory is it using munmapo_device_memory
The following files are attached:

  1. pcitest.c the intended file
  2. pcitest_mmap.c file using mmap function
  3. pcitest_mmap_device_memory.c using mmap_device_memory function
  4. pciinfo.txt: relevant output of pci -vvv
  5. mmap.txt output
  6. mmap_device.txt using mmap_device_memory function

I will convert code to [ before posting sorry no debug comments. will attach and resend.

Regards
Moreshwar

In your mmap() example, you are using MAP_ANON, which is giving you a chunk of shared memory (which of course you can read/write). In the other case, it appears to map the memory, but without more info about the board, I have no idea if the address (offset) you are trying to read/write is writable. You may also want to use the NOCACHE flag in case that matters.

Rick…

To make life easier, use the mmap_device_memeory and mmap_device_io functions instead of straight mmap().

Hello,

Managed to get the pci card detected. The problem was that I was being stupid. I did not realize that the device did not enable memory access be default (in PCI command register). Once I did it, it worked. You have to use mmap_device_memory_only. mmap does not work. Thanks to all for their valuable inputs and making me feel confident that the method was right.
Now I have bigger and last problem. The problem is how to map the Linux sk_buff structure (declared and defined in linux/skbuff.h) to QNX. I am seeing npkt_t structure. What should I use? The npkt_t structure seems quite different from linux sk_buff structure!!

Thanks in advance
Regards
Moreshwar

Hi,

Indeed memory access is not enabled by default. Can you also tell us how you enabled it, it would be a great help and really helpfull.

Thanks in advance

Well you have to give command via PCI command register in Configuration space. You may enable I/O or memory or both as applicable by writing bits 0 and 1 of the said register. The requirement is hardware should have memory decoder to use these bits

could you please be more specific?

I have declared a _pci_regs_config structure for this purpose. Does writing to the Command register within that structure write to the PCI Command Register? Is some kind of initialisation required for the structure?

It would help a lot to see your working code on this thread, since we already have seen the one which did not work. It will help in comparing notes. Could you please post your corrected code?

Thanks
Ninad