new device model from Ron

This tree shows the new model. It demonstrates the constructor array
in use, for devices that are and are not specified in the dts. It
introduces a new generic structure, device_id, analogous to
device_path, which can describe all the types of device IDs we have.
It shows a way to set up arrays of structs, in the dts, for the
constructors, so we avoid ldscript hacks.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>



git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@233 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
Stefan Reinauer 2007-03-10 15:55:41 +00:00
commit 6869f4a129
19 changed files with 532 additions and 144 deletions

View file

@ -114,7 +114,6 @@ STAGE2_LIB_OBJ = $(obj)/stage2.o $(obj)/clog2.o $(obj)/mem.o $(obj)/malloc
$(obj)/tables.o $(obj)/delay.o $(obj)/compute_ip_checksum.o
STAGE2_ARCH_X86_OBJ = $(obj)/archtables.o $(obj)/linuxbios_table.o $(obj)/udelay_io.o
STAGE2_ARCH_X86_OBJ += $(obj)/pci_ops_auto.o $(obj)/pci_ops_conf1.o $(obj)/pci_ops_conf2.o
STAGE2_MAINBOARD_OBJ = $(obj)/mainboard.o
STAGE2_DYNAMIC_OBJ = $(obj)/statictree.o
STAGE2_OBJ := $(STAGE2_LIB_OBJ) $(STAGE2_DEVICE_OBJ) $(STAGE2_ARCH_X86_OBJ)

View file

@ -72,10 +72,96 @@ dev_init(void)
}
}
/**
* @brief The default constructor, which simply allocates and sets the ops pointer
*
* Allocte a new device structure and initalize device->ops.
*
* @param A pointer to a struct constructor
*
* @return pointer to the newly created device structure.
*
* @see
*/
struct device *default_device_constructor(struct constructor *constructor){
struct device *dev;
dev = malloc(sizeof(*dev));
if (dev == 0) {
die("DEV: out of memory.\n");
}
memset(dev, 0, sizeof(dev));
dev->ops = constructor->ops;
return dev;
}
/**
* @brief Given a path, find a constructor
*
* Given a path, locate the constructor for it from all_constructors
*
* @param path path to the device to be created.
*
* @return pointer to the constructor or 0, if none found
*
* @see device_path
*/
struct constructor *find_constructor(struct device_id *id){
extern struct constructor *all_constructors[];
struct constructor *c;
int i;
printk(BIOS_SPEW, "%s: find %s\n", __func__, dev_id_string(id));
for(i = 0; all_constructors[i]; i++) {
printk(BIOS_SPEW, "%s: check all_constructors[i] 0x%lx\n", __func__, all_constructors[i]);
for(c = all_constructors[i]; c->ops; c++) {
printk(BIOS_SPEW, "%s: cons 0x%lx, cons id %s\n", __func__, c, dev_id_string(&c->id));
if ((! c->ops) || (!c->ops->constructor)) {
printk(BIOS_ERR, "Constructor for %s with missing ops or ops->constructor!\n",
dev_id_string(&c->id));
continue;
}
if (id_eq(&c->id, id)){
printk(BIOS_SPEW, "%s: match\n", __func__);
return c;
}
}
}
return 0;
}
/**
* @brief Given a path, find a constructor, and run it
*
* Given a path, call find_constructor to find it call that
* constructor via constructor->ops->constructor, with itself as a parameter;
* return the result.
*
* @param path path to the device to be created.
*
* @return pointer to the newly created device structure.
*
* @see device_path
*/
struct device *constructor(struct device_id *id){
struct constructor *c;
struct device *dev = 0;
c = find_constructor(id);
printk(BIOS_INFO, "%s constructor is 0x%lx\n", __func__, c);
if (! c)
return 0;
dev = c->ops->constructor(c);
printk(BIOS_INFO, "%s returns 0x%lx\n", __func__, dev);
return dev;
}
/**
* @brief Allocate a new device structure.
*
* Allocte a new device structure and attached it to the device tree as a
* Allocate a new device structure and attached it to the device tree as a
* child of the parent bus.
*
* @param parent parent bus the newly created device attached to.
@ -86,7 +172,7 @@ dev_init(void)
* @see device_path
*/
//static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED;
struct device * alloc_dev(struct bus *parent, struct device_path *path)
struct device * alloc_dev(struct bus *parent, struct device_path *path, struct device_id *devid)
{
struct device * dev, *child;
int link;
@ -98,11 +184,15 @@ struct device * alloc_dev(struct bus *parent, struct device_path *path)
child = child->sibling;
}
dev = malloc(sizeof(*dev));
if (dev == 0) {
die("DEV: out of memory.\n");
}
memset(dev, 0, sizeof(*dev));
dev = constructor(devid);
if (! dev)
printk(BIOS_INFO, "%s: No constructor, going with empty dev", dev_id_string(devid));
dev = malloc(sizeof(*dev));
if (dev == 0) {
die("DEV: alloc_dev: out of memory.\n");
}
memset(dev, 0, sizeof(*dev));
memcpy(&dev->path, path, sizeof(*path));
/* Initialize the back pointers in the link fields */
@ -559,6 +649,7 @@ void dev_phase5(struct device *dev)
printk(BIOS_ERR, "%s: %s(%s) ops are missing phase5_enable_resources\n", __FUNCTION__, dev->dtsname, dev_path(dev));
return;
}
dev->ops->phase5_enable_resources(dev);
}
@ -597,13 +688,12 @@ void dev_phase1(void)
post_code(0x31);
for(dev = all_devices; dev; dev = dev->next) {
if (dev->ops && dev->ops->phase1)
if (dev->ops && dev->ops->phase1_set_device_operations)
{
dev->ops->phase1(dev);
dev->ops->phase1_set_device_operations(dev);
}
}
post_code(0x3e);
/* printk should be working at this point ... */
printk(BIOS_INFO, "Phase 1: done\n");
post_code(0x3f);
}
@ -623,19 +713,19 @@ void dev_phase2(void)
printk(BIOS_INFO, "Phase 2: Early setup...\n");
for(dev = all_devices; dev; dev = dev->next) {
printk(BIOS_SPEW, "%s: dev %s: ", __FUNCTION__, dev->dtsname);
if (dev->ops && dev->ops->phase1) {
printk(BIOS_SPEW, "Calling phase2 ..");
dev->ops->phase2(dev);
if (dev->ops && dev->ops->phase2_setup_scan_bus) {
printk(BIOS_SPEW, "Calling phase2 phase2_setup_scan_bus ..");
dev->ops->phase2_setup_scan_bus(dev);
printk(BIOS_SPEW, " DONE");
}
printk(BIOS_SPEW, "\n");
}
post_code(0x4e);
printk(BIOS_INFO, "Phase 2: Done.\n");
post_code(0x4f);
}
/**
* @brief Scan for devices on a bus.
*
@ -665,6 +755,10 @@ unsigned int dev_phase3_scan(struct device * busdevice, unsigned int max)
printk(BIOS_INFO, "%s: can not scan from here, returning %d\n", __FUNCTION__, max);
return max;
}
if (busdevice->ops->phase3_enable_scan)
busdevice->ops->phase3_enable_scan(busdevice);
do_phase3 = 1;
while(do_phase3) {
int link;
@ -715,8 +809,9 @@ void dev_root_phase3(void)
unsigned subordinate;
printk(BIOS_INFO, "Phase 3: Enumerating buses...\n");
root = &dev_root;
if (root->chip_ops && root->chip_ops->enable_dev) {
root->chip_ops->enable_dev(root);
if (root->ops && root->ops->phase3_enable_scan) {
root->ops->phase3_enable_scan(root);
}
post_code(0x41);
if (!root->ops) {

View file

@ -50,12 +50,12 @@ struct device * find_dev_path(struct bus *parent, struct device_path *path)
* @param path The relative path from the bus to the appropriate device
* @return pointer to a device structure for the device on bus at path
*/
struct device * alloc_find_dev(struct bus *parent, struct device_path *path)
struct device * alloc_find_dev(struct bus *parent, struct device_path *path, struct device_id *id)
{
struct device * child;
child = find_dev_path(parent, path);
if (!child) {
child = alloc_dev(parent, path);
child = alloc_dev(parent, path, id);
}
return child;
}
@ -145,6 +145,7 @@ struct device *dev_find_class(unsigned int class, struct device *from)
}
/* WARNING: NOT SMP-safe!*/
const char *dev_path(struct device * dev)
{
static char buffer[DEVICE_PATH_MAX];
@ -203,6 +204,54 @@ const char *dev_path(struct device * dev)
return buffer;
}
/* WARNING: NOT SMP-safe!*/
const char *dev_id_string(struct device_id *id)
{
static char buffer[DEVICE_ID_MAX];
buffer[0] = '\0';
if (!id) {
memcpy(buffer, "<null>", 7);
}
else {
switch(id->type) {
case DEVICE_ID_ROOT:
memcpy(buffer, "Root Device", 12);
break;
case DEVICE_ID_PCI:
sprintf(buffer, "PCI: %02x:%02x",id->u.pci.vendor, id->u.pci.device);
break;
case DEVICE_ID_PNP:
sprintf(buffer, "PNP: %04x", id->u.pnp.device);
break;
case DEVICE_ID_I2C:
sprintf(buffer, "I2C: %04x", id->u.i2c.id);
break;
case DEVICE_ID_APIC:
sprintf(buffer, "APIC: %02x:%02x",id->u.apic.vendor, id->u.apic.device);
break;
case DEVICE_ID_PCI_DOMAIN:
sprintf(buffer, "PCI_DOMAIN: %02x:%02x",id->u.pci_domain.vendor, id->u.pci_domain.device);
break;
case DEVICE_ID_APIC_CLUSTER:
sprintf(buffer, "APIC_CLUSTER: %02x:%02x",id->u.apic_cluster.vendor, id->u.apic_cluster.device);
break;
case DEVICE_ID_CPU:
sprintf(buffer, "CPU", id->u.cpu.cpuid[0], id->u.cpu.cpuid[1], id->u.cpu.cpuid[2]);
break;
case DEVICE_ID_CPU_BUS:
sprintf(buffer, "CPU_BUS: %02x:%02x",id->u.cpu_bus.vendor, id->u.cpu_bus.device);
break;
default:
printk(BIOS_ERR, "%s: Unknown device id type: %d\n", __func__, id->type);
memcpy(buffer, "Unknown", 8);
break;
}
}
return buffer;
}
const char *bus_path(struct bus *bus)
{
static char buffer[BUS_PATH_MAX];
@ -254,6 +303,49 @@ int path_eq(struct device_path *path1, struct device_path *path2)
return equal;
}
int id_eq(struct device_id *path1, struct device_id *path2)
{
int equal = 0;
if (path1->type == path2->type) {
switch(path1->type) {
case DEVICE_ID_NONE:
break;
case DEVICE_ID_ROOT:
equal = 1;
break;
case DEVICE_ID_PCI:
equal = (path1->u.pci.vendor == path2->u.pci.vendor) && (path1->u.pci.device == path2->u.pci.device);
break;
case DEVICE_ID_PNP:
equal = (path1->u.pnp.device == path2->u.pnp.device);
break;
case DEVICE_ID_I2C:
equal = (path1->u.i2c.id == path2->u.i2c.id);
break;
case DEVICE_ID_APIC:
equal = (path1->u.apic.vendor == path2->u.apic.vendor) && (path1->u.apic.device == path2->u.apic.device);
break;
case DEVICE_ID_PCI_DOMAIN:
equal = (path1->u.pci_domain.vendor == path2->u.pci_domain.vendor) && (path1->u.pci_domain.device == path2->u.pci_domain.device);
break;
case DEVICE_ID_APIC_CLUSTER:
equal = (path1->u.apic_cluster.vendor == path2->u.apic_cluster.vendor) && (path1->u.apic_cluster.device == path2->u.apic_cluster.device);
break;
case DEVICE_ID_CPU:
equal = (path1->u.cpu.cpuid == path2->u.cpu.cpuid);
break;
case DEVICE_ID_CPU_BUS:
equal = (path1->u.cpu_bus.vendor == path2->u.cpu_bus.vendor) && (path1->u.cpu_bus.device == path2->u.cpu_bus.device);
break;
default:
printk(BIOS_ERR, "Uknown device type: %d\n", path1->type);
break;
}
}
return equal;
}
/**
* See if we have unused but allocated resource structures.
* If so remove the allocation.
@ -538,9 +630,6 @@ void dev_set_enabled(struct device * dev, int enable)
if (dev->ops && dev->ops->phase5_enable_resources) {
dev->ops->phase5_enable_resources(dev);
}
else if (dev->chip_ops && dev->chip_ops->enable_dev) {
dev->chip_ops->enable_dev(dev);
}
}
void disable_children(struct bus *bus)

View file

@ -671,7 +671,7 @@ void pci_dev_init(struct device *dev)
}
/** Default device operation for PCI devices */
static struct pci_operations pci_dev_ops_pci = {
struct pci_operations pci_dev_ops_pci = {
.set_subsystem = pci_dev_set_subsystem,
};
@ -686,7 +686,7 @@ struct device_operations default_pci_ops_dev = {
};
/** Default device operations for PCI bridges */
static struct pci_operations pci_bus_ops_pci = {
struct pci_operations pci_bus_ops_pci = {
.set_subsystem = 0,
};
@ -779,32 +779,29 @@ static struct device_operations *get_pci_bridge_ops(struct device * dev)
*/
static void set_pci_ops(struct device *dev)
{
#if 0
struct pci_driver *driver;
#endif
struct constructor *c;
struct device_id id = {.type = DEVICE_ID_PCI};
if (dev->ops) {
printk(BIOS_INFO, "%s: dev %p(%s) already has ops %p\n", __func__, dev, dev->dtsname, dev->ops);
printk(BIOS_SPEW, "%s: dev %p(%s) already has ops %p\n", __func__, dev, dev->dtsname, dev->ops);
return;
}
#warning "need to fix this leftover PCI bogosity from V2"
#if 0
/* we need to make the id in the device a device_id type ... */
id.u.pci.vendor = dev->vendor;
id.u.pci.device = dev->device;
/* Look through the list of setup drivers and find one for
* this pci device
*/
for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
if ((driver->vendor == dev->vendor) &&
(driver->device == dev->device))
{
dev->ops = driver->ops;
printk(BIOS_SPEW,"%s [%04x/%04x] %sops\n",
dev_path(dev),
driver->vendor, driver->device,
(driver->ops->phase3_scan?"bus ":""));
return;
}
c = find_constructor(&id);
if (c) {
dev->ops = c->ops;
printk(BIOS_SPEW,"%s id %s [%04x/%04x] %sops\n",
dev_path(dev), dev_id_string(&id), dev->vendor, dev->device,
(dev->ops->phase3_scan?"bus ":""));
return;
}
#endif
/* If I don't have a specific driver use the default operations */
switch(dev->hdr_type & 0x7f) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
@ -913,6 +910,7 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev
/* Detect if a device is present */
if (!dev) {
struct device dummy;
struct device_id devid;
dummy.bus = bus;
dummy.path.type = DEVICE_PATH_PCI;
dummy.path.u.pci.devfn = devfn;
@ -926,7 +924,10 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev
printk(BIOS_SPEW,"PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
return NULL;
}
dev = alloc_dev(bus, &dummy.path);
devid.type = DEVICE_PATH_PCI;
devid.u.pci.vendor = id & 0xffff;
devid.u.pci.device = id >> 16;
dev = alloc_dev(bus, &dummy.path, &devid);
}
else {
/* Enable/disable the device. Once we have
@ -942,8 +943,8 @@ struct device * pci_probe_dev(struct device * dev, struct bus *bus, unsigned dev
*
*/
/* Run the magice enable sequence for the device */
if (dev->chip_ops && dev->chip_ops->enable_dev) {
dev->chip_ops->enable_dev(dev);
if (dev->ops && dev->ops->phase3_enable_scan) {
dev->ops->phase3_enable_scan(dev);
}
/* Now read the vendor and device id */
id = pci_read_config32(dev, PCI_VENDOR_ID);

View file

@ -144,7 +144,7 @@ struct device_operations pnp_ops = {
.enable = pnp_enable,
};
/* PNP chip opertations */
/* PNP chip operations */
static void pnp_get_ioresource(device_t dev, unsigned index, struct io_info *info)
{

View file

@ -107,8 +107,8 @@ unsigned int scan_static_bus(struct device * busdevice, unsigned int max)
busdevice->link[link].secondary = ++smbus_max;
}
for(child = busdevice->link[link].children; child; child = child->sibling) {
if (child->chip_ops && child->chip_ops->enable_dev) {
child->chip_ops->enable_dev(child);
if (child->ops && child->ops->phase3_enable_scan) {
child->ops->phase3_enable_scan(child);
}
/* sigh. Have to enable to scan ... */
if (child->ops && child->ops->phase5_enable_resources) {
@ -192,8 +192,9 @@ void root_dev_reset(struct bus *bus)
* @brief Default device operation for root device
*
* This is the default device operation for root devices. These operations
* should be fully usable as is. However the chip_operations::enable_dev()
* of a motherboard can override this if you want non-default behavior.
* should be fully usable as is. If you need something else, set up your own ops
* in (e.g.) the mainboard, and initialize it in the dts in the mainboard directory.
*
*/
struct device_operations default_dev_ops_root = {
.phase4_read_resources = root_dev_read_resources,

View file

@ -1,5 +1,6 @@
/*
* This file is part of the LinuxBIOS project.
* Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
*
* 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
@ -23,37 +24,114 @@
#include <device/resource.h>
#include <device/path.h>
#define DEVICE_ID_MAX 64
enum device_id_type {
DEVICE_ID_NONE = 0,
DEVICE_ID_ROOT,
DEVICE_ID_PCI,
DEVICE_ID_PNP,
DEVICE_ID_I2C,
DEVICE_ID_APIC,
DEVICE_ID_PCI_DOMAIN,
DEVICE_ID_APIC_CLUSTER,
DEVICE_ID_CPU,
DEVICE_ID_CPU_BUS,
};
struct device;
struct pci_operations;
struct pci_bus_operations;
struct smbus_bus_operations;
/* Chip operations */
struct chip_operations {
void (*enable_dev)(struct device *dev);
char *name;
};
struct bus;
/* we are moving from the confusing naming scheme to a numbering scheme. We are hoping
* this makes it easier for people to know the order of operations.
* So far, it is not clear. We may actually want to have names like dev_phase5_enable_resources.
* The numbering is nice, the naming is nice, what to do?
*/
struct pci_domain_id
{
u16 vendor, device;
};
struct pci_id
{
u16 vendor, device;
};
struct pnp_id
{
u32 device;
};
struct i2c_id
{
u32 id;
};
struct apic_id
{
u16 vendor, device;
};
struct apic_cluster_id
{
u16 vendor, device;
};
struct cpu_id
{
u32 cpuid[3];
};
struct cpu_bus_id
{
u16 vendor, device;
};
struct device_id {
enum device_id_type type;
union {
struct pci_id pci;
struct pnp_id pnp;
struct i2c_id i2c;
struct apic_id apic;
struct pci_domain_id pci_domain;
struct apic_cluster_id apic_cluster;
struct cpu_id cpu;
struct cpu_bus_id cpu_bus;
} u;
};
struct constructor {
struct device_id id;
struct device_operations *ops;
};
struct device_operations {
/* for now, we leave these, since they seem generic */
void (*set_link)(struct device * dev, unsigned int link);
void (*reset_bus)(struct bus *bus);
/* phase1 is called ONLY if you CAN NEVER use printk. Only very early console needs this now */
void (*phase1)(struct device * dev);
/* a constructor. The constructor for a given device is defined in the device source file.
* When is this called? Not for the static tree. When the scan bus code finds a new device, it must
* create it and insert it into the device tree. To do this, it calls a device constructor.
* The set of all device constructors is concatenated into the constructors array of structures via the usual
* gcc hack of naming a segment.
* The dev_constructor code in device.c iterates over the constructors array.
* A match consists of a path type, a vendor (which may be ignored if the constructo vendor value is 0),
* and a device id.
* When it finds a match, the dev_constructor calls the
* function constructors->constructor(constructors->constructor) and a new device is created.
*/
struct device *(*constructor)(struct constructor *);
/* set device ops */
void (*phase1_set_device_operations)(struct device *dev);
/* phase 2 is for any magic you have to do before the busses are scanned */
void (*phase2)(struct device * dev);
void (*phase2_setup_scan_bus)(struct device * dev);
/* phase 3 is for scanning the bus, if needed. */
void (*phase3_enable_scan)(struct device *dev);
unsigned int (*phase3_scan)(struct device * bus, unsigned int max);
/* typically used by phase4 */
@ -127,8 +205,7 @@ struct device {
unsigned int links;
struct device_operations *ops;
struct chip_operations *chip_ops;
void *chip_info;
void *device_configuration;
};
extern struct device dev_root; /* root bus */
@ -136,7 +213,8 @@ extern struct device *all_devices; /* list of all devices */
/* Generic device interface functions */
struct device * alloc_dev(struct bus *parent, struct device_path *path);
struct constructor *find_constructor(struct device_id *id);
struct device * alloc_dev(struct bus *parent, struct device_path *path, struct device_id *id);
void dev_enumerate(void);
void dev_configure(void);
void dev_enable(void);
@ -153,17 +231,19 @@ void enable_resources(struct device *dev);
void enumerate_static_device(void);
void enumerate_static_devices(void);
const char *dev_path(struct device * dev);
const char *dev_id_string(struct device_id *id);
const char *bus_path(struct bus *bus);
void dev_set_enabled(struct device * dev, int enable);
void disable_children(struct bus *bus);
/* Helper functions */
struct device * find_dev_path(struct bus *parent, struct device_path *path);
struct device * alloc_find_dev(struct bus *parent, struct device_path *path);
struct device * alloc_find_dev(struct bus *parent, struct device_path *path, struct device_id *id);
struct device * dev_find_device (unsigned int vendor, unsigned int device, struct device * from);
struct device * dev_find_class (unsigned int class, struct device * from);
struct device * dev_find_slot (unsigned int bus, unsigned int devfn);
struct device * dev_find_slot_on_smbus (unsigned int bus, unsigned int addr);
struct device *default_device_constructor(struct constructor *constructor);
/* Rounding for boundaries.
@ -174,6 +254,7 @@ struct device * dev_find_slot_on_smbus (unsigned int bus, unsigned int addr);
extern struct device_operations default_dev_ops_root;
extern int id_eq(struct device_id *id1, struct device_id *id2);
void root_dev_read_resources(struct device * dev);
void root_dev_set_resources(struct device * dev);
unsigned int scan_static_bus(struct device * bus, unsigned int max);

View file

@ -71,6 +71,8 @@ extern struct pci_driver epci_drivers[];
extern struct device_operations default_pci_ops_dev;
extern struct device_operations default_pci_ops_bus;
extern struct pci_operations pci_dev_ops_pci;
extern struct pci_operations pci_bus_ops_pci;
void pci_dev_read_resources(struct device * dev);
void pci_bus_read_resources(struct device * dev);

View file

@ -6,3 +6,4 @@ config MAINBOARD_NAME
This is the default mainboard name.
source northbridge/intel/i440bxemulation/Kconfig

View file

@ -58,7 +58,10 @@ $(obj)/statictree.o: $(obj)/statictree.c
$(obj)/statictree.c: mainboard/$(MAINBOARDDIR)/dts $(obj)/util/dtc/dtc
$(Q)$(obj)/util/dtc/dtc -O lb mainboard/$(MAINBOARDDIR)/dts >$(obj)/statictree.c
STAGE2_MAINBOARD_OBJ = $(obj)/mainboard.o
STAGE2_CHIPSET_OBJ =
# chipset
include $(src)/northbridge/intel/i440bxemulation/Makefile
include $(src)/southbridge/intel/i82371eb/Makefile

View file

@ -1,5 +1,3 @@
extern struct chip_operations mainboard_emulation_qemu_x86_ops;
struct mainboard_emulation_qemu_x86_config {
int nothing;
};

View file

@ -1,3 +1,22 @@
/*
* This file is part of the LinuxBIOS project.
*
* Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/{
config="mainboard,emulation,qemu-x86";
enabled;
@ -25,6 +44,8 @@
%%
#include <southbridge/intel/i82371eb/config.h>
struct mainboard_emulation_qemu_x86_config root = {
.nothing = 1,
};
@ -32,3 +53,7 @@ struct mainboard_emulation_qemu_x86_config root = {
struct northbridge_intel_i440bx_config domain0 = {
.ramsize = CONFIG_NORTHBRIDGE_INTEL_I440BXEMULATION_RAMSIZE,
};
struct constructor *all_constructors[] ={
i440bx_constructors, i82371eb_constructors, 0
};

View file

@ -14,18 +14,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <console/console.h>
#include <device/device.h>
const char *mainboard_vendor = "Emulation";
const char *mainboard_part_number = "QEMU x86";
const char *mainboard_vendor = "emulation";
const char *mainboard_part_number = "qemu-x86";
static void enable_dev(struct device *dev)
{
printk(BIOS_INFO, "qemu-x86 enable_dev done\n");
}
struct chip_operations mainboard_emulation_qemu_x86_ops = {
.name = "QEMU Mainboard",
.enable_dev = enable_dev
};

View file

@ -18,9 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern struct chip_operations northbridge_intel_i440bxemulation_ops;
extern struct device_operations i440bxemulation_pcidomainops;
extern struct constructor i440bx_constructors[];
struct northbridge_intel_i440bx_config {
/* The various emulators don't always get 440BX right. So we are
* going to allow users to set the RAM size via Kconfig.

View file

@ -27,59 +27,47 @@
#include "config.h"
#include "i440bx.h"
static void i440bxemulation_enable_dev(struct device *dev)
/* Here are the ops for 440BX as a PCI domain. */
/* a PCI domain contains the I/O and memory resource address space below it. */
static void pci_domain_read_resources(struct device * dev)
{
printk(BIOS_INFO, "%s: \n", __FUNCTION__);
printk(BIOS_INFO, "%s: Done.\n", __FUNCTION__);
struct resource *resource;
/* Initialize the system wide I/O space constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0));
resource->limit = 0xffffUL;
resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
/* Initialize the system wide memory resources constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0));
resource->limit = 0xffffffffULL;
resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
}
/* Here are the ops for 440BX as a PCI domain.
* A PCI domain contains the I/O and memory resource address space below it.
* Currently, the only functions in here are for the domain. If device
* functions are needed, they will come later.
*/
static void pci_domain_read_resources(struct device *dev)
static void ram_resource(struct device * dev, unsigned long index,
unsigned long basek, unsigned long sizek)
{
struct resource *resource;
struct resource *resource;
/* Initialize the system wide I/O space constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
resource->limit = 0xffffUL;
resource->flags =
IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
/* Initialize the system wide memory resources constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
resource->limit = 0xffffffffULL;
resource->flags =
IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
if (!sizek) {
return;
}
resource = new_resource(dev, index);
resource->base = ((resource_t)basek) << 10;
resource->size = ((resource_t)sizek) << 10;
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
printk(BIOS_INFO, "%s: add ram resoource %d bytes\n", __func__, resource->size);
}
static void ram_resource(struct device *dev, unsigned long index,
unsigned long basek, unsigned long sizek)
static void pci_domain_set_resources(struct device * dev)
{
struct resource *resource;
if (!sizek) {
return;
}
resource = new_resource(dev, index);
resource->base = ((resource_t) basek) << 10;
resource->size = ((resource_t) sizek) << 10;
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
printk(BIOS_INFO, "%s: add RAM ressource %d bytes\n", __func__,
resource->size);
}
static void pci_domain_set_resources(struct device *dev)
{
struct device *mc_dev;
u32 tolmk; /* Top of low mem, Kbytes. */
struct device * mc_dev;
u32 tolmk; /* Top of low mem, Kbytes. */
int idx;
struct northbridge_intel_i440bx_config *chip_info = dev->chip_info;
tolmk = chip_info->ramsize * 1024;
struct northbridge_intel_i440bx_config *device_configuration = dev->device_configuration;
tolmk = device_configuration->ramsize * 1024;
mc_dev = dev->link[0].children;
if (mc_dev) {
idx = 10;
@ -88,25 +76,33 @@ static void pci_domain_set_resources(struct device *dev)
phase4_assign_resources(&dev->link[0]);
}
static unsigned int pci_domain_scan_bus(struct device *dev, unsigned int max)
static unsigned int pci_domain_scan_bus(struct device * dev, unsigned int max)
{
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
return max;
/* there is only one link on this device, and it is always link 0 */
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
return max;
}
/* Here are the chip operations. These are for the chip-specific functions. */
struct chip_operations northbridge_intel_i440bxemulation_ops = {
.name = "Intel 440BX Northbridge Emulation",
.enable_dev = i440bxemulation_enable_dev,
/* here are the operations for when the northbridge is running a pci domain. */
/* see emulation/qemu-x86 for an example of how these are used. */
struct device_operations i440bxemulation_pcidomainops = {
.constructor = default_device_constructor,
.phase3_scan = pci_domain_scan_bus,
.phase4_read_resources = pci_domain_read_resources,
.phase4_set_resources = pci_domain_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = 0,
.ops_pci_bus = &pci_cf8_conf1,
};
/* Here are the operations for when the northbridge is running a PCI domain. */
/* See emulation/qemu-x86 for an example of how these are used. */
struct device_operations i440bxemulation_pcidomainops = {
.phase4_read_resources = pci_domain_read_resources,
.phase4_set_resources = pci_domain_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = 0,
.phase3_scan = pci_domain_scan_bus,
.ops_pci_bus = &pci_cf8_conf1,
/* the constructor for the device. */
/* the plain PCI device uses the standard PCI operations. */
struct constructor i440bx_constructors[] = {
{.id={.type=DEVICE_ID_PCI_DOMAIN, .u={.pci={.vendor=0x8086, .device=0x7190}}},
&i440bxemulation_pcidomainops},
{.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7190}}},
&default_pci_ops_bus},
{.ops = 0},
};

View file

@ -0,0 +1,25 @@
##
## This file is part of the LinuxBIOS project.
##
## Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
##
## 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, write to the Free Software
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
$(obj)/%.o: $(src)/southbridge/intel/i82371eb/%.c
$(Q)$(CC) $(INITCFLAGS) -c $< -o $@
STAGE2_CHIPSET_OBJ += $(obj)/i82371eb.o

View file

@ -0,0 +1,26 @@
/*
* This file is part of the LinuxBIOS project.
*
* Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern struct constructor i82371eb_constructors[];
struct southbridge_intel_i82371eb_config
{
int ide;
};

View file

@ -0,0 +1,60 @@
/*
* This file is part of the LinuxBIOS project.
*
* Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <console/console.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
// #include "i82371eb.h"
/* The plain PCI device uses the standard PCI operations. */
/* Note that this structure is not necessary (yet),
* but is here as an example of how you can set up your own ops
*/
/* You can override or extend each of these operations as needed for the device. */
static struct device_operations i82371eb_pci_ops_dev = {
.constructor = default_device_constructor,
.phase3_scan = 0,
.phase4_read_resources = pci_dev_read_resources,
.phase4_set_resources = pci_dev_set_resources,
.phase4_enable_disable = 0,
.phase5_enable_resources = pci_dev_enable_resources,
.phase6_init = pci_dev_init,
.ops_pci = &pci_dev_ops_pci,
};
struct constructor i82371eb_constructors[] = {
{.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7110}}},
&i82371eb_pci_ops_dev},
{.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7111}}},
&i82371eb_pci_ops_dev},
{.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7112}}},
&i82371eb_pci_ops_dev},
{.id={.type=DEVICE_ID_PCI, .u={.pci={.vendor=0x8086, .device=0x7113}}},
&i82371eb_pci_ops_dev},
{.ops = 0},
};

View file

@ -528,8 +528,7 @@ static void linuxbios_emit_special(FILE *e, struct node *tree)
}
if (streq(prop->name, "config")){
fprintf(f, "\t.chip_ops = &%s_ops,\n", clean(prop->val.val, 0));
fprintf(f, "\t.chip_info = &%s,\n", clean(tree->label, 1));
fprintf(f, "\t.device_configuration = &%s,\n", clean(tree->label, 1));
}
if (streq(prop->name, "ops")){