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

📄 hw_opic.c

📁 这个是LINUX下的GDB调度工具的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  This file is part of the program psim.    Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.     */#ifndef _HW_OPIC_C_#define _HW_OPIC_C_#include "device_table.h"#ifdef HAVE_STRING_H#include <string.h>#else#ifdef HAVE_STRINGS_H#include <strings.h>#endif#endif/* DEVICE   opic - Open Programmable Interrupt Controller (OpenPIC)   DESCRIPTION   This device implements the core of the OpenPIC interrupt controller   as described in the OpenPIC specification 1.2 and other related   documents.   The model includes:   o	Up to 2048 external interrupt sources   o	The four count down timers   o	The four interprocessor multicast interrupts   o	multiprocessor support   o	Full tracing to assist help debugging   o	Support for all variations of edge/level x high/low polarity.   PROPERTIES   reg = <address> <size> ... (required)   Determine where the device lives in the parents address space.  The   first <<address>> <<size>> pair specifies the address of the   interrupt destination unit (which might contain an interrupt source   unit) while successive reg entries specify additional interrupt   source units.   Note that for an <<opic>> device attached to a <<pci>> bus, the   first <<reg>> entry may need to be ignored it will be the address   of the devices configuration registers.   interrupt-ranges = <int-number> <range> ... (required)   A list of pairs.  Each pair corresponds to a block of interrupt   source units (the address of which being specified by the   corresponding reg tupple).  <<int-number>> is the number of the   first interrupt in the block while <<range>> is the number of   interrupts in the block.   timer-frequency = <integer>  (optional)   If present, specifies the default value of the timer frequency   reporting register.  By default a value of 1 HZ is used.  The value   is arbitrary, the timers are always updated once per machine cycle.   vendor-identification = <integer>  (optional)   If present, specifies the value to be returned when the vendor   identification register is read.   EXAMPLES   See the test suite directory:   |  psim-test/hw-opic   BUGS   For an OPIC controller attached to a PCI bus, it is not clear what   the value of the <<reg>> and <<interrupt-ranges>> properties should   be.  In particular, the PCI firmware bindings require the first   value of the <<reg>> property to specify the devices configuration   address while the OpenPIC bindings require that same entry to   specify the address of the Interrupt Delivery Unit.  This   implementation checks for and, if present, ignores any   configuration address (and its corresponding <<interrupt-ranges>>   entry).   The OpenPIC specification requires the controller to be fair when   distributing interrupts between processors.  At present the   algorithm used isn't fair.  It is biased towards processor zero.   The OpenPIC specification includes a 8259 pass through mode.  This   is not supported.   REFERENCES      PowerPC Multiprocessor Interrupt Controller (MPIC), January 19,   1996. Available from IBM.   The Open Programmable Interrupt Controller (PIC) Register Interface   Specification Revision 1.2.  Issue Date: Opctober 1995.  Available   somewhere on AMD's web page (http://www.amd.com/)   PowerPC Microprocessor Common Hardware Reference Platform (CHRP)   System bindings to: IEEE Std 1275-1994 Standard for Boot   (Initialization, Configuration) Firmware.  Revision 1.2b (INTERIM   DRAFT).  April 22, 1996.  Available on the Open Firmware web site   http://playground.sun.com/p1275/.   *//* forward types */typedef struct _hw_opic_device hw_opic_device;/* bounds */enum {  max_nr_interrupt_sources = 2048,  max_nr_interrupt_destinations = 32,  max_nr_task_priorities = 16,};enum {  opic_alignment = 16,};/* global configuration register */enum {  gcr0_8259_bit = 0x20000000,  gcr0_reset_bit = 0x80000000,};/* offsets and sizes */enum {  idu_isu_base = 0x10000,  sizeof_isu_register_block = 32,  idu_per_processor_register_base = 0x20000,  sizeof_idu_per_processor_register_block = 0x1000,  idu_timer_base = 0x01100,  sizeof_timer_register_block = 0x00040,};/* Interrupt sources */enum {  isu_mask_bit = 0x80000000,  isu_active_bit = 0x40000000,  isu_multicast_bit = 0x20000000,  isu_positive_polarity_bit = 0x00800000,  isu_level_triggered_bit = 0x00400000,  isu_priority_shift = 16,  isu_vector_bits = 0x000000ff,};typedef struct _opic_interrupt_source {  unsigned is_masked; /* left in place */  unsigned is_multicast; /* left in place */  unsigned is_positive_polarity; /* left in place */  unsigned is_level_triggered; /* left in place */  unsigned priority;  unsigned vector;  /* misc */  int nr;  unsigned destination;  unsigned pending;  unsigned in_service;} opic_interrupt_source;/* interrupt destinations (normally processors) */typedef struct _opic_interrupt_destination {  int nr;  unsigned base_priority;  opic_interrupt_source *current_pending;  opic_interrupt_source *current_in_service;  unsigned bit;  int init_port;  int intr_port;} opic_interrupt_destination;/* address map descriptors */typedef struct _opic_isu_block { /* interrupt source unit block */  int space;  unsigned_word address;  unsigned size;  unsigned_cell int_number;  unsigned_cell range;  int reg;} opic_isu_block;typedef struct _opic_idu { /* interrupt delivery unit */  int reg;  int space;  unsigned_word address;  unsigned size;} opic_idu;typedef enum {  /* bad */  invalid_opic_register,  /* interrupt source */  interrupt_source_N_destination_register,  interrupt_source_N_vector_priority_register,  /* timers */  timer_N_destination_register,  timer_N_vector_priority_register,  timer_N_base_count_register,  timer_N_current_count_register,  timer_frequency_reporting_register,  /* inter-processor interrupts */  ipi_N_vector_priority_register,  ipi_N_dispatch_register,  /* global configuration */  spurious_vector_register,  processor_init_register,  vendor_identification_register,  global_configuration_register_N,  feature_reporting_register_N,  /* per processor */  end_of_interrupt_register_N,  interrupt_acknowledge_register_N,  current_task_priority_register_N,} opic_register;static const char *opic_register_name(opic_register type){  switch (type) {  case invalid_opic_register: return "invalid_opic_register";  case interrupt_source_N_destination_register: return "interrupt_source_N_destination_register";  case interrupt_source_N_vector_priority_register: return "interrupt_source_N_vector_priority_register";  case timer_N_destination_register: return "timer_N_destination_register";  case timer_N_vector_priority_register: return "timer_N_vector_priority_register";  case timer_N_base_count_register: return "timer_N_base_count_register";  case timer_N_current_count_register: return "timer_N_current_count_register";  case timer_frequency_reporting_register: return "timer_frequency_reporting_register";  case ipi_N_vector_priority_register: return "ipi_N_vector_priority_register";  case ipi_N_dispatch_register: return "ipi_N_dispatch_register";  case spurious_vector_register: return "spurious_vector_register";  case processor_init_register: return "processor_init_register";  case vendor_identification_register: return "vendor_identification_register";  case global_configuration_register_N: return "global_configuration_register_N";  case feature_reporting_register_N: return "feature_reporting_register_N";  case end_of_interrupt_register_N: return "end_of_interrupt_register_N";  case interrupt_acknowledge_register_N: return "interrupt_acknowledge_register_N";  case current_task_priority_register_N: return "current_task_priority_register_N";  }  return NULL;}/* timers */typedef struct _opic_timer {  int nr;  device *me; /* find my way home */  hw_opic_device *opic; /* ditto */  unsigned base_count;  int inhibited;  signed64 count; /* *ONLY* if inhibited */  event_entry_tag timeout_event;  opic_interrupt_source *interrupt_source;} opic_timer;/* the OPIC */struct _hw_opic_device {  /* vendor id */  unsigned vendor_identification;  /* interrupt destinations - processors */  int nr_interrupt_destinations;  opic_interrupt_destination *interrupt_destination;  unsigned sizeof_interrupt_destination;  /* bogus interrupts */  int spurious_vector;  /* interrupt sources - external interrupt source units + extra internal ones */  int nr_interrupt_sources;  opic_interrupt_source *interrupt_source;  unsigned sizeof_interrupt_source;  /* external interrupts */  int nr_external_interrupts;  opic_interrupt_source *external_interrupt_source;  /* inter-processor-interrupts */  int nr_interprocessor_interrupts;  opic_interrupt_source *interprocessor_interrupt_source;  /* timers */  int nr_timer_interrupts;  opic_timer *timer;  unsigned sizeof_timer;  opic_interrupt_source *timer_interrupt_source;  unsigned timer_frequency;  /* init register */  unsigned32 init;  /* address maps */  opic_idu idu;  int nr_isu_blocks;  opic_isu_block *isu_block;};static voidhw_opic_init_data(device *me){  hw_opic_device *opic = (hw_opic_device*)device_data(me);  int isb;  int idu_reg;  int nr_isu_blocks;  int i;  /* determine the first valid reg property entry (there could be     leading reg entries with invalid (zero) size fields) and the     number of isu entries found in the reg property. */  idu_reg = 0;  nr_isu_blocks = 0;  while (1) {    reg_property_spec unit;    int attach_space;    unsigned_word attach_address;    unsigned attach_size;    if (!device_find_reg_array_property(me, "reg", idu_reg + nr_isu_blocks,					&unit))      break;    if (nr_isu_blocks > 0	|| (device_address_to_attach_address(device_parent(me), &unit.address,					     &attach_space, &attach_address,					     me)	    && device_size_to_attach_size(device_parent(me), &unit.size,					  &attach_size,					  me))) {      /* we count any thing once we've found one valid address/size pair */      nr_isu_blocks += 1;    }    else {      idu_reg += 1;    }  }  /* determine the number and location of the multiple interrupt     source units and the single interrupt delivery unit */  if (opic->isu_block == NULL) {    int reg_nr;    opic->nr_isu_blocks = nr_isu_blocks;    opic->isu_block = zalloc(sizeof(opic_isu_block) * opic->nr_isu_blocks);    isb = 0;    reg_nr = idu_reg;    while (isb < opic->nr_isu_blocks) {      reg_property_spec reg;      if (!device_find_reg_array_property(me, "reg", reg_nr, &reg))	device_error(me, "reg property missing entry number %d", reg_nr);      opic->isu_block[isb].reg = reg_nr;      if (!device_address_to_attach_address(device_parent(me), &reg.address,					    &opic->isu_block[isb].space,					    &opic->isu_block[isb].address,					    me)	  || !device_size_to_attach_size(device_parent(me), &reg.size,					 &opic->isu_block[isb].size,					 me)) {	device_error(me, "reg property entry %d invalid", reg_nr);      }      if (!device_find_integer_array_property(me, "interrupt-ranges",					      reg_nr * 2,					      &opic->isu_block[isb].int_number)	  || !device_find_integer_array_property(me, "interrupt-ranges",						 reg_nr * 2 + 1,						 &opic->isu_block[isb].range))	device_error(me, "missing or invalid interrupt-ranges property entry %d", reg_nr);      /* first reg entry specifies the address of both the IDU and the         first set of ISU registers, adjust things accordingly */      if (reg_nr == idu_reg) {	opic->idu.reg = opic->isu_block[isb].reg;	opic->idu.space = opic->isu_block[isb].space;	opic->idu.address = opic->isu_block[isb].address;	opic->idu.size = opic->isu_block[isb].size;	opic->isu_block[isb].address += idu_isu_base;	opic->isu_block[isb].size = opic->isu_block[isb].range * (16 + 16);      }      /* was this a valid reg entry? */      if (opic->isu_block[isb].range == 0) {	opic->nr_isu_blocks -= 1;      }      else {	opic->nr_external_interrupts += opic->isu_block[isb].range;	isb++;      }      reg_nr++;    }  }  DTRACE(opic, ("interrupt source unit block - effective number of blocks %d\n",		(int)opic->nr_isu_blocks));  /* the number of other interrupts */

⌨️ 快捷键说明

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