/* * Intel IO-APIC support for multi-Pentium hosts. * * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo * * Many thanks to Stig Venaas for trying out countless experimental * patches and reporting/debugging problems patiently! * * (c) 1999, Multiple IO-APIC support, developed by * Ken-ichi Yaku and * Hidemi Kishimoto , * further tested and cleaned up by Zach Brown * and Ingo Molnar * * Fixes * Maciej W. Rozycki : Bits for genuine 82489DX APICs; * thanks to Eric Gilmore * and Rolf G. Tews * for testing these extensively * Paul Diefenbaugh : Added full ACPI support */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_X86_IO_APIC #undef APIC_LOCKUP_DEBUG #define APIC_LOCKUP_DEBUG static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL; unsigned char int_delivery_mode = dest_LowestPrio; /* * # of IRQ routing registers */ int nr_ioapic_registers[MAX_IO_APICS]; /* * Rough estimation of how many shared IRQs there are, can * be changed anytime. */ #define MAX_PLUS_SHARED_IRQS NR_IRQS #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) /* * This is performance-critical, we want to do it O(1) * * the indexing order of this array favors 1:1 mappings * between pins and IRQs. */ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; while (entry->next) entry = irq_2_pin + entry->next; if (entry->pin != -1) { entry->next = first_free_entry; entry = irq_2_pin + entry->next; if (++first_free_entry >= PIN_MAP_SIZE) panic("io_apic.c: whoops"); } entry->apic = apic; entry->pin = pin; } /* * Reroute an IRQ to a different pin. */ static void __init replace_pin_at_irq(unsigned int irq, int oldapic, int oldpin, int newapic, int newpin) { struct irq_pin_list *entry = irq_2_pin + irq; while (1) { if (entry->apic == oldapic && entry->pin == oldpin) { entry->apic = newapic; entry->pin = newpin; } if (!entry->next) break; entry = irq_2_pin + entry->next; } } #define __DO_ACTION(R, ACTION, FINAL) \ \ { \ int pin; \ struct irq_pin_list *entry = irq_2_pin + irq; \ \ for (;;) { \ unsigned int reg; \ pin = entry->pin; \ if (pin == -1) \ break; \ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ reg ACTION; \ io_apic_write(entry->apic, 0x10 + R + pin*2, reg); \ if (!entry->next) \ break; \ entry = irq_2_pin + entry->next; \ } \ FINAL; \ } #define DO_ACTION(name,R,ACTION, FINAL) \ \ static void name##_IO_APIC_irq (unsigned int irq) \ __DO_ACTION(R, ACTION, FINAL) DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) DO_ACTION( __unmask, 0, &= 0xfffeffff, ) DO_ACTION( __edge, 0, &= 0xffff7fff, ) DO_ACTION( __level, 0, |= 0x00008000, ) static void mask_IO_APIC_irq (unsigned int irq) { unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); __mask_IO_APIC_irq(irq); spin_unlock_irqrestore(&ioapic_lock, flags); } static void unmask_IO_APIC_irq (unsigned int irq) { unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); __unmask_IO_APIC_irq(irq); spin_unlock_irqrestore(&ioapic_lock, flags); } void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; unsigned long flags; /* Check delivery_mode to be sure we're not clearing an SMI pin */ spin_lock_irqsave(&ioapic_lock, flags); *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin); spin_unlock_irqrestore(&ioapic_lock, flags); if (entry.delivery_mode == dest_SMI) return; /* * Disable it in the IO-APIC irq-routing table: */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0)); io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1)); spin_unlock_irqrestore(&ioapic_lock, flags); } static void clear_IO_APIC (void) { int apic, pin; for (apic = 0; apic < nr_ioapics; apic++) for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) clear_IO_APIC_pin(apic, pin); } static void set_ioapic_affinity (unsigned int irq, unsigned long mask) { unsigned long flags; /* * Only the first 8 bits are valid. */ mask = mask << 24; spin_lock_irqsave(&ioapic_lock, flags); __DO_ACTION(1, = mask, ) spin_unlock_irqrestore(&ioapic_lock, flags); } #define balance_irq(_irq) ((void)0) /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. */ #define MAX_PIRQS 8 int pirq_entries [MAX_PIRQS]; int pirqs_enabled; int skip_ioapic_setup; #if 0 static int __init noioapic_setup(char *str) { skip_ioapic_setup = 1; return 1; } __setup("noapic", noioapic_setup); static int __init ioapic_setup(char *str) { skip_ioapic_setup = 0; return 1; } __setup("apic", ioapic_setup); static int __init ioapic_pirq_setup(char *str) { int i, max; int ints[MAX_PIRQS+1]; get_options(str, ARRAY_SIZE(ints), ints); for (i = 0; i < MAX_PIRQS; i++) pirq_entries[i] = -1; pirqs_enabled = 1; printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); max = MAX_PIRQS; if (ints[0] < MAX_PIRQS) max = ints[0]; for (i = 0; i < max; i++) { printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* * PIRQs are mapped upside down, usually. */ pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; } return 1; } __setup("pirq=", ioapic_pirq_setup); #endif /* * Find the IRQ entry number of a certain pin. */ static int __init find_irq_entry(int apic, int pin, int type) { int i; for (i = 0; i < mp_irq_entries; i++) if (mp_irqs[i].mpc_irqtype == type && (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid || mp_irqs[i].mpc_dstapic == MP_APIC_ALL) && mp_irqs[i].mpc_dstirq == pin) return i; return -1; } /* * Find the pin to which IRQ[irq] (ISA) is connected */ static int __init find_isa_irq_pin(int irq, int type) { int i; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || mp_bus_id_to_type[lbus] == MP_BUS_MCA) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) return mp_irqs[i].mpc_dstirq; } return -1; } /* * Find a specific PCI IRQ entry. * Not an __init, possibly needed by modules */ static int pin_2_irq(int idx, int apic, int pin); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) { int apic, i, best_guess = -1; Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", bus, slot, pin); if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) { printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); return -1; } for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; for (apic = 0; apic < nr_ioapics; apic++) if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || mp_irqs[i].mpc_dstapic == MP_APIC_ALL) break; if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == lbus) && (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); if (!(apic || IO_APIC_IRQ(irq))) continue; if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) return irq; /* * Use the first all-but-pin matching entry as a * best-guess fuzzy result for broken mptables. */ if (best_guess < 0) best_guess = irq; } } return best_guess; } /* * EISA Edge/Level control register, ELCR */ static int __init EISA_ELCR(unsigned int irq) { if (irq < 16) { unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); return 0; } /* EISA interrupts are always polarity zero and can be edge or level * trigger depending on the ELCR value. If an interrupt is listed as * EISA conforming in the MP table, that means its trigger type must * be read in from the ELCR */ #define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_srcbusirq)) #define default_EISA_polarity(idx) (0) /* ISA interrupts are always polarity zero edge triggered, * when listed as conforming in the MP table. */ #define default_ISA_trigger(idx) (0) #define default_ISA_polarity(idx) (0) /* PCI interrupts are always polarity one level triggered, * when listed as conforming in the MP table. */ #define default_PCI_trigger(idx) (1) #define default_PCI_polarity(idx) (1) /* MCA interrupts are always polarity zero level triggered, * when listed as conforming in the MP table. */ #define default_MCA_trigger(idx) (1) #define default_MCA_polarity(idx) (0) static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int polarity; /* * Determine IRQ line polarity (high active or low active): */ switch (mp_irqs[idx].mpc_irqflag & 3) { case 0: /* conforms, ie. bus-type dependent polarity */ { switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ { polarity = default_ISA_polarity(idx); break; } case MP_BUS_EISA: /* EISA pin */ { polarity = default_EISA_polarity(idx); break; } case MP_BUS_PCI: /* PCI pin */ { polarity = default_PCI_polarity(idx); break; } case MP_BUS_MCA: /* MCA pin */ { polarity = default_MCA_polarity(idx); break; } default: { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } } break; } case 1: /* high active */ { polarity = 0; break; } case 2: /* reserved */ { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } case 3: /* low active */ { polarity = 1; break; } default: /* invalid */ { printk(KERN_WARNING "broken BIOS!!\n"); polarity = 1; break; } } return polarity; } static int __init MPBIOS_trigger(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int trigger; /* * Determine IRQ trigger mode (edge or level sensitive): */ switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) { case 0: /* conforms, ie. bus-type dependent */ { switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ { trigger = default_ISA_trigger(idx); break; } case MP_BUS_EISA: /* EISA pin */ { trigger = default_EISA_trigger(idx); break; } case MP_BUS_PCI: /* PCI pin */ { trigger = default_PCI_trigger(idx); break; } case MP_BUS_MCA: /* MCA pin */ { trigger = default_MCA_trigger(idx); break; } default: { printk(KERN_WARNING "broken BIOS!!\n"); trigger = 1; break; } } break; } case 1: /* edge */ { trigger = 0; break; } case 2: /* reserved */ { printk(KERN_WARNING "broken BIOS!!\n"); trigger = 1; break; } case 3: /* level */ { trigger = 1; break; } default: /* invalid */ { printk(KERN_WARNING "broken BIOS!!\n"); trigger = 0; break; } } return trigger; } static inline int irq_polarity(int idx) { return MPBIOS_polarity(idx); } static inline int irq_trigger(int idx) { return MPBIOS_trigger(idx); } static int pin_2_irq(int idx, int apic, int pin) { int irq, i; int bus = mp_irqs[idx].mpc_srcbus; /* * Debugging check, we are in big trouble if this message pops up! */ if (mp_irqs[idx].mpc_dstirq != pin) printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n"); switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ case MP_BUS_EISA: case MP_BUS_MCA: { irq = mp_irqs[idx].mpc_srcbusirq; break; } case MP_BUS_PCI: /* PCI pin */ { /* * PCI IRQs are mapped in order */ i = irq = 0; while (i < apic) irq += nr_ioapic_registers[i++]; irq += pin; break; } default: { printk(KERN_ERR "unknown bus type %d.\n",bus); irq = 0; break; } } /* * PCI IRQ command line redirection. Yes, limits are hardcoded. */ if ((pin >= 16) && (pin <= 23)) { if (pirq_entries[pin-16] != -1) { if (!pirq_entries[pin-16]) { printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); } else { irq = pirq_entries[pin-16]; printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", pin-16, irq); } } } return irq; } static inline int IO_APIC_irq_trigger(int irq) { int apic, idx, pin; for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { idx = find_irq_entry(apic,pin,mp_INT); if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) return irq_trigger(idx); } } /* * nonexistent IRQs are edge default */ return 0; } int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 }; #ifdef CONFIG_VMX int vector_irq[256]; #endif static int __init assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; if (IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq); next: current_vector += 8; /* Skip the hypercall vector. */ if (current_vector == HYPERCALL_VECTOR) goto next; /* Skip the Linux/BSD fast-trap vector. */ if (current_vector == 0x80) goto next; if (current_vector > FIRST_SYSTEM_VECTOR) { offset++; current_vector = FIRST_DEVICE_VECTOR + offset; } if (current_vector == FIRST_SYSTEM_VECTOR) panic("ran out of interrupt sources!"); IO_APIC_VECTOR(irq) = current_vector; #ifdef CONFIG_VMX vector_irq[current_vector] = irq; printk("vector_irq[%x] = %d\n", current_vector, irq); #endif return current_vector; } extern void (*interrupt[NR_IRQS])(void); /* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be * handled with the level-triggered descriptor, but that one has slightly * more overhead. Level-triggered interrupts cannot be handled with the * edge-triggered handler, without risking IRQ storms and other ugly * races. */ static unsigned int startup_edge_ioapic_irq(unsigned int irq); #define shutdown_edge_ioapic_irq disable_edge_ioapic_irq #define enable_edge_ioapic_irq unmask_IO_APIC_irq static void disable_edge_ioapic_irq (unsigned int irq); static void ack_edge_ioapic_irq(unsigned int irq); static void end_edge_ioapic_irq (unsigned int i); static struct hw_interrupt_type ioapic_edge_irq_type = { "IO-APIC-edge", startup_edge_ioapic_irq, shutdown_edge_ioapic_irq, enable_edge_ioapic_irq, disable_edge_ioapic_irq, ack_edge_ioapic_irq, end_edge_ioapic_irq, set_ioapic_affinity, }; static unsigned int startup_level_ioapic_irq (unsigned int irq); #define shutdown_level_ioapic_irq mask_IO_APIC_irq #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq static void mask_and_ack_level_ioapic_irq (unsigned int irq); static void end_level_ioapic_irq (unsigned int irq); static struct hw_interrupt_type ioapic_level_irq_type = { "IO-APIC-level", startup_level_ioapic_irq, shutdown_level_ioapic_irq, enable_level_ioapic_irq, disable_level_ioapic_irq,
/*
    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

/**
 * @file    templates/halconf.h
 * @brief   HAL configuration header.
 * @details HAL configuration file, this file allows to enable or disable the
 *          various device drivers from your application. You may also use
 *          this file in order to override the device drivers default settings.
 *
 * @addtogroup HAL_CONF
 * @{
 */

#ifndef HALCONF_H
#define HALCONF_H

#include "mcuconf.h"

/**
 * @brief   Enables the TM subsystem.
 */
#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
#define HAL_USE_TM                  FALSE
#endif

/**
 * @brief   Enables the PAL subsystem.
 */
#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
#define HAL_USE_PAL                 TRUE
#endif

/**
 * @brief   Enables the ADC subsystem.
 */
#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
#define HAL_USE_ADC                 FALSE
#endif

/**
 * @brief   Enables the DAC subsystem.
 */
#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
#define HAL_USE_DAC                 FALSE
#endif

/**
 * @brief   Enables the CAN subsystem.
 */
#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
#define HAL_USE_CAN                 FALSE
#endif

/**
 * @brief   Enables the EXT subsystem.
 */
#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
#define HAL_USE_EXT                 FALSE
#endif

/**
 * @brief   Enables the GPT subsystem.
 */
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
#define HAL_USE_GPT                 FALSE
#endif

/**
 * @brief   Enables the I2C subsystem.
 */
#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
#define HAL_USE_I2C                 FALSE
#endif

/**
 * @brief   Enables the ICU subsystem.
 */
#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
#define HAL_USE_ICU                 FALSE
#endif

/**
 * @brief   Enables the MAC subsystem.
 */
#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
#define HAL_USE_MAC                 FALSE
#endif

/**
 * @brief   Enables the MMC_SPI subsystem.
 */
#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
#define HAL_USE_MMC_SPI             FALSE
#endif

/**
 * @brief   Enables the PWM subsystem.
 */
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
#define HAL_USE_PWM                 FALSE
#endif

/**
 * @brief   Enables the RTC subsystem.
 */
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
#define HAL_USE_RTC                 FALSE
#endif

/**
 * @brief   Enables the SDC subsystem.
 */
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
#define HAL_USE_SDC                 FALSE
#endif

/**
 * @brief   Enables the SERIAL subsystem.
 */
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL              FALSE
#endif

/**
 * @brief   Enables the SERIAL over USB subsystem.
 */
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL_USB          TRUE
#endif

/**
 * @brief   Enables the SPI subsystem.
 */
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
#define HAL_USE_SPI                 FALSE
#endif

/**
 * @brief   Enables the UART subsystem.
 */
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
#define HAL_USE_UART                FALSE
#endif

/**
 * @brief   Enables the USB subsystem.
 */
#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
#define HAL_USE_USB                 TRUE
#endif

/**
 * @brief   Enables the I2S subsystem.
 */
#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
#define HAL_USE_I2S                 FALSE
#endif

/**
 * @brief   Enables the WDG subsystem.
 */
#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
#define HAL_USE_WDG                 FALSE
#endif

/*===========================================================================*/
/* ADC driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables synchronous APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
#define ADC_USE_WAIT                TRUE
#endif

/**
 * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define ADC_USE_MUTUAL_EXCLUSION    TRUE
#endif

/*===========================================================================*/
/* CAN driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Sleep mode related APIs inclusion switch.
 */
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
#define CAN_USE_SLEEP_MODE          TRUE
#endif

/*===========================================================================*/
/* I2C driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables the mutual exclusion APIs on the I2C bus.
 */
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define I2C_USE_MUTUAL_EXCLUSION    TRUE
#endif

/*===========================================================================*/
/* MAC driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables an event sources for incoming packets.
 */
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
#define MAC_USE_ZERO_COPY           FALSE
#endif

/**
 * @brief   Enables an event sources for incoming packets.
 */
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
#define MAC_USE_EVENTS              TRUE
#endif

/*===========================================================================*/
/* MMC_SPI driver related settings.                                          */
/*===========================================================================*/

/**
 * @brief   Delays insertions.
 * @details If enabled this options inserts delays into the MMC waiting
 *          routines releasing some extra CPU time for the threads with
 *          lower priority, this may slow down the driver a bit however.
 *          This option is recommended also if the SPI driver does not
 *          use a DMA channel and heavily loads the CPU.
 */
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING            TRUE
#endif

/*===========================================================================*/
/* SDC driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Number of initialization attempts before rejecting the card.
 * @note    Attempts are performed at 10mS intervals.
 */
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
#define SDC_INIT_RETRY              100
#endif

/**
 * @brief   Include support for MMC cards.
 * @note    MMC support is not yet implemented so this option must be kept
 *          at @p FALSE.
 */
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
#define SDC_MMC_SUPPORT             FALSE
#endif

/**
 * @brief   Delays insertions.
 * @details If enabled this options inserts delays into the MMC waiting
 *          routines releasing some extra CPU time for the threads with
 *          lower priority, this may slow down the driver a bit however.
 */
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
#define SDC_NICE_WAITING            TRUE
#endif

/*===========================================================================*/
/* SERIAL driver related settings.                                           */
/*===========================================================================*/

/**
 * @brief   Default bit rate.
 * @details Configuration parameter, this is the baud rate selected for the
 *          default configuration.
 */
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
#define SERIAL_DEFAULT_BITRATE      38400
#endif

/**
 * @brief   Serial buffers size.
 * @details Configuration parameter, you can change the depth of the queue
 *          buffers depending on the requirements of your application.
 * @note    The default is 16 bytes for both the transmission and receive
 *          buffers.
 */
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_BUFFERS_SIZE         16
#endif

/*===========================================================================*/
/* SERIAL_USB driver related setting.                                        */
/*===========================================================================*/

/**
 * @brief   Serial over USB buffers size.
 * @details Configuration parameter, the buffer size must be a multiple of
 *          the USB data endpoint maximum packet size.
 * @note    The default is 256 bytes for both the transmission and receive
 *          buffers.
 */
#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_USB_BUFFERS_SIZE     64
#endif

/*===========================================================================*/
/* SPI driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables synchronous APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT                TRUE
#endif

/**
 * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION    TRUE
#endif

/*===========================================================================*/
/* UART driver related settings.                                             */
/*===========================================================================*/

/**
 * @brief   Enables synchronous APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
#define UART_USE_WAIT               FALSE
#endif

/**
 * @brief   Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define UART_USE_MUTUAL_EXCLUSION   FALSE
#endif

/*===========================================================================*/
/* USB driver related settings.                                              */
/*===========================================================================*/

/**
 * @brief   Enables synchronous APIs.
 * @note    Disabling this option saves both code and data space.
 */
#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
#define USB_USE_WAIT                FALSE
#endif

#endif /* HALCONF_H */

/** @} */
nected to IO APIC #0 */ setup_ExtINT_IRQ0_pin(pin2, vector); if (timer_irq_works()) { printk("works.\n"); if (pin1 != -1) replace_pin_at_irq(0, 0, pin1, 0, pin2); else add_pin_to_irq(0, 0, pin2); return; } /* * Cleanup, just in case ... */ clear_IO_APIC_pin(0, pin2); } printk(" failed.\n"); printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); irq_desc[0].handler = &lapic_irq_type; apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ enable_8259A_irq(0); if (timer_irq_works()) { printk(" works.\n"); return; } apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | vector); printk(" failed.\n"); printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); init_8259A(0); make_8259A_irq(0); apic_write_around(APIC_LVT0, APIC_DM_EXTINT); unlock_ExtINT_logic(); if (timer_irq_works()) { printk(" works.\n"); return; } printk(" failed :(.\n"); panic("IO-APIC + timer doesn't work! pester mingo@redhat.com"); } /* * * IRQ's that are handled by the old PIC in all cases: * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. * - There used to be IRQ13 here as well, but all * MPS-compliant must not use it for FPU coupling and we * want to use exception 16 anyway. And there are * systems who connect it to an I/O APIC for other uses. * Thus we don't mark it special any longer. * * Additionally, something is definitely wrong with irq9 * on PIIX4 boards. */ #define PIC_IRQS (1<<2) void __init setup_IO_APIC(void) { enable_IO_APIC(); io_apic_irqs = ~PIC_IRQS; printk("ENABLING IO-APIC IRQs\n"); /* * Set up IO-APIC IRQ routing. */ if (!acpi_ioapic) setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); if (!acpi_ioapic) print_IO_APIC(); } #endif /* CONFIG_X86_IO_APIC */ /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_BOOT #define IO_APIC_MAX_ID 15 int __init io_apic_get_unique_id (int ioapic, int apic_id) { struct IO_APIC_reg_00 reg_00; static unsigned long apic_id_map = 0; unsigned long flags; int i = 0; /* * The P4 platform supports up to 256 APIC IDs on two separate APIC * buses (one for LAPICs, one for IOAPICs), where predecessors only * supports up to 16 on one shared APIC bus. * * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full * advantage of new APIC bus architecture. */ if (!apic_id_map) apic_id_map = phys_cpu_present_map; spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); if (apic_id >= IO_APIC_MAX_ID) { printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " "%d\n", ioapic, apic_id, reg_00.ID); apic_id = reg_00.ID; } /* XAPICs do not need unique IDs */ if (clustered_apic_mode == CLUSTERED_APIC_XAPIC){ printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } /* * Every APIC in a system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ if (apic_id_map & (1 << apic_id)) { for (i = 0; i < IO_APIC_MAX_ID; i++) { if (!(apic_id_map & (1 << i))) break; } if (i == IO_APIC_MAX_ID) panic("Max apic_id exceeded!\n"); printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " "trying %d\n", ioapic, apic_id, i); apic_id = i; } apic_id_map |= (1 << apic_id); if (reg_00.ID != apic_id) { reg_00.ID = apic_id; spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(ioapic, 0, *(int *)®_00); *(int *)®_00 = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); /* Sanity check */ if (reg_00.ID != apic_id) panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } int __init io_apic_get_version (int ioapic) { struct IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_01 = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); return reg_01.version; } int __init io_apic_get_redir_entries (int ioapic) { struct IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_01 = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); return reg_01.entries; } int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low) { struct IO_APIC_route_entry entry; unsigned long flags; if (!IO_APIC_IRQ(irq)) { printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n", ioapic); return -EINVAL; } /* * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. * Note that we mask (disable) IRQs now -- these get enabled when the * corresponding device driver registers for this IRQ. */ memset(&entry,0,sizeof(entry)); entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; entry.dest.logical.logical_dest = target_cpus(); entry.mask = 1; /* Disabled (masked) */ entry.trigger = edge_level; entry.polarity = active_high_low; /* * IRQs < 16 are already in the irq_2_pin[] map */ if (irq >= 16) add_pin_to_irq(irq, ioapic, pin); entry.vector = assign_irq_vector(irq); printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " "IRQ %d Mode:%i Active:%i)\n", ioapic, mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); if (edge_level) { irq_desc[irq].handler = &ioapic_level_irq_type; } else { irq_desc[irq].handler = &ioapic_edge_irq_type; } set_intr_gate(entry.vector, interrupt[irq]); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); spin_unlock_irqrestore(&ioapic_lock, flags); return 0; } #endif /*CONFIG_ACPI_BOOT*/ extern char opt_leveltrigger[], opt_edgetrigger[]; static int __init ioapic_trigger_setup(void) { char *p; irq_desc_t *desc; long irq; p = opt_leveltrigger; while ( *p != '\0' ) { irq = simple_strtol(p, &p, 10); if ( (irq <= 0) || (irq >= NR_IRQS) ) { printk("IRQ '%ld' out of range in level-trigger list '%s'\n", irq, opt_leveltrigger); break; } printk("Forcing IRQ %ld to level-trigger: ", irq); desc = &irq_desc[irq]; spin_lock_irq(&desc->lock); if ( desc->handler == &ioapic_level_irq_type ) { printk("already level-triggered (no force applied).\n"); } else if ( desc->handler != &ioapic_edge_irq_type ) { printk("cannot force (can only force IO-APIC-edge IRQs).\n"); } else { desc->handler = &ioapic_level_irq_type; __mask_IO_APIC_irq(irq); __level_IO_APIC_irq(irq); printk("done.\n"); } spin_unlock_irq(&desc->lock); if ( *p == '\0' ) break; if ( *p != ',' ) { printk("Unexpected character '%c' in level-trigger list '%s'\n", *p, opt_leveltrigger); break; } p++; } p = opt_edgetrigger; while ( *p != '\0' ) { irq = simple_strtol(p, &p, 10); if ( (irq <= 0) || (irq >= NR_IRQS) ) { printk("IRQ '%ld' out of range in edge-trigger list '%s'\n", irq, opt_edgetrigger); break; } printk("Forcing IRQ %ld to edge-trigger: ", irq); desc = &irq_desc[irq]; spin_lock_irq(&desc->lock); if ( desc->handler == &ioapic_edge_irq_type ) { printk("already edge-triggered (no force applied).\n"); } else if ( desc->handler != &ioapic_level_irq_type ) { printk("cannot force (can only force IO-APIC-level IRQs).\n"); } else { desc->handler = &ioapic_edge_irq_type; __edge_IO_APIC_irq(irq); desc->status |= IRQ_PENDING; /* may have lost a masked edge */ printk("done.\n"); } spin_unlock_irq(&desc->lock); if ( *p == '\0' ) break; if ( *p != ',' ) { printk("Unexpected character '%c' in edge-trigger list '%s'\n", *p, opt_edgetrigger); break; } p++; } return 0; } __initcall(ioapic_trigger_setup);