⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmphp_res.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * IBM Hot Plug Controller Driver * * Written By: Irene Zubarev, IBM Corporation * * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001,2002 IBM Corp. * * All rights reserved. * * 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, GOOD TITLE or * NON INFRINGEMENT.  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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to <gregkh@us.ibm.com> * */#include <linux/module.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/list.h>#include <linux/init.h>#include "ibmphp.h"static int flags = 0;		/* for testing */static void update_resources (struct bus_node *bus_cur, int type, int rangeno);static int once_over (void);static int remove_ranges (struct bus_node *, struct bus_node *);static int update_bridge_ranges (struct bus_node **);static int add_range (int type, struct range_node *, struct bus_node *);static void fix_resources (struct bus_node *);static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);static LIST_HEAD(gbuses);static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag){	struct bus_node * newbus;	if (!(curr) && !(flag)) {		err ("NULL pointer passed\n");		return NULL;	}	newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);	if (!newbus) {		err ("out of system memory\n");		return NULL;	}	memset (newbus, 0, sizeof (struct bus_node));	if (flag)		newbus->busno = busno;	else		newbus->busno = curr->bus_num;	list_add_tail (&newbus->bus_list, &gbuses);	return newbus;}static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr){	struct resource_node *rs;		if (!curr) {		err ("NULL passed to allocate\n");		return NULL;	}	rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);	if (!rs) {		err ("out of system memory\n");		return NULL;	}	memset (rs, 0, sizeof (struct resource_node));	rs->busno = curr->bus_num;	rs->devfunc = curr->dev_fun;	rs->start = curr->start_addr;	rs->end = curr->end_addr;	rs->len = curr->end_addr - curr->start_addr + 1;	return rs;}static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus){	struct bus_node * newbus;	struct range_node *newrange;	u8 num_ranges = 0;	if (first_bus) {		newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);		if (!newbus) {			err ("out of system memory.\n");			return -ENOMEM;		}		memset (newbus, 0, sizeof (struct bus_node));		newbus->busno = curr->bus_num;	} else {		newbus = *new_bus;		switch (flag) {			case MEM:				num_ranges = newbus->noMemRanges;				break;			case PFMEM:				num_ranges = newbus->noPFMemRanges;				break;			case IO:				num_ranges = newbus->noIORanges;				break;		}	}	newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL);	if (!newrange) {		if (first_bus)			kfree (newbus);		err ("out of system memory\n");		return -ENOMEM;	}	memset (newrange, 0, sizeof (struct range_node));	newrange->start = curr->start_addr;	newrange->end = curr->end_addr;			if (first_bus || (!num_ranges))		newrange->rangeno = 1;	else {		/* need to insert our range */		add_range (flag, newrange, newbus);		debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);	}	switch (flag) {		case MEM:			newbus->rangeMem = newrange;			if (first_bus)				newbus->noMemRanges = 1;			else {				debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				++newbus->noMemRanges;				fix_resources (newbus);			}			break;		case IO:			newbus->rangeIO = newrange;			if (first_bus)				newbus->noIORanges = 1;			else {				debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				++newbus->noIORanges;				fix_resources (newbus);			}			break;		case PFMEM:			newbus->rangePFMem = newrange;			if (first_bus)				newbus->noPFMemRanges = 1;			else {					debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				++newbus->noPFMemRanges;				fix_resources (newbus);			}			break;	}	*new_bus = newbus;	*new_range = newrange;	return 0;}/* Notes: * 1. The ranges are ordered.  The buses are not ordered.  (First come) * * 2. If cannot allocate out of PFMem range, allocate from Mem ranges.  PFmemFromMem * are not sorted. (no need since use mem node). To not change the entire code, we * also add mem node whenever this case happens so as not to change * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) *//***************************************************************************** * This is the Resource Management initialization function.  It will go through * the Resource list taken from EBDA and fill in this module's data structures * * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES,  * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW * * Input: ptr to the head of the resource list from EBDA * Output: 0, -1 or error codes ***************************************************************************/int __init ibmphp_rsrc_init (void){	struct ebda_pci_rsrc *curr;	struct range_node *newrange = NULL;	struct bus_node *newbus = NULL;	struct bus_node *bus_cur;	struct bus_node *bus_prev;	struct list_head *tmp;	struct resource_node *new_io = NULL;	struct resource_node *new_mem = NULL;	struct resource_node *new_pfmem = NULL;	int rc;	struct list_head *tmp_ebda;	list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) {		curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list);		if (!(curr->rsrc_type & PCIDEVMASK)) {			/* EBDA still lists non PCI devices, so ignore... */			debug ("this is not a PCI DEVICE in rsrc_init, please take care\n");			// continue;		}		/* this is a primary bus resource */		if (curr->rsrc_type & PRIMARYBUSMASK) {			/* memory */			if ((curr->rsrc_type & RESTYPE) == MMASK) {				/* no bus structure exists in place yet */				if (list_empty (&gbuses)) {					if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))						return rc;					list_add_tail (&newbus->bus_list, &gbuses);					debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				} else {					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);					/* found our bus */					if (bus_cur) {						rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0);						if (rc)							return rc;					} else {						/* went through all the buses and didn't find ours, need to create a new bus node */						if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))							return rc;						list_add_tail (&newbus->bus_list, &gbuses);						debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);					}				}			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {				/* prefetchable memory */				if (list_empty (&gbuses)) {					/* no bus structure exists in place yet */					if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))						return rc;					list_add_tail (&newbus->bus_list, &gbuses);					debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				} else {					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);					if (bus_cur) {						/* found our bus */						rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0);						if (rc)							return rc;					} else {						/* went through all the buses and didn't find ours, need to create a new bus node */						if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))							return rc;						list_add_tail (&newbus->bus_list, &gbuses);						debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);					}				}			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {				/* IO */				if (list_empty (&gbuses)) {					/* no bus structure exists in place yet */					if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))						return rc;					list_add_tail (&newbus->bus_list, &gbuses);					debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);				} else {					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);					if (bus_cur) {						rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0);						if (rc)							return rc;					} else {						/* went through all the buses and didn't find ours, need to create a new bus node */						if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))							return rc;						list_add_tail (&newbus->bus_list, &gbuses);						debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);					}				}			} else {				;	/* type is reserved  WHAT TO DO IN THIS CASE???					   NOTHING TO DO??? */			}		} else {			/* regular pci device resource */			if ((curr->rsrc_type & RESTYPE) == MMASK) {				/* Memory resource */				new_mem = alloc_resources (curr);				if (!new_mem)					return -ENOMEM;				new_mem->type = MEM;				/*				 * if it didn't find the bus, means PCI dev				 * came b4 the Primary Bus info, so need to				 * create a bus rangeno becomes a problem...				 * assign a -1 and then update once the range				 * actually appears...				 */				if (ibmphp_add_resource (new_mem) < 0) {					newbus = alloc_error_bus (curr, 0, 0);					if (!newbus)						return -ENOMEM;					newbus->firstMem = new_mem;					++newbus->needMemUpdate;					new_mem->rangeno = -1;				}				debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end);			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {				/* PFMemory resource */				new_pfmem = alloc_resources (curr);				if (!new_pfmem)					return -ENOMEM;				new_pfmem->type = PFMEM;				new_pfmem->fromMem = FALSE;				if (ibmphp_add_resource (new_pfmem) < 0) {					newbus = alloc_error_bus (curr, 0, 0);					if (!newbus)						return -ENOMEM;					newbus->firstPFMem = new_pfmem;					++newbus->needPFMemUpdate;					new_pfmem->rangeno = -1;				}				debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end);			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {				/* IO resource */				new_io = alloc_resources (curr);				if (!new_io)					return -ENOMEM;				new_io->type = IO;				/*				 * if it didn't find the bus, means PCI dev				 * came b4 the Primary Bus info, so need to				 * create a bus rangeno becomes a problem...				 * Can assign a -1 and then update once the				 * range actually appears...				 */				if (ibmphp_add_resource (new_io) < 0) {					newbus = alloc_error_bus (curr, 0, 0);					if (!newbus)						return -ENOMEM;					newbus->firstIO = new_io;					++newbus->needIOUpdate;					new_io->rangeno = -1;				}				debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end);			}		}	}	list_for_each (tmp, &gbuses) {		bus_cur = list_entry (tmp, struct bus_node, bus_list);		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */		rc = update_bridge_ranges (&bus_cur);		if (rc)			return rc;	}	rc = once_over ();  /* This is to align ranges (so no -1) */	if (rc)		return rc;	return 0;}/******************************************************************************** * This function adds a range into a sorted list of ranges per bus for a particular * range type, it then calls another routine to update the range numbers on the * pci devices' resources for the appropriate resource * * Input: type of the resource, range to add, current bus * Output: 0 or -1, bus and range ptrs  ********************************************************************************/static int add_range (int type, struct range_node *range, struct bus_node *bus_cur){	struct range_node *range_cur = NULL;	struct range_node *range_prev;	int count = 0, i_init;	int noRanges = 0;	switch (type) {		case MEM:			range_cur = bus_cur->rangeMem;			noRanges = bus_cur->noMemRanges;			break;		case PFMEM:			range_cur = bus_cur->rangePFMem;			noRanges = bus_cur->noPFMemRanges;			break;		case IO:			range_cur = bus_cur->rangeIO;			noRanges = bus_cur->noIORanges;			break;	}	range_prev = NULL;	while (range_cur) {		if (range->start < range_cur->start)			break;		range_prev = range_cur;		range_cur = range_cur->next;		count = count + 1;	}	if (!count) {		/* our range will go at the beginning of the list */		switch (type) {			case MEM:				bus_cur->rangeMem = range;				break;			case PFMEM:				bus_cur->rangePFMem = range;				break;			case IO:				bus_cur->rangeIO = range;				break;		}		range->next = range_cur;		range->rangeno = 1;		i_init = 0;	} else if (!range_cur) {		/* our range will go at the end of the list */		range->next = NULL;		range_prev->next = range;		range->rangeno = range_prev->rangeno + 1;		return 0;	} else {		/* the range is in the middle */		range_prev->next = range;		range->next = range_cur;		range->rangeno = range_cur->rangeno;		i_init = range_prev->rangeno;	}	for (count = i_init; count < noRanges; ++count) {		++range_cur->rangeno;		range_cur = range_cur->next;	}	update_resources (bus_cur, type, i_init + 1);	return 0;}/******************************************************************************* * This routine goes through the list of resources of type 'type' and updates * the range numbers that they correspond to.  It was called from add_range fnc * * Input: bus, type of the resource, the rangeno starting from which to update ******************************************************************************/static void update_resources (struct bus_node *bus_cur, int type, int rangeno){	struct resource_node *res = NULL;	u8 eol = FALSE;	/* end of list indicator */	switch (type) {		case MEM:			if (bus_cur->firstMem) 				res = bus_cur->firstMem;			break;		case PFMEM:			if (bus_cur->firstPFMem)				res = bus_cur->firstPFMem;			break;		case IO:			if (bus_cur->firstIO)				res = bus_cur->firstIO;			break;	}	if (res) {		while (res) {			if (res->rangeno == rangeno)				break;			if (res->next)				res = res->next;			else if (res->nextRange)				res = res->nextRange;			else {				eol = TRUE;				break;			}		}		if (!eol) {			/* found the range */			while (res) {				++res->rangeno;				res = res->next;			}		}	}}static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range){	char * str = "";	switch (res->type) {		case IO:			str = "io";			break;		case MEM:			str = "mem";			break;		case PFMEM:			str = "pfmem";			break;	}	while (res) {		if (res->rangeno == -1) {			while (range) {				if ((res->start >= range->start) && (res->end <= range->end)) {					res->rangeno = range->rangeno;					debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno);					switch (res->type) {						case IO:							--bus_cur->needIOUpdate;							break;						case MEM:							--bus_cur->needMemUpdate;							break;						case PFMEM:							--bus_cur->needPFMemUpdate;							break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -