Page 1 of 1

PCI :read config space get wrong code

Posted: Fri Jun 10, 2016 10:56 pm
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

Re: PCI :read config space get wrong code

Posted: Sat Jun 11, 2016 1:37 am
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.

Re: PCI :read config space get wrong code

Posted: Sat Jun 11, 2016 2:34 am
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.

Re: PCI :read config space get wrong code

Posted: Sat Jun 11, 2016 3:18 pm
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.

Re: PCI :read config space get wrong code

Posted: Sat Jun 11, 2016 11:34 pm
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.