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

📄 ibmphp_pci.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 "ibmphp.h"static int configure_device(struct pci_func *);static int configure_bridge(struct pci_func **, u8);static struct res_needed *scan_behind_bridge(struct pci_func *, u8);static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8);static u8 find_sec_number (u8 primary_busno, u8 slotno);/* * NOTE..... If BIOS doesn't provide default routing, we assign: * 9 for SCSI, 10 for LAN adapters, and 11 for everything else.  * If adapter is bridged, then we assign 11 to it and devices behind it. * We also assign the same irq numbers for multi function devices. * These are PIC mode, so shouldn't matter n.e.ways (hopefully) */static void assign_alt_irq (struct pci_func * cur_func, u8 class_code){	int j;	for (j = 0; j < 4; j++) {		if (cur_func->irq[j] == 0xff) {			switch (class_code) {				case PCI_BASE_CLASS_STORAGE:					cur_func->irq[j] = SCSI_IRQ;					break;				case PCI_BASE_CLASS_NETWORK:					cur_func->irq[j] = LAN_IRQ;					break;				default:					cur_func->irq[j] = OTHER_IRQ;					break;			}		}	}}/* * Configures the device to be added (will allocate needed resources if it * can), the device can be a bridge or a regular pci device, can also be * multi-functional *  * Input: function to be added *  * TO DO:  The error case with Multifunction device or multi function bridge, * if there is an error, will need to go through all previous functions and  * unconfigure....or can add some code into unconfigure_card.... */int ibmphp_configure_card (struct pci_func *func, u8 slotno){	u16 vendor_id;	u32 class;	u8 class_code;	u8 hdr_type, device, sec_number;	u8 function;	struct pci_func *newfunc;	/* for multi devices */	struct pci_func *cur_func, *prev_func;	int rc, i, j;	int cleanup_count;	u8 flag;	u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */	debug ("inside configure_card, func->busno = %x\n", func->busno);	device = func->device;	cur_func = func;	/* We only get bus and device from IRQ routing table.  So at this point,	 * func->busno is correct, and func->device contains only device (at the 5 	 * highest bits)	 */	/* For every function on the card */	for (function = 0x00; function < 0x08; function++) {		unsigned int devfn = PCI_DEVFN(device, function);		ibmphp_pci_bus->number = cur_func->busno;		cur_func->function = function;		debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n",			cur_func->busno, cur_func->device, cur_func->function);		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);		debug ("vendor_id is %x\n", vendor_id);		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {			/* found correct device!!! */			debug ("found valid device, vendor_id = %x\n", vendor_id);			++valid_device;			/* header: x x x x x x x x			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge			 *         |_=> 0 = single function device, 1 = multi-function device			 */			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);			class_code = class >> 24;			debug ("hrd_type = %x, class = %x, class_code %x\n", hdr_type, class, class_code);			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */			if (class == PCI_CLASS_NOT_DEFINED_VGA) {				err ("The device %x is VGA compatible and as is not supported for hot plugging. "				     "Please choose another device.\n", cur_func->device);				return -ENODEV;			} else if (class == PCI_CLASS_DISPLAY_VGA) {				err ("The device %x is not supported for hot plugging. "				     "Please choose another device.\n", cur_func->device);				return -ENODEV;			}			switch (hdr_type) {				case PCI_HEADER_TYPE_NORMAL:					debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class);					assign_alt_irq (cur_func, class_code);					if ((rc = configure_device (cur_func)) < 0) {						/* We need to do this in case some other BARs were properly inserted */						err ("was not able to configure devfunc %x on bus %x.\n",						     cur_func->device, cur_func->busno);						cleanup_count = 6;						goto error;					}						cur_func->next = NULL;					function = 0x8;					break;				case PCI_HEADER_TYPE_MULTIDEVICE:					assign_alt_irq (cur_func, class_code);					if ((rc = configure_device (cur_func)) < 0) {						/* We need to do this in case some other BARs were properly inserted */						err ("was not able to configure devfunc %x on bus %x...bailing out\n",						     cur_func->device, cur_func->busno);						cleanup_count = 6;						goto error;					}					newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);					if (!newfunc) {						err ("out of system memory\n");						return -ENOMEM;					}					memset (newfunc, 0, sizeof (struct pci_func));					newfunc->busno = cur_func->busno;					newfunc->device = device;					cur_func->next = newfunc;					cur_func = newfunc;					for (j = 0; j < 4; j++)						newfunc->irq[j] = cur_func->irq[j];					break;				case PCI_HEADER_TYPE_MULTIBRIDGE:					class >>= 8;					if (class != PCI_CLASS_BRIDGE_PCI) {						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "						     "Please insert another card.\n", cur_func->device);						return -ENODEV;					}					assign_alt_irq (cur_func, class_code);					rc = configure_bridge (&cur_func, slotno);					if (rc == -ENODEV) {						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");						err ("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);						return rc;					}					if (rc) {						/* We need to do this in case some other BARs were properly inserted */						err ("was not able to hot-add PPB properly.\n");						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */						cleanup_count = 2;						goto error;					}					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);					flag = FALSE;					for (i = 0; i < 32; i++) {						if (func->devices[i]) {							newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);							if (!newfunc) {								err ("out of system memory\n");								return -ENOMEM;							}							memset (newfunc, 0, sizeof (struct pci_func));							newfunc->busno = sec_number;							newfunc->device = (u8) i;							for (j = 0; j < 4; j++)								newfunc->irq[j] = cur_func->irq[j];							if (flag) {								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;								prev_func->next = newfunc;							} else								cur_func->next = newfunc;							rc = ibmphp_configure_card (newfunc, slotno);							/* This could only happen if kmalloc failed */							if (rc) {								/* We need to do this in case bridge itself got configured properly, but devices behind it failed */								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */								cleanup_count = 2;								goto error;							}							flag = TRUE;						}					}					newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);					if (!newfunc) {						err ("out of system memory\n");						return -ENOMEM;					}					memset (newfunc, 0, sizeof (struct pci_func));					newfunc->busno = cur_func->busno;					newfunc->device = device;					for (j = 0; j < 4; j++)						newfunc->irq[j] = cur_func->irq[j];					for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;					prev_func->next = newfunc;					cur_func = newfunc;					break;				case PCI_HEADER_TYPE_BRIDGE:					class >>= 8;					debug ("class now is %x\n", class);					if (class != PCI_CLASS_BRIDGE_PCI) {						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "						     "Please insert another card.\n", cur_func->device);						return -ENODEV;					}					assign_alt_irq (cur_func, class_code);					debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno);					rc = configure_bridge (&cur_func, slotno);					if (rc == -ENODEV) {						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");						err ("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);						return rc;					}					if (rc) {						/* We need to do this in case some other BARs were properly inserted */						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */						err ("was not able to hot-add PPB properly.\n");						cleanup_count = 2;						goto error;					}					debug ("cur_func->busno = %x, device = %x, function = %x\n",						cur_func->busno, device, function);					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);					debug ("after configuring bridge..., sec_number = %x\n", sec_number);					flag = FALSE;					for (i = 0; i < 32; i++) {						if (func->devices[i]) {							debug ("inside for loop, device is %x\n", i);							newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);							if (!newfunc) {								err (" out of system memory\n");								return -ENOMEM;							}							memset (newfunc, 0, sizeof (struct pci_func));							newfunc->busno = sec_number;							newfunc->device = (u8) i;							for (j = 0; j < 4; j++)								newfunc->irq[j] = cur_func->irq[j];							if (flag) {								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;								prev_func->next = newfunc;							} else								cur_func->next = newfunc;							rc = ibmphp_configure_card (newfunc, slotno);							/* Again, this case should not happen... For complete paranoia, will need to call remove_bus */							if (rc) {								/* We need to do this in case some other BARs were properly inserted */								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */								cleanup_count = 2;								goto error;							}							flag = TRUE;						}					}					function = 0x8;					break;				default:					err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);					return -ENXIO;					break;			}	/* end of switch */		}	/* end of valid device */	}	/* end of for */	if (!valid_device) {		err ("Cannot find any valid devices on the card.  Or unable to read from card.\n");		return -ENODEV;	}	return 0;error:	for (i = 0; i < cleanup_count; i++) {		if (cur_func->io[i]) {			ibmphp_remove_resource (cur_func->io[i]);			cur_func->io[i] = NULL;		} else if (cur_func->pfmem[i]) {			ibmphp_remove_resource (cur_func->pfmem[i]);			cur_func->pfmem[i] = NULL;		} else if (cur_func->mem[i]) {			ibmphp_remove_resource (cur_func->mem[i]);			cur_func->mem[i] = NULL;		}	}	return rc;}/* * This function configures the pci BARs of a single device.   * Input: pointer to the pci_func * Output: configured PCI, 0, or error */static int configure_device (struct pci_func *func){	u32 bar[6];	u32 address[] = {		PCI_BASE_ADDRESS_0,		PCI_BASE_ADDRESS_1,		PCI_BASE_ADDRESS_2,		PCI_BASE_ADDRESS_3,		PCI_BASE_ADDRESS_4,		PCI_BASE_ADDRESS_5,		0	};	u8 irq;	int count;	int len[6];	struct resource_node *io[6];	struct resource_node *mem[6];	struct resource_node *mem_tmp;	struct resource_node *pfmem[6];	unsigned int devfn;	debug ("%s - inside\n", __FUNCTION__);	devfn = PCI_DEVFN(func->device, func->function);	ibmphp_pci_bus->number = func->busno;	for (count = 0; address[count]; count++) {	/* for 6 BARs */		/* not sure if i need this.  per scott, said maybe need smth like this		   if devices don't adhere 100% to the spec, so don't want to write		   to the reserved bits		pcibios_read_config_byte(cur_func->busno, cur_func->device, 		PCI_BASE_ADDRESS_0 + 4 * count, &tmp);		if (tmp & 0x01) // IO			pcibios_write_config_dword(cur_func->busno, cur_func->device, 			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD);		else  // Memory			pcibios_write_config_dword(cur_func->busno, cur_func->device, 			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF);		 */		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);		if (!bar[count])	/* This BAR is not implemented */			continue;		debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]);		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {			/* This is IO */			debug ("inside IO SPACE\n");			len[count] = bar[count] & 0xFFFFFFFC;			len[count] = ~len[count] + 1;			debug ("len[count] in IO %x, count %d\n", len[count], count);			io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);			if (!io[count]) {				err ("out of system memory\n");				return -ENOMEM;			}			memset (io[count], 0, sizeof (struct resource_node));			io[count]->type = IO;			io[count]->busno = func->busno;			io[count]->devfunc = ((func->device << 3) | (func->function & 0x7));			io[count]->len = len[count];			if (ibmphp_check_resource(io[count], 0) == 0) {				ibmphp_add_resource (io[count]);				func->io[count] = io[count];			} else {				err ("cannot allocate requested io for bus %x device %x function %x len %x\n",				     func->busno, func->device, func->function, len[count]);				kfree (io[count]);				return -EIO;			}			pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start);				/* _______________This is for debugging purposes only_____________________ */ 			debug ("b4 writing, the IO address is %x\n", func->io[count]->start);			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);			debug ("after writing.... the start address is %x\n", bar[count]);			/* _________________________________________________________________________*/		} else {			/* This is Memory */			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {				/* pfmem */				debug ("PFMEM SPACE\n");

⌨️ 快捷键说明

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