PCI :read config space get wrong code

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
firekylin
Posts: 11
Joined: Thu Jun 09, 2016 11:41 pm

PCI :read config space get wrong code

Post by firekylin »

hi , I want to read some thing about PCI ,first I scan the bus 0 , and print there info . but get the wrong munber (I think)

Code: Select all

/*
 *    include/firekylin/pci.h
 *
 *    Copyright (C) 2016 ximo<[email protected]>
 */

#ifndef _PCI_H
#define _PCI_H

#define PCI_CONFIG_ADDR_PORT	0xCF8
#define PCI_CONFIG_DATA_PORT	0xCFC

/* offset in pic config space */
#define PCI_VENDOR_ID		0x00
#define PCI_DEVICE_ID		0x02
#define PCI_COMMAND		0x04
#define PCI_STATUS		0x06
#define PCI_REVISION_ID		0x08
#define PCI_PROG_IF		0x09
#define PCI_SUBCLASS		0x0a
#define PCI_CLASSCODE		0x0b
#define PCI_CACHE_LINE_SIZE	0x0c
#define PCI_LATENCY_TIMER	0x0d
#define PCI_HEADER_TYPE		0x0e
#define PCI_BIST		0x0f
#define PCI_BAR0		0x10
#define PCI_BAR1		0x14
#define PCI_BAR2		0x18
#define PCI_BAR3		0x1C
#define PCI_BAR4		0x20
#define PCI_BAR5		0x24

#define PCI_INTERRUPT_LINE	0x3C

typedef int 	pci_dev_t; 	/* pci config addr base */

struct pci_device{
	pci_dev_t	pci_dev;
	short		pci_vendor_id;
	short		pci_device_id;
};

#include <firekylin/portio.h>

static inline pci_dev_t pci_dev(char bus, char slot, char func)
{
	return (pci_dev_t) ((bus << 16) | (slot << 11) | (func << 8));
}

static inline
unsigned int pci_read_config(pci_dev_t pci_dev, char offset)
{
	outl(PCI_CONFIG_ADDR_PORT, 0x80000000 | pci_dev | (offset & 0xfc));
	return inl(PCI_CONFIG_DATA_PORT);
}

static inline
unsigned short pci_read_config_word(pci_dev_t pci_dev, char offset)
{
	union {
		unsigned int ret_i;
		unsigned short ret_s[2];
	} ret;

	ret.ret_i = pci_read_config(pci_dev, offset);

	if ((offset % 3) == 0)
		return ret.ret_s[0];
	else if ((offset % 3) == 2)
		return ret.ret_s[1];
	else
		return 0x7777;
}

static inline
unsigned char pci_read_config_byte(pci_dev_t pci_dev, char offset)
{
	union {
		unsigned int ret_i;
		unsigned char ret_c[4];
	} ret;

	ret.ret_i = pci_read_config(pci_dev, offset);

	if ((offset % 3) == 0)
		return ret.ret_c[0];
	else if ((offset % 3) == 1)
		return ret.ret_c[1];
	else if ((offset % 3) == 2)
		return ret.ret_c[2];
	else if ((offset % 3) == 3)
		return ret.ret_c[3];
	else
		return 0xff;
}

#endif

Code: Select all

/*
 *    driver/pci.c
 *
 *    Copyright (C) 2016 ximo<[email protected]>
 */

#include <firekylin/kernel.h>
#include <firekylin/pci.h>

#define MAX_PCI_DEVICE		32

int pci_device_count;

struct pci_device pci_device_table[MAX_PCI_DEVICE];

/*
 * only scan the 0 bus.
 */
void pci_init(void)
{
	char bus = 0;
	char slot;
	char func;
	unsigned short vendor_id;
	unsigned short device_id;

	printk("sacn pci:\n  vendor_id\t device_id\t slot\t func\n");
	for (slot = 0; slot < 32; slot++) {
		for (func = 0; func < 8; func++) {
			vendor_id = pci_read_config_word(
					pci_dev(bus, slot, func), 0);
			if (vendor_id == 0xffff)
				continue;
			device_id = pci_read_config_word(
					pci_dev(bus, slot, func), 2);
			printk("  %x\t  %x\t %x\t %x --%x\n", vendor_id,
					device_id, slot, func,
					pci_read_config(
							pci_dev(bus, slot,
									func),
							0));
		}
	}
}
QQ图片20160611124935.png
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: PCI :read config space get wrong code

Post by iansjack »

Without wading through all your code I notice that every time the vendor_id is greater than 0x8000 you get a device_id of 0xFFFF and when it is less than 0x8000 you get 0x0000. This looks to me as if you are reading a 16-bit signed value into a 32-bit signed variable. The upper 16 bits are then being expanded into all 1s for a negative value and all 0s for a positive value.
firekylin
Posts: 11
Joined: Thu Jun 09, 2016 11:41 pm

Re: PCI :read config space get wrong code

Post by firekylin »

iansjack wrote:Without wading through all your code I notice that every time the vendor_id is greater than 0x8000 you get a device_id of 0xFFFF and when it is less than 0x8000 you get 0x0000. This looks to me as if you are reading a 16-bit signed value into a 32-bit signed variable. The upper 16 bits are then being expanded into all 1s for a negative value and all 0s for a positive value.
ok ,thank you ,I have found the mistake of my code.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: PCI :read config space get wrong code

Post by Combuster »

Code: Select all

    for (slot = 0; slot < 32; slot++) {
      for (func = 0; func < 8; func++) {
You should not be trying func>0 on PCI devices that aren't multifunction ones. You''ll get duplicates and other weird issues that way.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: PCI :read config space get wrong code

Post by SpyderTL »

Combuster wrote:You should not be trying func>0 on PCI devices that aren't multifunction ones. You''ll get duplicates and other weird issues that way.
This might explain why I get a ton of PCI-to-PCI bridge devices when enumerating the PCI bus on my HP laptop, and not in any of my VMs.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Post Reply