Automatic merge of rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git branch HEAD

This commit is contained in:
2005-05-31 11:50:32 -04:00 committed by Jeff Garzik
commit edb3e182b6
184 changed files with 16090 additions and 5084 deletions

View File

@ -1163,7 +1163,7 @@ config PCI_DIRECT
config PCI_MMCONFIG
bool
depends on PCI && (PCI_GOMMCONFIG || (PCI_GOANY && ACPI))
depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
select ACPI_BOOT
default y

View File

@ -118,7 +118,7 @@ struct _cpuid4_info {
};
#define MAX_CACHE_LEAVES 4
static unsigned short __devinitdata num_cache_leaves;
static unsigned short num_cache_leaves;
static int __devinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
{

View File

@ -1074,8 +1074,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
cpu_set(cpu, cpu_sibling_map[cpu]);
}
if (siblings != smp_num_siblings)
if (siblings != smp_num_siblings) {
printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
smp_num_siblings = siblings;
}
if (c->x86_num_cores > 1) {
for (i = 0; i < NR_CPUS; i++) {

View File

@ -1029,7 +1029,6 @@ void pcibios_penalize_isa_irq(int irq)
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin;
extern int via_interrupt_line_quirk;
struct pci_dev *temp_dev;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
@ -1084,10 +1083,6 @@ static int pirq_enable_irq(struct pci_dev *dev)
printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
'A' + pin, pci_name(dev), msg);
}
/* VIA bridges use interrupt line for apic/pci steering across
the V-Link */
else if (via_interrupt_line_quirk)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15);
return 0;
}

View File

@ -1143,12 +1143,12 @@ config PCI_QSPAN
config PCI_8260
bool
depends on PCI && 8260 && !8272
depends on PCI && 8260
default y
config 8260_PCI9
bool " Enable workaround for MPC826x erratum PCI 9"
depends on PCI_8260
depends on PCI_8260 && !ADS8272
default y
choice

View File

@ -22,7 +22,8 @@ targets += uImage
$(obj)/uImage: $(obj)/vmlinux.gz
$(Q)rm -f $@
$(call if_changed,uimage)
@echo ' Image: $@' $(if $(wildcard $@),'is ready','not made')
@echo -n ' Image: $@ '
@if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
# Files generated that shall be removed upon make clean
clean-files := sImage vmapus vmlinux* miboot* zImage* uImage

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.11-rc1
# Thu Jan 20 01:25:35 2005
# Linux kernel version: 2.6.12-rc4
# Tue May 17 11:56:01 2005
#
CONFIG_MMU=y
CONFIG_GENERIC_HARDIRQS=y
@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
CONFIG_PPC=y
CONFIG_PPC32=y
CONFIG_GENERIC_NVRAM=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
#
# Code maturity level options
@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@ -29,12 +31,14 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
# CONFIG_EPOLL is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@ -44,6 +48,7 @@ CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
#
# Loadable module support
@ -62,10 +67,12 @@ CONFIG_CC_ALIGN_JUMPS=0
CONFIG_E500=y
CONFIG_BOOKE=y
CONFIG_FSL_BOOKE=y
# CONFIG_PHYS_64BIT is not set
CONFIG_SPE=y
CONFIG_MATH_EMULATION=y
# CONFIG_CPU_FREQ is not set
CONFIG_PPC_GEN550=y
# CONFIG_PM is not set
CONFIG_85xx=y
CONFIG_PPC_INDIRECT_PCI_BE=y
@ -76,6 +83,7 @@ CONFIG_PPC_INDIRECT_PCI_BE=y
CONFIG_MPC8555_CDS=y
# CONFIG_MPC8560_ADS is not set
# CONFIG_SBC8560 is not set
# CONFIG_STX_GP3 is not set
CONFIG_MPC8555=y
CONFIG_85xx_PCI2=y
@ -90,6 +98,7 @@ CONFIG_CPM2=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_CMDLINE_BOOL is not set
CONFIG_ISA_DMA_API=y
#
# Bus options
@ -104,10 +113,6 @@ CONFIG_PCI_NAMES=y
#
# CONFIG_PCCARD is not set
#
# PC-card bridges
#
#
# Advanced setup
#
@ -180,7 +185,59 @@ CONFIG_IOSCHED_CFQ=y
#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_IDE_SATA is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_IDE_TASK_IOCTL is not set
#
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
CONFIG_BLK_DEV_VIA82CXXX=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
# SCSI device support
@ -220,7 +277,6 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
@ -369,14 +425,6 @@ CONFIG_INPUT=y
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
# CONFIG_SERIO_I8042 is not set
#
# Input Device Drivers
#
@ -386,6 +434,13 @@ CONFIG_SOUND_GAMEPORT=y
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
#
# Character devices
#
@ -406,6 +461,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_CPM is not set
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@ -433,6 +489,11 @@ CONFIG_GEN_RTC=y
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
# TPM devices
#
# CONFIG_TCG_TPM is not set
#
# I2C support
#
@ -456,11 +517,11 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
@ -483,7 +544,9 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_ASB100 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
@ -494,9 +557,11 @@ CONFIG_I2C_MPC=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_W83781D is not set
@ -506,10 +571,12 @@ CONFIG_I2C_MPC=y
#
# Other I2C Chip support
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
# CONFIG_SENSORS_M41T00 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@ -538,7 +605,6 @@ CONFIG_I2C_MPC=y
# Graphics support
#
# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@ -548,13 +614,9 @@ CONFIG_I2C_MPC=y
#
# USB support
#
# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
#
# CONFIG_USB is not set
#
# USB Gadget Support
@ -585,6 +647,10 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
#
# XFS support
#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@ -646,7 +712,6 @@ CONFIG_NFS_FS=y
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
# CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@ -698,7 +763,9 @@ CONFIG_CRC32=y
#
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_KGDB_CONSOLE is not set
# CONFIG_SERIAL_TEXT_DEBUG is not set

View File

@ -232,7 +232,8 @@ skpinv: addi r6,r6,1 /* Increment */
tlbwe
/* 7. Jump to KERNELBASE mapping */
li r7,0
lis r7,MSR_KERNEL@h
ori r7,r7,MSR_KERNEL@l
bl 1f /* Find our address */
1: mflr r9
rlwimi r6,r9,0,20,31
@ -293,6 +294,18 @@ skpinv: addi r6,r6,1 /* Increment */
mtspr SPRN_HID0, r2
#endif
#if !defined(CONFIG_BDI_SWITCH)
/*
* The Abatron BDI JTAG debugger does not tolerate others
* mucking with the debug registers.
*/
lis r2,DBCR0_IDM@h
mtspr SPRN_DBCR0,r2
/* clear any residual debug events */
li r2,-1
mtspr SPRN_DBSR,r2
#endif
/*
* This is where the main kernel code starts.
*/

View File

@ -408,12 +408,7 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
/* Early out if we are an invalid form of lswx */
if ((instword & INST_STRING_MASK) == INST_LSWX)
if ((rA >= rT) || (NB_RB >= rT) || (rT == rA) || (rT == NB_RB))
return -EINVAL;
/* Early out if we are an invalid form of lswi */
if ((instword & INST_STRING_MASK) == INST_LSWI)
if ((rA >= rT) || (rT == rA))
if ((rT == rA) || (rT == NB_RB))
return -EINVAL;
EA = (rA == 0) ? 0 : regs->gpr[rA];

View File

@ -127,7 +127,6 @@ mpc834x_sys_map_io(void)
{
/* we steal the lowest ioremap addr for virt space */
io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO);
io_block_mapping(BCSR_VIRT_ADDR, BCSR_PHYS_ADDR, BCSR_SIZE, _PAGE_IO);
}
int

View File

@ -26,9 +26,14 @@
#define VIRT_IMMRBAR ((uint)0xfe000000)
#define BCSR_PHYS_ADDR ((uint)0xf8000000)
#define BCSR_VIRT_ADDR ((uint)0xfe100000)
#define BCSR_SIZE ((uint)(32 * 1024))
#define BCSR_MISC_REG2_OFF 0x07
#define BCSR_MISC_REG2_PORESET 0x01
#define BCSR_MISC_REG3_OFF 0x08
#define BCSR_MISC_REG3_CNFLOCK 0x80
#ifdef CONFIG_PCI
/* PCI interrupt controller */
#define PIRQA MPC83xx_IRQ_IRQ4

View File

@ -210,6 +210,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
ppc_md.progress = gen550_progress;
#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
ppc_md.early_serial_map = mpc85xx_early_serial_map;
#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */
if (ppc_md.progress)
ppc_md.progress("mpc8540ads_init(): exit", 0);

View File

@ -44,6 +44,7 @@
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/open_pic.h>
#include <asm/i8259.h>
#include <asm/bootinfo.h>
#include <asm/pci-bridge.h>
#include <asm/mpc85xx.h>
@ -181,6 +182,7 @@ void __init
mpc85xx_cds_init_IRQ(void)
{
bd_t *binfo = (bd_t *) __res;
int i;
/* Determine the Physical Address of the OpenPIC regs */
phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
@ -198,6 +200,15 @@ mpc85xx_cds_init_IRQ(void)
*/
openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
#ifdef CONFIG_PCI
openpic_hookup_cascade(PIRQ0A, "82c59 cascade", i8259_irq);
for (i = 0; i < NUM_8259_INTERRUPTS; i++)
irq_desc[i].handler = &i8259_pic;
i8259_init(0);
#endif
#ifdef CONFIG_CPM2
/* Setup CPM2 PIC */
cpm2_init_IRQ();
@ -231,7 +242,7 @@ mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
* interrupt on slot */
{
{ 0, 1, 2, 3 }, /* 16 - PMC */
{ 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */
{ 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */
{ 0, 1, 2, 3 }, /* 18 - Slot 1 */
{ 1, 2, 3, 0 }, /* 19 - Slot 2 */
{ 2, 3, 0, 1 }, /* 20 - Slot 3 */
@ -280,13 +291,135 @@ mpc85xx_exclude_device(u_char bus, u_char devfn)
return PCIBIOS_DEVICE_NOT_FOUND;
#endif
/* We explicitly do not go past the Tundra 320 Bridge */
if (bus == 1)
if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
return PCIBIOS_DEVICE_NOT_FOUND;
if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
return PCIBIOS_DEVICE_NOT_FOUND;
else
return PCIBIOS_SUCCESSFUL;
}
void __init
mpc85xx_cds_enable_via(struct pci_controller *hose)
{
u32 pci_class;
u16 vid, did;
early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class);
if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI)
return;
/* Configure P2P so that we can reach bus 1 */
early_write_config_byte(hose, 0, 0x88, PCI_PRIMARY_BUS, 0);
early_write_config_byte(hose, 0, 0x88, PCI_SECONDARY_BUS, 1);
early_write_config_byte(hose, 0, 0x88, PCI_SUBORDINATE_BUS, 0xff);
early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid);
early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did);
if ((vid != PCI_VENDOR_ID_VIA) ||
(did != PCI_DEVICE_ID_VIA_82C686))
return;
/* Enable USB and IDE functions */
early_write_config_byte(hose, 1, 0x10, 0x48, 0x08);
}
void __init
mpc85xx_cds_fixup_via(struct pci_controller *hose)
{
u32 pci_class;
u16 vid, did;
early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class);
if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI)
return;
/*
* Force the backplane P2P bridge to have a window
* open from 0x00000000-0x00001fff in PCI I/O space.
* This allows legacy I/O (i8259, etc) on the VIA
* southbridge to be accessed.
*/
early_write_config_byte(hose, 0, 0x88, PCI_IO_BASE, 0x00);
early_write_config_word(hose, 0, 0x88, PCI_IO_BASE_UPPER16, 0x0000);
early_write_config_byte(hose, 0, 0x88, PCI_IO_LIMIT, 0x10);
early_write_config_word(hose, 0, 0x88, PCI_IO_LIMIT_UPPER16, 0x0000);
early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid);
early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did);
if ((vid != PCI_VENDOR_ID_VIA) ||
(did != PCI_DEVICE_ID_VIA_82C686))
return;
/*
* Since the P2P window was forced to cover the fixed
* legacy I/O addresses, it is necessary to manually
* place the base addresses for the IDE and USB functions
* within this window.
*/
/* Function 1, IDE */
early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_0, 0x1ff8);
early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_1, 0x1ff4);
early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_2, 0x1fe8);
early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_3, 0x1fe4);
early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_4, 0x1fd0);
/* Function 2, USB ports 0-1 */
early_write_config_dword(hose, 1, 0x12, PCI_BASE_ADDRESS_4, 0x1fa0);
/* Function 3, USB ports 2-3 */
early_write_config_dword(hose, 1, 0x13, PCI_BASE_ADDRESS_4, 0x1f80);
/* Function 5, Power Management */
early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_0, 0x1e00);
early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_1, 0x1dfc);
early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_2, 0x1df8);
/* Function 6, AC97 Interface */
early_write_config_dword(hose, 1, 0x16, PCI_BASE_ADDRESS_0, 0x1c00);
}
void __init
mpc85xx_cds_pcibios_fixup(void)
{
struct pci_dev *dev = NULL;
u_char c;
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_1, NULL))) {
/*
* U-Boot does not set the enable bits
* for the IDE device. Force them on here.
*/
pci_read_config_byte(dev, 0x40, &c);
c |= 0x03; /* IDE: Chip Enable Bits */
pci_write_config_byte(dev, 0x40, c);
/*
* Since only primary interface works, force the
* IDE function to standard primary IDE interrupt
* w/ 8259 offset
*/
dev->irq = 14;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
}
/*
* Force legacy USB interrupt routing
*/
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
dev->irq = 10;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
}
if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C586_2, dev))) {
dev->irq = 11;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
}
}
#endif /* CONFIG_PCI */
TODC_ALLOC();
@ -328,6 +461,9 @@ mpc85xx_cds_setup_arch(void)
loops_per_jiffy = freq / HZ;
#ifdef CONFIG_PCI
/* VIA IDE configuration */
ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup;
/* setup PCI host bridges */
mpc85xx_setup_hose();
#endif
@ -459,6 +595,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
ppc_md.progress = gen550_progress;
#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
ppc_md.early_serial_map = mpc85xx_early_serial_map;
#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */
if (ppc_md.progress)
ppc_md.progress("mpc85xx_cds_init(): exit", 0);

View File

@ -77,4 +77,7 @@
#define MPC85XX_PCI2_IO_SIZE 0x01000000
#define NR_8259_INTS 16
#define CPM_IRQ_OFFSET NR_8259_INTS
#endif /* __MACH_MPC85XX_CDS_H__ */

View File

@ -221,6 +221,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
ppc_md.progress = gen550_progress;
#endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB)
ppc_md.early_serial_map = sbc8560_early_serial_map;
#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */
if (ppc_md.progress)
ppc_md.progress("sbc8560_init(): exit", 0);

View File

@ -85,14 +85,11 @@ static int no_schedule;
static int has_cpu_l2lve;
#define PMAC_CPU_LOW_SPEED 1
#define PMAC_CPU_HIGH_SPEED 0
/* There are only two frequency states for each processor. Values
* are in kHz for the time being.
*/
#define CPUFREQ_HIGH PMAC_CPU_HIGH_SPEED
#define CPUFREQ_LOW PMAC_CPU_LOW_SPEED
#define CPUFREQ_HIGH 0
#define CPUFREQ_LOW 1
static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
{CPUFREQ_HIGH, 0},
@ -100,6 +97,11 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
{0, CPUFREQ_TABLE_END},
};
static struct freq_attr* pmac_cpu_freqs_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static inline void local_delay(unsigned long ms)
{
if (no_schedule)
@ -269,6 +271,8 @@ static int __pmac pmu_set_cpu_speed(int low_speed)
#ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
#endif
pmu_suspend();
/* Disable all interrupt sources on openpic */
pic_prio = openpic_get_priority();
openpic_set_priority(0xf);
@ -343,6 +347,8 @@ static int __pmac pmu_set_cpu_speed(int low_speed)
debug_calc_bogomips();
#endif
pmu_resume();
preempt_enable();
return 0;
@ -355,7 +361,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify)
static unsigned long prev_l3cr;
freqs.old = cur_freq;
freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
freqs.cpu = smp_processor_id();
if (freqs.old == freqs.new)
@ -363,7 +369,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify)
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (speed_mode == PMAC_CPU_LOW_SPEED &&
if (speed_mode == CPUFREQ_LOW &&
cpu_has_feature(CPU_FTR_L3CR)) {
l3cr = _get_L3CR();
if (l3cr & L3CR_L3E) {
@ -371,8 +377,8 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify)
_set_L3CR(0);
}
}
set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED);
if (speed_mode == PMAC_CPU_HIGH_SPEED &&
set_speed_proc(speed_mode == CPUFREQ_LOW);
if (speed_mode == CPUFREQ_HIGH &&
cpu_has_feature(CPU_FTR_L3CR)) {
l3cr = _get_L3CR();
if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
@ -380,7 +386,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify)
}
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq;
cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
return 0;
}
@ -423,7 +429,8 @@ static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = cur_freq;
return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]);
cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
}
static u32 __pmac read_gpio(struct device_node *np)
@ -457,7 +464,7 @@ static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state)
no_schedule = 1;
sleep_freq = cur_freq;
if (cur_freq == low_freq)
do_set_cpu_speed(PMAC_CPU_HIGH_SPEED, 0);
do_set_cpu_speed(CPUFREQ_HIGH, 0);
return 0;
}
@ -473,8 +480,8 @@ static int __pmac pmac_cpufreq_resume(struct cpufreq_policy *policy)
* is that we force a switch to whatever it was, which is
* probably high speed due to our suspend() routine
*/
do_set_cpu_speed(sleep_freq == low_freq ? PMAC_CPU_LOW_SPEED
: PMAC_CPU_HIGH_SPEED, 0);
do_set_cpu_speed(sleep_freq == low_freq ?
CPUFREQ_LOW : CPUFREQ_HIGH, 0);
no_schedule = 0;
return 0;
@ -488,6 +495,7 @@ static struct cpufreq_driver pmac_cpufreq_driver = {
.suspend = pmac_cpufreq_suspend,
.resume = pmac_cpufreq_resume,
.flags = CPUFREQ_PM_NO_WARN,
.attr = pmac_cpu_freqs_attr,
.name = "powermac",
.owner = THIS_MODULE,
};

View File

@ -49,10 +49,10 @@
/* PCI interrupt controller */
#define PCI_INT_STAT_REG 0xF8200000
#define PCI_INT_MASK_REG 0xF8200004
#define PIRQA (NR_SIU_INTS + 0)
#define PIRQB (NR_SIU_INTS + 1)
#define PIRQC (NR_SIU_INTS + 2)
#define PIRQD (NR_SIU_INTS + 3)
#define PIRQA (NR_CPM_INTS + 0)
#define PIRQB (NR_CPM_INTS + 1)
#define PIRQC (NR_CPM_INTS + 2)
#define PIRQD (NR_CPM_INTS + 3)
/*
* PCI memory map definitions for MPC8266ADS-PCI.
@ -68,28 +68,23 @@
* 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory
*/
/* window for a PCI master to access MPC8266 memory */
#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */
#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */
/* All the other PCI memory map definitions reside at syslib/m82xx_pci.h
Here we should redefine what is unique for this board */
#define M82xx_PCI_SLAVE_MEM_LOCAL 0x00000000 /* Local base */
#define M82xx_PCI_SLAVE_MEM_BUS 0x00000000 /* PCI base */
#define M82xx_PCI_SLAVE_MEM_SIZE 0x10000000 /* 256 Mb */
/* window for the processor to access PCI memory with prefetching */
#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */
#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */
#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */
#define M82xx_PCI_SLAVE_SEC_WND_SIZE ~(0x40000000 - 1U) /* 2 x 512Mb */
#define M82xx_PCI_SLAVE_SEC_WND_BASE 0x80000000 /* PCI Memory base */
/* window for the processor to access PCI memory without prefetching */
#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */
#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */
#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */
#if defined(CONFIG_ADS8272)
#define PCI_INT_TO_SIU SIU_INT_IRQ2
#elif defined(CONFIG_PQ2FADS)
#define PCI_INT_TO_SIU SIU_INT_IRQ6
#else
#warning PCI Bridge will be without interrupts support
#endif
/* window for the processor to access PCI I/O */
#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */
#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */
#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */
#define _IO_BASE PCI_MSTR_IO_LOCAL
#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL
#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS
#endif /* CONFIG_PCI */
#endif /* __MACH_ADS8260_DEFS */

View File

@ -81,7 +81,7 @@ obj-$(CONFIG_SBC82xx) += todc_time.o
obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \
todc_time.o
obj-$(CONFIG_8260) += m8260_setup.o
obj-$(CONFIG_PCI_8260) += m8260_pci.o indirect_pci.o
obj-$(CONFIG_PCI_8260) += m82xx_pci.o indirect_pci.o pci_auto.o
obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o
obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
ifeq ($(CONFIG_PPC_GEN550),y)
@ -97,7 +97,7 @@ obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o
obj-$(CONFIG_40x) += dcr.o
obj-$(CONFIG_BOOKE) += dcr.o
obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \
ppc_sys.o mpc85xx_sys.o \
ppc_sys.o i8259.o mpc85xx_sys.o \
mpc85xx_devices.o
ifeq ($(CONFIG_85xx),y)
obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o

View File

@ -1,193 +0,0 @@
/*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2004 Red Hat, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include "m8260_pci.h"
/* PCI bus configuration registers.
*/
static void __init m8260_setup_pci(struct pci_controller *hose)
{
volatile cpm2_map_t *immap = cpm2_immr;
unsigned long pocmr;
u16 tempShort;
#ifndef CONFIG_ATC /* already done in U-Boot */
/*
* Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
* and local bus for PCI (SIUMCR [LBPC]).
*/
immap->im_siu_conf.siu_82xx.sc_siumcr = 0x00640000;
#endif
/* Make PCI lowest priority */
/* Each 4 bits is a device bus request and the MS 4bits
is highest priority */
/* Bus 4bit value
--- ----------
CPM high 0b0000
CPM middle 0b0001
CPM low 0b0010
PCI reguest 0b0011
Reserved 0b0100
Reserved 0b0101
Internal Core 0b0110
External Master 1 0b0111
External Master 2 0b1000
External Master 3 0b1001
The rest are reserved */
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
/* Park bus on core while modifying PCI Bus accesses */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = 0x6;
/*
* Set up master window that allows the CPU to access PCI space. This
* window is set up using the first SIU PCIBR registers.
*/
immap->im_memctl.memc_pcimsk0 = MPC826x_PCI_MASK;
immap->im_memctl.memc_pcibr0 = MPC826x_PCI_BASE | PCIBR_ENABLE;
/* Disable machine check on no response or target abort */
immap->im_pci.pci_emr = cpu_to_le32(0x1fe7);
/* Release PCI RST (by default the PCI RST signal is held low) */
immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
/* give it some time */
mdelay(1);
/*
* Set up master window that allows the CPU to access PCI Memory (prefetch)
* space. This window is set up using the first set of Outbound ATU registers.
*/
immap->im_pci.pci_potar0 = cpu_to_le32(MPC826x_PCI_LOWER_MEM >> 12);
immap->im_pci.pci_pobar0 = cpu_to_le32((MPC826x_PCI_LOWER_MEM - MPC826x_PCI_MEM_OFFSET) >> 12);
pocmr = ((MPC826x_PCI_UPPER_MEM - MPC826x_PCI_LOWER_MEM) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr0 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PREFETCH_EN);
/*
* Set up master window that allows the CPU to access PCI Memory (non-prefetch)
* space. This window is set up using the second set of Outbound ATU registers.
*/
immap->im_pci.pci_potar1 = cpu_to_le32(MPC826x_PCI_LOWER_MMIO >> 12);
immap->im_pci.pci_pobar1 = cpu_to_le32((MPC826x_PCI_LOWER_MMIO - MPC826x_PCI_MMIO_OFFSET) >> 12);
pocmr = ((MPC826x_PCI_UPPER_MMIO - MPC826x_PCI_LOWER_MMIO) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr1 = cpu_to_le32(pocmr | POCMR_ENABLE);
/*
* Set up master window that allows the CPU to access PCI IO space. This window
* is set up using the third set of Outbound ATU registers.
*/
immap->im_pci.pci_potar2 = cpu_to_le32(MPC826x_PCI_IO_BASE >> 12);
immap->im_pci.pci_pobar2 = cpu_to_le32(MPC826x_PCI_LOWER_IO >> 12);
pocmr = ((MPC826x_PCI_UPPER_IO - MPC826x_PCI_LOWER_IO) >> 12) ^ 0xfffff;
immap->im_pci.pci_pocmr2 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PCI_IO);
/*
* Set up slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
immap->im_pci.pci_pitar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_LOCAL >> 12);
immap->im_pci.pci_pibar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_BUS >> 12);
pocmr = ((MPC826x_PCI_SLAVE_MEM_SIZE-1) >> 12) ^ 0xfffff;
immap->im_pci.pci_picmr0 = cpu_to_le32(pocmr | PICMR_ENABLE | PICMR_PREFETCH_EN);
/* See above for description - puts PCI request as highest priority */
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
/* Park the bus on the PCI */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
/* Host mode - specify the bridge as a host-PCI bridge */
early_write_config_word(hose, 0, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_HOST);
/* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
early_read_config_word(hose, 0, 0, PCI_COMMAND, &tempShort);
early_write_config_word(hose, 0, 0, PCI_COMMAND,
tempShort | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
}
void __init m8260_find_bridges(void)
{
extern int pci_assign_all_busses;
struct pci_controller * hose;
pci_assign_all_busses = 1;
hose = pcibios_alloc_controller();
if (!hose)
return;
ppc_md.pci_swizzle = common_swizzle;
hose->first_busno = 0;
hose->bus_offset = 0;
hose->last_busno = 0xff;
setup_m8260_indirect_pci(hose,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
m8260_setup_pci(hose);
hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET;
hose->io_base_virt = ioremap(MPC826x_PCI_IO_BASE,
MPC826x_PCI_IO_SIZE);
isa_io_base = (unsigned long) hose->io_base_virt;
/* setup resources */
pci_init_resource(&hose->mem_resources[0],
MPC826x_PCI_LOWER_MEM,
MPC826x_PCI_UPPER_MEM,
IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
pci_init_resource(&hose->mem_resources[1],
MPC826x_PCI_LOWER_MMIO,
MPC826x_PCI_UPPER_MMIO,
IORESOURCE_MEM, "PCI memory");
pci_init_resource(&hose->io_resource,
MPC826x_PCI_LOWER_IO,
MPC826x_PCI_UPPER_IO,
IORESOURCE_IO, "PCI I/O");
}

View File

@ -1,76 +0,0 @@
#ifndef _PPC_KERNEL_M8260_PCI_H
#define _PPC_KERNEL_M8260_PCI_H
#include <asm/m8260_pci.h>
/*
* Local->PCI map (from CPU) controlled by
* MPC826x master window
*
* 0x80000000 - 0xBFFFFFFF Total CPU2PCI space PCIBR0
*
* 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1)
* 0xA0000000 - 0xAFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2)
* 0xB0000000 - 0xB0FFFFFF 32-bit PCI IO (Outbound ATU #3)
*
* PCI->Local map (from PCI)
* MPC826x slave window controlled by
*
* 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1)
*/
/*
* Slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
#ifndef MPC826x_PCI_SLAVE_MEM_LOCAL
#define MPC826x_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart)
#define MPC826x_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart)
#define MPC826x_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize)
#endif
/*
* This is the window that allows the CPU to access PCI address space.
* It will be setup with the SIU PCIBR0 register. All three PCI master
* windows, which allow the CPU to access PCI prefetch, non prefetch,
* and IO space (see below), must all fit within this window.
*/
#ifndef MPC826x_PCI_BASE
#define MPC826x_PCI_BASE 0x80000000
#define MPC826x_PCI_MASK 0xc0000000
#endif
#ifndef MPC826x_PCI_LOWER_MEM
#define MPC826x_PCI_LOWER_MEM 0x80000000
#define MPC826x_PCI_UPPER_MEM 0x9fffffff
#define MPC826x_PCI_MEM_OFFSET 0x00000000
#endif
#ifndef MPC826x_PCI_LOWER_MMIO
#define MPC826x_PCI_LOWER_MMIO 0xa0000000
#define MPC826x_PCI_UPPER_MMIO 0xafffffff
#define MPC826x_PCI_MMIO_OFFSET 0x00000000
#endif
#ifndef MPC826x_PCI_LOWER_IO
#define MPC826x_PCI_LOWER_IO 0x00000000
#define MPC826x_PCI_UPPER_IO 0x00ffffff
#define MPC826x_PCI_IO_BASE 0xb0000000
#define MPC826x_PCI_IO_SIZE 0x01000000
#endif
#ifndef _IO_BASE
#define _IO_BASE isa_io_base
#endif
#ifdef CONFIG_8260_PCI9
struct pci_controller;
extern void setup_m8260_indirect_pci(struct pci_controller* hose,
u32 cfg_addr, u32 cfg_data);
#else
#define setup_m8260_indirect_pci setup_indirect_pci
#endif
#endif /* _PPC_KERNEL_M8260_PCI_H */

View File

@ -31,7 +31,7 @@
#include <asm/immap_cpm2.h>
#include <asm/cpm2.h>
#include "m8260_pci.h"
#include "m82xx_pci.h"
#ifdef CONFIG_8260_PCI9
/*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
@ -248,11 +248,11 @@ EXPORT_SYMBOL(idma_pci9_read_le);
static inline int is_pci_mem(unsigned long addr)
{
if (addr >= MPC826x_PCI_LOWER_MMIO &&
addr <= MPC826x_PCI_UPPER_MMIO)
if (addr >= M82xx_PCI_LOWER_MMIO &&
addr <= M82xx_PCI_UPPER_MMIO)
return 1;
if (addr >= MPC826x_PCI_LOWER_MEM &&
addr <= MPC826x_PCI_UPPER_MEM)
if (addr >= M82xx_PCI_LOWER_MEM &&
addr <= M82xx_PCI_UPPER_MEM)
return 1;
return 0;
}

View File

@ -34,7 +34,8 @@
unsigned char __res[sizeof(bd_t)];
extern void cpm2_reset(void);
extern void m8260_find_bridges(void);
extern void pq2_find_bridges(void);
extern void pq2pci_init_irq(void);
extern void idma_pci9_init(void);
/* Place-holder for board-specific init */
@ -56,7 +57,7 @@ m8260_setup_arch(void)
idma_pci9_init();
#endif
#ifdef CONFIG_PCI_8260
m8260_find_bridges();
pq2_find_bridges();
#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
@ -173,6 +174,12 @@ m8260_init_IRQ(void)
* in case the boot rom changed something on us.
*/
cpm2_immr->im_intctl.ic_siprr = 0x05309770;
#if defined(CONFIG_PCI) && (defined(CONFIG_ADS8272) || defined(CONFIG_PQ2FADS))
/* Initialize stuff for the 82xx CPLD IC and install demux */
pq2pci_init_irq();
#endif
}
/*

383
arch/ppc/syslib/m82xx_pci.c Normal file
View File

@ -0,0 +1,383 @@
/*
*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2004 Red Hat, Inc.
*
* 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
#include <asm/cpm2.h>
#include "m82xx_pci.h"
/*
* Interrupt routing
*/
static inline int
pq2pci_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
{
static char pci_irq_table[][4] =
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{
{ PIRQA, PIRQB, PIRQC, PIRQD }, /* IDSEL 22 - PCI slot 0 */
{ PIRQD, PIRQA, PIRQB, PIRQC }, /* IDSEL 23 - PCI slot 1 */
{ PIRQC, PIRQD, PIRQA, PIRQB }, /* IDSEL 24 - PCI slot 2 */
};
const long min_idsel = 22, max_idsel = 24, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
static void
pq2pci_mask_irq(unsigned int irq)
{
int bit = irq - NR_CPM_INTS;
*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));
return;
}
static void
pq2pci_unmask_irq(unsigned int irq)
{
int bit = irq - NR_CPM_INTS;
*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));
return;
}
static void
pq2pci_mask_and_ack(unsigned int irq)
{
int bit = irq - NR_CPM_INTS;
*(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit));
return;
}
static void
pq2pci_end_irq(unsigned int irq)
{
int bit = irq - NR_CPM_INTS;
*(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit));
return;
}
struct hw_interrupt_type pq2pci_ic = {
"PQ2 PCI",
NULL,
NULL,
pq2pci_unmask_irq,
pq2pci_mask_irq,
pq2pci_mask_and_ack,
pq2pci_end_irq,
0
};
static irqreturn_t
pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long stat, mask, pend;
int bit;
for(;;) {
stat = *(volatile unsigned long *) PCI_INT_STAT_REG;
mask = *(volatile unsigned long *) PCI_INT_MASK_REG;
pend = stat & ~mask & 0xf0000000;
if (!pend)
break;
for (bit = 0; pend != 0; ++bit, pend <<= 1) {
if (pend & 0x80000000)
__do_IRQ(NR_CPM_INTS + bit, regs);
}
}
return IRQ_HANDLED;
}
static struct irqaction pq2pci_irqaction = {
.handler = pq2pci_irq_demux,
.flags = SA_INTERRUPT,
.mask = CPU_MASK_NONE,
.name = "PQ2 PCI cascade",
};
void
pq2pci_init_irq(void)
{
int irq;
volatile cpm2_map_t *immap = cpm2_immr;
#if defined CONFIG_ADS8272
/* configure chip select for PCI interrupt controller */
immap->im_memctl.memc_br3 = PCI_INT_STAT_REG | 0x00001801;
immap->im_memctl.memc_or3 = 0xffff8010;
#elif defined CONFIG_PQ2FADS
immap->im_memctl.memc_br8 = PCI_INT_STAT_REG | 0x00001801;
immap->im_memctl.memc_or8 = 0xffff8010;
#endif
for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++)
irq_desc[irq].handler = &pq2pci_ic;
/* make PCI IRQ level sensitive */
immap->im_intctl.ic_siexr &=
~(1 << (14 - (PCI_INT_TO_SIU - SIU_INT_IRQ1)));
/* mask all PCI interrupts */
*(volatile unsigned long *) PCI_INT_MASK_REG |= 0xfff00000;
/* install the demultiplexer for the PCI cascade interrupt */
setup_irq(PCI_INT_TO_SIU, &pq2pci_irqaction);
return;
}
static int
pq2pci_exclude_device(u_char bus, u_char devfn)
{
return PCIBIOS_SUCCESSFUL;
}
/* PCI bus configuration registers.
*/
static void
pq2ads_setup_pci(struct pci_controller *hose)
{
__u32 val;
volatile cpm2_map_t *immap = cpm2_immr;
bd_t* binfo = (bd_t*) __res;
u32 sccr = immap->im_clkrst.car_sccr;
uint pci_div,freq,time;
/* PCI int lowest prio */
/* Each 4 bits is a device bus request and the MS 4bits
is highest priority */
/* Bus 4bit value
--- ----------
CPM high 0b0000
CPM middle 0b0001
CPM low 0b0010
PCI reguest 0b0011
Reserved 0b0100
Reserved 0b0101
Internal Core 0b0110
External Master 1 0b0111
External Master 2 0b1000
External Master 3 0b1001
The rest are reserved
*/
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
/* park bus on core */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_CORE;
/*
* Set up master windows that allow the CPU to access PCI space. These
* windows are set up using the two SIU PCIBR registers.
*/
immap->im_memctl.memc_pcimsk0 = M82xx_PCI_PRIM_WND_SIZE;
immap->im_memctl.memc_pcibr0 = M82xx_PCI_PRIM_WND_BASE | PCIBR_ENABLE;
#ifdef M82xx_PCI_SEC_WND_SIZE
immap->im_memctl.memc_pcimsk1 = M82xx_PCI_SEC_WND_SIZE;
immap->im_memctl.memc_pcibr1 = M82xx_PCI_SEC_WND_BASE | PCIBR_ENABLE;
#endif
#if defined CONFIG_ADS8272
immap->im_siu_conf.siu_82xx.sc_siumcr =
(immap->im_siu_conf.siu_82xx.sc_siumcr &
~(SIUMCR_BBD | SIUMCR_ESE | SIUMCR_PBSE |
SIUMCR_CDIS | SIUMCR_DPPC11 | SIUMCR_L2CPC11 |
SIUMCR_LBPC11 | SIUMCR_APPC11 |
SIUMCR_CS10PC11 | SIUMCR_BCTLC11 | SIUMCR_MMR11)) |
SIUMCR_DPPC11 | SIUMCR_L2CPC01 | SIUMCR_LBPC00 |
SIUMCR_APPC10 | SIUMCR_CS10PC00 |
SIUMCR_BCTLC00 | SIUMCR_MMR11 ;
#elif defined CONFIG_PQ2FADS
/*
* Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
* and local bus for PCI (SIUMCR [LBPC]).
*/
immap->im_siu_conf.siu_82xx.sc_siumcr = (immap->im_siu_conf.sc_siumcr &
~(SIUMCR_L2PC11 | SIUMCR_LBPC11 | SIUMCR_CS10PC11 | SIUMCR_APPC11) |
SIUMCR_BBD | SIUMCR_LBPC01 | SIUMCR_DPPC11 | SIUMCR_APPC10;
#endif
/* Enable PCI */
immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) *
( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1);
freq = (uint)((2*binfo->bi_cpmfreq)/(pci_div));
time = (int)666666/freq;
/* due to PCI Local Bus spec, some devices needs to wait such a long
time after RST deassertion. More specifically, 0.508s for 66MHz & twice more for 33 */
printk("%s: The PCI bus is %d Mhz.\nWaiting %s after deasserting RST...\n",__FILE__,freq,
(time==1) ? "0.5 seconds":"1 second" );
{
int i;
for(i=0;i<(500*time);i++)
udelay(1000);
}
/* setup ATU registers */
immap->im_pci.pci_pocmr0 = cpu_to_le32(POCMR_ENABLE | POCMR_PCI_IO |
((~(M82xx_PCI_IO_SIZE - 1U)) >> POTA_ADDR_SHIFT));
immap->im_pci.pci_potar0 = cpu_to_le32(M82xx_PCI_LOWER_IO >> POTA_ADDR_SHIFT);
immap->im_pci.pci_pobar0 = cpu_to_le32(M82xx_PCI_IO_BASE >> POTA_ADDR_SHIFT);
/* Set-up non-prefetchable window */
immap->im_pci.pci_pocmr1 = cpu_to_le32(POCMR_ENABLE | ((~(M82xx_PCI_MMIO_SIZE-1U)) >> POTA_ADDR_SHIFT));
immap->im_pci.pci_potar1 = cpu_to_le32(M82xx_PCI_LOWER_MMIO >> POTA_ADDR_SHIFT);
immap->im_pci.pci_pobar1 = cpu_to_le32((M82xx_PCI_LOWER_MMIO - M82xx_PCI_MMIO_OFFSET) >> POTA_ADDR_SHIFT);
/* Set-up prefetchable window */
immap->im_pci.pci_pocmr2 = cpu_to_le32(POCMR_ENABLE |POCMR_PREFETCH_EN |
(~(M82xx_PCI_MEM_SIZE-1U) >> POTA_ADDR_SHIFT));
immap->im_pci.pci_potar2 = cpu_to_le32(M82xx_PCI_LOWER_MEM >> POTA_ADDR_SHIFT);
immap->im_pci.pci_pobar2 = cpu_to_le32((M82xx_PCI_LOWER_MEM - M82xx_PCI_MEM_OFFSET) >> POTA_ADDR_SHIFT);
/* Inbound transactions from PCI memory space */
immap->im_pci.pci_picmr0 = cpu_to_le32(PICMR_ENABLE | PICMR_PREFETCH_EN |
((~(M82xx_PCI_SLAVE_MEM_SIZE-1U)) >> PITA_ADDR_SHIFT));
immap->im_pci.pci_pibar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_BUS >> PITA_ADDR_SHIFT);
immap->im_pci.pci_pitar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_LOCAL>> PITA_ADDR_SHIFT);
#if defined CONFIG_ADS8272
/* PCI int highest prio */
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x01236745;
#elif defined CONFIG_PQ2FADS
immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
#endif
/* park bus on PCI */
immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
/* Enable bus mastering and inbound memory transactions */
early_read_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, &val);
val &= 0xffff0000;
val |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER;
early_write_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, val);
}
void __init pq2_find_bridges(void)
{
extern int pci_assign_all_busses;
struct pci_controller * hose;
int host_bridge;
pci_assign_all_busses = 1;
hose = pcibios_alloc_controller();
if (!hose)
return;
ppc_md.pci_swizzle = common_swizzle;
hose->first_busno = 0;
hose->bus_offset = 0;
hose->last_busno = 0xff;
#ifdef CONFIG_ADS8272
hose->set_cfg_type = 1;
#endif
setup_m8260_indirect_pci(hose,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
(unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
/* Make sure it is a supported bridge */
early_read_config_dword(hose,
0,
PCI_DEVFN(0,0),
PCI_VENDOR_ID,
&host_bridge);
switch (host_bridge) {
case PCI_DEVICE_ID_MPC8265:
break;
case PCI_DEVICE_ID_MPC8272:
break;
default:
printk("Attempting to use unrecognized host bridge ID"
" 0x%08x.\n", host_bridge);
break;
}
pq2ads_setup_pci(hose);
hose->io_space.start = M82xx_PCI_LOWER_IO;
hose->io_space.end = M82xx_PCI_UPPER_IO;
hose->mem_space.start = M82xx_PCI_LOWER_MEM;
hose->mem_space.end = M82xx_PCI_UPPER_MMIO;
hose->pci_mem_offset = M82xx_PCI_MEM_OFFSET;
isa_io_base =
(unsigned long) ioremap(M82xx_PCI_IO_BASE,
M82xx_PCI_IO_SIZE);
hose->io_base_virt = (void *) isa_io_base;
/* setup resources */
pci_init_resource(&hose->mem_resources[0],
M82xx_PCI_LOWER_MEM,
M82xx_PCI_UPPER_MEM,
IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
pci_init_resource(&hose->mem_resources[1],
M82xx_PCI_LOWER_MMIO,
M82xx_PCI_UPPER_MMIO,
IORESOURCE_MEM, "PCI memory");
pci_init_resource(&hose->io_resource,
M82xx_PCI_LOWER_IO,
M82xx_PCI_UPPER_IO,
IORESOURCE_IO | 1, "PCI I/O");
ppc_md.pci_exclude_device = pq2pci_exclude_device;
hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
ppc_md.pci_map_irq = pq2pci_map_irq;
ppc_md.pcibios_fixup = NULL;
ppc_md.pcibios_fixup_bus = NULL;
}

View File

@ -0,0 +1,92 @@
#ifndef _PPC_KERNEL_M82XX_PCI_H
#define _PPC_KERNEL_M82XX_PCI_H
#include <asm/m8260_pci.h>
/*
* Local->PCI map (from CPU) controlled by
* MPC826x master window
*
* 0xF6000000 - 0xF7FFFFFF IO space
* 0x80000000 - 0xBFFFFFFF CPU2PCI memory space PCIBR0
*
* 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1)
* 0xA0000000 - 0xBFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2)
* 0xF6000000 - 0xF7FFFFFF 32-bit PCI IO (Outbound ATU #3)
*
* PCI->Local map (from PCI)
* MPC826x slave window controlled by
*
* 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1)
*/
/*
* Slave window that allows PCI masters to access MPC826x local memory.
* This window is set up using the first set of Inbound ATU registers
*/
#ifndef M82xx_PCI_SLAVE_MEM_LOCAL
#define M82xx_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart)
#define M82xx_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart)
#define M82xx_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize)
#endif
/*
* This is the window that allows the CPU to access PCI address space.
* It will be setup with the SIU PCIBR0 register. All three PCI master
* windows, which allow the CPU to access PCI prefetch, non prefetch,
* and IO space (see below), must all fit within this window.
*/
#ifndef M82xx_PCI_LOWER_MEM
#define M82xx_PCI_LOWER_MEM 0x80000000
#define M82xx_PCI_UPPER_MEM 0x9fffffff
#define M82xx_PCI_MEM_OFFSET 0x00000000
#define M82xx_PCI_MEM_SIZE 0x20000000
#endif
#ifndef M82xx_PCI_LOWER_MMIO
#define M82xx_PCI_LOWER_MMIO 0xa0000000
#define M82xx_PCI_UPPER_MMIO 0xafffffff
#define M82xx_PCI_MMIO_OFFSET 0x00000000
#define M82xx_PCI_MMIO_SIZE 0x20000000
#endif
#ifndef M82xx_PCI_LOWER_IO
#define M82xx_PCI_LOWER_IO 0x00000000
#define M82xx_PCI_UPPER_IO 0x01ffffff
#define M82xx_PCI_IO_BASE 0xf6000000
#define M82xx_PCI_IO_SIZE 0x02000000
#endif
#ifndef M82xx_PCI_PRIM_WND_SIZE
#define M82xx_PCI_PRIM_WND_SIZE ~(M82xx_PCI_IO_SIZE - 1U)
#define M82xx_PCI_PRIM_WND_BASE (M82xx_PCI_IO_BASE)
#endif
#ifndef M82xx_PCI_SEC_WND_SIZE
#define M82xx_PCI_SEC_WND_SIZE ~(M82xx_PCI_MEM_SIZE + M82xx_PCI_MMIO_SIZE - 1U)
#define M82xx_PCI_SEC_WND_BASE (M82xx_PCI_LOWER_MEM)
#endif
#ifndef POTA_ADDR_SHIFT
#define POTA_ADDR_SHIFT 12
#endif
#ifndef PITA_ADDR_SHIFT
#define PITA_ADDR_SHIFT 12
#endif
#ifndef _IO_BASE
#define _IO_BASE isa_io_base
#endif
#ifdef CONFIG_8260_PCI9
struct pci_controller;
extern void setup_m8260_indirect_pci(struct pci_controller* hose,
u32 cfg_addr, u32 cfg_data);
#else
#define setup_m8260_indirect_pci setup_indirect_pci
#endif
#endif /* _PPC_KERNEL_M8260_PCI_H */

View File

@ -275,7 +275,7 @@ static void __init openpic_enable_sie(void)
}
#endif
#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM)
#if defined(CONFIG_EPIC_SERIAL_MODE)
static void openpic_reset(void)
{
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
@ -993,8 +993,6 @@ int openpic_resume(struct sys_device *sysdev)
return 0;
}
openpic_reset();
/* OpenPIC sometimes seem to need some time to be fully back up... */
do {
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);

View File

@ -29,6 +29,7 @@
#include <asm/mmu.h>
#include <asm/ppc_sys.h>
#include <asm/kgdb.h>
#include <asm/delay.h>
#include <syslib/ppc83xx_setup.h>
@ -117,7 +118,34 @@ mpc83xx_early_serial_map(void)
void
mpc83xx_restart(char *cmd)
{
volatile unsigned char __iomem *reg;
unsigned char tmp;
reg = ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
local_irq_disable();
/*
* Unlock the BCSR bits so a PRST will update the contents.
* Otherwise the reset asserts but doesn't clear.
*/
tmp = in_8(reg + BCSR_MISC_REG3_OFF);
tmp |= BCSR_MISC_REG3_CNFLOCK; /* low true, high false */
out_8(reg + BCSR_MISC_REG3_OFF, tmp);
/*
* Trigger a reset via a low->high transition of the
* PORESET bit.
*/
tmp = in_8(reg + BCSR_MISC_REG2_OFF);
tmp &= ~BCSR_MISC_REG2_PORESET;
out_8(reg + BCSR_MISC_REG2_OFF, tmp);
udelay(1);
tmp |= BCSR_MISC_REG2_PORESET;
out_8(reg + BCSR_MISC_REG2_OFF, tmp);
for(;;);
}

View File

@ -132,6 +132,12 @@ mpc85xx_halt(void)
}
#ifdef CONFIG_PCI
#if defined(CONFIG_MPC8555_CDS)
extern void mpc85xx_cds_enable_via(struct pci_controller *hose);
extern void mpc85xx_cds_fixup_via(struct pci_controller *hose);
#endif
static void __init
mpc85xx_setup_pci1(struct pci_controller *hose)
{
@ -302,8 +308,18 @@ mpc85xx_setup_hose(void)
ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#if defined(CONFIG_MPC8555_CDS)
/* Pre pciauto_bus_scan VIA init */
mpc85xx_cds_enable_via(hose_a);
#endif
hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
#if defined(CONFIG_MPC8555_CDS)
/* Post pciauto_bus_scan VIA fixup */
mpc85xx_cds_fixup_via(hose_a);
#endif
#ifdef CONFIG_85xx_PCI2
hose_b = pcibios_alloc_controller();

View File

@ -2,10 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
config FRAME_POINTER
bool
default y if DEBUG_INFO
config PT_PROXY
bool "Enable ptrace proxy"
depends on XTERM_CHAN && DEBUG_INFO && MODE_TT

View File

@ -1,5 +1,10 @@
/* Much of this ripped from hw_random.c */
/* Copyright (C) 2005 Jeff Dike <jdike@addtoit.com> */
/* Much of this ripped from drivers/char/hw_random.c, see there for other
* copyright.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@ -12,8 +17,6 @@
*/
#define RNG_VERSION "1.0.0"
#define RNG_MODULE_NAME "random"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " virtual driver " RNG_VERSION
#define PFX RNG_MODULE_NAME ": "
#define RNG_MISCDEV_MINOR 183 /* official */
@ -98,7 +101,7 @@ static int __init rng_init (void)
err = misc_register (&rng_miscdev);
if (err) {
printk (KERN_ERR PFX "misc device register failed\n");
printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n");
goto err_out_cleanup_hw;
}
@ -120,3 +123,6 @@ static void __exit rng_cleanup (void)
module_init (rng_init);
module_exit (rng_cleanup);
MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");

View File

@ -22,7 +22,6 @@
#include "init.h"
#include "irq_user.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
static int ssl_version = 1;

View File

@ -28,7 +28,6 @@
#include "irq_user.h"
#include "mconsole_kern.h"
#include "init.h"
#include "2_5compat.h"
#define MAX_TTYS (16)

View File

@ -49,7 +49,6 @@
#include "irq_user.h"
#include "irq_kern.h"
#include "ubd_user.h"
#include "2_5compat.h"
#include "os.h"
#include "mem.h"
#include "mem_kern.h"
@ -440,9 +439,9 @@ static int udb_setup(char *str)
__setup("udb", udb_setup);
__uml_help(udb_setup,
"udb\n"
" This option is here solely to catch ubd -> udb typos, which can be\n\n"
" to impossible to catch visually unless you specifically look for\n\n"
" them. The only result of any option starting with 'udb' is an error\n\n"
" This option is here solely to catch ubd -> udb typos, which can be\n"
" to impossible to catch visually unless you specifically look for\n"
" them. The only result of any option starting with 'udb' is an error\n"
" in the boot output.\n\n"
);

View File

@ -1,24 +0,0 @@
/*
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#ifndef __2_5_COMPAT_H__
#define __2_5_COMPAT_H__
#define INIT_HARDSECT(arr, maj, sizes)
#define SET_PRI(task) do ; while(0)
#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -1,6 +1,7 @@
#ifndef __UM_SYSRQ_H
#define __UM_SYSRQ_H
extern void show_trace(unsigned long *stack);
struct task_struct;
extern void show_trace(struct task_struct* task, unsigned long *stack);
#endif

View File

@ -16,7 +16,6 @@
#include "kern.h"
#include "irq_user.h"
#include "tlb.h"
#include "2_5compat.h"
#include "os.h"
#include "time_user.h"
#include "choose-mode.h"

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include "linux/init.h"
#include "linux/bootmem.h"
#include "linux/initrd.h"
#include "asm/types.h"
#include "user_util.h"
#include "kern_util.h"
#include "initrd.h"
#include "init.h"
#include "os.h"
/* Changed by uml_initrd_setup, which is a setup */
static char *initrd __initdata = NULL;
static int __init read_initrd(void)
{
void *area;
long long size;
int err;
if(initrd == NULL) return 0;
err = os_file_size(initrd, &size);
if(err) return 0;
area = alloc_bootmem(size);
if(area == NULL) return 0;
if(load_initrd(initrd, area, size) == -1) return 0;
initrd_start = (unsigned long) area;
initrd_end = initrd_start + size;
return 0;
}
__uml_postsetup(read_initrd);
static int __init uml_initrd_setup(char *line, int *add)
{
initrd = line;
return 0;
}
__uml_setup("initrd=", uml_initrd_setup,
"initrd=<initrd image>\n"
" This is used to boot UML from an initrd image. The argument is the\n"
" name of the file containing the image.\n\n"
);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "initrd.h"
#include "os.h"
int load_initrd(char *filename, void *buf, int size)
{
int fd, n;
fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
if(fd < 0){
printk("Opening '%s' failed - err = %d\n", filename, -fd);
return(-1);
}
n = os_read_file(fd, buf, size);
if(n != size){
printk("Read of %d bytes from '%s' failed, err = %d\n", size,
filename, -n);
return(-1);
}
os_close_file(fd);
return(0);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -71,7 +71,7 @@ static __init void do_uml_initcalls(void)
static void last_ditch_exit(int sig)
{
CHOOSE_MODE(kmalloc_ok = 0, (void) 0);
kmalloc_ok = 0;
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
@ -87,7 +87,7 @@ int main(int argc, char **argv, char **envp)
{
char **new_argv;
sigset_t mask;
int ret, i;
int ret, i, err;
/* Enable all signals except SIGIO - in some environments, we can
* enter with some signals blocked
@ -160,27 +160,29 @@ int main(int argc, char **argv, char **envp)
*/
change_sig(SIGPROF, 0);
/* This signal stuff used to be in the reboot case. However,
* sometimes a SIGVTALRM can come in when we're halting (reproducably
* when writing out gcov information, presumably because that takes
* some time) and cause a segfault.
*/
/* stop timers and set SIG*ALRM to be ignored */
disable_timer();
/* disable SIGIO for the fds and set SIGIO to be ignored */
err = deactivate_all_fds();
if(err)
printf("deactivate_all_fds failed, errno = %d\n", -err);
/* Let any pending signals fire now. This ensures
* that they won't be delivered after the exec, when
* they are definitely not expected.
*/
unblock_signals();
/* Reboot */
if(ret){
int err;
printf("\n");
/* stop timers and set SIG*ALRM to be ignored */
disable_timer();
/* disable SIGIO for the fds and set SIGIO to be ignored */
err = deactivate_all_fds();
if(err)
printf("deactivate_all_fds failed, errno = %d\n",
-err);
/* Let any pending signals fire now. This ensures
* that they won't be delivered after the exec, when
* they are definitely not expected.
*/
unblock_signals();
execvp(new_argv[0], new_argv);
perror("Failed to exec kernel");
ret = 1;

View File

@ -43,7 +43,6 @@
#include "tlb.h"
#include "frame_kern.h"
#include "sigcontext.h"
#include "2_5compat.h"
#include "os.h"
#include "mode.h"
#include "mode_kern.h"
@ -55,18 +54,6 @@
*/
struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
struct task_struct *get_task(int pid, int require)
{
struct task_struct *ret;
read_lock(&tasklist_lock);
ret = find_task_by_pid(pid);
read_unlock(&tasklist_lock);
if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
return(ret);
}
int external_pid(void *t)
{
struct task_struct *task = t ? t : current;
@ -189,7 +176,6 @@ void default_idle(void)
while(1){
/* endless idle loop with no priority at all */
SET_PRI(current);
/*
* although we are an idle CPU, we do not want to
@ -212,11 +198,6 @@ int page_size(void)
return(PAGE_SIZE);
}
unsigned long page_mask(void)
{
return(PAGE_MASK);
}
void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte_out)
{
@ -349,11 +330,6 @@ char *uml_strdup(char *string)
return(new);
}
void *get_init_task(void)
{
return(&init_thread_union.thread_info.task);
}
int copy_to_user_proc(void __user *to, void *from, int size)
{
return(copy_to_user(to, from, size));
@ -480,15 +456,3 @@ unsigned long arch_align_stack(unsigned long sp)
return sp & ~0xf;
}
#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -322,11 +322,9 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit)
UPT_SYSCALL_ARG2(regs),
UPT_SYSCALL_ARG3(regs),
UPT_SYSCALL_ARG4(regs));
else {
int res = UPT_SYSCALL_RET(regs);
audit_syscall_exit(current, AUDITSC_RESULT(res),
res);
}
else audit_syscall_exit(current,
AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
UPT_SYSCALL_RET(regs));
}
/* Fake a debug trap */
@ -356,14 +354,3 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit)
current->exit_code = 0;
}
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -3,6 +3,7 @@
* Licensed under the GPL
*/
#include "linux/config.h"
#include "linux/sched.h"
#include "linux/kernel.h"
#include "linux/module.h"
@ -12,14 +13,14 @@
#include "sysrq.h"
#include "user_util.h"
void show_trace(unsigned long * stack)
/* Catch non-i386 SUBARCH's. */
#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
void show_trace(struct task_struct *task, unsigned long * stack)
{
/* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from
* arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/
unsigned long addr;
if (!stack) {
stack = (unsigned long*) &stack;
stack = (unsigned long*) &stack;
WARN_ON(1);
}
@ -35,6 +36,7 @@ void show_trace(unsigned long * stack)
}
printk("\n");
}
#endif
/*
* stack dumps generator - this is used by arch-independent code.
@ -44,7 +46,7 @@ void dump_stack(void)
{
unsigned long stack;
show_trace(&stack);
show_trace(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
@ -59,7 +61,11 @@ void show_stack(struct task_struct *task, unsigned long *esp)
int i;
if (esp == NULL) {
if (task != current) {
if (task != current && task != NULL) {
/* XXX: Isn't this bogus? I.e. isn't this the
* *userspace* stack of this task? If not so, use this
* even when task == current (as in i386).
*/
esp = (unsigned long *) KSTK_ESP(task);
/* Which one? No actual difference - just coding style.*/
//esp = (unsigned long *) PT_REGS_IP(&task->thread.regs);
@ -77,5 +83,6 @@ void show_stack(struct task_struct *task, unsigned long *esp)
printk("%08lx ", *stack++);
}
show_trace(esp);
printk("Call Trace: \n");
show_trace(current, esp);
}

View File

@ -23,7 +23,6 @@
#include "kern.h"
#include "chan_kern.h"
#include "mconsole_kern.h"
#include "2_5compat.h"
#include "mem.h"
#include "mem_kern.h"

View File

@ -32,10 +32,6 @@ void *switch_to_tt(void *prev, void *next, void *last)
unsigned long flags;
int err, vtalrm, alrm, prof, cpu;
char c;
/* jailing and SMP are incompatible, so this doesn't need to be
* made per-cpu
*/
static int reading;
from = prev;
to = next;
@ -59,13 +55,11 @@ void *switch_to_tt(void *prev, void *next, void *last)
c = 0;
set_current(to);
reading = 0;
err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
if(err != sizeof(c))
panic("write of switch_pipe failed, err = %d", -err);
reading = 1;
if(from->thread.mode.tt.switch_pipe[0] == -1)
if(from->thread.mode.tt.switch_pipe[0] == -1)
os_kill_process(os_getpid(), 0);
err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));

View File

@ -111,12 +111,6 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
pte_t * __bad_pagetable(void)
{
panic("Someone should implement __bad_pagetable");
return(NULL);
}
/* Set in linux_main */
unsigned long host_task_size;
unsigned long task_size;

View File

@ -3,12 +3,15 @@
* Licensed under the GPL
*/
#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/smp.h"
#include "linux/sched.h"
#include "linux/kallsyms.h"
#include "asm/ptrace.h"
#include "sysrq.h"
/* This is declared by <linux/sched.h> */
void show_regs(struct pt_regs *regs)
{
printk("\n");
@ -31,5 +34,80 @@ void show_regs(struct pt_regs *regs)
0xffff & PT_REGS_DS(regs),
0xffff & PT_REGS_ES(regs));
show_trace((unsigned long *) &regs);
show_trace(NULL, (unsigned long *) &regs);
}
/* Copied from i386. */
static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
{
return p > (void *)tinfo &&
p < (void *)tinfo + THREAD_SIZE - 3;
}
/* Adapted from i386 (we also print the address we read from). */
static inline unsigned long print_context_stack(struct thread_info *tinfo,
unsigned long *stack, unsigned long ebp)
{
unsigned long addr;
#ifdef CONFIG_FRAME_POINTER
while (valid_stack_ptr(tinfo, (void *)ebp)) {
addr = *(unsigned long *)(ebp + 4);
printk("%08lx: [<%08lx>]", ebp + 4, addr);
print_symbol(" %s", addr);
printk("\n");
ebp = *(unsigned long *)ebp;
}
#else
while (valid_stack_ptr(tinfo, stack)) {
addr = *stack;
if (__kernel_text_address(addr)) {
printk("%08lx: [<%08lx>]", (unsigned long) stack, addr);
print_symbol(" %s", addr);
printk("\n");
}
stack++;
}
#endif
return ebp;
}
void show_trace(struct task_struct* task, unsigned long * stack)
{
unsigned long ebp;
struct thread_info *context;
/* Turn this into BUG_ON if possible. */
if (!stack) {
stack = (unsigned long*) &stack;
printk("show_trace: got NULL stack, implicit assumption task == current");
WARN_ON(1);
}
if (!task)
task = current;
if (task != current) {
//ebp = (unsigned long) KSTK_EBP(task);
/* Which one? No actual difference - just coding style.*/
ebp = (unsigned long) PT_REGS_EBP(&task->thread.regs);
} else {
asm ("movl %%ebp, %0" : "=r" (ebp) : );
}
context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
print_context_stack(context, stack, ebp);
/*while (((long) stack & (THREAD_SIZE-1)) != 0) {
addr = *stack;
if (__kernel_text_address(addr)) {
printk("%08lx: [<%08lx>]", (unsigned long) stack, addr);
print_symbol(" %s", addr);
printk("\n");
}
stack++;
}*/
printk("\n");
}

View File

@ -27,17 +27,5 @@ void show_regs(struct pt_regs_subarch *regs)
0xffff & regs->xds, 0xffff & regs->xes);
#endif
show_trace(&regs->gpr[1]);
show_trace(current, &regs->gpr[1]);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -133,23 +133,27 @@ static long arch_prctl_tt(int code, unsigned long addr)
#ifdef CONFIG_MODE_SKAS
/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */
static long arch_prctl_skas(int code, unsigned long addr)
{
long ret = 0;
switch(code){
case ARCH_SET_GS:
current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
break;
case ARCH_SET_FS:
current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
break;
case ARCH_SET_GS:
current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
break;
case ARCH_GET_FS:
ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr);
ret = put_user(current->thread.regs.regs.skas.
regs[FS_BASE / sizeof(unsigned long)],
(unsigned long __user *)addr);
break;
case ARCH_GET_GS:
ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \
long)], &addr);
ret = put_user(current->thread.regs.regs.skas.
regs[GS_BASE / sizeof(unsigned long)],
(unsigned long __user *)addr);
break;
default:
ret = -EINVAL;

View File

@ -36,14 +36,5 @@ void __show_regs(struct pt_regs * regs)
void show_regs(struct pt_regs *regs)
{
__show_regs(regs);
show_trace((unsigned long *) &regs);
show_trace(current, (unsigned long *) &regs);
}
/* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@ -421,7 +421,7 @@ config PCI_DIRECT
config PCI_MMCONFIG
bool "Support mmconfig PCI config space access"
depends on PCI
depends on PCI && ACPI
select ACPI_BOOT
config UNORDERED_IO

View File

@ -28,6 +28,7 @@
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/proto.h>
#include <asm/ia32_unistd.h>
/* #define DEBUG_SIG 1 */

View File

@ -40,13 +40,12 @@ config ACPI
available at:
<http://www.acpi.info>
if ACPI
config ACPI_BOOT
bool
depends on ACPI || X86_HT
default y
if ACPI
config ACPI_INTERPRETER
bool
depends on !IA64_SGI_SN

View File

@ -391,7 +391,6 @@ acpi_pci_irq_enable (
u8 pin = 0;
int edge_level = ACPI_LEVEL_SENSITIVE;
int active_high_low = ACPI_ACTIVE_LOW;
extern int via_interrupt_line_quirk;
char *link = NULL;
ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
@ -444,9 +443,6 @@ acpi_pci_irq_enable (
}
}
if (via_interrupt_line_quirk)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15);
dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",

View File

@ -488,6 +488,20 @@ static int viocd_packet(struct cdrom_device_info *cdi,
& (CDC_DVD_RAM | CDC_RAM)) != 0;
}
break;
case GPCMD_GET_CONFIGURATION:
if (cgc->cmd[3] == CDF_RWRT) {
struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
if ((buflen >=
(sizeof(struct feature_header) + sizeof(*rfd))) &&
(cdi->ops->capability & ~cdi->mask
& (CDC_DVD_RAM | CDC_RAM))) {
rfd->feature_code = cpu_to_be16(CDF_RWRT);
rfd->curr = 1;
ret = 0;
}
}
break;
default:
if (cgc->sense) {
/* indicate Unknown code */

View File

@ -1932,8 +1932,11 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
/*
* check if dma is safe
*
* NOTE! The "len" and "addr" checks should possibly have
* separate masks.
*/
if ((rq->data_len & 3) || (addr & mask))
if ((rq->data_len & mask) || (addr & mask))
info->dma = 0;
}
@ -3255,16 +3258,12 @@ sector_t ide_cdrom_capacity (ide_drive_t *drive)
return capacity * sectors_per_frame;
}
static
int ide_cdrom_cleanup(ide_drive_t *drive)
static int ide_cd_remove(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
struct cdrom_info *info = drive->driver_data;
if (ide_unregister_subdriver(drive)) {
printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n",
__FUNCTION__, drive->name);
return 1;
}
ide_unregister_subdriver(drive, info->driver);
del_gendisk(info->disk);
@ -3297,7 +3296,7 @@ static void ide_cd_release(struct kref *kref)
kfree(info);
}
static int ide_cdrom_attach (ide_drive_t *drive);
static int ide_cd_probe(struct device *);
#ifdef CONFIG_PROC_FS
static int proc_idecd_read_capacity
@ -3320,19 +3319,20 @@ static ide_proc_entry_t idecd_proc[] = {
static ide_driver_t ide_cdrom_driver = {
.owner = THIS_MODULE,
.name = "ide-cdrom",
.gen_driver = {
.name = "ide-cdrom",
.bus = &ide_bus_type,
.probe = ide_cd_probe,
.remove = ide_cd_remove,
},
.version = IDECD_VERSION,
.media = ide_cdrom,
.busy = 0,
.supports_dsc_overlap = 1,
.cleanup = ide_cdrom_cleanup,
.do_request = ide_do_rw_cdrom,
.end_request = ide_end_request,
.error = __ide_error,
.abort = __ide_abort,
.proc = idecd_proc,
.attach = ide_cdrom_attach,
.drives = LIST_HEAD_INIT(ide_cdrom_driver.drives),
};
static int idecd_open(struct inode * inode, struct file * file)
@ -3418,8 +3418,9 @@ static char *ignore = NULL;
module_param(ignore, charp, 0400);
MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
static int ide_cdrom_attach (ide_drive_t *drive)
static int ide_cd_probe(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
struct cdrom_info *info;
struct gendisk *g;
struct request_sense sense;
@ -3453,11 +3454,8 @@ static int ide_cdrom_attach (ide_drive_t *drive)
ide_init_disk(g, drive);
if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
printk(KERN_ERR "%s: Failed to register the driver with ide.c\n",
drive->name);
goto out_put_disk;
}
ide_register_subdriver(drive, &ide_cdrom_driver);
memset(info, 0, sizeof (struct cdrom_info));
kref_init(&info->kref);
@ -3470,7 +3468,6 @@ static int ide_cdrom_attach (ide_drive_t *drive)
drive->driver_data = info;
DRIVER(drive)->busy++;
g->minors = 1;
snprintf(g->devfs_name, sizeof(g->devfs_name),
"%s/cd", drive->devfs_name);
@ -3478,8 +3475,7 @@ static int ide_cdrom_attach (ide_drive_t *drive)
g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
if (ide_cdrom_setup(drive)) {
struct cdrom_device_info *devinfo = &info->devinfo;
DRIVER(drive)->busy--;
ide_unregister_subdriver(drive);
ide_unregister_subdriver(drive, &ide_cdrom_driver);
if (info->buffer != NULL)
kfree(info->buffer);
if (info->toc != NULL)
@ -3492,7 +3488,6 @@ static int ide_cdrom_attach (ide_drive_t *drive)
drive->driver_data = NULL;
goto failed;
}
DRIVER(drive)->busy--;
cdrom_read_toc(drive, &sense);
g->fops = &idecd_ops;
@ -3500,23 +3495,20 @@ static int ide_cdrom_attach (ide_drive_t *drive)
add_disk(g);
return 0;
out_put_disk:
put_disk(g);
out_free_cd:
kfree(info);
failed:
return 1;
return -ENODEV;
}
static void __exit ide_cdrom_exit(void)
{
ide_unregister_driver(&ide_cdrom_driver);
driver_unregister(&ide_cdrom_driver.gen_driver);
}
static int ide_cdrom_init(void)
{
ide_register_driver(&ide_cdrom_driver);
return 0;
return driver_register(&ide_cdrom_driver.gen_driver);
}
module_init(ide_cdrom_init);

View File

@ -1024,14 +1024,16 @@ static void ide_cacheflush_p(ide_drive_t *drive)
printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
}
static int idedisk_cleanup (ide_drive_t *drive)
static int ide_disk_remove(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
struct ide_disk_obj *idkp = drive->driver_data;
struct gendisk *g = idkp->disk;
ide_cacheflush_p(drive);
if (ide_unregister_subdriver(drive))
return 1;
ide_unregister_subdriver(drive, idkp->driver);
del_gendisk(g);
ide_disk_put(idkp);
@ -1052,7 +1054,7 @@ static void ide_disk_release(struct kref *kref)
kfree(idkp);
}
static int idedisk_attach(ide_drive_t *drive);
static int ide_disk_probe(struct device *dev);
static void ide_device_shutdown(struct device *dev)
{
@ -1082,27 +1084,23 @@ static void ide_device_shutdown(struct device *dev)
dev->bus->suspend(dev, PMSG_SUSPEND);
}
/*
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idedisk_driver = {
.owner = THIS_MODULE,
.gen_driver = {
.name = "ide-disk",
.bus = &ide_bus_type,
.probe = ide_disk_probe,
.remove = ide_disk_remove,
.shutdown = ide_device_shutdown,
},
.name = "ide-disk",
.version = IDEDISK_VERSION,
.media = ide_disk,
.busy = 0,
.supports_dsc_overlap = 0,
.cleanup = idedisk_cleanup,
.do_request = ide_do_rw_disk,
.end_request = ide_end_request,
.error = __ide_error,
.abort = __ide_abort,
.proc = idedisk_proc,
.attach = idedisk_attach,
.drives = LIST_HEAD_INIT(idedisk_driver.drives),
};
static int idedisk_open(struct inode *inode, struct file *filp)
@ -1199,8 +1197,9 @@ static struct block_device_operations idedisk_ops = {
MODULE_DESCRIPTION("ATA DISK Driver");
static int idedisk_attach(ide_drive_t *drive)
static int ide_disk_probe(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
struct ide_disk_obj *idkp;
struct gendisk *g;
@ -1222,10 +1221,7 @@ static int idedisk_attach(ide_drive_t *drive)
ide_init_disk(g, drive);
if (ide_register_subdriver(drive, &idedisk_driver)) {
printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
goto out_put_disk;
}
ide_register_subdriver(drive, &idedisk_driver);
memset(idkp, 0, sizeof(*idkp));
@ -1239,7 +1235,6 @@ static int idedisk_attach(ide_drive_t *drive)
drive->driver_data = idkp;
DRIVER(drive)->busy++;
idedisk_setup(drive);
if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
@ -1247,7 +1242,7 @@ static int idedisk_attach(ide_drive_t *drive)
drive->attach = 0;
} else
drive->attach = 1;
DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS;
strcpy(g->devfs_name, drive->devfs_name);
g->driverfs_dev = &drive->gendev;
@ -1257,22 +1252,20 @@ static int idedisk_attach(ide_drive_t *drive)
add_disk(g);
return 0;
out_put_disk:
put_disk(g);
out_free_idkp:
kfree(idkp);
failed:
return 1;
return -ENODEV;
}
static void __exit idedisk_exit (void)
{
ide_unregister_driver(&idedisk_driver);
driver_unregister(&idedisk_driver.gen_driver);
}
static int idedisk_init (void)
{
return ide_register_driver(&idedisk_driver);
return driver_register(&idedisk_driver.gen_driver);
}
module_init(idedisk_init);

View File

@ -1865,13 +1865,13 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
idefloppy_add_settings(drive);
}
static int idefloppy_cleanup (ide_drive_t *drive)
static int ide_floppy_remove(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
idefloppy_floppy_t *floppy = drive->driver_data;
struct gendisk *g = floppy->disk;
if (ide_unregister_subdriver(drive))
return 1;
ide_unregister_subdriver(drive, floppy->driver);
del_gendisk(g);
@ -1916,26 +1916,24 @@ static ide_proc_entry_t idefloppy_proc[] = {
#endif /* CONFIG_PROC_FS */
static int idefloppy_attach(ide_drive_t *drive);
static int ide_floppy_probe(struct device *);
/*
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idefloppy_driver = {
.owner = THIS_MODULE,
.name = "ide-floppy",
.gen_driver = {
.name = "ide-floppy",
.bus = &ide_bus_type,
.probe = ide_floppy_probe,
.remove = ide_floppy_remove,
},
.version = IDEFLOPPY_VERSION,
.media = ide_floppy,
.busy = 0,
.supports_dsc_overlap = 0,
.cleanup = idefloppy_cleanup,
.do_request = idefloppy_do_request,
.end_request = idefloppy_do_end_request,
.error = __ide_error,
.abort = __ide_abort,
.proc = idefloppy_proc,
.attach = idefloppy_attach,
.drives = LIST_HEAD_INIT(idefloppy_driver.drives),
};
static int idefloppy_open(struct inode *inode, struct file *filp)
@ -2122,8 +2120,9 @@ static struct block_device_operations idefloppy_ops = {
.revalidate_disk= idefloppy_revalidate_disk
};
static int idefloppy_attach (ide_drive_t *drive)
static int ide_floppy_probe(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
idefloppy_floppy_t *floppy;
struct gendisk *g;
@ -2152,10 +2151,7 @@ static int idefloppy_attach (ide_drive_t *drive)
ide_init_disk(g, drive);
if (ide_register_subdriver(drive, &idefloppy_driver)) {
printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
goto out_put_disk;
}
ide_register_subdriver(drive, &idefloppy_driver);
memset(floppy, 0, sizeof(*floppy));
@ -2169,9 +2165,8 @@ static int idefloppy_attach (ide_drive_t *drive)
drive->driver_data = floppy;
DRIVER(drive)->busy++;
idefloppy_setup (drive, floppy);
DRIVER(drive)->busy--;
g->minors = 1 << PARTN_BITS;
g->driverfs_dev = &drive->gendev;
strcpy(g->devfs_name, drive->devfs_name);
@ -2181,19 +2176,17 @@ static int idefloppy_attach (ide_drive_t *drive)
add_disk(g);
return 0;
out_put_disk:
put_disk(g);
out_free_floppy:
kfree(floppy);
failed:
return 1;
return -ENODEV;
}
MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
static void __exit idefloppy_exit (void)
{
ide_unregister_driver(&idefloppy_driver);
driver_unregister(&idefloppy_driver.gen_driver);
}
/*
@ -2202,8 +2195,7 @@ static void __exit idefloppy_exit (void)
static int idefloppy_init (void)
{
printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
ide_register_driver(&idefloppy_driver);
return 0;
return driver_register(&idefloppy_driver.gen_driver);
}
module_init(idefloppy_init);

View File

@ -47,6 +47,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/pci.h>
@ -696,13 +697,13 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
SELECT_DRIVE(&hwif->drives[0]);
hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
mdelay(2);
rc = ide_wait_not_busy(hwif, 10000);
rc = ide_wait_not_busy(hwif, 35000);
if (rc)
return rc;
SELECT_DRIVE(&hwif->drives[1]);
hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
mdelay(2);
rc = ide_wait_not_busy(hwif, 10000);
rc = ide_wait_not_busy(hwif, 35000);
/* Exit function with master reselected (let's be sane) */
SELECT_DRIVE(&hwif->drives[0]);
@ -918,7 +919,7 @@ int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)
want them on default or a new "empty" class
for hotplug reprobing ? */
if (drive->present) {
ata_attach(drive);
device_register(&drive->gendev);
}
}
}
@ -1279,10 +1280,51 @@ void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
EXPORT_SYMBOL_GPL(ide_init_disk);
static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
if (drive == drive->next) {
/* special case: last drive from hwgroup. */
BUG_ON(hwgroup->drive != drive);
hwgroup->drive = NULL;
} else {
ide_drive_t *walk;
walk = hwgroup->drive;
while (walk->next != drive)
walk = walk->next;
walk->next = drive->next;
if (hwgroup->drive == drive) {
hwgroup->drive = drive->next;
hwgroup->hwif = hwgroup->drive->hwif;
}
}
BUG_ON(hwgroup->drive == drive);
}
static void drive_release_dev (struct device *dev)
{
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
spin_lock_irq(&ide_lock);
if (drive->devfs_name[0] != '\0') {
devfs_remove(drive->devfs_name);
drive->devfs_name[0] = '\0';
}
ide_remove_drive_from_hwgroup(drive);
if (drive->id != NULL) {
kfree(drive->id);
drive->id = NULL;
}
drive->present = 0;
/* Messed up locking ... */
spin_unlock_irq(&ide_lock);
blk_cleanup_queue(drive->queue);
spin_lock_irq(&ide_lock);
drive->queue = NULL;
spin_unlock_irq(&ide_lock);
up(&drive->gendev_rel_sem);
}
@ -1306,7 +1348,6 @@ static void init_gendisk (ide_hwif_t *hwif)
drive->gendev.driver_data = drive;
drive->gendev.release = drive_release_dev;
if (drive->present) {
device_register(&drive->gendev);
sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
(hwif->channel && hwif->mate) ?
hwif->mate->index : hwif->index,
@ -1412,7 +1453,7 @@ int ideprobe_init (void)
hwif->chipset = ide_generic;
for (unit = 0; unit < MAX_DRIVES; ++unit)
if (hwif->drives[unit].present)
ata_attach(&hwif->drives[unit]);
device_register(&hwif->drives[unit].gendev);
}
}
return 0;

View File

@ -307,17 +307,41 @@ static int proc_ide_read_driver
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
ide_drive_t *drive = (ide_drive_t *) data;
ide_driver_t *driver = drive->driver;
struct device *dev = &drive->gendev;
ide_driver_t *ide_drv;
int len;
if (driver) {
down_read(&dev->bus->subsys.rwsem);
if (dev->driver) {
ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
len = sprintf(page, "%s version %s\n",
driver->name, driver->version);
dev->driver->name, ide_drv->version);
} else
len = sprintf(page, "ide-default version 0.9.newide\n");
up_read(&dev->bus->subsys.rwsem);
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
{
struct device *dev = &drive->gendev;
int ret = 1;
down_write(&dev->bus->subsys.rwsem);
device_release_driver(dev);
/* FIXME: device can still be in use by previous driver */
strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
device_attach(dev);
drive->driver_req[0] = 0;
if (dev->driver == NULL)
device_attach(dev);
if (dev->driver && !strcmp(dev->driver->name, driver))
ret = 0;
up_write(&dev->bus->subsys.rwsem);
return ret;
}
static int proc_ide_write_driver
(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
@ -488,16 +512,32 @@ void destroy_proc_ide_interface(ide_hwif_t *hwif)
}
}
extern struct seq_operations ide_drivers_op;
static int proc_print_driver(struct device_driver *drv, void *data)
{
ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver);
struct seq_file *s = data;
seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
return 0;
}
static int ide_drivers_show(struct seq_file *s, void *p)
{
bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
return 0;
}
static int ide_drivers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &ide_drivers_op);
return single_open(file, &ide_drivers_show, NULL);
}
static struct file_operations ide_drivers_operations = {
.open = ide_drivers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.release = single_release,
};
void proc_ide_create(void)

View File

@ -4681,21 +4681,12 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
idetape_add_settings(drive);
}
static int idetape_cleanup (ide_drive_t *drive)
static int ide_tape_remove(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
idetape_tape_t *tape = drive->driver_data;
unsigned long flags;
spin_lock_irqsave(&ide_lock, flags);
if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
tape->first_stage != NULL || tape->merge_stage_size) {
spin_unlock_irqrestore(&ide_lock, flags);
return 1;
}
spin_unlock_irqrestore(&ide_lock, flags);
DRIVER(drive)->busy = 0;
(void) ide_unregister_subdriver(drive);
ide_unregister_subdriver(drive, tape->driver);
ide_unregister_region(tape->disk);
@ -4710,6 +4701,8 @@ static void ide_tape_release(struct kref *kref)
ide_drive_t *drive = tape->drive;
struct gendisk *g = tape->disk;
BUG_ON(tape->first_stage != NULL || tape->merge_stage_size);
drive->dsc_overlap = 0;
drive->driver_data = NULL;
devfs_remove("%s/mt", drive->devfs_name);
@ -4747,26 +4740,24 @@ static ide_proc_entry_t idetape_proc[] = {
#endif
static int idetape_attach(ide_drive_t *drive);
static int ide_tape_probe(struct device *);
/*
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idetape_driver = {
.owner = THIS_MODULE,
.name = "ide-tape",
.gen_driver = {
.name = "ide-tape",
.bus = &ide_bus_type,
.probe = ide_tape_probe,
.remove = ide_tape_remove,
},
.version = IDETAPE_VERSION,
.media = ide_tape,
.busy = 1,
.supports_dsc_overlap = 1,
.cleanup = idetape_cleanup,
.do_request = idetape_do_request,
.end_request = idetape_end_request,
.error = __ide_error,
.abort = __ide_abort,
.proc = idetape_proc,
.attach = idetape_attach,
.drives = LIST_HEAD_INIT(idetape_driver.drives),
};
/*
@ -4829,8 +4820,9 @@ static struct block_device_operations idetape_block_ops = {
.ioctl = idetape_ioctl,
};
static int idetape_attach (ide_drive_t *drive)
static int ide_tape_probe(struct device *dev)
{
ide_drive_t *drive = to_ide_device(dev);
idetape_tape_t *tape;
struct gendisk *g;
int minor;
@ -4865,10 +4857,7 @@ static int idetape_attach (ide_drive_t *drive)
ide_init_disk(g, drive);
if (ide_register_subdriver(drive, &idetape_driver)) {
printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
goto out_put_disk;
}
ide_register_subdriver(drive, &idetape_driver);
memset(tape, 0, sizeof(*tape));
@ -4902,12 +4891,11 @@ static int idetape_attach (ide_drive_t *drive)
ide_register_region(g);
return 0;
out_put_disk:
put_disk(g);
out_free_tape:
kfree(tape);
failed:
return 1;
return -ENODEV;
}
MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@ -4915,7 +4903,7 @@ MODULE_LICENSE("GPL");
static void __exit idetape_exit (void)
{
ide_unregister_driver(&idetape_driver);
driver_unregister(&idetape_driver.gen_driver);
unregister_chrdev(IDETAPE_MAJOR, "ht");
}
@ -4928,8 +4916,7 @@ static int idetape_init (void)
printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
return -EBUSY;
}
ide_register_driver(&idetape_driver);
return 0;
return driver_register(&idetape_driver.gen_driver);
}
module_init(idetape_init);

View File

@ -196,8 +196,6 @@ ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
EXPORT_SYMBOL(ide_hwifs);
static struct list_head ide_drives = LIST_HEAD_INIT(ide_drives);
/*
* Do not even *think* about calling this!
*/
@ -358,54 +356,6 @@ static int ide_system_bus_speed(void)
return system_bus_speed;
}
/*
* drives_lock protects the list of drives, drivers_lock the
* list of drivers. Currently nobody takes both at once.
*/
static DEFINE_SPINLOCK(drives_lock);
static DEFINE_SPINLOCK(drivers_lock);
static LIST_HEAD(drivers);
/* Iterator for the driver list. */
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct list_head *p;
loff_t l = *pos;
spin_lock(&drivers_lock);
list_for_each(p, &drivers)
if (!l--)
return list_entry(p, ide_driver_t, drivers);
return NULL;
}
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct list_head *p = ((ide_driver_t *)v)->drivers.next;
(*pos)++;
return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
}
static void m_stop(struct seq_file *m, void *v)
{
spin_unlock(&drivers_lock);
}
static int show_driver(struct seq_file *m, void *v)
{
ide_driver_t *driver = v;
seq_printf(m, "%s version %s\n", driver->name, driver->version);
return 0;
}
struct seq_operations ide_drivers_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
.show = show_driver
};
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_ide_root;
#endif
@ -630,7 +580,7 @@ void ide_unregister(unsigned int index)
ide_hwif_t *hwif, *g;
static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
ide_hwgroup_t *hwgroup;
int irq_count = 0, unit, i;
int irq_count = 0, unit;
BUG_ON(index >= MAX_HWIFS);
@ -643,23 +593,22 @@ void ide_unregister(unsigned int index)
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
if (!drive->present)
if (!drive->present) {
if (drive->devfs_name[0] != '\0') {
devfs_remove(drive->devfs_name);
drive->devfs_name[0] = '\0';
}
continue;
if (drive->usage || DRIVER(drive)->busy)
goto abort;
drive->dead = 1;
}
spin_unlock_irq(&ide_lock);
device_unregister(&drive->gendev);
down(&drive->gendev_rel_sem);
spin_lock_irq(&ide_lock);
}
hwif->present = 0;
spin_unlock_irq(&ide_lock);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
if (!drive->present)
continue;
DRIVER(drive)->cleanup(drive);
}
destroy_proc_ide_interface(hwif);
hwgroup = hwif->hwgroup;
@ -687,44 +636,6 @@ void ide_unregister(unsigned int index)
* Remove us from the hwgroup, and free
* the hwgroup if we were the only member
*/
for (i = 0; i < MAX_DRIVES; ++i) {
drive = &hwif->drives[i];
if (drive->devfs_name[0] != '\0') {
devfs_remove(drive->devfs_name);
drive->devfs_name[0] = '\0';
}
if (!drive->present)
continue;
if (drive == drive->next) {
/* special case: last drive from hwgroup. */
BUG_ON(hwgroup->drive != drive);
hwgroup->drive = NULL;
} else {
ide_drive_t *walk;
walk = hwgroup->drive;
while (walk->next != drive)
walk = walk->next;
walk->next = drive->next;
if (hwgroup->drive == drive) {
hwgroup->drive = drive->next;
hwgroup->hwif = HWIF(hwgroup->drive);
}
}
BUG_ON(hwgroup->drive == drive);
if (drive->id != NULL) {
kfree(drive->id);
drive->id = NULL;
}
drive->present = 0;
/* Messed up locking ... */
spin_unlock_irq(&ide_lock);
blk_cleanup_queue(drive->queue);
device_unregister(&drive->gendev);
down(&drive->gendev_rel_sem);
spin_lock_irq(&ide_lock);
drive->queue = NULL;
}
if (hwif->next == hwif) {
BUG_ON(hwgroup->hwif != hwif);
kfree(hwgroup);
@ -1304,73 +1215,6 @@ int system_bus_clock (void)
EXPORT_SYMBOL(system_bus_clock);
/*
* Locking is badly broken here - since way back. That sucker is
* root-only, but that's not an excuse... The real question is what
* exclusion rules do we want here.
*/
int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
{
if (!drive->present || drive->usage || drive->dead)
goto abort;
if (DRIVER(drive)->cleanup(drive))
goto abort;
strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
if (ata_attach(drive)) {
spin_lock(&drives_lock);
list_del_init(&drive->list);
spin_unlock(&drives_lock);
drive->driver_req[0] = 0;
ata_attach(drive);
} else {
drive->driver_req[0] = 0;
}
if (drive->driver && !strcmp(drive->driver->name, driver))
return 0;
abort:
return 1;
}
/**
* ata_attach - attach an ATA/ATAPI device
* @drive: drive to attach
*
* Takes a drive that is as yet not assigned to any midlayer IDE
* driver (or is assigned to the default driver) and figures out
* which driver would like to own it. If nobody claims the drive
* then it is automatically attached to the default driver used for
* unclaimed objects.
*
* A return of zero indicates attachment to a driver, of one
* attachment to the default driver.
*
* Takes drivers_lock.
*/
int ata_attach(ide_drive_t *drive)
{
struct list_head *p;
spin_lock(&drivers_lock);
list_for_each(p, &drivers) {
ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
if (!try_module_get(driver->owner))
continue;
spin_unlock(&drivers_lock);
if (driver->attach(drive) == 0) {
module_put(driver->owner);
drive->gendev.driver = &driver->gen_driver;
return 0;
}
spin_lock(&drivers_lock);
module_put(driver->owner);
}
drive->gendev.driver = NULL;
spin_unlock(&drivers_lock);
if (ide_register_subdriver(drive, NULL))
panic("ide: default attach failed");
return 1;
}
static int generic_ide_suspend(struct device *dev, pm_message_t state)
{
ide_drive_t *drive = dev->driver_data;
@ -2013,27 +1857,11 @@ static void __init probe_for_hwifs (void)
#endif
}
int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
{
unsigned long flags;
spin_lock_irqsave(&ide_lock, flags);
if (!drive->present || drive->driver != NULL ||
drive->usage || drive->dead) {
spin_unlock_irqrestore(&ide_lock, flags);
return 1;
}
drive->driver = driver;
spin_unlock_irqrestore(&ide_lock, flags);
spin_lock(&drives_lock);
list_add_tail(&drive->list, driver ? &driver->drives : &ide_drives);
spin_unlock(&drives_lock);
// printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
#ifdef CONFIG_PROC_FS
if (driver)
ide_add_proc_entries(drive->proc, driver->proc, drive);
ide_add_proc_entries(drive->proc, driver->proc, drive);
#endif
return 0;
}
EXPORT_SYMBOL(ide_register_subdriver);
@ -2041,136 +1869,51 @@ EXPORT_SYMBOL(ide_register_subdriver);
/**
* ide_unregister_subdriver - disconnect drive from driver
* @drive: drive to unplug
* @driver: driver
*
* Disconnect a drive from the driver it was attached to and then
* clean up the various proc files and other objects attached to it.
*
* Takes ide_setting_sem, ide_lock and drives_lock.
* Takes ide_setting_sem and ide_lock.
* Caller must hold none of the locks.
*
* No locking versus subdriver unload because we are moving to the
* default driver anyway. Wants double checking.
*/
int ide_unregister_subdriver (ide_drive_t *drive)
void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
{
unsigned long flags;
down(&ide_setting_sem);
spin_lock_irqsave(&ide_lock, flags);
if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) {
spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
return 1;
}
#ifdef CONFIG_PROC_FS
ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
ide_remove_proc_entries(drive->proc, driver->proc);
#endif
auto_remove_settings(drive);
drive->driver = NULL;
spin_unlock_irqrestore(&ide_lock, flags);
up(&ide_setting_sem);
spin_lock(&drives_lock);
list_del_init(&drive->list);
spin_unlock(&drives_lock);
/* drive will be added to &ide_drives in ata_attach() */
return 0;
}
EXPORT_SYMBOL(ide_unregister_subdriver);
static int ide_drive_remove(struct device * dev)
{
ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
DRIVER(drive)->cleanup(drive);
return 0;
}
/**
* ide_register_driver - register IDE device driver
* @driver: the IDE device driver
*
* Register a new device driver and then scan the devices
* on the IDE bus in case any should be attached to the
* driver we have just registered. If so attach them.
*
* Takes drivers_lock and drives_lock.
*/
int ide_register_driver(ide_driver_t *driver)
{
struct list_head list;
struct list_head *list_loop;
struct list_head *tmp_storage;
spin_lock(&drivers_lock);
list_add(&driver->drivers, &drivers);
spin_unlock(&drivers_lock);
INIT_LIST_HEAD(&list);
spin_lock(&drives_lock);
list_splice_init(&ide_drives, &list);
spin_unlock(&drives_lock);
list_for_each_safe(list_loop, tmp_storage, &list) {
ide_drive_t *drive = container_of(list_loop, ide_drive_t, list);
list_del_init(&drive->list);
if (drive->present)
ata_attach(drive);
}
driver->gen_driver.name = (char *) driver->name;
driver->gen_driver.bus = &ide_bus_type;
driver->gen_driver.remove = ide_drive_remove;
return driver_register(&driver->gen_driver);
}
EXPORT_SYMBOL(ide_register_driver);
/**
* ide_unregister_driver - unregister IDE device driver
* @driver: the IDE device driver
*
* Called when a driver module is being unloaded. We reattach any
* devices to whatever driver claims them next (typically the default
* driver).
*
* Takes drivers_lock and called functions will take ide_setting_sem.
*/
void ide_unregister_driver(ide_driver_t *driver)
{
ide_drive_t *drive;
spin_lock(&drivers_lock);
list_del(&driver->drivers);
spin_unlock(&drivers_lock);
driver_unregister(&driver->gen_driver);
while(!list_empty(&driver->drives)) {
drive = list_entry(driver->drives.next, ide_drive_t, list);
if (driver->cleanup(drive)) {
printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
BUG();
}
ata_attach(drive);
}
}
EXPORT_SYMBOL(ide_unregister_driver);
/*
* Probe module
*/
EXPORT_SYMBOL(ide_lock);
static int ide_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
struct bus_type ide_bus_type = {
.name = "ide",
.match = ide_bus_match,
.suspend = generic_ide_suspend,
.resume = generic_ide_resume,
};
EXPORT_SYMBOL_GPL(ide_bus_type);
/*
* This is gets invoked once during initialization, to set *everything* up
*/

View File

@ -68,23 +68,3 @@ config GAMEPORT_CS461X
depends on PCI
endif
# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
# in every .config. Please don't touch it. It is here to handle an
# unusual dependency between GAMEPORT and sound drivers.
#
# Some sound drivers call gameport functions. If GAMEPORT is
# not selected, empty stubs are provided for the functions and all is
# well.
# If GAMEPORT is built in, everything is fine.
# If GAMEPORT is a module, however, it would need to be loaded for the
# sound driver to be able to link properly. Therefore, the sound
# driver must be a module as well in that case. Since there's no way
# to express that directly in Kconfig, we use SOUND_GAMEPORT to
# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
# GAMEPORT is 'y' or 'n', it can be anything".
config SOUND_GAMEPORT
tristate
default m if GAMEPORT=m
default y

View File

@ -422,7 +422,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->nkey++;
}
for (i = 0; i < BTN_JOYSTICK - BTN_MISC + 1; i++)
for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
if (test_bit(i + BTN_MISC, dev->keybit)) {
joydev->keymap[i] = joydev->nkey;
joydev->keypam[joydev->nkey] = i + BTN_MISC;

View File

@ -171,9 +171,9 @@ static struct {
unsigned char set2;
} atkbd_scroll_keys[] = {
{ ATKBD_SCR_1, 0xc5 },
{ ATKBD_SCR_2, 0xa9 },
{ ATKBD_SCR_4, 0xb6 },
{ ATKBD_SCR_8, 0xa7 },
{ ATKBD_SCR_2, 0x9d },
{ ATKBD_SCR_4, 0xa4 },
{ ATKBD_SCR_8, 0x9b },
{ ATKBD_SCR_CLICK, 0xe0 },
{ ATKBD_SCR_LEFT, 0xcb },
{ ATKBD_SCR_RIGHT, 0xd2 },

View File

@ -518,13 +518,16 @@ static int psmouse_probe(struct psmouse *psmouse)
/*
* First, we check if it's a mouse. It should send 0x00 or 0x03
* in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
* Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent
* ID queries, probably due to a firmware bug.
*/
param[0] = 0xa5;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1;
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
if (param[0] != 0x00 && param[0] != 0x03 &&
param[0] != 0x04 && param[0] != 0xff)
return -1;
/*
@ -972,7 +975,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
return -EINVAL;
if (!strncmp(val, "any", 3)) {
*((unsigned int *)kp->arg) = -1UL;
*((unsigned int *)kp->arg) = -1U;
return 0;
}

View File

@ -143,39 +143,6 @@ static int synaptics_identify(struct psmouse *psmouse)
return -1;
}
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));
if (SYN_MODEL_ROT180(priv->model_id))
printk(KERN_INFO " 180 degree mounted touchpad\n");
if (SYN_MODEL_PORTRAIT(priv->model_id))
printk(KERN_INFO " portrait touchpad\n");
printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
if (SYN_MODEL_NEWABS(priv->model_id))
printk(KERN_INFO " new absolute packet format\n");
if (SYN_MODEL_PEN(priv->model_id))
printk(KERN_INFO " pen detection\n");
if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n");
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
(int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
printk(KERN_INFO " -> middle button\n");
if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
printk(KERN_INFO " -> pass-through port\n");
}
}
static int synaptics_query_hardware(struct psmouse *psmouse)
{
int retries = 0;
@ -666,7 +633,11 @@ int synaptics_init(struct psmouse *psmouse)
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
print_ident(priv);
printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
priv->model_id, priv->capabilities, priv->ext_cap);
set_input_params(&psmouse->dev, priv);
psmouse->protocol_handler = synaptics_process_byte;

View File

@ -101,6 +101,7 @@ struct mousedev_list {
unsigned char ready, buffer, bufsiz;
unsigned char imexseq, impsseq;
enum mousedev_emul mode;
unsigned long last_buttons;
};
#define MOUSEDEV_SEQ_LEN 6
@ -224,7 +225,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
spin_lock_irqsave(&list->packet_lock, flags);
p = &list->packets[list->head];
if (list->ready && p->buttons != packet->buttons) {
if (list->ready && p->buttons != mousedev->packet.buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
@ -249,10 +250,13 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
list->ready = 1;
if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
if (list->ready)
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&mousedev->wait);
@ -477,9 +481,10 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
}
if (!p->dx && !p->dy && !p->dz) {
if (list->tail == list->head)
if (list->tail == list->head) {
list->ready = 0;
else
list->last_buttons = p->buttons;
} else
list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
}

View File

@ -88,9 +88,11 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
};
/*
* Some Fujitsu notebooks are ahving trouble with touhcpads if
* Some Fujitsu notebooks are having trouble with touchpads if
* active multiplexing mode is activated. Luckily they don't have
* external PS/2 ports so we can safely disable it.
* ... apparently some Toshibas don't like MUX mode either and
* die horrible death on reboot.
*/
static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
{
@ -114,6 +116,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
},
},
{
.ident = "Fujitsu Lifebook S6230",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
},
},
{
.ident = "Fujitsu T70H",
.matches = {
@ -121,6 +130,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
},
},
{
.ident = "Toshiba P10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
},
},
{ }
};
@ -215,11 +231,15 @@ static struct pnp_driver i8042_pnp_aux_driver = {
static void i8042_pnp_exit(void)
{
if (i8042_pnp_kbd_registered)
if (i8042_pnp_kbd_registered) {
i8042_pnp_kbd_registered = 0;
pnp_unregister_driver(&i8042_pnp_kbd_driver);
}
if (i8042_pnp_aux_registered)
if (i8042_pnp_aux_registered) {
i8042_pnp_aux_registered = 0;
pnp_unregister_driver(&i8042_pnp_aux_driver);
}
}
static int i8042_pnp_init(void)
@ -227,7 +247,7 @@ static int i8042_pnp_init(void)
int result_kbd, result_aux;
if (i8042_nopnp) {
printk("i8042: PNP detection disabled\n");
printk(KERN_INFO "i8042: PNP detection disabled\n");
return 0;
}
@ -241,7 +261,7 @@ static int i8042_pnp_init(void)
#if defined(__ia64__)
return -ENODEV;
#else
printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n");
printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
return 0;
#endif
}
@ -265,7 +285,7 @@ static int i8042_pnp_init(void)
i8042_pnp_kbd_irq = i8042_kbd_irq;
}
if (result_aux > 0 && !i8042_pnp_aux_irq) {
if (!i8042_pnp_aux_irq) {
printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq;
}

View File

@ -698,6 +698,26 @@ static void i8042_timer_func(unsigned long data)
i8042_interrupt(0, NULL, NULL);
}
static int i8042_ctl_test(void)
{
unsigned char param;
if (!i8042_reset)
return 0;
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
return -1;
}
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
return -1;
}
return 0;
}
/*
* i8042_controller init initializes the i8042 controller, and,
@ -719,21 +739,8 @@ static int i8042_controller_init(void)
return -1;
}
if (i8042_reset) {
unsigned char param;
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
return -1;
}
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
return -1;
}
}
if (i8042_ctl_test())
return -1;
/*
* Save the CTR for restoral on unload / reboot.
@ -802,15 +809,11 @@ static int i8042_controller_init(void)
*/
static void i8042_controller_reset(void)
{
unsigned char param;
/*
* Reset the controller if requested.
*/
if (i8042_reset)
if (i8042_command(&param, I8042_CMD_CTL_TEST))
printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
i8042_ctl_test();
/*
* Disable MUX mode if present.
@ -922,8 +925,11 @@ static int i8042_resume(struct device *dev, u32 level)
if (level != RESUME_ENABLE)
return 0;
if (i8042_controller_init()) {
printk(KERN_ERR "i8042: resume failed\n");
if (i8042_ctl_test())
return -1;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042: Can't write CTR\n");
return -1;
}

View File

@ -68,8 +68,7 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
gunze->data[10] = 0;
printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
return;
}

View File

@ -2421,7 +2421,7 @@ pmac_wakeup_devices(void)
/* Re-enable local CPU interrupts */
local_irq_enable();
mdelay(100);
mdelay(10);
preempt_enable();
/* Re-enable clock spreading on some machines */
@ -2549,7 +2549,9 @@ powerbook_sleep_Core99(void)
return ret;
}
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
/* Stop environment and ADB interrupts */
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
pmu_wait_complete(&req);
/* Tell PMU what events will wake us up */
pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
@ -2611,8 +2613,6 @@ powerbook_sleep_Core99(void)
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
pmu_wait_complete(&req);
printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
pmac_wakeup_devices();
return 0;

View File

@ -906,22 +906,12 @@ static int dst_tone_power_cmd(struct dst_state* state)
if (state->dst_type == DST_TYPE_IS_TERR)
return 0;
if (state->voltage == SEC_VOLTAGE_OFF)
paket[4] = 0;
else
paket[4] = 1;
if (state->tone == SEC_TONE_ON)
paket[2] = 0x02;
else
paket[2] = 0;
if (state->minicmd == SEC_MINI_A)
paket[3] = 0x02;
else
paket[3] = 0;
paket[4] = state->tx_tuna[4];
paket[2] = state->tx_tuna[2];
paket[3] = state->tx_tuna[3];
paket[7] = dst_check_sum (paket, 7);
dst_command(state, paket, 8);
return 0;
}
@ -980,7 +970,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
static int dst_write_tuna(struct dvb_frontend* fe)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
int retval;
u8 reply;
@ -1048,10 +1038,10 @@ static int dst_write_tuna(struct dvb_frontend* fe)
static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
if (state->dst_type == DST_TYPE_IS_TERR)
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
if (cmd->msg_len == 0 || cmd->msg_len > 4)
@ -1064,39 +1054,32 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd*
static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
u8 *val;
int need_cmd;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
state->voltage = voltage;
if (state->dst_type == DST_TYPE_IS_TERR)
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
need_cmd = 0;
val = &state->tx_tuna[0];
val[8] &= ~0x40;
switch (voltage) {
case SEC_VOLTAGE_13:
if ((state->diseq_flags & HAS_POWER) == 0)
case SEC_VOLTAGE_13:
case SEC_VOLTAGE_18:
if ((state->diseq_flags & HAS_POWER) == 0)
need_cmd = 1;
state->diseq_flags |= HAS_POWER;
state->tx_tuna[4] = 0x01;
break;
case SEC_VOLTAGE_OFF:
need_cmd = 1;
state->diseq_flags |= HAS_POWER;
break;
state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
state->tx_tuna[4] = 0x00;
break;
case SEC_VOLTAGE_18:
if ((state->diseq_flags & HAS_POWER) == 0)
need_cmd = 1;
state->diseq_flags |= HAS_POWER;
val[8] |= 0x40;
break;
case SEC_VOLTAGE_OFF:
need_cmd = 1;
state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
if (need_cmd)
dst_tone_power_cmd(state);
@ -1106,37 +1089,56 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
u8 *val;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
state->tone = tone;
if (state->dst_type == DST_TYPE_IS_TERR)
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
val = &state->tx_tuna[0];
val[8] &= ~0x1;
switch (tone) {
case SEC_TONE_OFF:
break;
case SEC_TONE_OFF:
state->tx_tuna[2] = 0xff;
break;
case SEC_TONE_ON:
val[8] |= 1;
break;
case SEC_TONE_ON:
state->tx_tuna[2] = 0x02;
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
dst_tone_power_cmd(state);
return 0;
}
static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
{
struct dst_state *state = fe->demodulator_priv;
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
state->minicmd = minicmd;
switch (minicmd) {
case SEC_MINI_A:
state->tx_tuna[3] = 0x02;
break;
case SEC_MINI_B:
state->tx_tuna[3] = 0xff;
break;
}
dst_tone_power_cmd(state);
return 0;
}
static int dst_init(struct dvb_frontend* fe)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
@ -1168,7 +1170,7 @@ static int dst_init(struct dvb_frontend* fe)
static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
*status = 0;
if (state->diseq_flags & HAS_LOCK) {
@ -1182,7 +1184,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
dst_get_signal(state);
*strength = state->decode_strength;
@ -1192,7 +1194,7 @@ static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
dst_get_signal(state);
*snr = state->decode_snr;
@ -1202,7 +1204,7 @@ static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
dst_set_freq(state, p->frequency);
if (verbose > 4)
@ -1228,7 +1230,7 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
p->frequency = state->decode_freq;
p->inversion = state->inversion;
@ -1248,7 +1250,7 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
static void dst_release(struct dvb_frontend* fe)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
struct dst_state* state = fe->demodulator_priv;
kfree(state);
}
@ -1346,7 +1348,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
.diseqc_send_burst = dst_set_tone,
.diseqc_send_burst = dst_send_burst,
.diseqc_send_master_cmd = dst_set_diseqc,
.set_voltage = dst_set_voltage,
.set_tone = dst_set_tone,

View File

@ -1555,6 +1555,7 @@ config SIS900
tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
depends on NET_PCI && PCI
select CRC32
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
@ -2031,6 +2032,15 @@ config TIGON3
To compile this driver as a module, choose M here: the module
will be called tg3. This is recommended.
config BNX2
tristate "Broadcom NetXtremeII support"
depends on PCI
help
This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called bnx2. This is recommended.
config GIANFAR
tristate "Gianfar Ethernet"
depends on 85xx || 83xx

View File

@ -51,6 +51,7 @@ obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BNX2) += bnx2.o
obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SK98LIN) += sk98lin/
obj-$(CONFIG_SKFP) += skfp/

5530
drivers/net/bnx2.c Normal file

File diff suppressed because it is too large Load Diff

4352
drivers/net/bnx2.h Normal file

File diff suppressed because it is too large Load Diff

2468
drivers/net/bnx2_fw.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3037,7 +3037,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
bond_set_slave_inactive_flags(bond->current_arp_slave);
/* search for next candidate */
bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) {
bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
if (IS_UP(slave->dev)) {
slave->link = BOND_LINK_BACK;
bond_set_slave_active_flags(slave);

View File

@ -81,6 +81,7 @@
* cause DMA to kfree'd memory.
* 0.31: 14 Nov 2004: ethtool support for getting/setting link
* capabilities.
* 0.32: 16 Apr 2005: RX_ERROR4 handling added.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@ -92,7 +93,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
#define FORCEDETH_VERSION "0.31"
#define FORCEDETH_VERSION "0.32"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@ -109,6 +110,7 @@
#include <linux/mii.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/if_vlan.h>
#include <asm/irq.h>
#include <asm/io.h>
@ -1013,6 +1015,59 @@ static void nv_tx_timeout(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
/*
* Called when the nic notices a mismatch between the actual data len on the
* wire and the len indicated in the 802 header
*/
static int nv_getlen(struct net_device *dev, void *packet, int datalen)
{
int hdrlen; /* length of the 802 header */
int protolen; /* length as stored in the proto field */
/* 1) calculate len according to header */
if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
hdrlen = VLAN_HLEN;
} else {
protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
hdrlen = ETH_HLEN;
}
dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
dev->name, datalen, protolen, hdrlen);
if (protolen > ETH_DATA_LEN)
return datalen; /* Value in proto field not a len, no checks possible */
protolen += hdrlen;
/* consistency checks: */
if (datalen > ETH_ZLEN) {
if (datalen >= protolen) {
/* more data on wire than in 802 header, trim of
* additional data.
*/
dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
dev->name, protolen);
return protolen;
} else {
/* less data on wire than mentioned in header.
* Discard the packet.
*/
dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
dev->name);
return -1;
}
} else {
/* short packet. Accept only if 802 values are also short */
if (protolen > ETH_ZLEN) {
dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
dev->name);
return -1;
}
dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
dev->name, datalen);
return datalen;
}
}
static void nv_rx_process(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
@ -1064,7 +1119,7 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
@ -1078,22 +1133,24 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX_ERROR) {
/* framing errors are soft errors, the rest is fatal. */
if (Flags & NV_RX_FRAMINGERR) {
if (Flags & NV_RX_SUBSTRACT1) {
len--;
}
} else {
if (Flags & NV_RX_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors. */
if (Flags & NV_RX_FRAMINGERR) {
if (Flags & NV_RX_SUBSTRACT1) {
len--;
}
}
} else {
if (!(Flags & NV_RX2_DESCRIPTORVALID))
goto next_pkt;
if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
@ -1107,17 +1164,19 @@ static void nv_rx_process(struct net_device *dev)
np->stats.rx_errors++;
goto next_pkt;
}
if (Flags & NV_RX2_ERROR) {
/* framing errors are soft errors, the rest is fatal. */
if (Flags & NV_RX2_FRAMINGERR) {
if (Flags & NV_RX2_SUBSTRACT1) {
len--;
}
} else {
if (Flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
goto next_pkt;
}
}
/* framing errors are soft errors */
if (Flags & NV_RX2_FRAMINGERR) {
if (Flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
Flags &= NV_RX2_CHECKSUMMASK;
if (Flags == NV_RX2_CHECKSUMOK1 ||
Flags == NV_RX2_CHECKSUMOK2 ||
@ -1480,6 +1539,13 @@ static void nv_do_nic_poll(unsigned long data)
enable_irq(dev->irq);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void nv_poll_controller(struct net_device *dev)
{
nv_do_nic_poll((unsigned long) dev);
}
#endif
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct fe_priv *np = get_nvpriv(dev);
@ -1962,6 +2028,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_multicast_list = nv_set_multicast;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;

View File

@ -924,7 +924,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
spin_lock_irqsave(&cnx->lock, flags);
if (! cnx->state & VETH_STATE_READY)
if (! (cnx->state & VETH_STATE_READY))
goto drop;
if ((skb->len - 14) > VETH_MAX_MTU)
@ -1023,6 +1023,8 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
lpmask = veth_transmit_to_many(skb, lpmask, dev);
dev->trans_start = jiffies;
if (! lpmask) {
dev_kfree_skb(skb);
} else {
@ -1262,13 +1264,18 @@ static void veth_receive(struct veth_lpar_connection *cnx,
vlan = skb->data[9];
dev = veth_dev[vlan];
if (! dev)
/* Some earlier versions of the driver sent
broadcasts down all connections, even to
lpars that weren't on the relevant vlan.
So ignore packets belonging to a vlan we're
not on. */
if (! dev) {
/*
* Some earlier versions of the driver sent
* broadcasts down all connections, even to lpars
* that weren't on the relevant vlan. So ignore
* packets belonging to a vlan we're not on.
* We can also be here if we receive packets while
* the driver is going down, because then dev is NULL.
*/
dev_kfree_skb_irq(skb);
continue;
}
port = (struct veth_port *)dev->priv;
dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
@ -1381,18 +1388,25 @@ void __exit veth_module_cleanup(void)
{
int i;
vio_unregister_driver(&veth_driver);
/* Stop the queues first to stop any new packets being sent. */
for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
if (veth_dev[i])
netif_stop_queue(veth_dev[i]);
/* Stop the connections before we unregister the driver. This
* ensures there's no skbs lying around holding the device open. */
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
veth_stop_connection(i);
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
/* Hypervisor callbacks may have scheduled more work while we
* were destroying connections. Now that we've disconnected from
* were stoping connections. Now that we've disconnected from
* the hypervisor make sure everything's finished. */
flush_scheduled_work();
vio_unregister_driver(&veth_driver);
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
veth_destroy_connection(i);

View File

@ -2433,9 +2433,9 @@ static void __set_rx_mode(struct net_device *dev)
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptMulticast | AcceptMyPhys;
for (i = 0; i < 64; i += 2) {
writew(HASH_TABLE + i, ioaddr + RxFilterAddr);
writew((mc_filter[i+1]<<8) + mc_filter[i],
ioaddr + RxFilterData);
writel(HASH_TABLE + i, ioaddr + RxFilterAddr);
writel((mc_filter[i + 1] << 8) + mc_filter[i],
ioaddr + RxFilterData);
}
}
writel(rx_mode, ioaddr + RxFilterAddr);

View File

@ -1,4 +1,4 @@
#define _VERSION "0.20"
#define VERSION "0.22"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* Questions/comments/discussion to linux-ns83820@kvack.org.
@ -63,9 +63,11 @@
* - fix missed txok introduced during performance
* tuning
* 0.20 - fix stupid RFEN thinko. i am such a smurf.
*
* 20040828 0.21 - add hardware vlan accleration
* by Neil Horman <nhorman@redhat.com>
* 20050406 0.22 - improved DAC ifdefs from Andi Kleen
* - removal of dead code from Adrian Bunk
* - fix half duplex collision behaviour
* Driver Overview
* ===============
*
@ -129,18 +131,6 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */
#undef Dprintk
#define Dprintk dprintk
#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
#define USE_64BIT_ADDR "+"
#endif
#if defined(USE_64BIT_ADDR)
#define VERSION _VERSION USE_64BIT_ADDR
#define TRY_DAC 1
#else
#define VERSION _VERSION
#define TRY_DAC 0
#endif
/* tunables */
#define RX_BUF_SIZE 1500 /* 8192 */
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@ -386,22 +376,16 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */
#define LINK_DOWN 0x02
#define LINK_UP 0x04
#ifdef USE_64BIT_ADDR
#define HW_ADDR_LEN 8
#define HW_ADDR_LEN sizeof(dma_addr_t)
#define desc_addr_set(desc, addr) \
do { \
u64 __addr = (addr); \
(desc)[0] = cpu_to_le32(__addr); \
(desc)[1] = cpu_to_le32(__addr >> 32); \
((desc)[0] = cpu_to_le32(addr)); \
if (HW_ADDR_LEN == 8) \
(desc)[1] = cpu_to_le32(((u64)addr) >> 32); \
} while(0)
#define desc_addr_get(desc) \
(((u64)le32_to_cpu((desc)[1]) << 32) \
| le32_to_cpu((desc)[0]))
#else
#define HW_ADDR_LEN 4
#define desc_addr_set(desc, addr) ((desc)[0] = cpu_to_le32(addr))
#define desc_addr_get(desc) (le32_to_cpu((desc)[0]))
#endif
(le32_to_cpu((desc)[0]) | \
(HW_ADDR_LEN == 8 ? ((dma_addr_t)le32_to_cpu((desc)[1]))<<32 : 0))
#define DESC_LINK 0
#define DESC_BUFPTR (DESC_LINK + HW_ADDR_LEN/4)
@ -727,11 +711,23 @@ static void fastcall phy_intr(struct net_device *ndev)
speed = ((cfg / CFG_SPDSTS0) & 3);
fullduplex = (cfg & CFG_DUPSTS);
if (fullduplex)
if (fullduplex) {
new_cfg |= CFG_SB;
writel(readl(dev->base + TXCFG)
| TXCFG_CSI | TXCFG_HBI,
dev->base + TXCFG);
writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
dev->base + RXCFG);
} else {
writel(readl(dev->base + TXCFG)
& ~(TXCFG_CSI | TXCFG_HBI),
dev->base + TXCFG);
writel(readl(dev->base + RXCFG) & ~(RXCFG_RX_FD),
dev->base + RXCFG);
}
if ((cfg & CFG_LNKSTS) &&
((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
((new_cfg ^ dev->CFG_cache) != 0)) {
writel(new_cfg, dev->base + CFG);
dev->CFG_cache = new_cfg;
}
@ -1189,7 +1185,6 @@ again:
for (;;) {
volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE);
u32 residue = 0;
dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
(unsigned long long)buf);
@ -1199,17 +1194,11 @@ again:
desc_addr_set(desc + DESC_BUFPTR, buf);
desc[DESC_EXTSTS] = cpu_to_le32(extsts);
cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
cmdsts = ((nr_frags) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
cmdsts |= len;
desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
if (residue) {
buf += len;
len = residue;
continue;
}
if (!nr_frags)
break;
@ -1841,7 +1830,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
int using_dac = 0;
/* See if we can set the dma mask early on; failure is fatal. */
if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
if (sizeof(dma_addr_t) == 8 &&
!pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) {
using_dac = 1;
} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
using_dac = 0;
@ -1972,9 +1962,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
/* When compiled with 64 bit addressing, we must always enable
* the 64 bit descriptor format.
*/
#ifdef USE_64BIT_ADDR
dev->CFG_cache |= CFG_M64ADDR;
#endif
if (sizeof(dma_addr_t) == 8)
dev->CFG_cache |= CFG_M64ADDR;
if (using_dac)
dev->CFG_cache |= CFG_T64ADDR;

View File

@ -162,6 +162,7 @@ struct sis900_private {
struct mii_phy * mii;
struct mii_phy * first_mii; /* record the first mii structure */
unsigned int cur_phy;
struct mii_if_info mii_info;
struct timer_list timer; /* Link status detection timer. */
u8 autong_complete; /* 1: auto-negotiate complete */
@ -203,7 +204,7 @@ static int sis900_open(struct net_device *net_dev);
static int sis900_mii_probe (struct net_device * net_dev);
static void sis900_init_rxfilter (struct net_device * net_dev);
static u16 read_eeprom(long ioaddr, int location);
static u16 mdio_read(struct net_device *net_dev, int phy_id, int location);
static int mdio_read(struct net_device *net_dev, int phy_id, int location);
static void mdio_write(struct net_device *net_dev, int phy_id, int location, int val);
static void sis900_timer(unsigned long data);
static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy);
@ -478,7 +479,13 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
sis_priv->msg_enable = sis900_debug;
else
sis_priv->msg_enable = SIS900_DEF_MSG;
sis_priv->mii_info.dev = net_dev;
sis_priv->mii_info.mdio_read = mdio_read;
sis_priv->mii_info.mdio_write = mdio_write;
sis_priv->mii_info.phy_id_mask = 0x1f;
sis_priv->mii_info.reg_num_mask = 0x1f;
/* Get Mac address according to the chip revision */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev));
if(netif_msg_probe(sis_priv))
@ -725,6 +732,8 @@ static u16 sis900_default_phy(struct net_device * net_dev)
pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
}
sis_priv->mii_info.phy_id = sis_priv->cur_phy;
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
status &= (~MII_CNTL_ISOLATE);
@ -852,7 +861,7 @@ static void mdio_reset(long mdio_addr)
* Please see SiS7014 or ICS spec
*/
static u16 mdio_read(struct net_device *net_dev, int phy_id, int location)
static int mdio_read(struct net_device *net_dev, int phy_id, int location)
{
long mdio_addr = net_dev->base_addr + mear;
int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
@ -1966,10 +1975,47 @@ static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
sis_priv->msg_enable = value;
}
static u32 sis900_get_link(struct net_device *net_dev)
{
struct sis900_private *sis_priv = net_dev->priv;
return mii_link_ok(&sis_priv->mii_info);
}
static int sis900_get_settings(struct net_device *net_dev,
struct ethtool_cmd *cmd)
{
struct sis900_private *sis_priv = net_dev->priv;
spin_lock_irq(&sis_priv->lock);
mii_ethtool_gset(&sis_priv->mii_info, cmd);
spin_unlock_irq(&sis_priv->lock);
return 0;
}
static int sis900_set_settings(struct net_device *net_dev,
struct ethtool_cmd *cmd)
{
struct sis900_private *sis_priv = net_dev->priv;
int rt;
spin_lock_irq(&sis_priv->lock);
rt = mii_ethtool_sset(&sis_priv->mii_info, cmd);
spin_unlock_irq(&sis_priv->lock);
return rt;
}
static int sis900_nway_reset(struct net_device *net_dev)
{
struct sis900_private *sis_priv = net_dev->priv;
return mii_nway_restart(&sis_priv->mii_info);
}
static struct ethtool_ops sis900_ethtool_ops = {
.get_drvinfo = sis900_get_drvinfo,
.get_msglevel = sis900_get_msglevel,
.set_msglevel = sis900_set_msglevel,
.get_link = sis900_get_link,
.get_settings = sis900_get_settings,
.set_settings = sis900_set_settings,
.nway_reset = sis900_nway_reset,
};
/**

View File

@ -133,6 +133,8 @@
/* number of ETHTOOL_GSTATS u64's */
#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
#define TG3_NUM_TEST 6
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@ -316,6 +318,17 @@ static struct {
{ "nic_tx_threshold_hit" }
};
static struct {
const char string[ETH_GSTRING_LEN];
} ethtool_test_keys[TG3_NUM_TEST] = {
{ "nvram test (online) " },
{ "link test (online) " },
{ "register test (offline)" },
{ "memory test (offline)" },
{ "loopback test (offline)" },
{ "interrupt test (offline)" },
};
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
@ -3070,7 +3083,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
}
static int tg3_init_hw(struct tg3 *);
static int tg3_halt(struct tg3 *, int);
static int tg3_halt(struct tg3 *, int, int);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
@ -3094,7 +3107,7 @@ static void tg3_reset_task(void *_data)
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
tg3_halt(tp, 0);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
tg3_init_hw(tp);
tg3_netif_start(tp);
@ -3440,7 +3453,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_set_mtu(dev, tp, new_mtu);
@ -4131,19 +4144,19 @@ static void tg3_stop_fw(struct tg3 *tp)
}
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp, int silent)
static int tg3_halt(struct tg3 *tp, int kind, int silent)
{
int err;
tg3_stop_fw(tp);
tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN);
tg3_write_sig_pre_reset(tp, kind);
tg3_abort_hw(tp, silent);
err = tg3_chip_reset(tp);
tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN);
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
tg3_write_sig_legacy(tp, kind);
tg3_write_sig_post_reset(tp, kind);
if (err)
return err;
@ -4357,7 +4370,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
*/
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
/* It is possible that bootcode is still loading at this point.
* Get the nvram lock first before halting the cpu.
*/
tg3_nvram_lock(tp);
err = tg3_halt_cpu(tp, cpu_base);
tg3_nvram_unlock(tp);
if (err)
goto out;
@ -5881,6 +5899,9 @@ static int tg3_test_interrupt(struct tg3 *tp)
int err, i;
u32 int_mbox = 0;
if (!netif_running(dev))
return -ENODEV;
tg3_disable_ints(tp);
free_irq(tp->pdev->irq, dev);
@ -5984,7 +6005,7 @@ static int tg3_test_msi(struct tg3 *tp)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
err = tg3_init_hw(tp);
spin_unlock(&tp->tx_lock);
@ -6060,7 +6081,7 @@ static int tg3_open(struct net_device *dev)
err = tg3_init_hw(tp);
if (err) {
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
} else {
if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
@ -6104,7 +6125,7 @@ static int tg3_open(struct net_device *dev)
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
}
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
tg3_free_consistent(tp);
@ -6377,7 +6398,7 @@ static int tg3_close(struct net_device *dev)
tg3_disable_ints(tp);
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
tp->tg3_flags &=
~(TG3_FLAG_INIT_COMPLETE |
@ -7097,7 +7118,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tp->tx_pending = ering->tx_pending;
if (netif_running(dev)) {
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_init_hw(tp);
tg3_netif_start(tp);
}
@ -7140,7 +7161,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
if (netif_running(dev)) {
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_init_hw(tp);
tg3_netif_start(tp);
}
@ -7199,12 +7220,20 @@ static int tg3_get_stats_count (struct net_device *dev)
return TG3_NUM_STATS;
}
static int tg3_get_test_count (struct net_device *dev)
{
return TG3_NUM_TEST;
}
static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
break;
case ETH_SS_TEST:
memcpy(buf, &ethtool_test_keys, sizeof(ethtool_test_keys));
break;
default:
WARN_ON(1); /* we need a WARN() */
break;
@ -7218,6 +7247,516 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
}
#define NVRAM_TEST_SIZE 0x100
static int tg3_test_nvram(struct tg3 *tp)
{
u32 *buf, csum;
int i, j, err = 0;
buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) {
u32 val;
if ((err = tg3_nvram_read(tp, i, &val)) != 0)
break;
buf[j] = cpu_to_le32(val);
}
if (i < NVRAM_TEST_SIZE)
goto out;
err = -EIO;
if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC)
goto out;
/* Bootstrap checksum at offset 0x10 */
csum = calc_crc((unsigned char *) buf, 0x10);
if(csum != cpu_to_le32(buf[0x10/4]))
goto out;
/* Manufacturing block starts at offset 0x74, checksum at 0xfc */
csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
if (csum != cpu_to_le32(buf[0xfc/4]))
goto out;
err = 0;
out:
kfree(buf);
return err;
}
#define TG3_SERDES_TIMEOUT_SEC 2
#define TG3_COPPER_TIMEOUT_SEC 6
static int tg3_test_link(struct tg3 *tp)
{
int i, max;
if (!netif_running(tp->dev))
return -ENODEV;
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
max = TG3_SERDES_TIMEOUT_SEC;
else
max = TG3_COPPER_TIMEOUT_SEC;
for (i = 0; i < max; i++) {
if (netif_carrier_ok(tp->dev))
return 0;
if (msleep_interruptible(1000))
break;
}
return -EIO;
}
/* Only test the commonly used registers */
static int tg3_test_registers(struct tg3 *tp)
{
int i, is_5705;
u32 offset, read_mask, write_mask, val, save_val, read_val;
static struct {
u16 offset;
u16 flags;
#define TG3_FL_5705 0x1
#define TG3_FL_NOT_5705 0x2
#define TG3_FL_NOT_5788 0x4
u32 read_mask;
u32 write_mask;
} reg_tbl[] = {
/* MAC Control Registers */
{ MAC_MODE, TG3_FL_NOT_5705,
0x00000000, 0x00ef6f8c },
{ MAC_MODE, TG3_FL_5705,
0x00000000, 0x01ef6b8c },
{ MAC_STATUS, TG3_FL_NOT_5705,
0x03800107, 0x00000000 },
{ MAC_STATUS, TG3_FL_5705,
0x03800100, 0x00000000 },
{ MAC_ADDR_0_HIGH, 0x0000,
0x00000000, 0x0000ffff },
{ MAC_ADDR_0_LOW, 0x0000,
0x00000000, 0xffffffff },
{ MAC_RX_MTU_SIZE, 0x0000,
0x00000000, 0x0000ffff },
{ MAC_TX_MODE, 0x0000,
0x00000000, 0x00000070 },
{ MAC_TX_LENGTHS, 0x0000,
0x00000000, 0x00003fff },
{ MAC_RX_MODE, TG3_FL_NOT_5705,
0x00000000, 0x000007fc },
{ MAC_RX_MODE, TG3_FL_5705,
0x00000000, 0x000007dc },
{ MAC_HASH_REG_0, 0x0000,
0x00000000, 0xffffffff },
{ MAC_HASH_REG_1, 0x0000,
0x00000000, 0xffffffff },
{ MAC_HASH_REG_2, 0x0000,
0x00000000, 0xffffffff },
{ MAC_HASH_REG_3, 0x0000,
0x00000000, 0xffffffff },
/* Receive Data and Receive BD Initiator Control Registers. */
{ RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705,
0x00000000, 0x00000003 },
{ RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ RCVDBDI_STD_BD+0, 0x0000,
0x00000000, 0xffffffff },
{ RCVDBDI_STD_BD+4, 0x0000,
0x00000000, 0xffffffff },
{ RCVDBDI_STD_BD+8, 0x0000,
0x00000000, 0xffff0002 },
{ RCVDBDI_STD_BD+0xc, 0x0000,
0x00000000, 0xffffffff },
/* Receive BD Initiator Control Registers. */
{ RCVBDI_STD_THRESH, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ RCVBDI_STD_THRESH, TG3_FL_5705,
0x00000000, 0x000003ff },
{ RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
/* Host Coalescing Control Registers. */
{ HOSTCC_MODE, TG3_FL_NOT_5705,
0x00000000, 0x00000004 },
{ HOSTCC_MODE, TG3_FL_5705,
0x00000000, 0x000000f6 },
{ HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_RXCOL_TICKS, TG3_FL_5705,
0x00000000, 0x000003ff },
{ HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_TXCOL_TICKS, TG3_FL_5705,
0x00000000, 0x000003ff },
{ HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
0x00000000, 0x000000ff },
{ HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
0x00000000, 0x000000ff },
{ HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
0x00000000, 0x000000ff },
{ HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
0x00000000, 0x000000ff },
{ HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
{ HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000,
0x00000000, 0xffffffff },
{ HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000,
0x00000000, 0xffffffff },
{ HOSTCC_STATS_BLK_NIC_ADDR, 0x0000,
0xffffffff, 0x00000000 },
{ HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000,
0xffffffff, 0x00000000 },
/* Buffer Manager Control Registers. */
{ BUFMGR_MB_POOL_ADDR, 0x0000,
0x00000000, 0x007fff80 },
{ BUFMGR_MB_POOL_SIZE, 0x0000,
0x00000000, 0x007fffff },
{ BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
0x00000000, 0x0000003f },
{ BUFMGR_MB_MACRX_LOW_WATER, 0x0000,
0x00000000, 0x000001ff },
{ BUFMGR_MB_HIGH_WATER, 0x0000,
0x00000000, 0x000001ff },
{ BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705,
0xffffffff, 0x00000000 },
{ BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705,
0xffffffff, 0x00000000 },
/* Mailbox Registers */
{ GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000,
0x00000000, 0x000001ff },
{ GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705,
0x00000000, 0x000001ff },
{ GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000,
0x00000000, 0x000007ff },
{ GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000,
0x00000000, 0x000001ff },
{ 0xffff, 0x0000, 0x00000000, 0x00000000 },
};
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
is_5705 = 1;
else
is_5705 = 0;
for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
continue;
if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705))
continue;
if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
(reg_tbl[i].flags & TG3_FL_NOT_5788))
continue;
offset = (u32) reg_tbl[i].offset;
read_mask = reg_tbl[i].read_mask;
write_mask = reg_tbl[i].write_mask;
/* Save the original register content */
save_val = tr32(offset);
/* Determine the read-only value. */
read_val = save_val & read_mask;
/* Write zero to the register, then make sure the read-only bits
* are not changed and the read/write bits are all zeros.
*/
tw32(offset, 0);
val = tr32(offset);
/* Test the read-only and read/write bits. */
if (((val & read_mask) != read_val) || (val & write_mask))
goto out;
/* Write ones to all the bits defined by RdMask and WrMask, then
* make sure the read-only bits are not changed and the
* read/write bits are all ones.
*/
tw32(offset, read_mask | write_mask);
val = tr32(offset);
/* Test the read-only bits. */
if ((val & read_mask) != read_val)
goto out;
/* Test the read/write bits. */
if ((val & write_mask) != write_mask)
goto out;
tw32(offset, save_val);
}
return 0;
out:
printk(KERN_ERR PFX "Register test failed at offset %x\n", offset);
tw32(offset, save_val);
return -EIO;
}
static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
{
static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a };
int i;
u32 j;
for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
for (j = 0; j < len; j += 4) {
u32 val;
tg3_write_mem(tp, offset + j, test_pattern[i]);
tg3_read_mem(tp, offset + j, &val);
if (val != test_pattern[i])
return -EIO;
}
}
return 0;
}
static int tg3_test_memory(struct tg3 *tp)
{
static struct mem_entry {
u32 offset;
u32 len;
} mem_tbl_570x[] = {
{ 0x00000000, 0x01000},
{ 0x00002000, 0x1c000},
{ 0xffffffff, 0x00000}
}, mem_tbl_5705[] = {
{ 0x00000100, 0x0000c},
{ 0x00000200, 0x00008},
{ 0x00000b50, 0x00400},
{ 0x00004000, 0x00800},
{ 0x00006000, 0x01000},
{ 0x00008000, 0x02000},
{ 0x00010000, 0x0e000},
{ 0xffffffff, 0x00000}
};
struct mem_entry *mem_tbl;
int err = 0;
int i;
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
mem_tbl = mem_tbl_5705;
else
mem_tbl = mem_tbl_570x;
for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset,
mem_tbl[i].len)) != 0)
break;
}
return err;
}
static int tg3_test_loopback(struct tg3 *tp)
{
u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key;
u32 desc_idx;
struct sk_buff *skb, *rx_skb;
u8 *tx_data;
dma_addr_t map;
int num_pkts, tx_len, rx_len, i, err;
struct tg3_rx_buffer_desc *desc;
if (!netif_running(tp->dev))
return -ENODEV;
err = -EIO;
tg3_abort_hw(tp, 1);
/* Clearing this flag to keep interrupts disabled */
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_reset_hw(tp);
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
MAC_MODE_PORT_MODE_GMII;
tw32(MAC_MODE, mac_mode);
tx_len = 1514;
skb = dev_alloc_skb(tx_len);
tx_data = skb_put(skb, tx_len);
memcpy(tx_data, tp->dev->dev_addr, 6);
memset(tx_data + 6, 0x0, 8);
tw32(MAC_RX_MTU_SIZE, tx_len + 4);
for (i = 14; i < tx_len; i++)
tx_data[i] = (u8) (i & 0xff);
map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE);
tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
HOSTCC_MODE_NOW);
udelay(10);
rx_start_idx = tp->hw_status->idx[0].rx_producer;
send_idx = 0;
num_pkts = 0;
tg3_set_txd(tp, send_idx, map, tx_len, 0, 1);
send_idx++;
num_pkts++;
tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx);
tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
udelay(10);
for (i = 0; i < 10; i++) {
tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
HOSTCC_MODE_NOW);
udelay(10);
tx_idx = tp->hw_status->idx[0].tx_consumer;
rx_idx = tp->hw_status->idx[0].rx_producer;
if ((tx_idx == send_idx) &&
(rx_idx == (rx_start_idx + num_pkts)))
break;
}
pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
if (tx_idx != send_idx)
goto out;
if (rx_idx != rx_start_idx + num_pkts)
goto out;
desc = &tp->rx_rcb[rx_start_idx];
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
if (opaque_key != RXD_OPAQUE_RING_STD)
goto out;
if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
(desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII))
goto out;
rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4;
if (rx_len != tx_len)
goto out;
rx_skb = tp->rx_std_buffers[desc_idx].skb;
map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping);
pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE);
for (i = 14; i < tx_len; i++) {
if (*(rx_skb->data + i) != (u8) (i & 0xff))
goto out;
}
err = 0;
/* tg3_free_rings will unmap and free the rx_skb */
out:
return err;
}
static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
u64 *data)
{
struct tg3 *tp = netdev_priv(dev);
memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
if (tg3_test_nvram(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[0] = 1;
}
if (tg3_test_link(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[1] = 1;
}
if (etest->flags & ETH_TEST_FL_OFFLINE) {
if (netif_running(dev))
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_halt(tp, RESET_KIND_SUSPEND, 1);
tg3_nvram_lock(tp);
tg3_halt_cpu(tp, RX_CPU_BASE);
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
tg3_halt_cpu(tp, TX_CPU_BASE);
tg3_nvram_unlock(tp);
if (tg3_test_registers(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[2] = 1;
}
if (tg3_test_memory(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[3] = 1;
}
if (tg3_test_loopback(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
}
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
if (tg3_test_interrupt(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[5] = 1;
}
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
tg3_init_hw(tp);
tg3_netif_start(tp);
}
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
}
}
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
@ -7331,6 +7870,8 @@ static struct ethtool_ops tg3_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
#endif
.self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
.get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
@ -9478,7 +10019,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
err = tg3_test_dma(tp);
@ -9605,7 +10146,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_halt(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);

View File

@ -193,6 +193,12 @@ static int aui[MAX_TLAN_BOARDS];
static int duplex[MAX_TLAN_BOARDS];
static int speed[MAX_TLAN_BOARDS];
static int boards_found;
module_param_array(aui, int, NULL, 0);
module_param_array(duplex, int, NULL, 0);
module_param_array(speed, int, NULL, 0);
MODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)");
MODULE_PARM_DESC(duplex, "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)");
MODULE_PARM_DESC(speed, "ThunderLAN port speen setting(s) (0,10,100)");
MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>");
MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
@ -204,8 +210,13 @@ MODULE_LICENSE("GPL");
/* Turn on debugging. See Documentation/networking/tlan.txt for details */
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
static int bbuf;
module_param(bbuf, int, 0);
MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
static u8 *TLanPadBuffer;
static dma_addr_t TLanPadBufferDMA;
static char TLanSignature[] = "TLAN";
@ -2381,6 +2392,7 @@ TLan_FinishReset( struct net_device *dev )
TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
return;
}
TLan_SetMulticastList(dev);
} /* TLan_FinishReset */

View File

@ -754,7 +754,7 @@ typedef struct {
u8 zero;
u8 ssidLen;
u8 ssid[32];
u16 rssi;
u16 dBm;
#define CAP_ESS (1<<0)
#define CAP_IBSS (1<<1)
#define CAP_PRIVACY (1<<4)
@ -1125,6 +1125,9 @@ static int micsetup(struct airo_info *ai);
static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
#include <linux/crypto.h>
#endif
@ -1713,6 +1716,7 @@ static int readBSSListRid(struct airo_info *ai, int first,
list->fh.dwell = le16_to_cpu(list->fh.dwell);
list->dsChannel = le16_to_cpu(list->dsChannel);
list->atimWindow = le16_to_cpu(list->atimWindow);
list->dBm = le16_to_cpu(list->dBm);
return rc;
}
@ -3245,7 +3249,10 @@ badrx:
wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
else
wstats.level = (hdr.rssi[1] + 321) / 2;
wstats.updated = 3;
wstats.noise = apriv->wstats.qual.noise;
wstats.updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_QUAL_UPDATED
| IW_QUAL_NOISE_UPDATED;
/* Update spy records */
wireless_spy_update(dev, sa, &wstats);
}
@ -3588,7 +3595,10 @@ void mpi_receive_802_11 (struct airo_info *ai)
wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
else
wstats.level = (hdr.rssi[1] + 321) / 2;
wstats.updated = 3;
wstats.noise = ai->wstats.qual.noise;
wstats.updated = IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
/* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats);
}
@ -3679,7 +3689,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock);
if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
}
else {
if (ai->rssi) {
@ -5348,7 +5358,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
(int)BSSList_rid.bssid[5],
(int)BSSList_rid.ssidLen,
BSSList_rid.ssid,
(int)BSSList_rid.rssi);
(int)BSSList_rid.dBm);
ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
(int)BSSList_rid.dsChannel,
BSSList_rid.cap & CAP_ESS ? "ESS" : "",
@ -5593,6 +5603,29 @@ static void __exit airo_cleanup_module( void )
* would not work at all... - Jean II
*/
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
{
if( !rssi_rid )
return 0;
return (0x100 - rssi_rid[rssi].rssidBm);
}
static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
{
int i;
if( !rssi_rid )
return 0;
for( i = 0; i < 256; i++ )
if (rssi_rid[i].rssidBm == dbm)
return rssi_rid[i].rssipct;
return 0;
}
static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
{
int quality = 0;
@ -6443,12 +6476,30 @@ static int airo_get_range(struct net_device *dev,
}
range->num_frequency = k;
/* Hum... Should put the right values there */
range->max_qual.qual = airo_get_max_quality(&cap_rid);
range->max_qual.level = 0x100 - 120; /* -120 dBm */
range->max_qual.noise = 0;
range->sensitivity = 65535;
/* Hum... Should put the right values there */
if (local->rssi)
range->max_qual.qual = 100; /* % */
else
range->max_qual.qual = airo_get_max_quality(&cap_rid);
range->max_qual.level = 0; /* 0 means we use dBm */
range->max_qual.noise = 0;
range->max_qual.updated = 0;
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
if (local->rssi) {
range->avg_qual.qual = 50; /* % */
range->avg_qual.level = 186; /* -70 dBm */
} else {
range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
range->avg_qual.level = 176; /* -80 dBm */
}
range->avg_qual.noise = 0;
range->avg_qual.updated = 0;
for(i = 0 ; i < 8 ; i++) {
range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
if(range->bitrate[i] == 0)
@ -6508,15 +6559,6 @@ static int airo_get_range(struct net_device *dev,
range->max_retry = 65535;
range->min_r_time = 1024;
range->max_r_time = 65535 * 1024;
/* Experimental measurements - boundary 11/5.5 Mb/s */
/* Note : with or without the (local->rssi), results
* are somewhat different. - Jean II */
range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
if (local->rssi)
range->avg_qual.level = 186; /* -70 dBm */
else
range->avg_qual.level = 176; /* -80 dBm */
range->avg_qual.noise = 0;
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
@ -6676,12 +6718,18 @@ static int airo_get_aplist(struct net_device *dev,
loseSync = 0;
memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
address[i].sa_family = ARPHRD_ETHER;
if (local->rssi)
qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
else
qual[i].level = (BSSList.rssi + 321) / 2;
qual[i].qual = qual[i].noise = 0;
qual[i].updated = 2;
if (local->rssi) {
qual[i].level = 0x100 - BSSList.dBm;
qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
qual[i].updated = IW_QUAL_QUAL_UPDATED;
} else {
qual[i].level = (BSSList.dBm + 321) / 2;
qual[i].qual = 0;
qual[i].updated = IW_QUAL_QUAL_INVALID;
}
qual[i].noise = local->wstats.qual.noise;
qual[i].updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
if (BSSList.index == 0xffff)
break;
}
@ -6760,7 +6808,7 @@ static int airo_set_scan(struct net_device *dev,
static inline char *airo_translate_scan(struct net_device *dev,
char *current_ev,
char *end_buf,
BSSListRid *list)
BSSListRid *bss)
{
struct airo_info *ai = dev->priv;
struct iw_event iwe; /* Temporary buffer */
@ -6771,22 +6819,22 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* First entry *MUST* be the AP MAC address */
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN);
memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
/* Other entries will be displayed in the order we give them */
/* Add the ESSID */
iwe.u.data.length = list->ssidLen;
iwe.u.data.length = bss->ssidLen;
if(iwe.u.data.length > 32)
iwe.u.data.length = 32;
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Add mode */
iwe.cmd = SIOCGIWMODE;
capabilities = le16_to_cpu(list->cap);
capabilities = le16_to_cpu(bss->cap);
if(capabilities & (CAP_ESS | CAP_IBSS)) {
if(capabilities & CAP_ESS)
iwe.u.mode = IW_MODE_MASTER;
@ -6797,19 +6845,25 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Add frequency */
iwe.cmd = SIOCGIWFREQ;
iwe.u.freq.m = le16_to_cpu(list->dsChannel);
iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000;
iwe.u.freq.e = 1;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
/* Add quality statistics */
iwe.cmd = IWEVQUAL;
if (ai->rssi)
iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm;
else
iwe.u.qual.level = (list->rssi + 321) / 2;
iwe.u.qual.noise = 0;
iwe.u.qual.qual = 0;
if (ai->rssi) {
iwe.u.qual.level = 0x100 - bss->dBm;
iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED;
} else {
iwe.u.qual.level = (bss->dBm + 321) / 2;
iwe.u.qual.qual = 0;
iwe.u.qual.updated = IW_QUAL_QUAL_INVALID;
}
iwe.u.qual.noise = ai->wstats.qual.noise;
iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
| IW_QUAL_NOISE_UPDATED;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
/* Add encryption capability */
@ -6819,7 +6873,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
else
iwe.u.data.flags = IW_ENCODE_DISABLED;
iwe.u.data.length = 0;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid);
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid);
/* Rate : stuffing multiple values in a single event require a bit
* more of magic - Jean II */
@ -6831,10 +6885,10 @@ static inline char *airo_translate_scan(struct net_device *dev,
/* Max 8 values */
for(i = 0 ; i < 8 ; i++) {
/* NULL terminated */
if(list->rates[i] == 0)
if(bss->rates[i] == 0)
break;
/* Bit rate given in 500 kb/s units (+ 0x80) */
iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000);
iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
/* Add new value to event */
current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
}
@ -7153,18 +7207,22 @@ static void airo_read_wireless_stats(struct airo_info *local)
/* The status */
local->wstats.status = status_rid.mode;
/* Signal quality and co. But where is the noise level ??? */
local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
if (local->rssi)
local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
else
/* Signal quality and co */
if (local->rssi) {
local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
/* normalizedSignalStrength appears to be a percentage */
local->wstats.qual.qual = status_rid.normalizedSignalStrength;
} else {
local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
}
local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED;
if (status_rid.len >= 124) {
local->wstats.qual.noise = 256 - status_rid.noisedBm;
local->wstats.qual.updated = 7;
local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
local->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED;
} else {
local->wstats.qual.noise = 0;
local->wstats.qual.updated = 3;
local->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
}
/* Packets discarded in the wireless adapter due to wireless

View File

@ -321,6 +321,7 @@ static struct {
{ 0x01bf, 0x3302, NULL, ATMEL_FW_TYPE_502E, "Belkin F5D6020-V2" },
{ 0, 0, "BT/Voyager 1020 Laptop Adapter", ATMEL_FW_TYPE_502, "BT Voyager 1020" },
{ 0, 0, "IEEE 802.11b/Wireless LAN PC Card", ATMEL_FW_TYPE_502, "Siemens Gigaset PC Card II" },
{ 0, 0, "IEEE 802.11b/Wireless LAN Card S", ATMEL_FW_TYPE_504_2958, "Siemens Gigaset PC Card II" },
{ 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", ATMEL_FW_TYPE_502E, "CNet CNWLC-811ARL" },
{ 0, 0, "Wireless/PC_CARD", ATMEL_FW_TYPE_502D, "Planet WL-3552" },
{ 0, 0, "OEM/11Mbps Wireless LAN PC Card V-3", ATMEL_FW_TYPE_502, "OEM 11Mbps WLAN PCMCIA Card" },

View File

@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/acpi.h>
#include "pci.h"
/* Deal with broken BIOS'es that neglect to enable passive release,
@ -467,9 +468,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC,
* non-x86 architectures (yes Via exists on PPC among other places),
* we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
* interrupts delivered properly.
*
* TODO: When we have device-specific interrupt routers,
* quirk_via_irqpic will go away from quirks.
*/
/*
@ -494,6 +492,29 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi );
static void quirk_via_irqpic(struct pci_dev *dev)
{
u8 irq, new_irq;
#ifdef CONFIG_X86_IO_APIC
if (nr_ioapics && !skip_ioapic_setup)
return;
#endif
#ifdef CONFIG_ACPI
if (acpi_irq_model != ACPI_IRQ_MODEL_PIC)
return;
#endif
new_irq = dev->irq & 0xf;
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
printk(KERN_INFO "PCI: Via PIC IRQ fixup for %s, from %d to %d\n",
pci_name(dev), irq, new_irq);
udelay(15); /* unknown if delay really needed */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irqpic);
/*
* PIIX3 USB: We have to disable USB interrupts that are
* hardwired to PIRQD# and may be shared with an
@ -683,19 +704,6 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
/*
* VIA northbridges care about PCI_INTERRUPT_LINE
*/
int via_interrupt_line_quirk;
static void __devinit quirk_via_bridge(struct pci_dev *pdev)
{
if(pdev->devfn == 0) {
printk(KERN_INFO "PCI: Via IRQ fixup\n");
via_interrupt_line_quirk = 1;
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_bridge );
/*
* Serverworks CSB5 IDE does not fully support native mode

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
obj-$(CONFIG_CLAW) += claw.o cu3088.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o

View File

@ -1,6 +1,6 @@
/*
*
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.4 $)
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
*
* CTC / ESCON network driver - s390 dbf exploit.
*
@ -9,7 +9,7 @@
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.4 $ $Date: 2004/10/15 09:26:58 $
* $Revision: 1.5 $ $Date: 2005/02/27 19:46:44 $
*
* 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
@ -25,9 +25,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _CTCDBUG_H_
#define _CTCDBUG_H_
#include <asm/debug.h>
#include "ctcmain.h"
/**
* Debug Facility stuff
*/
@ -41,7 +43,7 @@
#define CTC_DBF_DATA_LEN 128
#define CTC_DBF_DATA_INDEX 3
#define CTC_DBF_DATA_NR_AREAS 1
#define CTC_DBF_DATA_LEVEL 2
#define CTC_DBF_DATA_LEVEL 3
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
@ -121,3 +123,5 @@ hex_dump(unsigned char *buf, size_t len)
printk("\n");
}
#endif

View File

@ -1,5 +1,5 @@
/*
* $Id: ctcmain.c,v 1.72 2005/03/17 10:51:52 ptiedem Exp $
* $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $
*
* CTC / ESCON network driver
*
@ -37,12 +37,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.72 $
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $
*
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@ -74,288 +73,13 @@
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
#include "ctcdbug.h"
#include "ctcmain.h"
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
MODULE_LICENSE("GPL");
/**
* CCW commands, used in this driver.
*/
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
#define CCW_CMD_SET_EXTENDED 0xc3
#define CCW_CMD_PREPARE 0xe3
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
#define CTC_PROTO_LINUX_TTY 2
#define CTC_PROTO_OS390 3
#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
#define CTC_TIMEOUT_5SEC 5000
#define CTC_INITIAL_BLOCKLEN 2
#define READ 0
#define WRITE 1
#define CTC_ID_SIZE BUS_ID_SIZE+3
struct ctc_profile {
unsigned long maxmulti;
unsigned long maxcqueue;
unsigned long doios_single;
unsigned long doios_multi;
unsigned long txlen;
unsigned long tx_time;
struct timespec send_stamp;
};
/**
* Definition of one channel
*/
struct channel {
/**
* Pointer to next channel in list.
*/
struct channel *next;
char id[CTC_ID_SIZE];
struct ccw_device *cdev;
/**
* Type of this channel.
* CTC/A or Escon for valid channels.
*/
enum channel_types type;
/**
* Misc. flags. See CHANNEL_FLAGS_... below
*/
__u32 flags;
/**
* The protocol of this channel
*/
__u16 protocol;
/**
* I/O and irq related stuff
*/
struct ccw1 *ccw;
struct irb *irb;
/**
* RX/TX buffer size
*/
int max_bufsize;
/**
* Transmit/Receive buffer.
*/
struct sk_buff *trans_skb;
/**
* Universal I/O queue.
*/
struct sk_buff_head io_queue;
/**
* TX queue for collecting skb's during busy.
*/
struct sk_buff_head collect_queue;
/**
* Amount of data in collect_queue.
*/
int collect_len;
/**
* spinlock for collect_queue and collect_len
*/
spinlock_t collect_lock;
/**
* Timer for detecting unresposive
* I/O operations.
*/
fsm_timer timer;
/**
* Retry counter for misc. operations.
*/
int retry;
/**
* The finite state machine of this channel
*/
fsm_instance *fsm;
/**
* The corresponding net_device this channel
* belongs to.
*/
struct net_device *netdev;
struct ctc_profile prof;
unsigned char *trans_skb_data;
__u16 logflags;
};
#define CHANNEL_FLAGS_READ 0
#define CHANNEL_FLAGS_WRITE 1
#define CHANNEL_FLAGS_INUSE 2
#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_FAILED 8
#define CHANNEL_FLAGS_WAITIRQ 16
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
#define LOG_FLAG_ILLEGALPKT 1
#define LOG_FLAG_ILLEGALSIZE 2
#define LOG_FLAG_OVERRUN 4
#define LOG_FLAG_NOMEM 8
#define CTC_LOGLEVEL_INFO 1
#define CTC_LOGLEVEL_NOTICE 2
#define CTC_LOGLEVEL_WARN 4
#define CTC_LOGLEVEL_EMERG 8
#define CTC_LOGLEVEL_ERR 16
#define CTC_LOGLEVEL_DEBUG 32
#define CTC_LOGLEVEL_CRIT 64
#define CTC_LOGLEVEL_DEFAULT \
(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
static int loglevel = CTC_LOGLEVEL_DEFAULT;
#define ctc_pr_debug(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
#define ctc_pr_info(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
#define ctc_pr_notice(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
#define ctc_pr_warn(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
#define ctc_pr_emerg(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
#define ctc_pr_err(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
#define ctc_pr_crit(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
/**
* Linked list of all detected channels.
*/
static struct channel *channels = NULL;
struct ctc_priv {
struct net_device_stats stats;
unsigned long tbusy;
/**
* The finite state machine of this interface.
*/
fsm_instance *fsm;
/**
* The protocol of this device
*/
__u16 protocol;
/**
* Timer for restarting after I/O Errors
*/
fsm_timer restart_timer;
int buffer_size;
struct channel *channel[2];
};
/**
* Definition of our link level header.
*/
struct ll_header {
__u16 length;
__u16 type;
__u16 unused;
};
#define LL_HEADER_LENGTH (sizeof(struct ll_header))
/**
* Compatibility macros for busy handling
* of network devices.
*/
static __inline__ void
ctc_clear_busy(struct net_device * dev)
{
clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
netif_wake_queue(dev);
}
static __inline__ int
ctc_test_and_set_busy(struct net_device * dev)
{
if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
netif_stop_queue(dev);
return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
}
/**
* Print Banner.
*/
static void
print_banner(void)
{
static int printed = 0;
char vbuf[] = "$Revision: 1.72 $";
char *version = vbuf;
if (printed)
return;
if ((version = strchr(version, ':'))) {
char *p = strchr(version + 1, '$');
if (p)
*p = '\0';
} else
version = " ??? ";
printk(KERN_INFO "CTC driver Version%s"
#ifdef DEBUG
" (DEBUG-VERSION, " __DATE__ __TIME__ ")"
#endif
" initialized\n", version);
printed = 1;
}
/**
* Return type of a detected device.
*/
static enum channel_types
get_channel_type(struct ccw_device_id *id)
{
enum channel_types type = (enum channel_types) id->driver_info;
if (type == channel_type_ficon)
type = channel_type_escon;
return type;
}
/**
* States of the interface statemachine.
*/
@ -371,7 +95,7 @@ enum dev_states {
/**
* MUST be always the last element!!
*/
NR_DEV_STATES
CTC_NR_DEV_STATES
};
static const char *dev_state_names[] = {
@ -399,7 +123,7 @@ enum dev_events {
/**
* MUST be always the last element!!
*/
NR_DEV_EVENTS
CTC_NR_DEV_EVENTS
};
static const char *dev_event_names[] = {
@ -476,40 +200,6 @@ enum ch_events {
NR_CH_EVENTS,
};
static const char *ch_event_names[] = {
"ccw_device success",
"ccw_device busy",
"ccw_device enodev",
"ccw_device ioerr",
"ccw_device unknown",
"Status ATTN & BUSY",
"Status ATTN",
"Status BUSY",
"Unit check remote reset",
"Unit check remote system reset",
"Unit check TX timeout",
"Unit check TX parity",
"Unit check Hardware failure",
"Unit check RX parity",
"Unit check ZERO",
"Unit check Unknown",
"SubChannel check Unknown",
"Machine check failure",
"Machine check operational",
"IRQ normal",
"IRQ final",
"Timer",
"Start",
"Stop",
};
/**
* States of the channel statemachine.
*/
@ -545,6 +235,87 @@ enum ch_states {
NR_CH_STATES,
};
static int loglevel = CTC_LOGLEVEL_DEFAULT;
/**
* Linked list of all detected channels.
*/
static struct channel *channels = NULL;
/**
* Print Banner.
*/
static void
print_banner(void)
{
static int printed = 0;
char vbuf[] = "$Revision: 1.74 $";
char *version = vbuf;
if (printed)
return;
if ((version = strchr(version, ':'))) {
char *p = strchr(version + 1, '$');
if (p)
*p = '\0';
} else
version = " ??? ";
printk(KERN_INFO "CTC driver Version%s"
#ifdef DEBUG
" (DEBUG-VERSION, " __DATE__ __TIME__ ")"
#endif
" initialized\n", version);
printed = 1;
}
/**
* Return type of a detected device.
*/
static enum channel_types
get_channel_type(struct ccw_device_id *id)
{
enum channel_types type = (enum channel_types) id->driver_info;
if (type == channel_type_ficon)
type = channel_type_escon;
return type;
}
static const char *ch_event_names[] = {
"ccw_device success",
"ccw_device busy",
"ccw_device enodev",
"ccw_device ioerr",
"ccw_device unknown",
"Status ATTN & BUSY",
"Status ATTN",
"Status BUSY",
"Unit check remote reset",
"Unit check remote system reset",
"Unit check TX timeout",
"Unit check TX parity",
"Unit check Hardware failure",
"Unit check RX parity",
"Unit check ZERO",
"Unit check Unknown",
"SubChannel check Unknown",
"Machine check failure",
"Machine check operational",
"IRQ normal",
"IRQ final",
"Timer",
"Start",
"Stop",
};
static const char *ch_state_names[] = {
"Idle",
"Stopped",
@ -1934,7 +1705,6 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
ch->cdev = cdev;
snprintf(ch->id, CTC_ID_SIZE, "ch-%s", cdev->dev.bus_id);
ch->type = type;
loglevel = CTC_LOGLEVEL_DEFAULT;
ch->fsm = init_fsm(ch->id, ch_state_names,
ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
ch_fsm, CH_FSM_LEN, GFP_KERNEL);
@ -2697,6 +2467,7 @@ ctc_stats(struct net_device * dev)
/*
* sysfs attributes
*/
static ssize_t
buffer_show(struct device *dev, char *buf)
{
@ -2715,57 +2486,61 @@ buffer_write(struct device *dev, const char *buf, size_t count)
struct ctc_priv *priv;
struct net_device *ndev;
int bs1;
char buffer[16];
DBF_TEXT(trace, 3, __FUNCTION__);
DBF_TEXT(trace, 3, buf);
priv = dev->driver_data;
if (!priv)
if (!priv) {
DBF_TEXT(trace, 3, "bfnopriv");
return -ENODEV;
ndev = priv->channel[READ]->netdev;
if (!ndev)
return -ENODEV;
sscanf(buf, "%u", &bs1);
}
sscanf(buf, "%u", &bs1);
if (bs1 > CTC_BUFSIZE_LIMIT)
return -EINVAL;
goto einval;
if (bs1 < (576 + LL_HEADER_LENGTH + 2))
goto einval;
priv->buffer_size = bs1; // just to overwrite the default
ndev = priv->channel[READ]->netdev;
if (!ndev) {
DBF_TEXT(trace, 3, "bfnondev");
return -ENODEV;
}
if ((ndev->flags & IFF_RUNNING) &&
(bs1 < (ndev->mtu + LL_HEADER_LENGTH + 2)))
return -EINVAL;
if (bs1 < (576 + LL_HEADER_LENGTH + 2))
return -EINVAL;
goto einval;
priv->buffer_size = bs1;
priv->channel[READ]->max_bufsize =
priv->channel[WRITE]->max_bufsize = bs1;
priv->channel[READ]->max_bufsize = bs1;
priv->channel[WRITE]->max_bufsize = bs1;
if (!(ndev->flags & IFF_RUNNING))
ndev->mtu = bs1 - LL_HEADER_LENGTH - 2;
priv->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
priv->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
sprintf(buffer, "%d",priv->buffer_size);
DBF_TEXT(trace, 3, buffer);
return count;
einval:
DBF_TEXT(trace, 3, "buff_err");
return -EINVAL;
}
static ssize_t
loglevel_show(struct device *dev, char *buf)
{
struct ctc_priv *priv;
priv = dev->driver_data;
if (!priv)
return -ENODEV;
return sprintf(buf, "%d\n", loglevel);
}
static ssize_t
loglevel_write(struct device *dev, const char *buf, size_t count)
{
struct ctc_priv *priv;
int ll1;
DBF_TEXT(trace, 5, __FUNCTION__);
priv = dev->driver_data;
if (!priv)
return -ENODEV;
sscanf(buf, "%i", &ll1);
if ((ll1 > CTC_LOGLEVEL_MAX) || (ll1 < 0))
@ -2835,27 +2610,6 @@ stats_write(struct device *dev, const char *buf, size_t count)
return count;
}
static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
static int
ctc_add_attributes(struct device *dev)
{
// device_create_file(dev, &dev_attr_buffer);
device_create_file(dev, &dev_attr_loglevel);
device_create_file(dev, &dev_attr_stats);
return 0;
}
static void
ctc_remove_attributes(struct device *dev)
{
device_remove_file(dev, &dev_attr_stats);
device_remove_file(dev, &dev_attr_loglevel);
// device_remove_file(dev, &dev_attr_buffer);
}
static void
ctc_netdev_unregister(struct net_device * dev)
@ -2899,52 +2653,6 @@ ctc_free_netdevice(struct net_device * dev, int free_dev)
#endif
}
/**
* Initialize everything of the net device except the name and the
* channel structs.
*/
static struct net_device *
ctc_init_netdevice(struct net_device * dev, int alloc_device,
struct ctc_priv *privptr)
{
if (!privptr)
return NULL;
DBF_TEXT(setup, 3, __FUNCTION__);
if (alloc_device) {
dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof (struct net_device));
}
dev->priv = privptr;
privptr->fsm = init_fsm("ctcdev", dev_state_names,
dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
if (privptr->fsm == NULL) {
if (alloc_device)
kfree(dev);
return NULL;
}
fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
fsm_settimer(privptr->fsm, &privptr->restart_timer);
if (dev->mtu == 0)
dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
dev->hard_start_xmit = ctc_tx;
dev->open = ctc_open;
dev->stop = ctc_close;
dev->get_stats = ctc_stats;
dev->change_mtu = ctc_change_mtu;
dev->hard_header_len = LL_HEADER_LENGTH + 2;
dev->addr_len = 0;
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 100;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
SET_MODULE_OWNER(dev);
return dev;
}
static ssize_t
ctc_proto_show(struct device *dev, char *buf)
{
@ -2977,7 +2685,6 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count)
return count;
}
static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
static ssize_t
ctc_type_show(struct device *dev, char *buf)
@ -2991,8 +2698,13 @@ ctc_type_show(struct device *dev, char *buf)
return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);
}
static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
static DEVICE_ATTR(protocol, 0644, ctc_proto_show, ctc_proto_store);
static DEVICE_ATTR(type, 0444, ctc_type_show, NULL);
static DEVICE_ATTR(loglevel, 0644, loglevel_show, loglevel_write);
static DEVICE_ATTR(stats, 0644, stats_show, stats_write);
static struct attribute *ctc_attr[] = {
&dev_attr_protocol.attr,
&dev_attr_type.attr,
@ -3004,6 +2716,21 @@ static struct attribute_group ctc_attr_group = {
.attrs = ctc_attr,
};
static int
ctc_add_attributes(struct device *dev)
{
device_create_file(dev, &dev_attr_loglevel);
device_create_file(dev, &dev_attr_stats);
return 0;
}
static void
ctc_remove_attributes(struct device *dev)
{
device_remove_file(dev, &dev_attr_stats);
device_remove_file(dev, &dev_attr_loglevel);
}
static int
ctc_add_files(struct device *dev)
{
@ -3028,15 +2755,15 @@ ctc_remove_files(struct device *dev)
*
* @returns 0 on success, !0 on failure.
*/
static int
ctc_probe_device(struct ccwgroup_device *cgdev)
{
struct ctc_priv *priv;
int rc;
char buffer[16];
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(trace, 3, __FUNCTION__);
DBF_TEXT(setup, 3, __FUNCTION__);
if (!get_device(&cgdev->dev))
return -ENODEV;
@ -3060,9 +2787,69 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
cgdev->cdev[1]->handler = ctc_irq_handler;
cgdev->dev.driver_data = priv;
sprintf(buffer, "%p", priv);
DBF_TEXT(data, 3, buffer);
sprintf(buffer, "%u", (unsigned int)sizeof(struct ctc_priv));
DBF_TEXT(data, 3, buffer);
sprintf(buffer, "%p", &channels);
DBF_TEXT(data, 3, buffer);
sprintf(buffer, "%u", (unsigned int)sizeof(struct channel));
DBF_TEXT(data, 3, buffer);
return 0;
}
/**
* Initialize everything of the net device except the name and the
* channel structs.
*/
static struct net_device *
ctc_init_netdevice(struct net_device * dev, int alloc_device,
struct ctc_priv *privptr)
{
if (!privptr)
return NULL;
DBF_TEXT(setup, 3, __FUNCTION__);
if (alloc_device) {
dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof (struct net_device));
}
dev->priv = privptr;
privptr->fsm = init_fsm("ctcdev", dev_state_names,
dev_event_names, CTC_NR_DEV_STATES, CTC_NR_DEV_EVENTS,
dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
if (privptr->fsm == NULL) {
if (alloc_device)
kfree(dev);
return NULL;
}
fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
fsm_settimer(privptr->fsm, &privptr->restart_timer);
if (dev->mtu == 0)
dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
dev->hard_start_xmit = ctc_tx;
dev->open = ctc_open;
dev->stop = ctc_close;
dev->get_stats = ctc_stats;
dev->change_mtu = ctc_change_mtu;
dev->hard_header_len = LL_HEADER_LENGTH + 2;
dev->addr_len = 0;
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 100;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
SET_MODULE_OWNER(dev);
return dev;
}
/**
*
* Setup an interface.
@ -3081,6 +2868,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
struct ctc_priv *privptr;
struct net_device *dev;
int ret;
char buffer[16];
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(setup, 3, __FUNCTION__);
@ -3089,6 +2877,9 @@ ctc_new_device(struct ccwgroup_device *cgdev)
if (!privptr)
return -ENODEV;
sprintf(buffer, "%d", privptr->buffer_size);
DBF_TEXT(setup, 3, buffer);
type = get_channel_type(&cgdev->cdev[0]->id);
snprintf(read_id, CTC_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id);
@ -3177,9 +2968,10 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
struct net_device *ndev;
DBF_TEXT(trace, 3, __FUNCTION__);
DBF_TEXT(setup, 3, __FUNCTION__);
pr_debug("%s() called\n", __FUNCTION__);
priv = cgdev->dev.driver_data;
ndev = NULL;
if (!priv)
@ -3215,7 +3007,6 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
channel_remove(priv->channel[READ]);
if (priv->channel[WRITE])
channel_remove(priv->channel[WRITE]);
priv->channel[READ] = priv->channel[WRITE] = NULL;
return 0;
@ -3228,7 +3019,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(trace, 3, __FUNCTION__);
DBF_TEXT(setup, 3, __FUNCTION__);
priv = cgdev->dev.driver_data;
if (!priv)
@ -3265,6 +3056,7 @@ static struct ccwgroup_driver ctc_group_driver = {
static void __exit
ctc_exit(void)
{
DBF_TEXT(setup, 3, __FUNCTION__);
unregister_cu3088_discipline(&ctc_group_driver);
ctc_tty_cleanup();
ctc_unregister_dbf_views();
@ -3282,6 +3074,10 @@ ctc_init(void)
{
int ret = 0;
loglevel = CTC_LOGLEVEL_DEFAULT;
DBF_TEXT(setup, 3, __FUNCTION__);
print_banner();
ret = ctc_register_dbf_views();

276
drivers/s390/net/ctcmain.h Normal file
View File

@ -0,0 +1,276 @@
/*
* $Id: ctcmain.h,v 1.4 2005/03/24 09:04:17 mschwide Exp $
*
* CTC / ESCON network driver
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
Peter Tiedemann (ptiedem@de.ibm.com)
*
*
* Documentation used:
* - Principles of Operation (IBM doc#: SA22-7201-06)
* - Common IO/-Device Commands and Self Description (IBM doc#: SA22-7204-02)
* - Common IO/-Device Commands and Self Description (IBM doc#: SN22-5535)
* - ESCON Channel-to-Channel Adapter (IBM doc#: SA22-7203-00)
* - ESCON I/O Interface (IBM doc#: SA22-7202-029
*
* 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.4 $
*
*/
#ifndef _CTCMAIN_H_
#define _CTCMAIN_H_
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
/**
* CCW commands, used in this driver.
*/
#define CCW_CMD_WRITE 0x01
#define CCW_CMD_READ 0x02
#define CCW_CMD_SET_EXTENDED 0xc3
#define CCW_CMD_PREPARE 0xe3
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
#define CTC_PROTO_LINUX_TTY 2
#define CTC_PROTO_OS390 3
#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
#define CTC_TIMEOUT_5SEC 5000
#define CTC_INITIAL_BLOCKLEN 2
#define READ 0
#define WRITE 1
#define CTC_ID_SIZE BUS_ID_SIZE+3
struct ctc_profile {
unsigned long maxmulti;
unsigned long maxcqueue;
unsigned long doios_single;
unsigned long doios_multi;
unsigned long txlen;
unsigned long tx_time;
struct timespec send_stamp;
};
/**
* Definition of one channel
*/
struct channel {
/**
* Pointer to next channel in list.
*/
struct channel *next;
char id[CTC_ID_SIZE];
struct ccw_device *cdev;
/**
* Type of this channel.
* CTC/A or Escon for valid channels.
*/
enum channel_types type;
/**
* Misc. flags. See CHANNEL_FLAGS_... below
*/
__u32 flags;
/**
* The protocol of this channel
*/
__u16 protocol;
/**
* I/O and irq related stuff
*/
struct ccw1 *ccw;
struct irb *irb;
/**
* RX/TX buffer size
*/
int max_bufsize;
/**
* Transmit/Receive buffer.
*/
struct sk_buff *trans_skb;
/**
* Universal I/O queue.
*/
struct sk_buff_head io_queue;
/**
* TX queue for collecting skb's during busy.
*/
struct sk_buff_head collect_queue;
/**
* Amount of data in collect_queue.
*/
int collect_len;
/**
* spinlock for collect_queue and collect_len
*/
spinlock_t collect_lock;
/**
* Timer for detecting unresposive
* I/O operations.
*/
fsm_timer timer;
/**
* Retry counter for misc. operations.
*/
int retry;
/**
* The finite state machine of this channel
*/
fsm_instance *fsm;
/**
* The corresponding net_device this channel
* belongs to.
*/
struct net_device *netdev;
struct ctc_profile prof;
unsigned char *trans_skb_data;
__u16 logflags;
};
#define CHANNEL_FLAGS_READ 0
#define CHANNEL_FLAGS_WRITE 1
#define CHANNEL_FLAGS_INUSE 2
#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_FAILED 8
#define CHANNEL_FLAGS_WAITIRQ 16
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
#define LOG_FLAG_ILLEGALPKT 1
#define LOG_FLAG_ILLEGALSIZE 2
#define LOG_FLAG_OVERRUN 4
#define LOG_FLAG_NOMEM 8
#define CTC_LOGLEVEL_INFO 1
#define CTC_LOGLEVEL_NOTICE 2
#define CTC_LOGLEVEL_WARN 4
#define CTC_LOGLEVEL_EMERG 8
#define CTC_LOGLEVEL_ERR 16
#define CTC_LOGLEVEL_DEBUG 32
#define CTC_LOGLEVEL_CRIT 64
#define CTC_LOGLEVEL_DEFAULT \
(CTC_LOGLEVEL_INFO | CTC_LOGLEVEL_NOTICE | CTC_LOGLEVEL_WARN | CTC_LOGLEVEL_CRIT)
#define CTC_LOGLEVEL_MAX ((CTC_LOGLEVEL_CRIT<<1)-1)
#define ctc_pr_debug(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG fmt,##arg); } while (0)
#define ctc_pr_info(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_INFO) printk(KERN_INFO fmt,##arg); } while (0)
#define ctc_pr_notice(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_NOTICE) printk(KERN_NOTICE fmt,##arg); } while (0)
#define ctc_pr_warn(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING fmt,##arg); } while (0)
#define ctc_pr_emerg(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_EMERG) printk(KERN_EMERG fmt,##arg); } while (0)
#define ctc_pr_err(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_ERR) printk(KERN_ERR fmt,##arg); } while (0)
#define ctc_pr_crit(fmt, arg...) \
do { if (loglevel & CTC_LOGLEVEL_CRIT) printk(KERN_CRIT fmt,##arg); } while (0)
struct ctc_priv {
struct net_device_stats stats;
unsigned long tbusy;
/**
* The finite state machine of this interface.
*/
fsm_instance *fsm;
/**
* The protocol of this device
*/
__u16 protocol;
/**
* Timer for restarting after I/O Errors
*/
fsm_timer restart_timer;
int buffer_size;
struct channel *channel[2];
};
/**
* Definition of our link level header.
*/
struct ll_header {
__u16 length;
__u16 type;
__u16 unused;
};
#define LL_HEADER_LENGTH (sizeof(struct ll_header))
/**
* Compatibility macros for busy handling
* of network devices.
*/
static __inline__ void
ctc_clear_busy(struct net_device * dev)
{
clear_bit(0, &(((struct ctc_priv *) dev->priv)->tbusy));
if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
netif_wake_queue(dev);
}
static __inline__ int
ctc_test_and_set_busy(struct net_device * dev)
{
if (((struct ctc_priv *)dev->priv)->protocol != CTC_PROTO_LINUX_TTY)
netif_stop_queue(dev);
return test_and_set_bit(0, &((struct ctc_priv *) dev->priv)->tbusy);
}
#endif

View File

@ -1,5 +1,5 @@
/*
* $Id: ctctty.c,v 1.26 2004/08/04 11:06:55 mschwide Exp $
* $Id: ctctty.c,v 1.29 2005/04/05 08:50:44 mschwide Exp $
*
* CTC / ESCON network driver, tty interface.
*
@ -1056,8 +1056,7 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
info->tty = 0;
tty->closing = 0;
if (info->blocked_open) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/2);
msleep_interruptible(500);
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);

View File

@ -1,5 +1,5 @@
/*
* $Id: cu3088.c,v 1.34 2004/06/15 13:16:27 pavlic Exp $
* $Id: cu3088.c,v 1.35 2005/03/30 19:28:52 richtera Exp $
*
* CTC / LCS ccw_device driver
*
@ -39,6 +39,7 @@ const char *cu3088_type[] = {
"FICON channel",
"P390 LCS card",
"OSA LCS card",
"CLAW channel device",
"unknown channel type",
"unsupported channel type",
};
@ -51,6 +52,7 @@ static struct ccw_device_id cu3088_ids[] = {
{ CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon },
{ CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 },
{ CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 },
{ CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw },
{ /* end of list */ }
};

View File

@ -23,6 +23,9 @@ enum channel_types {
/* Device is a OSA2 card */
channel_type_osa2,
/* Device is a CLAW channel device */
channel_type_claw,
/* Device is a channel, but we don't know
* anything about it */
channel_type_unknown,

View File

@ -1,5 +1,5 @@
/*
* $Id: iucv.c,v 1.43 2005/02/09 14:47:43 braunu Exp $
* $Id: iucv.c,v 1.45 2005/04/26 22:59:06 braunu Exp $
*
* IUCV network driver
*
@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.43 $
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.45 $
*
*/
@ -355,7 +355,7 @@ do { \
static void
iucv_banner(void)
{
char vbuf[] = "$Revision: 1.43 $";
char vbuf[] = "$Revision: 1.45 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
@ -2553,12 +2553,12 @@ EXPORT_SYMBOL (iucv_resume);
#endif
EXPORT_SYMBOL (iucv_reply_prmmsg);
EXPORT_SYMBOL (iucv_send);
#if 0
EXPORT_SYMBOL (iucv_send2way);
EXPORT_SYMBOL (iucv_send2way_array);
EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send2way_prmmsg);
EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
#if 0
EXPORT_SYMBOL (iucv_send_array);
EXPORT_SYMBOL (iucv_send_prmmsg);
EXPORT_SYMBOL (iucv_setmask);
#endif

View File

@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* $Revision: 1.96 $ $Date: 2004/11/11 13:42:33 $
* $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $
*
* 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
@ -59,7 +59,7 @@
/**
* initialization string for output
*/
#define VERSION_LCS_C "$Revision: 1.96 $"
#define VERSION_LCS_C "$Revision: 1.98 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255];
@ -1098,14 +1098,6 @@ lcs_check_multicast_support(struct lcs_card *card)
PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");
return -EOPNOTSUPP;
}
/* Print out supported assists: IPv6 */
PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
(card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
"with" : "without");
/* Print out supported assist: Multicast */
PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
(card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
"with" : "without");
if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)
return 0;
return -EOPNOTSUPP;
@ -1160,7 +1152,7 @@ list_modified:
}
}
/* re-insert all entries from the failed_list into ipm_list */
list_for_each_entry(ipm, &failed_list, list) {
list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
list_del_init(&ipm->list);
list_add_tail(&ipm->list, &card->ipm_list);
}
@ -2198,30 +2190,39 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
if (!dev)
goto out;
card->dev = dev;
netdev_out:
card->dev->priv = card;
card->dev->open = lcs_open_device;
card->dev->stop = lcs_stop_device;
card->dev->hard_start_xmit = lcs_start_xmit;
card->dev->get_stats = lcs_getstats;
SET_MODULE_OWNER(dev);
if (lcs_register_netdev(ccwgdev) != 0)
goto out;
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (!lcs_check_multicast_support(card))
card->dev->set_multicast_list = lcs_set_multicast_list;
#endif
netif_stop_queue(card->dev);
netdev_out:
lcs_set_allowed_threads(card,0xffffffff);
if (recover_state == DEV_STATE_RECOVER) {
lcs_set_multicast_list(card->dev);
card->dev->flags |= IFF_UP;
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
} else
} else {
lcs_stopcard(card);
}
if (lcs_register_netdev(ccwgdev) != 0)
goto out;
/* Print out supported assists: IPv6 */
PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,
(card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?
"with" : "without");
/* Print out supported assist: Multicast */
PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,
(card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?
"with" : "without");
return 0;
out:

View File

@ -24,7 +24,7 @@
#include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.135 $"
#define VERSION_QETH_H "$Revision: 1.139 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
@ -288,7 +288,8 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_TX_TIMEOUT 100 * HZ
#define QETH_HEADER_SIZE 32
#define MAX_PORTNO 15
#define QETH_FAKE_LL_LEN ETH_HLEN
#define QETH_FAKE_LL_LEN_ETH ETH_HLEN
#define QETH_FAKE_LL_LEN_TR (sizeof(struct trh_hdr)-TR_MAXRIFLEN+sizeof(struct trllc))
#define QETH_FAKE_LL_V6_ADDR_POS 24
/*IPv6 address autoconfiguration stuff*/
@ -369,6 +370,25 @@ struct qeth_hdr {
} hdr;
} __attribute__ ((packed));
/*TCP Segmentation Offload header*/
struct qeth_hdr_ext_tso {
__u16 hdr_tot_len;
__u8 imb_hdr_no;
__u8 reserved;
__u8 hdr_type;
__u8 hdr_version;
__u16 hdr_len;
__u32 payload_len;
__u16 mss;
__u16 dg_hdr_len;
__u8 padding[16];
} __attribute__ ((packed));
struct qeth_hdr_tso {
struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/
struct qeth_hdr_ext_tso ext;
} __attribute__ ((packed));
/* flags for qeth_hdr.flags */
#define QETH_HDR_PASSTHRU 0x10
@ -866,6 +886,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
return hdr;
}
inline static int
qeth_get_hlen(__u8 link_type)
{
@ -873,19 +894,19 @@ qeth_get_hlen(__u8 link_type)
switch (link_type) {
case QETH_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_LANE_TR:
return sizeof(struct qeth_hdr) + TR_HLEN;
return sizeof(struct qeth_hdr_tso) + TR_HLEN;
default:
#ifdef CONFIG_QETH_VLAN
return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
return sizeof(struct qeth_hdr_tso) + VLAN_ETH_HLEN;
#else
return sizeof(struct qeth_hdr) + ETH_HLEN;
return sizeof(struct qeth_hdr_tso) + ETH_HLEN;
#endif
}
#else /* CONFIG_QETH_IPV6 */
#ifdef CONFIG_QETH_VLAN
return sizeof(struct qeth_hdr) + VLAN_HLEN;
return sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
#else
return sizeof(struct qeth_hdr);
return sizeof(struct qeth_hdr_tso);
#endif
#endif /* CONFIG_QETH_IPV6 */
}

View File

@ -1,6 +1,6 @@
/*
*
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.11 $)
* linux/drivers/s390/net/qeth_eddp.c ($Revision: 1.13 $)
*
* Enhanced Device Driver Packing (EDDP) support for the qeth driver.
*
@ -8,7 +8,7 @@
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.11 $ $Date: 2005/03/24 09:04:18 $
* $Revision: 1.13 $ $Date: 2005/05/04 20:19:18 $
*
*/
#include <linux/config.h>
@ -85,7 +85,7 @@ void
qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
{
struct qeth_eddp_context_reference *ref;
QETH_DBF_TEXT(trace, 6, "eddprctx");
while (!list_empty(&buf->ctx_list)){
ref = list_entry(buf->ctx_list.next,
@ -139,7 +139,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
"buffer!\n");
goto out;
}
}
}
/* check if the whole next skb fits into current buffer */
if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) -
buf->next_element_to_fill)
@ -152,7 +152,7 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
* and increment ctx's refcnt */
must_refcnt = 1;
continue;
}
}
if (must_refcnt){
must_refcnt = 0;
if (qeth_eddp_buf_ref_context(buf, ctx)){
@ -202,40 +202,29 @@ out:
return flush_cnt;
}
static inline int
qeth_get_skb_data_len(struct sk_buff *skb)
{
int len = skb->len;
int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i)
len -= skb_shinfo(skb)->frags[i].size;
return len;
}
static inline void
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp)
struct qeth_eddp_data *eddp, int data_len)
{
u8 *page;
int page_remainder;
int page_offset;
int hdr_len;
int pkt_len;
struct qeth_eddp_element *element;
QETH_DBF_TEXT(trace, 5, "eddpcrsh");
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
page_offset = ctx->offset % PAGE_SIZE;
element = &ctx->elements[ctx->num_elements];
hdr_len = eddp->nhl + eddp->thl;
pkt_len = eddp->nhl + eddp->thl + data_len;
/* FIXME: layer2 and VLAN !!! */
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
hdr_len += ETH_HLEN;
pkt_len += ETH_HLEN;
if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))
hdr_len += VLAN_HLEN;
/* does complete header fit in current page ? */
pkt_len += VLAN_HLEN;
/* does complete packet fit in current page ? */
page_remainder = PAGE_SIZE - page_offset;
if (page_remainder < (sizeof(struct qeth_hdr) + hdr_len)){
if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)){
/* no -> go to start of next page */
ctx->offset += page_remainder;
page = ctx->pages[ctx->offset >> PAGE_SHIFT];
@ -281,7 +270,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
int left_in_frag;
int copy_len;
u8 *src;
QETH_DBF_TEXT(trace, 5, "eddpcdtc");
if (skb_shinfo(eddp->skb)->nr_frags == 0) {
memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
@ -292,7 +281,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
while (len > 0) {
if (eddp->frag < 0) {
/* we're in skb->data */
left_in_frag = qeth_get_skb_data_len(eddp->skb)
left_in_frag = (eddp->skb->len - eddp->skb->data_len)
- eddp->skb_offset;
src = eddp->skb->data + eddp->skb_offset;
} else {
@ -424,7 +413,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct tcphdr *tcph;
int data_len;
u32 hcsum;
QETH_DBF_TEXT(trace, 5, "eddpftcp");
eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;
tcph = eddp->skb->h.th;
@ -464,7 +453,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
else
hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);
/* fill the next segment into the context */
qeth_eddp_create_segment_hdrs(ctx, eddp);
qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);
qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);
if (eddp->skb_offset >= eddp->skb->len)
break;
@ -474,13 +463,13 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
eddp->th.tcp.h.seq += data_len;
}
}
static inline int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
struct qeth_eddp_data *eddp = NULL;
QETH_DBF_TEXT(trace, 5, "eddpficx");
/* create our segmentation headers and copy original headers */
if (skb->protocol == ETH_P_IP)
@ -520,7 +509,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
int skbs_per_page;
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
@ -600,7 +589,7 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
struct qeth_eddp_context *ctx = NULL;
QETH_DBF_TEXT(trace, 5, "creddpct");
if (skb->protocol == ETH_P_IP)
ctx = qeth_eddp_create_context_generic(card, skb,

View File

@ -1,6 +1,6 @@
/*
*
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.206 $)
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.206 $ $Date: 2005/03/24 09:04:18 $
* $Revision: 1.214 $ $Date: 2005/05/04 20:19:18 $
*
* 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
@ -80,7 +80,7 @@ qeth_eyecatcher(void)
#include "qeth_eddp.h"
#include "qeth_tso.h"
#define VERSION_QETH_C "$Revision: 1.206 $"
#define VERSION_QETH_C "$Revision: 1.214 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
@ -158,6 +158,9 @@ qeth_irq_tasklet(unsigned long);
static int
qeth_set_online(struct ccwgroup_device *);
static int
__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode);
static struct qeth_ipaddr *
qeth_get_addr_buffer(enum qeth_prot_versions);
@ -510,10 +513,10 @@ qeth_irq_tasklet(unsigned long data)
wake_up(&card->wait_q);
}
static int qeth_stop_card(struct qeth_card *);
static int qeth_stop_card(struct qeth_card *, int);
static int
qeth_set_offline(struct ccwgroup_device *cgdev)
__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode)
{
struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
int rc = 0;
@ -523,7 +526,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
recover_flag = card->state;
if (qeth_stop_card(card) == -ERESTARTSYS){
if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){
PRINT_WARN("Stopping card %s interrupted by user!\n",
CARD_BUS_ID(card));
return -ERESTARTSYS;
@ -539,6 +542,12 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
return 0;
}
static int
qeth_set_offline(struct ccwgroup_device *cgdev)
{
return __qeth_set_offline(cgdev, 0);
}
static int
qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
@ -953,8 +962,8 @@ qeth_recover(void *ptr)
PRINT_WARN("Recovery of device %s started ...\n",
CARD_BUS_ID(card));
card->use_hard_stop = 1;
qeth_set_offline(card->gdev);
rc = qeth_set_online(card->gdev);
__qeth_set_offline(card->gdev,1);
rc = __qeth_set_online(card->gdev,1);
if (!rc)
PRINT_INFO("Device %s successfully recovered!\n",
CARD_BUS_ID(card));
@ -2152,9 +2161,15 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
if (!skb_len)
return NULL;
if (card->options.fake_ll){
if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN)))
goto no_mem;
skb_pull(skb, QETH_FAKE_LL_LEN);
if(card->dev->type == ARPHRD_IEEE802_TR){
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR)))
goto no_mem;
skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
} else {
if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH)))
goto no_mem;
skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
}
} else if (!(skb = qeth_get_skb(skb_len)))
goto no_mem;
data_ptr = element->addr + offset;
@ -2229,14 +2244,68 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
}
static inline void
qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
struct trh_hdr *fake_hdr;
struct trllc *fake_llc;
struct iphdr *ip_hdr;
QETH_DBF_TEXT(trace,5,"skbfktr");
skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
/* this is a fake ethernet header */
fake_hdr = (struct trh_hdr *) skb->mac.raw;
/* the destination MAC address */
switch (skb->pkt_type){
case PACKET_MULTICAST:
switch (skb->protocol){
#ifdef CONFIG_QETH_IPV6
case __constant_htons(ETH_P_IPV6):
ndisc_mc_map((struct in6_addr *)
skb->data + QETH_FAKE_LL_V6_ADDR_POS,
fake_hdr->daddr, card->dev, 0);
break;
#endif /* CONFIG_QETH_IPV6 */
case __constant_htons(ETH_P_IP):
ip_hdr = (struct iphdr *)skb->data;
ip_tr_mc_map(ip_hdr->daddr, fake_hdr->daddr);
break;
default:
memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
}
break;
case PACKET_BROADCAST:
memset(fake_hdr->daddr, 0xff, TR_ALEN);
break;
default:
memcpy(fake_hdr->daddr, card->dev->dev_addr, TR_ALEN);
}
/* the source MAC address */
if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
memcpy(fake_hdr->saddr, &hdr->hdr.l3.dest_addr[2], TR_ALEN);
else
memset(fake_hdr->saddr, 0, TR_ALEN);
fake_hdr->rcf=0;
fake_llc = (struct trllc*)&(fake_hdr->rcf);
fake_llc->dsap = EXTENDED_SAP;
fake_llc->ssap = EXTENDED_SAP;
fake_llc->llc = UI_CMD;
fake_llc->protid[0] = 0;
fake_llc->protid[1] = 0;
fake_llc->protid[2] = 0;
fake_llc->ethertype = ETH_P_IP;
}
static inline void
qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
struct ethhdr *fake_hdr;
struct iphdr *ip_hdr;
QETH_DBF_TEXT(trace,5,"skbfake");
skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
QETH_DBF_TEXT(trace,5,"skbfketh");
skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
/* this is a fake ethernet header */
fake_hdr = (struct ethhdr *) skb->mac.raw;
@ -2253,10 +2322,7 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
#endif /* CONFIG_QETH_IPV6 */
case __constant_htons(ETH_P_IP):
ip_hdr = (struct iphdr *)skb->data;
if (card->dev->type == ARPHRD_IEEE802_TR)
ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
else
ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
break;
default:
memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
@ -2277,6 +2343,16 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
fake_hdr->h_proto = skb->protocol;
}
static inline void
qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
if (card->dev->type == ARPHRD_IEEE802_TR)
qeth_rebuild_skb_fake_ll_tr(card, skb, hdr);
else
qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
}
static inline void
qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
@ -3440,16 +3516,25 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len)
{
struct ethhdr *hdr;
if(dev->type == ARPHRD_IEEE802_TR){
struct trh_hdr *hdr;
hdr = (struct trh_hdr *)skb_push(skb, QETH_FAKE_LL_LEN_TR);
memcpy(hdr->saddr, dev->dev_addr, TR_ALEN);
memcpy(hdr->daddr, "FAKELL", TR_ALEN);
return QETH_FAKE_LL_LEN_TR;
hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN);
memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
if (type != ETH_P_802_3)
hdr->h_proto = htons(type);
else
hdr->h_proto = htons(len);
return QETH_FAKE_LL_LEN;
} else {
struct ethhdr *hdr;
hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN_ETH);
memcpy(hdr->h_source, dev->dev_addr, ETH_ALEN);
memcpy(hdr->h_dest, "FAKELL", ETH_ALEN);
if (type != ETH_P_802_3)
hdr->h_proto = htons(type);
else
hdr->h_proto = htons(len);
return QETH_FAKE_LL_LEN_ETH;
}
}
static inline int
@ -3710,16 +3795,12 @@ static inline int
qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
struct qeth_hdr **hdr, int ipv)
{
int rc = 0;
#ifdef CONFIG_QETH_VLAN
u16 *tag;
#endif
QETH_DBF_TEXT(trace, 6, "prepskb");
rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
if (rc)
return rc;
#ifdef CONFIG_QETH_VLAN
if (card->vlangrp && vlan_tx_tag_present(*skb) &&
((ipv == 6) || card->options.layer2) ) {
@ -3882,9 +3963,15 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
}
} else { /* passthrough */
if (!memcmp(skb->data + sizeof(struct qeth_hdr),
if((skb->dev->type == ARPHRD_IEEE802_TR) &&
!memcmp(skb->data + sizeof(struct qeth_hdr) +
sizeof(__u16), skb->dev->broadcast, 6)) {
hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
QETH_HDR_PASSTHRU;
} else if (!memcmp(skb->data + sizeof(struct qeth_hdr),
skb->dev->broadcast, 6)) { /* broadcast? */
hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU;
hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
QETH_HDR_PASSTHRU;
} else {
hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
@ -3893,68 +3980,30 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
static inline void
__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer,
int *next_element_to_fill)
{
int length = skb->len;
struct skb_frag_struct *frag;
int fragno;
unsigned long addr;
int element;
int first_lap = 1;
fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */
element = *next_element_to_fill + fragno;
while (length > 0) {
if (fragno > 0) {
frag = &skb_shinfo(skb)->frags[fragno - 1];
addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
frag->page_offset;
buffer->element[element].addr = (char *)addr;
buffer->element[element].length = frag->size;
length -= frag->size;
if (first_lap)
buffer->element[element].flags =
SBAL_FLAGS_LAST_FRAG;
else
buffer->element[element].flags =
SBAL_FLAGS_MIDDLE_FRAG;
} else {
buffer->element[element].addr = skb->data;
buffer->element[element].length = length;
length = 0;
buffer->element[element].flags =
SBAL_FLAGS_FIRST_FRAG;
}
element--;
fragno--;
first_lap = 0;
}
*next_element_to_fill += skb_shinfo(skb)->nr_frags + 1;
}
static inline void
__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
int *next_element_to_fill)
int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
int element;
char *data;
int first_lap = 1;
int first_lap ;
element = *next_element_to_fill;
data = skb->data;
first_lap = (is_tso == 0 ? 1 : 0);
while (length > 0) {
/* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
if (length < length_here)
length_here = length;
buffer->element[element].addr = data;
buffer->element[element].length = length_here;
length -= length_here;
if (!length){
if (!length) {
if (first_lap)
buffer->element[element].flags = 0;
else
@ -3981,17 +4030,35 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct sk_buff *skb)
{
struct qdio_buffer *buffer;
int flush_cnt = 0;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
QETH_DBF_TEXT(trace, 6, "qdfillbf");
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
hdr = (struct qeth_hdr_tso *) skb->data;
/*check first on TSO ....*/
if (hdr->hdr.hdr.l3.id == QETH_HEADER_TYPE_TSO) {
int element = buf->next_element_to_fill;
hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
/*fill first buffer entry only with header information */
buffer->element[element].addr = skb->data;
buffer->element[element].length = hdr_len;
buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
buf->next_element_to_fill++;
skb->data += hdr_len;
skb->len -= hdr_len;
large_send = 1;
}
if (skb_shinfo(skb)->nr_frags == 0)
__qeth_fill_buffer(skb, buffer,
__qeth_fill_buffer(skb, buffer, large_send,
(int *)&buf->next_element_to_fill);
else
__qeth_fill_buffer_frag(skb, buffer,
__qeth_fill_buffer_frag(skb, buffer, large_send,
(int *)&buf->next_element_to_fill);
if (!queue->do_pack) {
@ -4183,6 +4250,25 @@ out:
return rc;
}
static inline int
qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb)
{
int elements_needed = 0;
if (skb_shinfo(skb)->nr_frags > 0) {
elements_needed = (skb_shinfo(skb)->nr_frags + 1);
}
if (elements_needed == 0 )
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+ skb->len) >> PAGE_SHIFT);
if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
PRINT_ERR("qeth_do_send_packet: invalid size of "
"IP packet. Discarded.");
return 0;
}
return elements_needed;
}
static inline int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
@ -4205,7 +4291,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
dev_kfree_skb_irq(skb);
return 0;
}
skb_pull(skb, QETH_FAKE_LL_LEN);
if(card->dev->type == ARPHRD_IEEE802_TR){
skb_pull(skb, QETH_FAKE_LL_LEN_TR);
} else {
skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
}
}
}
cast_type = qeth_get_cast_type(card, skb);
@ -4221,19 +4311,25 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
if (skb_shinfo(skb)->tso_size)
large_send = card->options.large_send;
if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
return rc;
}
/*are we able to do TSO ? If so ,prepare and send it from here */
if ((large_send == QETH_LARGE_SEND_TSO) &&
(cast_type == RTN_UNSPEC)) {
rc = qeth_tso_send_packet(card, skb, queue,
ipv, cast_type);
goto do_statistics;
rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
if (rc) {
card->stats.tx_dropped++;
card->stats.tx_errors++;
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
elements_needed++;
} else {
if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
return rc;
}
qeth_fill_header(card, hdr, skb, ipv, cast_type);
}
qeth_fill_header(card, hdr, skb, ipv, cast_type);
if (large_send == QETH_LARGE_SEND_EDDP) {
ctx = qeth_eddp_create_context(card, skb, hdr);
if (ctx == NULL) {
@ -4241,7 +4337,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
return -EINVAL;
}
} else {
elements_needed = qeth_get_elements_no(card,(void*) hdr, skb);
elements_needed += qeth_get_elements_no(card,(void*) hdr, skb);
if (!elements_needed)
return -EINVAL;
}
@ -4252,12 +4348,12 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
else
rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
elements_needed, ctx);
do_statistics:
if (!rc){
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
#ifdef CONFIG_QETH_PERF_STATS
if (skb_shinfo(skb)->tso_size) {
if (skb_shinfo(skb)->tso_size &&
!(large_send == QETH_LARGE_SEND_NO)) {
card->perf_stats.large_send_bytes += skb->len;
card->perf_stats.large_send_cnt++;
}
@ -7154,7 +7250,7 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
}
static int
qeth_stop_card(struct qeth_card *card)
qeth_stop_card(struct qeth_card *card, int recovery_mode)
{
int rc = 0;
@ -7167,9 +7263,13 @@ qeth_stop_card(struct qeth_card *card)
if (card->read.state == CH_STATE_UP &&
card->write.state == CH_STATE_UP &&
(card->state == CARD_STATE_UP)) {
rtnl_lock();
dev_close(card->dev);
rtnl_unlock();
if(recovery_mode) {
qeth_stop(card->dev);
} else {
rtnl_lock();
dev_close(card->dev);
rtnl_unlock();
}
if (!card->use_hard_stop) {
__u8 *mac = &card->dev->dev_addr[0];
rc = qeth_layer2_send_delmac(card, mac);
@ -7341,13 +7441,17 @@ qeth_register_netdev(struct qeth_card *card)
}
static void
qeth_start_again(struct qeth_card *card)
qeth_start_again(struct qeth_card *card, int recovery_mode)
{
QETH_DBF_TEXT(setup ,2, "startag");
rtnl_lock();
dev_open(card->dev);
rtnl_unlock();
if(recovery_mode) {
qeth_open(card->dev);
} else {
rtnl_lock();
dev_open(card->dev);
rtnl_unlock();
}
/* this also sets saved unicast addresses */
qeth_set_multicast_list(card->dev);
}
@ -7404,7 +7508,7 @@ static void qeth_make_parameters_consistent(struct qeth_card *card)
static int
qeth_set_online(struct ccwgroup_device *gdev)
__qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
{
struct qeth_card *card = gdev->dev.driver_data;
int rc = 0;
@ -7464,12 +7568,12 @@ qeth_set_online(struct ccwgroup_device *gdev)
* we can also use this state for recovery purposes*/
qeth_set_allowed_threads(card, 0xffffffff, 0);
if (recover_flag == CARD_STATE_RECOVER)
qeth_start_again(card);
qeth_start_again(card, recovery_mode);
qeth_notify_processes();
return 0;
out_remove:
card->use_hard_stop = 1;
qeth_stop_card(card);
qeth_stop_card(card, 0);
ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card));
@ -7480,6 +7584,12 @@ out_remove:
return -ENODEV;
}
static int
qeth_set_online(struct ccwgroup_device *gdev)
{
return __qeth_set_online(gdev, 0);
}
static struct ccw_device_id qeth_ids[] = {
{CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
{CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},

View File

@ -1,285 +0,0 @@
/*
* linux/drivers/s390/net/qeth_tso.c ($Revision: 1.6 $)
*
* Header file for qeth TCP Segmentation Offload support.
*
* Copyright 2004 IBM Corporation
*
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
*
* $Revision: 1.6 $ $Date: 2005/03/24 09:04:18 $
*
*/
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip6_checksum.h>
#include "qeth.h"
#include "qeth_mpc.h"
#include "qeth_tso.h"
/**
* skb already partially prepared
* classic qdio header in skb->data
* */
static inline struct qeth_hdr_tso *
qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
{
int rc = 0;
QETH_DBF_TEXT(trace, 5, "tsoprsk");
rc = qeth_realloc_headroom(card, skb,sizeof(struct qeth_hdr_ext_tso));
if (rc)
return NULL;
return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_ext_tso));
}
/**
* fill header for a TSO packet
*/
static inline void
qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb)
{
struct qeth_hdr_tso *hdr;
struct tcphdr *tcph;
struct iphdr *iph;
QETH_DBF_TEXT(trace, 5, "tsofhdr");
hdr = (struct qeth_hdr_tso *) skb->data;
iph = skb->nh.iph;
tcph = skb->h.th;
/*fix header to TSO values ...*/
hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
/*set values which are fix for the first approach ...*/
hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
hdr->ext.imb_hdr_no = 1;
hdr->ext.hdr_type = 1;
hdr->ext.hdr_version = 1;
hdr->ext.hdr_len = 28;
/*insert non-fix values */
hdr->ext.mss = skb_shinfo(skb)->tso_size;
hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
sizeof(struct qeth_hdr_tso));
}
/**
* change some header values as requested by hardware
*/
static inline void
qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
{
struct iphdr *iph;
struct ipv6hdr *ip6h;
struct tcphdr *tcph;
iph = skb->nh.iph;
ip6h = skb->nh.ipv6h;
tcph = skb->h.th;
tcph->check = 0;
if (skb->protocol == ETH_P_IPV6) {
ip6h->payload_len = 0;
tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
0, IPPROTO_TCP, 0);
return;
}
/*OSA want us to set these values ...*/
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
0, IPPROTO_TCP, 0);
iph->tot_len = 0;
iph->check = 0;
}
static inline struct qeth_hdr_tso *
qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb,
int ipv, int cast_type)
{
struct qeth_hdr_tso *hdr;
int rc = 0;
QETH_DBF_TEXT(trace, 5, "tsoprep");
/*get headroom for tso qdio header */
hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb);
if (hdr == NULL) {
QETH_DBF_TEXT_(trace, 4, "2err%d", rc);
return NULL;
}
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
/*fill first 32 bytes of qdio header as used
*FIXME: TSO has two struct members
* with different names but same size
* */
qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type);
qeth_tso_fill_header(card, skb);
qeth_tso_set_tcpip_header(card, skb);
return hdr;
}
static inline int
qeth_tso_get_queue_buffer(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
int flush_cnt = 0;
QETH_DBF_TEXT(trace, 5, "tsobuf");
/* force to non-packing*/
if (queue->do_pack)
queue->do_pack = 0;
buffer = &queue->bufs[queue->next_buf_to_fill];
/* get a new buffer if current is already in use*/
if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
(buffer->next_element_to_fill > 0)) {
atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
flush_cnt++;
}
return flush_cnt;
}
static inline void
__qeth_tso_fill_buffer_frag(struct qeth_qdio_out_buffer *buf,
struct sk_buff *skb)
{
struct skb_frag_struct *frag;
struct qdio_buffer *buffer;
int fragno, cnt, element;
unsigned long addr;
QETH_DBF_TEXT(trace, 6, "tsfilfrg");
/*initialize variables ...*/
fragno = skb_shinfo(skb)->nr_frags;
buffer = buf->buffer;
element = buf->next_element_to_fill;
/*fill buffer elements .....*/
for (cnt = 0; cnt < fragno; cnt++) {
frag = &skb_shinfo(skb)->frags[cnt];
addr = (page_to_pfn(frag->page) << PAGE_SHIFT) +
frag->page_offset;
buffer->element[element].addr = (char *)addr;
buffer->element[element].length = frag->size;
if (cnt < (fragno - 1))
buffer->element[element].flags =
SBAL_FLAGS_MIDDLE_FRAG;
else
buffer->element[element].flags =
SBAL_FLAGS_LAST_FRAG;
element++;
}
buf->next_element_to_fill = element;
}
static inline int
qeth_tso_fill_buffer(struct qeth_qdio_out_buffer *buf,
struct sk_buff *skb)
{
int length, length_here, element;
int hdr_len;
struct qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
char *data;
QETH_DBF_TEXT(trace, 3, "tsfilbuf");
/*increment user count and queue skb ...*/
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
/*initialize all variables...*/
buffer = buf->buffer;
hdr = (struct qeth_hdr_tso *)skb->data;
hdr_len = sizeof(struct qeth_hdr_tso) + hdr->ext.dg_hdr_len;
data = skb->data + hdr_len;
length = skb->len - hdr_len;
element = buf->next_element_to_fill;
/*fill first buffer entry only with header information */
buffer->element[element].addr = skb->data;
buffer->element[element].length = hdr_len;
buffer->element[element].flags = SBAL_FLAGS_FIRST_FRAG;
buf->next_element_to_fill++;
if (skb_shinfo(skb)->nr_frags > 0) {
__qeth_tso_fill_buffer_frag(buf, skb);
goto out;
}
/*start filling buffer entries ...*/
element++;
while (length > 0) {
/* length_here is the remaining amount of data in this page */
length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
if (length < length_here)
length_here = length;
buffer->element[element].addr = data;
buffer->element[element].length = length_here;
length -= length_here;
if (!length)
buffer->element[element].flags =
SBAL_FLAGS_LAST_FRAG;
else
buffer->element[element].flags =
SBAL_FLAGS_MIDDLE_FRAG;
data += length_here;
element++;
}
/*set the buffer to primed ...*/
buf->next_element_to_fill = element;
out:
atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED);
return 1;
}
int
qeth_tso_send_packet(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv, int cast_type)
{
int flush_cnt = 0;
struct qeth_hdr_tso *hdr;
struct qeth_qdio_out_buffer *buffer;
int start_index;
QETH_DBF_TEXT(trace, 3, "tsosend");
if (!(hdr = qeth_tso_prepare_packet(card, skb, ipv, cast_type)))
return -ENOMEM;
/*check if skb fits in one SBAL ...*/
if (!(qeth_get_elements_no(card, (void*)hdr, skb)))
return -EINVAL;
/*lock queue, force switching to non-packing and send it ...*/
while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED,
&queue->state));
start_index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill];
/*check if card is too busy ...*/
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
card->stats.tx_dropped++;
goto out;
}
/*let's force to non-packing and get a new SBAL*/
flush_cnt += qeth_tso_get_queue_buffer(queue);
buffer = &queue->bufs[queue->next_buf_to_fill];
if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
card->stats.tx_dropped++;
goto out;
}
flush_cnt += qeth_tso_fill_buffer(buffer, skb);
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
out:
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
if (flush_cnt)
qeth_flush_buffers(queue, 0, start_index, flush_cnt);
/*do some statistics */
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
return 0;
}

Some files were not shown because too many files have changed in this diff Show More