diff options
Diffstat (limited to 'drivers')
71 files changed, 6341 insertions, 4706 deletions
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 667fa1dfa1a3..91082ce6f5d1 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -296,7 +296,7 @@ static int bay_add(acpi_handle handle, int id) /* * Initialize bay device structure */ - new_bay = kzalloc(GFP_ATOMIC, sizeof(*new_bay)); + new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC); INIT_LIST_HEAD(&new_bay->list); new_bay->handle = handle; new_bay->name = (char *)nbuffer.pointer; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 48616c6fee9d..e2796fb40eb7 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1173,7 +1173,7 @@ static void ahci_host_intr(struct ata_port *ap) * dangerous, we need to know more about them. Print * more of it. */ - const u32 *f = pp->rx_fis + RX_FIS_SDB; + const __le32 *f = pp->rx_fis + RX_FIS_SDB; ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 46d8a94669b4..5f4e82ade6cd 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -116,7 +116,7 @@ static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -125,7 +125,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -262,7 +262,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) static u8 k2_stat_check_status(struct ata_port *ap) { - return readl((void *) ap->ioaddr.status_addr); + return readl((void __iomem *) ap->ioaddr.status_addr); } #ifdef CONFIG_PPC_OF diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 276577d08fba..4d730fdbd528 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -325,7 +325,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return put_user(0, p); case WDIOC_KEEPALIVE: - zf_ping(0); + zf_ping(NULL); break; default: diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 43a68398656f..31ea405f2eeb 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -457,7 +457,7 @@ static struct pci_driver geode_aes_driver = { static int __init geode_aes_init(void) { - return pci_module_init(&geode_aes_driver); + return pci_register_driver(&geode_aes_driver); } static void __exit diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index f126aa485134..18210164e307 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c @@ -153,7 +153,7 @@ int ams_input_init(void) } /* Call with ams_info.lock held! */ -void ams_input_exit() +void ams_input_exit(void) { ams_input_disable(); device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 0a7d1ab60e6d..89e37283c836 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -567,7 +567,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc, opcode = hdr->opcode & ISCSI_OPCODE_MASK; if (opcode == ISCSI_OP_SCSI_CMD_RSP) { - itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */ + itt = get_itt(hdr->itt); /* mask out cid and age bits */ if (!(itt < session->cmds_max)) iser_err("itt can't be matched to task!!!" "conn %p opcode %d cmds_max %d itt %d\n", @@ -625,7 +625,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) /* this arithmetic is legal by libiscsi dd_data allocation */ mtask = (void *) ((long)(void *)tx_desc - sizeof(struct iscsi_mgmt_task)); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock(&conn->session->lock); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 4358a0a78eaa..c7db4032ef02 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -83,7 +83,7 @@ struct ucb1400 { - ac97_t *ac97; + struct snd_ac97 *ac97; struct input_dev *ts_idev; int irq; diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index b10972ed0c9f..099f0afd394d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -62,7 +62,7 @@ static struct kvm_stats_debugfs_item { { "halt_exits", &kvm_stat.halt_exits }, { "request_irq", &kvm_stat.request_irq_exits }, { "irq_exits", &kvm_stat.irq_exits }, - { 0, 0 } + { NULL, NULL } }; static struct dentry *debugfs_dir; @@ -205,7 +205,7 @@ static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot) mutex_lock(&vcpu->mutex); if (unlikely(!vcpu->vmcs)) { mutex_unlock(&vcpu->mutex); - return 0; + return NULL; } return kvm_arch_ops->vcpu_load(vcpu); } @@ -257,9 +257,9 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free, if (!dont || free->dirty_bitmap != dont->dirty_bitmap) vfree(free->dirty_bitmap); - free->phys_mem = 0; + free->phys_mem = NULL; free->npages = 0; - free->dirty_bitmap = 0; + free->dirty_bitmap = NULL; } static void kvm_free_physmem(struct kvm *kvm) @@ -267,7 +267,7 @@ static void kvm_free_physmem(struct kvm *kvm) int i; for (i = 0; i < kvm->nmemslots; ++i) - kvm_free_physmem_slot(&kvm->memslots[i], 0); + kvm_free_physmem_slot(&kvm->memslots[i], NULL); } static void kvm_free_vcpu(struct kvm_vcpu *vcpu) @@ -640,11 +640,11 @@ raced: /* Deallocate if slot is being removed */ if (!npages) - new.phys_mem = 0; + new.phys_mem = NULL; /* Free page dirty bitmap if unneeded */ if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) - new.dirty_bitmap = 0; + new.dirty_bitmap = NULL; r = -ENOMEM; @@ -799,14 +799,14 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) && gfn < memslot->base_gfn + memslot->npages) return memslot; } - return 0; + return NULL; } EXPORT_SYMBOL_GPL(gfn_to_memslot); void mark_page_dirty(struct kvm *kvm, gfn_t gfn) { int i; - struct kvm_memory_slot *memslot = 0; + struct kvm_memory_slot *memslot = NULL; unsigned long rel_gfn; for (i = 0; i < kvm->nmemslots; ++i) { @@ -1778,6 +1778,7 @@ static long kvm_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; int r = -EINVAL; switch (ioctl) { @@ -1794,12 +1795,12 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_run kvm_run; r = -EFAULT; - if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run)) + if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) goto out; r = kvm_dev_ioctl_run(kvm, &kvm_run); if (r < 0 && r != -EINTR) goto out; - if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) { + if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { r = -EFAULT; goto out; } @@ -1809,13 +1810,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs)) + if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs)) goto out; r = 0; break; @@ -1824,7 +1825,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_regs kvm_regs; r = -EFAULT; - if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs)) + if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs); if (r) @@ -1836,13 +1837,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs)) + if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs)) goto out; r = 0; break; @@ -1851,7 +1852,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_sregs kvm_sregs; r = -EFAULT; - if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs)) + if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs); if (r) @@ -1863,13 +1864,13 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_translation tr; r = -EFAULT; - if (copy_from_user(&tr, (void *)arg, sizeof tr)) + if (copy_from_user(&tr, argp, sizeof tr)) goto out; r = kvm_dev_ioctl_translate(kvm, &tr); if (r) goto out; r = -EFAULT; - if (copy_to_user((void *)arg, &tr, sizeof tr)) + if (copy_to_user(argp, &tr, sizeof tr)) goto out; r = 0; break; @@ -1878,7 +1879,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_interrupt irq; r = -EFAULT; - if (copy_from_user(&irq, (void *)arg, sizeof irq)) + if (copy_from_user(&irq, argp, sizeof irq)) goto out; r = kvm_dev_ioctl_interrupt(kvm, &irq); if (r) @@ -1890,7 +1891,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_debug_guest dbg; r = -EFAULT; - if (copy_from_user(&dbg, (void *)arg, sizeof dbg)) + if (copy_from_user(&dbg, argp, sizeof dbg)) goto out; r = kvm_dev_ioctl_debug_guest(kvm, &dbg); if (r) @@ -1902,7 +1903,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_memory_region kvm_mem; r = -EFAULT; - if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem)) + if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) goto out; r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem); if (r) @@ -1913,7 +1914,7 @@ static long kvm_dev_ioctl(struct file *filp, struct kvm_dirty_log log; r = -EFAULT; - if (copy_from_user(&log, (void *)arg, sizeof log)) + if (copy_from_user(&log, argp, sizeof log)) goto out; r = kvm_dev_ioctl_get_dirty_log(kvm, &log); if (r) @@ -1921,13 +1922,13 @@ static long kvm_dev_ioctl(struct file *filp, break; } case KVM_GET_MSRS: - r = msr_io(kvm, (void __user *)arg, get_msr, 1); + r = msr_io(kvm, argp, get_msr, 1); break; case KVM_SET_MSRS: - r = msr_io(kvm, (void __user *)arg, do_set_msr, 0); + r = msr_io(kvm, argp, do_set_msr, 0); break; case KVM_GET_MSR_INDEX_LIST: { - struct kvm_msr_list __user *user_msr_list = (void __user *)arg; + struct kvm_msr_list __user *user_msr_list = argp; struct kvm_msr_list msr_list; unsigned n; @@ -2014,7 +2015,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val, * in vmx root mode. */ printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); } return NOTIFY_OK; } @@ -2028,7 +2029,7 @@ static __init void kvm_init_debug(void) { struct kvm_stats_debugfs_item *p; - debugfs_dir = debugfs_create_dir("kvm", 0); + debugfs_dir = debugfs_create_dir("kvm", NULL); for (p = debugfs_entries; p->name; ++p) p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir, p->data); @@ -2069,7 +2070,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) if (r < 0) return r; - on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); register_reboot_notifier(&kvm_reboot_notifier); kvm_chardev_ops.owner = module; @@ -2084,7 +2085,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) out_free: unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); return r; } @@ -2094,7 +2095,7 @@ void kvm_exit_arch(void) misc_deregister(&kvm_dev); unregister_reboot_notifier(&kvm_reboot_notifier); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); kvm_arch_ops->hardware_unsetup(); kvm_arch_ops = NULL; } diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 22c426cd8cb2..be793770f31b 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -333,7 +333,7 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu, for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) ; desc->shadow_ptes[i] = desc->shadow_ptes[j]; - desc->shadow_ptes[j] = 0; + desc->shadow_ptes[j] = NULL; if (j != 0) return; if (!prev_desc && !desc->more) diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index c79df79307ed..85f61dd1e936 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -274,7 +274,7 @@ static void svm_hardware_disable(void *garbage) wrmsrl(MSR_VM_HSAVE_PA, 0); rdmsrl(MSR_EFER, efer); wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); - per_cpu(svm_data, raw_smp_processor_id()) = 0; + per_cpu(svm_data, raw_smp_processor_id()) = NULL; __free_page(svm_data->save_area); kfree(svm_data); } @@ -642,7 +642,7 @@ static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) case VCPU_SREG_LDTR: return &save->ldtr; } BUG(); - return 0; + return NULL; } static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) @@ -934,7 +934,7 @@ static int io_get_override(struct kvm_vcpu *vcpu, return 0; *addr_override = 0; - *seg = 0; + *seg = NULL; for (i = 0; i < ins_length; i++) switch (inst[i]) { case 0xf0: @@ -1087,7 +1087,7 @@ static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE) + if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE) printk(KERN_ERR "%s: failed\n", __FUNCTION__); return 1; } diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 54c35c0b3181..27e05a77e21a 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -98,7 +98,7 @@ static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr) for (i = 0; i < vcpu->nmsrs; ++i) if (vcpu->guest_msrs[i].index == msr) return &vcpu->guest_msrs[i]; - return 0; + return NULL; } static void vmcs_clear(struct vmcs *vmcs) diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 5ed41fe84e57..f83fad2a3ff4 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm) /* Make sure dbdma is reset */ DBDMA_DO_RESET(rm->dma_regs); - pr_debug("rackmeter: mark offset=0x%lx\n", + pr_debug("rackmeter: mark offset=0x%zx\n", offsetof(struct rackmeter_dma, mark)); - pr_debug("rackmeter: buf1 offset=0x%lx\n", + pr_debug("rackmeter: buf1 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf1)); - pr_debug("rackmeter: buf2 offset=0x%lx\n", + pr_debug("rackmeter: buf2 offset=0x%zx\n", offsetof(struct rackmeter_dma, buf2)); /* Prepare 4 dbdma commands for the 2 buffers */ diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index f51e02fe3655..0e948a5c5a03 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = { [ 0x29 ] = KEY_TEXT, [ 0x2a ] = KEY_MEDIA, [ 0x18 ] = KEY_EPG, - [ 0x27 ] = KEY_RECORD, }; EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey); diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 7243337b771a..bdd6301d2a47 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1072,7 +1072,7 @@ static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, } -static ssize_t usbvision_v4l2_read(struct file *file, char *buf, +static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = video_devdata(file); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 89bba277da5f..bedae4ad3f74 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -42,7 +42,7 @@ config SGI_IOC4 config TIFM_CORE tristate "TI Flash Media interface support (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on EXPERIMENTAL && PCI help If you want support for Texas Instruments(R) Flash Media adapters you should select this option and then also choose an appropriate diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index db9d7df75ae0..552b7957a92a 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -108,8 +108,8 @@ static struct jprobe lkdtm; static int lkdtm_parse_commandline(void); static void lkdtm_handler(void); -static char* cpoint_name = INVALID; -static char* cpoint_type = NONE; +static char* cpoint_name; +static char* cpoint_type; static int cpoint_count = DEFAULT_COUNT; static int recur_count = REC_NUM_DEFAULT; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 4224686fdf2a..12af9c718764 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -111,7 +111,7 @@ config MMC_IMX config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL + depends on MMC && EXPERIMENTAL && PCI select TIFM_CORE help Say Y here if you want to be able to access MMC/SD cards with diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 7e34c4f07b70..bc7e906571d3 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring count -= semi_count; memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, base + ring_offset, count, 0); + memcpy_fromio(skb->data, base + ring_offset, count); } return; } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b79711d441a4..38f41a593b12 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2335,6 +2335,17 @@ config QLA3XXX To compile this driver as a module, choose M here: the module will be called qla3xxx. +config ATL1 + tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Attansic L1 gigabit ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl1. + endmenu # diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0878e3df5174..33af833667da 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o gianfar_driver-objs := gianfar.o \ diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index c01f87f5bed7..644c408515df 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -327,8 +327,7 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES*256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, start, count, 0); + memcpy_fromio(skb->data, start, count); } } diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile new file mode 100644 index 000000000000..a6b707e4e69e --- /dev/null +++ b/drivers/net/atl1/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ATL1) += atl1.o +atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h new file mode 100644 index 000000000000..b1c6034e68fa --- /dev/null +++ b/drivers/net/atl1/atl1.h @@ -0,0 +1,283 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL1_H_ +#define _ATL1_H_ + +#include <linux/types.h> +#include <linux/if_vlan.h> + +#include "atl1_hw.h" + +/* function prototypes needed by multiple files */ +s32 atl1_up(struct atl1_adapter *adapter); +void atl1_down(struct atl1_adapter *adapter); +int atl1_reset(struct atl1_adapter *adapter); +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter); +void atl1_free_ring_resources(struct atl1_adapter *adapter); + +extern char atl1_driver_name[]; +extern char atl1_driver_version[]; +extern const struct ethtool_ops atl1_ethtool_ops; + +struct atl1_adapter; + +#define ATL1_MAX_INTR 3 + +#define ATL1_DEFAULT_TPD 256 +#define ATL1_MAX_TPD 1024 +#define ATL1_MIN_TPD 64 +#define ATL1_DEFAULT_RFD 512 +#define ATL1_MIN_RFD 128 +#define ATL1_MAX_RFD 2048 + +#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc) +#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc) +#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) + +/* + * Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ + +/* + * wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct atl1_buffer { + struct sk_buff *skb; + u16 length; + u16 alloced; + dma_addr_t dma; +}; + +#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ + +struct atl1_tpd_ring { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + u16 size; /* length of descriptor ring in bytes */ + u16 count; /* number of descriptors in the ring */ + u16 hw_idx; /* hardware index */ + atomic_t next_to_clean; + atomic_t next_to_use; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rfd_ring { + void *desc; + dma_addr_t dma; + u16 size; + u16 count; + atomic_t next_to_use; + u16 next_to_clean; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rrd_ring { + void *desc; + dma_addr_t dma; + unsigned int size; + u16 count; + u16 next_to_use; + atomic_t next_to_clean; +}; + +struct atl1_ring_header { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + unsigned int size; /* length of descriptor ring in bytes */ +}; + +struct atl1_cmb { + struct coals_msg_block *cmb; + dma_addr_t dma; +}; + +struct atl1_smb { + struct stats_msg_block *smb; + dma_addr_t dma; +}; + +/* Statistics counters */ +struct atl1_sft_stats { + u64 rx_packets; + u64 tx_packets; + u64 rx_bytes; + u64 tx_bytes; + u64 multicast; + u64 collisions; + u64 rx_errors; + u64 rx_length_errors; + u64 rx_crc_errors; + u64 rx_frame_errors; + u64 rx_fifo_errors; + u64 rx_missed_errors; + u64 tx_errors; + u64 tx_fifo_errors; + u64 tx_aborted_errors; + u64 tx_window_errors; + u64 tx_carrier_errors; + + u64 tx_pause; /* num Pause packet transmitted. */ + u64 excecol; /* num tx packets aborted due to excessive collisions. */ + u64 deffer; /* num deferred tx packets */ + u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ + u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ + u64 latecol; /* num tx packets w/ late collisions. */ + u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ + u64 rx_pause; /* num Pause packets received. */ + u64 rx_rrd_ov; + u64 rx_trunc; +}; + +/* board specific private data structure */ +#define ATL1_REGS_LEN 8 + +/* Structure containing variables used by the shared code */ +struct atl1_hw { + u8 __iomem *hw_addr; + struct atl1_adapter *back; + enum atl1_dma_order dma_ord; + enum atl1_dma_rcb rcb_value; + enum atl1_dma_req_block dmar_block; + enum atl1_dma_req_block dmaw_block; + u8 preamble_len; + u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ + u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ + u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ + u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ + u8 ipgr1; /* 64bit Carrier-Sense window */ + u8 ipgr2; /* 96-bit IPG window */ + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ + u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ + u8 rfd_fetch_gap; + u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ + u8 tpd_fetch_th; + u8 tpd_fetch_gap; + u16 tx_jumbo_task_th; + u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is + 8 bytes long */ + u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ + u16 rx_jumbo_lkah; + u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ + u16 lcol; /* Collision Window */ + + u16 cmb_tpd; + u16 cmb_rrd; + u16 cmb_rx_timer; + u16 cmb_tx_timer; + u32 smb_timer; + u16 media_type; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg; + + u32 mem_rang; + u32 txcw; + u32 max_frame_size; + u32 min_frame_size; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 dev_rev; + u8 revision_id; + + /* spi flash */ + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[ETH_ALEN]; + u8 perm_mac_addr[ETH_ALEN]; + + /* bool phy_preamble_sup; */ + bool phy_configured; +}; + +struct atl1_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; + + struct vlan_group *vlgrp; + u32 rx_buffer_len; + u32 wol; + u16 link_speed; + u16 link_duplex; + spinlock_t lock; + atomic_t irq_sem; + struct work_struct tx_timeout_task; + struct work_struct link_chg_task; + struct work_struct pcie_dma_to_rst_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + bool phy_timer_pending; + + bool mac_disabled; + + /* All descriptor rings' memory */ + struct atl1_ring_header ring_header; + + /* TX */ + struct atl1_tpd_ring tpd_ring; + spinlock_t mb_lock; + + /* RX */ + struct atl1_rfd_ring rfd_ring; + struct atl1_rrd_ring rrd_ring; + u64 hw_csum_err; + u64 hw_csum_good; + + u32 gorcl; + u64 gorcl_old; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + /* MII interface info */ + struct mii_if_info mii; + + /* structs defined in atl1_hw.h */ + u32 bd_number; /* board number */ + bool pci_using_64; + struct atl1_hw hw; + struct atl1_smb smb; + struct atl1_cmb cmb; + + u32 pci_state[16]; +}; + +#endif /* _ATL1_H_ */ diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c new file mode 100644 index 000000000000..c11c27798e5c --- /dev/null +++ b/drivers/net/atl1/atl1_ethtool.c @@ -0,0 +1,508 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. 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/types.h> +#include <linux/pci.h> +#include <linux/ethtool.h> +#include <linux/netdevice.h> +#include <linux/mii.h> +#include <asm/uaccess.h> + +#include "atl1.h" + +struct atl1_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \ + offsetof(struct atl1_adapter, m) + +static struct atl1_stats atl1_gstrings_stats[] = { + {"rx_packets", ATL1_STAT(soft_stats.rx_packets)}, + {"tx_packets", ATL1_STAT(soft_stats.tx_packets)}, + {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)}, + {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, + {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, + {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, + {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, + {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, + {"multicast", ATL1_STAT(soft_stats.multicast)}, + {"collisions", ATL1_STAT(soft_stats.collisions)}, + {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, + {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)}, + {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)}, + {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)}, + {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)}, + {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)}, + {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)}, + {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)}, + {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)}, + {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)}, + {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)}, + {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)}, + {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)}, + {"tx_underun", ATL1_STAT(soft_stats.tx_underun)}, + {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)}, + {"tx_pause", ATL1_STAT(soft_stats.tx_pause)}, + {"rx_pause", ATL1_STAT(soft_stats.rx_pause)}, + {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)}, + {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)} +}; + +static void atl1_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int i; + char *p; + + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + p = (char *)adapter+atl1_gstrings_stats[i].stat_offset; + data[i] = (atl1_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + +} + +static int atl1_get_stats_count(struct net_device *netdev) +{ + return ARRAY_SIZE(atl1_gstrings_stats); +} + +static int atl1_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + ecmd->advertising |= ADVERTISED_Autoneg; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= + (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + } + else + ecmd->advertising |= (ADVERTISED_1000baseT_Full); + } + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + u16 link_speed, link_duplex; + atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); + ecmd->speed = link_speed; + if (link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + ecmd->autoneg = AUTONEG_ENABLE; + else + ecmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static int atl1_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u16 phy_data; + int ret_val = 0; + u16 old_media_type = hw->media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool shutting down adapter\n", + atl1_driver_name); + atl1_down(adapter); + } + + if (ecmd->autoneg == AUTONEG_ENABLE) + hw->media_type = MEDIA_TYPE_AUTO_SENSOR; + else { + if (ecmd->speed == SPEED_1000) { + if (ecmd->duplex != DUPLEX_FULL) { + printk(KERN_WARNING + "%s: can't force to 1000M half duplex\n", + atl1_driver_name); + ret_val = -EINVAL; + goto exit_sset; + } + hw->media_type = MEDIA_TYPE_1000M_FULL; + } else if (ecmd->speed == SPEED_100) { + if (ecmd->duplex == DUPLEX_FULL) { + hw->media_type = MEDIA_TYPE_100M_FULL; + } else + hw->media_type = MEDIA_TYPE_100M_HALF; + } else { + if (ecmd->duplex == DUPLEX_FULL) + hw->media_type = MEDIA_TYPE_10M_FULL; + else + hw->media_type = MEDIA_TYPE_10M_HALF; + } + } + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + ecmd->advertising = + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + case MEDIA_TYPE_1000M_FULL: + ecmd->advertising = + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + default: + ecmd->advertising = 0; + break; + } + if (atl1_phy_setup_autoneg_adv(hw)) { + ret_val = -EINVAL; + printk(KERN_WARNING + "%s: invalid ethtool speed/duplex setting\n", + atl1_driver_name); + goto exit_sset; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); +exit_sset: + if (ret_val) + hw->media_type = old_media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool starting adapter\n", + atl1_driver_name); + atl1_up(adapter); + } else if (!ret_val) { + printk(KERN_DEBUG "%s: ethtool resetting adapter\n", + atl1_driver_name); + atl1_reset(adapter); + } + return ret_val; +} + +static void atl1_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver)); + strncpy(drvinfo->version, atl1_driver_version, + sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); + drvinfo->eedump_len = ATL1_EEDUMP_LEN; +} + +static void atl1_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = 0; + if (adapter->wol & ATL1_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATL1_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATL1_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATL1_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + return; +} + +static int atl1_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + adapter->wol = 0; + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= ATL1_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= ATL1_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= ATL1_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATL1_WUFC_MAG; + return 0; +} + +static void atl1_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *txdr = &adapter->tpd_ring; + struct atl1_rfd_ring *rxdr = &adapter->rfd_ring; + + ring->rx_max_pending = ATL1_MAX_RFD; + ring->tx_max_pending = ATL1_MAX_TPD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int atl1_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *tpdr = &adapter->tpd_ring; + struct atl1_rrd_ring *rrdr = &adapter->rrd_ring; + struct atl1_rfd_ring *rfdr = &adapter->rfd_ring; + + struct atl1_tpd_ring tpd_old, tpd_new; + struct atl1_rfd_ring rfd_old, rfd_new; + struct atl1_rrd_ring rrd_old, rrd_new; + struct atl1_ring_header rhdr_old, rhdr_new; + int err; + + tpd_old = adapter->tpd_ring; + rfd_old = adapter->rfd_ring; + rrd_old = adapter->rrd_ring; + rhdr_old = adapter->ring_header; + + if (netif_running(adapter->netdev)) + atl1_down(adapter); + + rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD); + rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD : + rfdr->count; + rfdr->count = (rfdr->count + 3) & ~3; + rrdr->count = rfdr->count; + + tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD); + tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD : + tpdr->count; + tpdr->count = (tpdr->count + 3) & ~3; + + if (netif_running(adapter->netdev)) { + /* try to get new resources before deleting old */ + err = atl1_setup_ring_resources(adapter); + if (err) + goto err_setup_ring; + + /* + * save the new, restore the old in order to free it, + * then restore the new back again + */ + + rfd_new = adapter->rfd_ring; + rrd_new = adapter->rrd_ring; + tpd_new = adapter->tpd_ring; + rhdr_new = adapter->ring_header; + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_free_ring_resources(adapter); + adapter->rfd_ring = rfd_new; + adapter->rrd_ring = rrd_new; + adapter->tpd_ring = tpd_new; + adapter->ring_header = rhdr_new; + + err = atl1_up(adapter); + if (err) + return err; + } + return 0; + +err_setup_ring: + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_up(adapter); + return err; +} + +static void atl1_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + epause->rx_pause = 1; + epause->tx_pause = 1; +} + +static int atl1_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + + epause->rx_pause = 1; + epause->tx_pause = 1; + + return 0; +} + +static u32 atl1_get_rx_csum(struct net_device *netdev) +{ + return 1; +} + +static void atl1_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + memcpy(p, atl1_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int atl1_nway_reset(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (netif_running(netdev)) { + u16 phy_data; + atl1_down(adapter); + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + } else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + atl1_up(adapter); + } + return 0; +} + +const struct ethtool_ops atl1_ethtool_ops = { + .get_settings = atl1_get_settings, + .set_settings = atl1_set_settings, + .get_drvinfo = atl1_get_drvinfo, + .get_wol = atl1_get_wol, + .set_wol = atl1_set_wol, + .get_ringparam = atl1_get_ringparam, + .set_ringparam = atl1_set_ringparam, + .get_pauseparam = atl1_get_pauseparam, + .set_pauseparam = atl1_set_pauseparam, + .get_rx_csum = atl1_get_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_strings = atl1_get_strings, + .nway_reset = atl1_nway_reset, + .get_ethtool_stats = atl1_get_ethtool_stats, + .get_stats_count = atl1_get_stats_count, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, +}; diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c new file mode 100644 index 000000000000..08b2d785469d --- /dev/null +++ b/drivers/net/atl1/atl1_hw.c @@ -0,0 +1,718 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. 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/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/if_vlan.h> +#include <linux/etherdevice.h> +#include <linux/crc32.h> +#include <asm/byteorder.h> + +#include "atl1.h" + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * hw - Struct containing variables accessed by shared code + * return : ATL1_SUCCESS or idle status (if error) + */ +s32 atl1_reset_hw(struct atl1_hw *hw) +{ + u32 icr; + int i; + + /* + * Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ + /* + * iowrite32(0, hw->hw_addr + REG_IMR); + * iowrite32(0xffffffff, hw->hw_addr + REG_ISR); + */ + + /* + * Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL); + ioread32(hw->hw_addr + REG_MASTER_CTRL); + + iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE); + ioread16(hw->hw_addr + REG_GPHY_ENABLE); + + msleep(1); /* delay about 1ms */ + + /* Wait at least 10ms for All module to be Idle */ + for (i = 0; i < 10; i++) { + icr = ioread32(hw->hw_addr + REG_IDLE_STATUS); + if (!icr) + break; + msleep(1); /* delay 1 ms */ + cpu_relax(); /* FIXME: is this still the right way to do this? */ + } + + if (icr) { + printk (KERN_DEBUG "icr = %x\n", icr); + return icr; + } + + return ATL1_SUCCESS; +} + +/* function about EEPROM + * + * check_eeprom_exist + * return 0 if eeprom exist + */ +static int atl1_check_eeprom_exist(struct atl1_hw *hw) +{ + u32 value; + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + } + + value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value) +{ + int i; + u32 control; + + if (offset & 3) + return false; /* address do not align */ + + iowrite32(0, hw->hw_addr + REG_VPD_DATA); + control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + iowrite32(control, hw->hw_addr + REG_VPD_CAP); + ioread32(hw->hw_addr + REG_VPD_CAP); + + for (i = 0; i < 10; i++) { + msleep(2); + control = ioread32(hw->hw_addr + REG_VPD_CAP); + if (control & VPD_CAP_VPD_FLAG) + break; + } + if (control & VPD_CAP_VPD_FLAG) { + *p_value = ioread32(hw->hw_addr + REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << + MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + if (!(val & (MDIO_START | MDIO_BUSY))) { + *phy_data = (u16) val; + return ATL1_SUCCESS; + } + return ATL1_ERR_PHY; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf) +{ + int i; + u32 value; + + iowrite32(0, hw->hw_addr + REG_SPI_DATA); + iowrite32(addr, hw->hw_addr + REG_SPI_ADDR); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << + SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI & + SPI_FLASH_CTRL_CLK_HI_MASK) << + SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO & + SPI_FLASH_CTRL_CLK_LO_MASK) << + SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD & + SPI_FLASH_CTRL_CS_HOLD_MASK) << + SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI & + SPI_FLASH_CTRL_CS_HI_MASK) << + SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) << + SPI_FLASH_CTRL_INS_SHIFT; + + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + + value |= SPI_FLASH_CTRL_START; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + + for (i = 0; i < 10; i++) { + msleep(1); /* 1ms */ + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ioread32(hw->hw_addr + REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int atl1_get_permanent_address(struct atl1_hw *hw) +{ + u32 addr[2]; + u32 i, control; + u16 reg; + u8 eth_addr[ETH_ALEN]; + bool key_valid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + /* init */ + addr[0] = addr[1] = 0; + + if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */ + reg = 0; + key_valid = false; + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl1_read_eeprom(hw, i + 0x100, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* assume data end while encount an invalid KEYWORD */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; + } + + /* see if SPI FLAGS exist ? */ + addr[0] = addr[1] = 0; + reg = 0; + key_valid = false; + i = 0; + while (1) { + if (atl1_spi_read(hw, i + 0x1f000, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* data end */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_read_mac_addr(struct atl1_hw *hw) +{ + u16 i; + + if (atl1_get_permanent_address(hw)) + random_ether_addr(hw->perm_mac_addr); + + for (i = 0; i < ETH_ALEN; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + return ATL1_SUCCESS; +} + +/* + * Hashes an address to determine its location in the multicast table + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl1_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr) +{ + u32 crc32, value = 0; + int i; + + crc32 = ether_crc_le(6, mc_addr); + crc32 = ~crc32; + for (i = 0; i < 32; i++) + value |= (((crc32 >> i) & 1) << (31 - i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* + * The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta |= (1 << hash_bit); + iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); +} + +/* + * Writes a value to a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to write + * data - data to write to the PHY + */ +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data) +{ + int i; + u32 val; + + val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | + (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | + MDIO_SUP_PREAMBLE | + MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (!(val & (MDIO_START | MDIO_BUSY))) + return ATL1_SUCCESS; + + return ATL1_ERR_PHY; +} + +/* + * Make L001's PHY out of Power Saving State (bug) + * hw - Struct containing variables accessed by shared code + * when power on, L001's PHY always on Power saving State + * (Gigabit Link forbidden) + */ +static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) +{ + s32 ret; + ret = atl1_write_phy_reg(hw, 29, 0x0029); + if (ret) + return ret; + return atl1_write_phy_reg(hw, 30, 0); +} + +/* + *TODO: do something or get rid of this + */ +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) +{ +/* s32 ret_val; + * u16 phy_data; + */ + +/* + ret_val = atl1_write_phy_reg(hw, ...); + ret_val = atl1_write_phy_reg(hw, ...); + .... +*/ + return ATL1_SUCCESS; +} + +/* + * Resets the PHY and make all config validate + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 atl1_phy_reset(struct atl1_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + + ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { + u32 val; + int i; + /* pcie serdes link may be down! */ + printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", + atl1_driver_name); + + for (i = 0; i < 25; i++) { + msleep(1); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if ((val & (MDIO_START | MDIO_BUSY)) != 0) { + printk(KERN_WARNING + "%s: pcie link down at least for 25ms\n", + atl1_driver_name); + return ret_val; + } + } + return ATL1_SUCCESS; +} + +/* + * Configures PHY autoneg and flow control advertisement settings + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw) +{ + s32 ret_val; + s16 mii_autoneg_adv_reg; + s16 mii_1000t_ctrl_reg; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; + + /* + * First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; + mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; + + /* + * Need to parse media_type and set up + * the appropriate PHY registers. + */ + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS | + MII_AR_100TX_FD_CAPS); + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_1000M_FULL: + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + break; + + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + break; + + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + break; + + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; + + ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + + return ATL1_SUCCESS; +} + +/* + * Configures link settings. + * hw - Struct containing variables accessed by shared code + * Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + */ +static s32 atl1_setup_link(struct atl1_hw *hw) +{ + s32 ret_val; + + /* + * Options: + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * no matter what autoneg is , We will not wait link result. + */ + ret_val = atl1_phy_setup_autoneg_adv(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error setting up autonegotiation\n", + atl1_driver_name); + return ret_val; + } + /* SW.Reset , En-Auto-Neg if needed */ + ret_val = atl1_phy_reset(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error resetting the phy\n", + atl1_driver_name); + return ret_val; + } + hw->phy_configured = true; + return ret_val; +} + +static struct atl1_spi_flash_dev flash_table[] = { +/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ + {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62}, + {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60}, + {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7}, +}; + +static void atl1_init_flash_opcode(struct atl1_hw *hw) +{ + if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + hw->flash_vendor = 0; /* ATMEL */ + + /* Init OP table */ + iowrite8(flash_table[hw->flash_vendor].cmd_program, + hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM); + iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase, + hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase, + hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_rdid, + hw->hw_addr + REG_SPI_FLASH_OP_RDID); + iowrite8(flash_table[hw->flash_vendor].cmd_wren, + hw->hw_addr + REG_SPI_FLASH_OP_WREN); + iowrite8(flash_table[hw->flash_vendor].cmd_rdsr, + hw->hw_addr + REG_SPI_FLASH_OP_RDSR); + iowrite8(flash_table[hw->flash_vendor].cmd_wrsr, + hw->hw_addr + REG_SPI_FLASH_OP_WRSR); + iowrite8(flash_table[hw->flash_vendor].cmd_read, + hw->hw_addr + REG_SPI_FLASH_OP_READ); +} + +/* + * Performs basic configuration of the adapter. + * hw - Struct containing variables accessed by shared code + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes multicast table, + * and Calls routines to setup link + * Leaves the transmit and receive units disabled and uninitialized. + */ +s32 atl1_init_hw(struct atl1_hw *hw) +{ + u32 ret_val = 0; + + /* Zero out the Multicast HASH table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + /* clear the old settings from the multicast hash table */ + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + atl1_init_flash_opcode(hw); + + if (!hw->phy_configured) { + /* enable GPHY LinkChange Interrrupt */ + ret_val = atl1_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + /* make PHY out of power-saving state */ + ret_val = atl1_phy_leave_power_saving(hw); + if (ret_val) + return ret_val; + /* Call a subroutine to configure the link */ + ret_val = atl1_setup_link(hw); + } + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + /* ; --- Read PHY Specific Status Register (17) */ + ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) + return ATL1_ERR_PHY_RES; + + switch (phy_data & MII_AT001_PSSR_SPEED) { + case MII_AT001_PSSR_1000MBS: + *speed = SPEED_1000; + break; + case MII_AT001_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_AT001_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + printk(KERN_DEBUG "%s: error getting speed\n", + atl1_driver_name); + return ATL1_ERR_PHY_SPEED; + break; + } + if (phy_data & MII_AT001_PSSR_DPLX) + *duplex = FULL_DUPLEX; + else + *duplex = HALF_DUPLEX; + + return ATL1_SUCCESS; +} + +void atl1_set_mac_addr(struct atl1_hw *hw) +{ + u32 value; + /* + * 00-0B-6A-F6-00-DC + * 0: 6AF600DC 1: 000B + * low dword + */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + /* high dword */ + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2)); +} diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h new file mode 100644 index 000000000000..100c09c66e64 --- /dev/null +++ b/drivers/net/atl1/atl1_hw.h @@ -0,0 +1,951 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. 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. + * + * There are a lot of defines in here that are unused and/or have cryptic + * names. Please leave them alone, as they're the closest thing we have + * to a spec from Attansic at present. *ahem* -- CHS + */ + +#ifndef _ATL1_HW_H_ +#define _ATL1_HW_H_ + +#include <linux/types.h> +#include <linux/mii.h> + +struct atl1_adapter; +struct atl1_hw; + +/* function prototypes needed by multiple files */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw); +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_read_mac_addr(struct atl1_hw *hw); +s32 atl1_init_hw(struct atl1_hw *hw); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex); +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr); +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value); +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data); +void atl1_set_mac_addr(struct atl1_hw *hw); +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw); +s32 atl1_reset_hw(struct atl1_hw *hw); +void atl1_check_options(struct atl1_adapter *adapter); + +/* register definitions */ +#define REG_PCIE_CAP_LIST 0x58 + +#define REG_VPD_CAP 0x6C +#define VPD_CAP_ID_MASK 0xff +#define VPD_CAP_ID_SHIFT 0 +#define VPD_CAP_NEXT_PTR_MASK 0xFF +#define VPD_CAP_NEXT_PTR_SHIFT 8 +#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +#define VPD_CAP_VPD_ADDR_SHIFT 16 +#define VPD_CAP_VPD_FLAG 0x80000000 + +#define REG_VPD_DATA 0x70 + +#define REG_SPI_FLASH_CTRL 0x200 +#define SPI_FLASH_CTRL_STS_NON_RDY 0x1 +#define SPI_FLASH_CTRL_STS_WEN 0x2 +#define SPI_FLASH_CTRL_STS_WPEN 0x80 +#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF +#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0 +#define SPI_FLASH_CTRL_INS_MASK 0x7 +#define SPI_FLASH_CTRL_INS_SHIFT 8 +#define SPI_FLASH_CTRL_START 0x800 +#define SPI_FLASH_CTRL_EN_VPD 0x2000 +#define SPI_FLASH_CTRL_LDSTART 0x8000 +#define SPI_FLASH_CTRL_CS_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HI_SHIFT 16 +#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18 +#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20 +#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22 +#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3 +#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24 +#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3 +#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26 +#define SPI_FLASH_CTRL_WAIT_READY 0x10000000 + +#define REG_SPI_ADDR 0x204 + +#define REG_SPI_DATA 0x208 + +#define REG_SPI_FLASH_CONFIG 0x20C +#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF +#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0 +#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3 +#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24 +#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000 + +#define REG_SPI_FLASH_OP_PROGRAM 0x210 +#define REG_SPI_FLASH_OP_SC_ERASE 0x211 +#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212 +#define REG_SPI_FLASH_OP_RDID 0x213 +#define REG_SPI_FLASH_OP_WREN 0x214 +#define REG_SPI_FLASH_OP_RDSR 0x215 +#define REG_SPI_FLASH_OP_WRSR 0x216 +#define REG_SPI_FLASH_OP_READ 0x217 + +#define REG_TWSI_CTRL 0x218 +#define TWSI_CTRL_LD_OFFSET_MASK 0xFF +#define TWSI_CTRL_LD_OFFSET_SHIFT 0 +#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +#define TWSI_CTRL_SW_LDSTART 0x800 +#define TWSI_CTRL_HW_LDSTART 0x1000 +#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F +#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +#define TWSI_CTRL_LD_EXIST 0x400000 +#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +#define TWSI_CTRL_FREQ_SEL_100K 0 +#define TWSI_CTRL_FREQ_SEL_200K 1 +#define TWSI_CTRL_FREQ_SEL_300K 2 +#define TWSI_CTRL_FREQ_SEL_400K 3 +#define TWSI_CTRL_SMB_SLV_ADDR +#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 + +#define REG_PCIE_DEV_MISC_CTRL 0x21C +#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2 +#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1 +#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4 +#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8 +#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10 + +/* Selene Master Control Register */ +#define REG_MASTER_CTRL 0x1400 +#define MASTER_CTRL_SOFT_RST 0x1 +#define MASTER_CTRL_MTIMER_EN 0x2 +#define MASTER_CTRL_ITIMER_EN 0x4 +#define MASTER_CTRL_MANUAL_INT 0x8 +#define MASTER_CTRL_REV_NUM_SHIFT 16 +#define MASTER_CTRL_REV_NUM_MASK 0xff +#define MASTER_CTRL_DEV_ID_SHIFT 24 +#define MASTER_CTRL_DEV_ID_MASK 0xff + +/* Timer Initial Value Register */ +#define REG_MANUAL_TIMER_INIT 0x1404 + +/* IRQ ModeratorTimer Initial Value Register */ +#define REG_IRQ_MODU_TIMER_INIT 0x1408 + +#define REG_GPHY_ENABLE 0x140C + +/* IRQ Anti-Lost Timer Initial Value Register */ +#define REG_CMBDISDMA_TIMER 0x140E + +/* Block IDLE Status Register */ +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_RXMAC 1 +#define IDLE_STATUS_TXMAC 2 +#define IDLE_STATUS_RXQ 4 +#define IDLE_STATUS_TXQ 8 +#define IDLE_STATUS_DMAR 0x10 +#define IDLE_STATUS_DMAW 0x20 +#define IDLE_STATUS_SMB 0x40 +#define IDLE_STATUS_CMB 0x80 + +/* MDIO Control Register */ +#define REG_MDIO_CTRL 0x1414 +#define MDIO_DATA_MASK 0xffff +#define MDIO_DATA_SHIFT 0 +#define MDIO_REG_ADDR_MASK 0x1f +#define MDIO_REG_ADDR_SHIFT 16 +#define MDIO_RW 0x200000 +#define MDIO_SUP_PREAMBLE 0x400000 +#define MDIO_START 0x800000 +#define MDIO_CLK_SEL_SHIFT 24 +#define MDIO_CLK_25_4 0 +#define MDIO_CLK_25_6 2 +#define MDIO_CLK_25_8 3 +#define MDIO_CLK_25_10 4 +#define MDIO_CLK_25_14 5 +#define MDIO_CLK_25_20 6 +#define MDIO_CLK_25_28 7 +#define MDIO_BUSY 0x8000000 +#define MDIO_WAIT_TIMES 30 + +/* MII PHY Status Register */ +#define REG_PHY_STATUS 0x1418 + +/* BIST Control and Status Register0 (for the Packet Memory) */ +#define REG_BIST0_CTRL 0x141c +#define BIST0_NOW 0x1 +#define BIST0_SRAM_FAIL 0x2 +#define BIST0_FUSE_FLAG 0x4 +#define REG_BIST1_CTRL 0x1420 +#define BIST1_NOW 0x1 +#define BIST1_SRAM_FAIL 0x2 +#define BIST1_FUSE_FLAG 0x4 + +/* MAC Control Register */ +#define REG_MAC_CTRL 0x1480 +#define MAC_CTRL_TX_EN 1 +#define MAC_CTRL_RX_EN 2 +#define MAC_CTRL_TX_FLOW 4 +#define MAC_CTRL_RX_FLOW 8 +#define MAC_CTRL_LOOPBACK 0x10 +#define MAC_CTRL_DUPLX 0x20 +#define MAC_CTRL_ADD_CRC 0x40 +#define MAC_CTRL_PAD 0x80 +#define MAC_CTRL_LENCHK 0x100 +#define MAC_CTRL_HUGE_EN 0x200 +#define MAC_CTRL_PRMLEN_SHIFT 10 +#define MAC_CTRL_PRMLEN_MASK 0xf +#define MAC_CTRL_RMV_VLAN 0x4000 +#define MAC_CTRL_PROMIS_EN 0x8000 +#define MAC_CTRL_TX_PAUSE 0x10000 +#define MAC_CTRL_SCNT 0x20000 +#define MAC_CTRL_SRST_TX 0x40000 +#define MAC_CTRL_TX_SIMURST 0x80000 +#define MAC_CTRL_SPEED_SHIFT 20 +#define MAC_CTRL_SPEED_MASK 0x300000 +#define MAC_CTRL_SPEED_1000 2 +#define MAC_CTRL_SPEED_10_100 1 +#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 +#define MAC_CTRL_TX_HUGE 0x800000 +#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 +#define MAC_CTRL_MC_ALL_EN 0x2000000 +#define MAC_CTRL_BC_EN 0x4000000 +#define MAC_CTRL_DBG 0x8000000 + +/* MAC IPG/IFG Control Register */ +#define REG_MAC_IPG_IFG 0x1484 +#define MAC_IPG_IFG_IPGT_SHIFT 0 +#define MAC_IPG_IFG_IPGT_MASK 0x7f +#define MAC_IPG_IFG_MIFG_SHIFT 8 +#define MAC_IPG_IFG_MIFG_MASK 0xff +#define MAC_IPG_IFG_IPGR1_SHIFT 16 +#define MAC_IPG_IFG_IPGR1_MASK 0x7f +#define MAC_IPG_IFG_IPGR2_SHIFT 24 +#define MAC_IPG_IFG_IPGR2_MASK 0x7f + +/* MAC STATION ADDRESS */ +#define REG_MAC_STA_ADDR 0x1488 + +/* Hash table for multicast address */ +#define REG_RX_HASH_TABLE 0x1490 + +/* MAC Half-Duplex Control Register */ +#define REG_MAC_HALF_DUPLX_CTRL 0x1498 +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12 +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 +#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf + +/* Maximum Frame Length Control Register */ +#define REG_MTU 0x149c + +/* Wake-On-Lan control register */ +#define REG_WOL_CTRL 0x14a0 +#define WOL_PATTERN_EN 0x00000001 +#define WOL_PATTERN_PME_EN 0x00000002 +#define WOL_MAGIC_EN 0x00000004 +#define WOL_MAGIC_PME_EN 0x00000008 +#define WOL_LINK_CHG_EN 0x00000010 +#define WOL_LINK_CHG_PME_EN 0x00000020 +#define WOL_PATTERN_ST 0x00000100 +#define WOL_MAGIC_ST 0x00000200 +#define WOL_LINKCHG_ST 0x00000400 +#define WOL_CLK_SWITCH_EN 0x00008000 +#define WOL_PT0_EN 0x00010000 +#define WOL_PT1_EN 0x00020000 +#define WOL_PT2_EN 0x00040000 +#define WOL_PT3_EN 0x00080000 +#define WOL_PT4_EN 0x00100000 +#define WOL_PT5_EN 0x00200000 +#define WOL_PT6_EN 0x00400000 + +/* WOL Length ( 2 DWORD ) */ +#define REG_WOL_PATTERN_LEN 0x14a4 +#define WOL_PT_LEN_MASK 0x7f +#define WOL_PT0_LEN_SHIFT 0 +#define WOL_PT1_LEN_SHIFT 8 +#define WOL_PT2_LEN_SHIFT 16 +#define WOL_PT3_LEN_SHIFT 24 +#define WOL_PT4_LEN_SHIFT 0 +#define WOL_PT5_LEN_SHIFT 8 +#define WOL_PT6_LEN_SHIFT 16 + +/* Internal SRAM Partition Register */ +#define REG_SRAM_RFD_ADDR 0x1500 +#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4) +#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8) +#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12) +#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16) +#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20) +#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24) +#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28) +#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32) +#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36) +#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40) +#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44) +#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48) +#define SRAM_TCPH_ADDR_MASK 0x0fff +#define SRAM_TCPH_ADDR_SHIFT 0 +#define SRAM_PATH_ADDR_MASK 0x0fff +#define SRAM_PATH_ADDR_SHIFT 16 + +/* Load Ptr Register */ +#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52) + +/* Descriptor Control register */ +#define REG_DESC_BASE_ADDR_HI 0x1540 +#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4) +#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8) +#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12) +#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16) +#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20) +#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24) +#define DESC_RFD_RING_SIZE_MASK 0x7ff +#define DESC_RFD_RING_SIZE_SHIFT 0 +#define DESC_RRD_RING_SIZE_MASK 0x7ff +#define DESC_RRD_RING_SIZE_SHIFT 16 +#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28) +#define DESC_TPD_RING_SIZE_MASK 0x3ff +#define DESC_TPD_RING_SIZE_SHIFT 0 + +/* TXQ Control Register */ +#define REG_TXQ_CTRL 0x1580 +#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0 +#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f +#define TXQ_CTRL_EN 0x20 +#define TXQ_CTRL_ENH_MODE 0x40 +#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8 +#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f +#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16 +#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff + +/* Jumbo packet Threshold for task offload */ +#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584 +#define TX_JUMBO_TASK_TH_MASK 0x7ff +#define TX_JUMBO_TASK_TH_SHIFT 0 +#define TX_TPD_MIN_IPG_MASK 0x1f +#define TX_TPD_MIN_IPG_SHIFT 16 + +/* RXQ Control Register */ +#define REG_RXQ_CTRL 0x15a0 +#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0 +#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff +#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8 +#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff +#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16 +#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f +#define RXQ_CTRL_CUT_THRU_EN 0x40000000 +#define RXQ_CTRL_EN 0x80000000 + +/* Rx jumbo packet threshold and rrd retirement timer */ +#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4) +#define RXQ_JMBOSZ_TH_MASK 0x7ff +#define RXQ_JMBOSZ_TH_SHIFT 0 +#define RXQ_JMBO_LKAH_MASK 0xf +#define RXQ_JMBO_LKAH_SHIFT 11 +#define RXQ_RRD_TIMER_MASK 0xffff +#define RXQ_RRD_TIMER_SHIFT 16 + +/* RFD flow control register */ +#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8) +#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16 +#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0 +#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff + +/* RRD flow control register */ +#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12) +#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0 +#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16 +#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff + +/* DMA Engine Control Register */ +#define REG_DMA_CTRL 0x15c0 +#define DMA_CTRL_DMAR_IN_ORDER 0x1 +#define DMA_CTRL_DMAR_ENH_ORDER 0x2 +#define DMA_CTRL_DMAR_OUT_ORDER 0x4 +#define DMA_CTRL_RCB_VALUE 0x8 +#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 +#define DMA_CTRL_DMAR_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 +#define DMA_CTRL_DMAW_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAR_EN 0x400 +#define DMA_CTRL_DMAW_EN 0x800 + +/* CMB/SMB Control Register */ +#define REG_CSMB_CTRL 0x15d0 +#define CSMB_CTRL_CMB_NOW 1 +#define CSMB_CTRL_SMB_NOW 2 +#define CSMB_CTRL_CMB_EN 4 +#define CSMB_CTRL_SMB_EN 8 + +/* CMB DMA Write Threshold Register */ +#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4) +#define CMB_RRD_TH_SHIFT 0 +#define CMB_RRD_TH_MASK 0x7ff +#define CMB_TPD_TH_SHIFT 16 +#define CMB_TPD_TH_MASK 0x7ff + +/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */ +#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8) +#define CMB_RX_TM_SHIFT 0 +#define CMB_RX_TM_MASK 0xffff +#define CMB_TX_TM_SHIFT 16 +#define CMB_TX_TM_MASK 0xffff + +/* Number of packet received since last CMB write */ +#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12) + +/* Number of packet transmitted since last CMB write */ +#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16) + +/* SMB auto DMA timer register */ +#define REG_SMB_TIMER (REG_CSMB_CTRL+20) + +/* Mailbox Register */ +#define REG_MAILBOX 0x15f0 +#define MB_RFD_PROD_INDX_SHIFT 0 +#define MB_RFD_PROD_INDX_MASK 0x7ff +#define MB_RRD_CONS_INDX_SHIFT 11 +#define MB_RRD_CONS_INDX_MASK 0x7ff +#define MB_TPD_PROD_INDX_SHIFT 22 +#define MB_TPD_PROD_INDX_MASK 0x3ff + +/* Interrupt Status Register */ +#define REG_ISR 0x1600 +#define ISR_SMB 1 +#define ISR_TIMER 2 +#define ISR_MANUAL 4 +#define ISR_RXF_OV 8 +#define ISR_RFD_UNRUN 0x10 +#define ISR_RRD_OV 0x20 +#define ISR_TXF_UNRUN 0x40 +#define ISR_LINK 0x80 +#define ISR_HOST_RFD_UNRUN 0x100 +#define ISR_HOST_RRD_OV 0x200 +#define ISR_DMAR_TO_RST 0x400 +#define ISR_DMAW_TO_RST 0x800 +#define ISR_GPHY 0x1000 +#define ISR_RX_PKT 0x10000 +#define ISR_TX_PKT 0x20000 +#define ISR_TX_DMA 0x40000 +#define ISR_RX_DMA 0x80000 +#define ISR_CMB_RX 0x100000 +#define ISR_CMB_TX 0x200000 +#define ISR_MAC_RX 0x400000 +#define ISR_MAC_TX 0x800000 +#define ISR_UR_DETECTED 0x1000000 +#define ISR_FERR_DETECTED 0x2000000 +#define ISR_NFERR_DETECTED 0x4000000 +#define ISR_CERR_DETECTED 0x8000000 +#define ISR_PHY_LINKDOWN 0x10000000 +#define ISR_DIS_SMB 0x20000000 +#define ISR_DIS_DMA 0x40000000 +#define ISR_DIS_INT 0x80000000 + +/* Interrupt Mask Register */ +#define REG_IMR 0x1604 + +/* Normal Interrupt mask */ +#define IMR_NORMAL_MASK (\ + ISR_SMB |\ + ISR_GPHY |\ + ISR_PHY_LINKDOWN|\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_CMB_TX |\ + ISR_CMB_RX ) + +/* Debug Interrupt Mask (enable all interrupt) */ +#define IMR_DEBUG_MASK (\ + ISR_SMB |\ + ISR_TIMER |\ + ISR_MANUAL |\ + ISR_RXF_OV |\ + ISR_RFD_UNRUN |\ + ISR_RRD_OV |\ + ISR_TXF_UNRUN |\ + ISR_LINK |\ + ISR_CMB_TX |\ + ISR_CMB_RX |\ + ISR_RX_PKT |\ + ISR_TX_PKT |\ + ISR_MAC_RX |\ + ISR_MAC_TX ) + +/* Interrupt Status Register */ +#define REG_RFD_RRD_IDX 0x1800 +#define REG_TPD_IDX 0x1804 + +/* MII definition */ +/* PHY Common Register */ +#define MII_AT001_CR 0x09 +#define MII_AT001_SR 0x0A +#define MII_AT001_ESR 0x0F +#define MII_AT001_PSCR 0x10 +#define MII_AT001_PSSR 0x11 + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_MASK 0x2040 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Link partner ability register. */ +#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ +#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ +#define MII_LPA_PAUSE 0x0400 /* PAUSE */ +#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ +#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ +#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ +#define MII_LPA_NPAGE 0x8000 /* Next page bit */ + +/* Autoneg Advertisement Register */ +#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ +#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ +#define MII_AR_SPEED_MASK 0x01E0 +#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 + +/* 1000BASE-T Control Register */ +#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */ +#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */ +#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */ +#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ +#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 + +/* 1000BASE-T Status Register */ +#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +/* AT001 PHY Specific Control Register */ +#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008 +#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */ +#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */ +#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */ +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */ +#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5 +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* AT001 PHY Specific Status Register */ +#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 /* PCI Command Register */ +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +/* Wake Up Filter Control */ +#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */ +#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Error Codes */ +#define ATL1_SUCCESS 0 +#define ATL1_ERR_EEPROM 1 +#define ATL1_ERR_PHY 2 +#define ATL1_ERR_CONFIG 3 +#define ATL1_ERR_PARAM 4 +#define ATL1_ERR_MAC_TYPE 5 +#define ATL1_ERR_PHY_TYPE 6 +#define ATL1_ERR_PHY_SPEED 7 +#define ATL1_ERR_PHY_RES 8 + +#define SPEED_0 0xffff +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define MEDIA_TYPE_AUTO_SENSOR 0 +#define MEDIA_TYPE_1000M_FULL 1 +#define MEDIA_TYPE_100M_FULL 2 +#define MEDIA_TYPE_100M_HALF 3 +#define MEDIA_TYPE_10M_FULL 4 +#define MEDIA_TYPE_10M_HALF 5 + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2800 + +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ + +/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */ +#define EEPROM_SUM 0xBABA + +#define ATL1_EEDUMP_LEN 48 + +/* Statistics counters collected by the MAC */ +struct stats_msg_block { + /* rx */ + u32 rx_ok; /* The number of good packet received. */ + u32 rx_bcast; /* The number of good broadcast packet received. */ + u32 rx_mcast; /* The number of good multicast packet received. */ + u32 rx_pause; /* The number of Pause packet received. */ + u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */ + u32 rx_fcs_err; /* The number of packets with bad FCS. */ + u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */ + u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */ + u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */ + u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */ + u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */ + u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */ + u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */ + u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */ + u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */ + u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */ + u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */ + u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */ + u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */ + u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */ + u32 rx_align_err; /* Alignment Error */ + u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */ + u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */ + u32 rx_err_addr; /* The number of packets dropped due to address filtering. */ + + /* tx */ + u32 tx_ok; /* The number of good packet transmitted. */ + u32 tx_bcast; /* The number of good broadcast packet transmitted. */ + u32 tx_mcast; /* The number of good multicast packet transmitted. */ + u32 tx_pause; /* The number of Pause packet transmitted. */ + u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */ + u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */ + u32 tx_defer; /* The number of packets transmitted that is deferred. */ + u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */ + u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */ + u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */ + u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */ + u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */ + u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */ + u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */ + u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */ + u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */ + u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */ + u32 tx_late_col; /* The number of packets transmitted with late collisions. */ + u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */ + u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */ + u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */ + u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */ + u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */ + u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */ + u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update. + * Software should clear this bit as soon as retrieving the statistics information. */ +}; + +/* Coalescing Message Block */ +struct coals_msg_block { + u32 int_stats; /* interrupt status */ + u16 rrd_prod_idx; /* TRD Producer Index. */ + u16 rfd_cons_idx; /* RFD Consumer Index. */ + u16 update; /* Selene sets this bit every time it DMA the CMB to host memory. + * Software supposes to clear this bit when CMB information is processed. */ + u16 tpd_cons_idx; /* TPD Consumer Index. */ +}; + +/* RRD descriptor */ +struct rx_return_desc { + u8 num_buf; /* Number of RFD buffers used by the received packet */ + u8 resved; + u16 buf_indx; /* RFD Index of the first buffer */ + union { + u32 valid; + struct { + u16 rx_chksum; + u16 pkt_size; + } xsum_sz; + } xsz; + + u16 pkt_flg; /* Packet flags */ + u16 err_flg; /* Error flags */ + u16 resved2; + u16 vlan_tag; /* VLAN TAG */ +}; + +#define PACKET_FLAG_ETH_TYPE 0x0080 +#define PACKET_FLAG_VLAN_INS 0x0100 +#define PACKET_FLAG_ERR 0x0200 +#define PACKET_FLAG_IPV4 0x0400 +#define PACKET_FLAG_UDP 0x0800 +#define PACKET_FLAG_TCP 0x1000 +#define PACKET_FLAG_BCAST 0x2000 +#define PACKET_FLAG_MCAST 0x4000 +#define PACKET_FLAG_PAUSE 0x8000 + +#define ERR_FLAG_CRC 0x0001 +#define ERR_FLAG_CODE 0x0002 +#define ERR_FLAG_DRIBBLE 0x0004 +#define ERR_FLAG_RUNT 0x0008 +#define ERR_FLAG_OV 0x0010 +#define ERR_FLAG_TRUNC 0x0020 +#define ERR_FLAG_IP_CHKSUM 0x0040 +#define ERR_FLAG_L4_CHKSUM 0x0080 +#define ERR_FLAG_LEN 0x0100 +#define ERR_FLAG_DES_ADDR 0x0200 + +/* RFD descriptor */ +struct rx_free_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 buf_len; /* Size of the receive buffer in host memory, in byte */ + u16 coalese; /* Update consumer index to host after the reception of this frame */ + /* __attribute__ ((packed)) is required */ +} __attribute__ ((packed)); + +/* tsopu defines */ +#define TSO_PARAM_BUFLEN_MASK 0x3FFF +#define TSO_PARAM_BUFLEN_SHIFT 0 +#define TSO_PARAM_DMAINT_MASK 0x0001 +#define TSO_PARAM_DMAINT_SHIFT 14 +#define TSO_PARAM_PKTNT_MASK 0x0001 +#define TSO_PARAM_PKTINT_SHIFT 15 +#define TSO_PARAM_VLANTAG_MASK 0xFFFF +#define TSO_PARAM_VLAN_SHIFT 16 + +/* tsopl defines */ +#define TSO_PARAM_EOP_MASK 0x0001 +#define TSO_PARAM_EOP_SHIFT 0 +#define TSO_PARAM_COALESCE_MASK 0x0001 +#define TSO_PARAM_COALESCE_SHIFT 1 +#define TSO_PARAM_INSVLAG_MASK 0x0001 +#define TSO_PARAM_INSVLAG_SHIFT 2 +#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3 +#define TSO_PARAM_SEGMENT_MASK 0x0001 +#define TSO_PARAM_SEGMENT_SHIFT 4 +#define TSO_PARAM_IPCKSUM_MASK 0x0001 +#define TSO_PARAM_IPCKSUM_SHIFT 5 +#define TSO_PARAM_TCPCKSUM_MASK 0x0001 +#define TSO_PARAM_TCPCKSUM_SHIFT 6 +#define TSO_PARAM_UDPCKSUM_MASK 0x0001 +#define TSO_PARAM_UDPCKSUM_SHIFT 7 +#define TSO_PARAM_VLANTAGGED_MASK 0x0001 +#define TSO_PARAM_VLANTAGGED_SHIFT 8 +#define TSO_PARAM_ETHTYPE_MASK 0x0001 +#define TSO_PARAM_ETHTYPE_SHIFT 9 +#define TSO_PARAM_IPHL_MASK 0x000F +#define TSO_PARAM_IPHL_SHIFT 10 +#define TSO_PARAM_TCPHDRLEN_MASK 0x000F +#define TSO_PARAM_TCPHDRLEN_SHIFT 14 +#define TSO_PARAM_HDRFLAG_MASK 0x0001 +#define TSO_PARAM_HDRFLAG_SHIFT 18 +#define TSO_PARAM_MSS_MASK 0x1FFF +#define TSO_PARAM_MSS_SHIFT 19 + +/* csumpu defines */ +#define CSUM_PARAM_BUFLEN_MASK 0x3FFF +#define CSUM_PARAM_BUFLEN_SHIFT 0 +#define CSUM_PARAM_DMAINT_MASK 0x0001 +#define CSUM_PARAM_DMAINT_SHIFT 14 +#define CSUM_PARAM_PKTINT_MASK 0x0001 +#define CSUM_PARAM_PKTINT_SHIFT 15 +#define CSUM_PARAM_VALANTAG_MASK 0xFFFF +#define CSUM_PARAM_VALAN_SHIFT 16 + +/* csumpl defines*/ +#define CSUM_PARAM_EOP_MASK 0x0001 +#define CSUM_PARAM_EOP_SHIFT 0 +#define CSUM_PARAM_COALESCE_MASK 0x0001 +#define CSUM_PARAM_COALESCE_SHIFT 1 +#define CSUM_PARAM_INSVLAG_MASK 0x0001 +#define CSUM_PARAM_INSVLAG_SHIFT 2 +#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3 +#define CSUM_PARAM_SEGMENT_MASK 0x0001 +#define CSUM_PARAM_SEGMENT_SHIFT 4 +#define CSUM_PARAM_IPCKSUM_MASK 0x0001 +#define CSUM_PARAM_IPCKSUM_SHIFT 5 +#define CSUM_PARAM_TCPCKSUM_MASK 0x0001 +#define CSUM_PARAM_TCPCKSUM_SHIFT 6 +#define CSUM_PARAM_UDPCKSUM_MASK 0x0001 +#define CSUM_PARAM_UDPCKSUM_SHIFT 7 +#define CSUM_PARAM_VLANTAGGED_MASK 0x0001 +#define CSUM_PARAM_VLANTAGGED_SHIFT 8 +#define CSUM_PARAM_ETHTYPE_MASK 0x0001 +#define CSUM_PARAM_ETHTYPE_SHIFT 9 +#define CSUM_PARAM_IPHL_MASK 0x000F +#define CSUM_PARAM_IPHL_SHIFT 10 +#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF +#define CSUM_PARAM_PLOADOFFSET_SHIFT 16 +#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF +#define CSUM_PARAM_XSUMOFFSET_SHIFT 24 + +/* TPD descriptor */ +struct tso_param { + /* The order of these declarations is important -- don't change it */ + u32 tsopu; /* tso_param upper word */ + u32 tsopl; /* tso_param lower word */ +}; + +struct csum_param { + /* The order of these declarations is important -- don't change it */ + u32 csumpu; /* csum_param upper word */ + u32 csumpl; /* csum_param lower word */ +}; + +union tpd_descr { + u64 data; + struct csum_param csum; + struct tso_param tso; +}; + +struct tx_packet_desc { + __le64 buffer_addr; + union tpd_descr desc; +}; + +/* DMA Order Settings */ +enum atl1_dma_order { + atl1_dma_ord_in = 1, + atl1_dma_ord_enh = 2, + atl1_dma_ord_out = 4 +}; + +enum atl1_dma_rcb { + atl1_rcb_64 = 0, + atl1_rcb_128 = 1 +}; + +enum atl1_dma_req_block { + atl1_dma_req_128 = 0, + atl1_dma_req_256 = 1, + atl1_dma_req_512 = 2, + atl1_dam_req_1024 = 3, + atl1_dam_req_2048 = 4, + atl1_dma_req_4096 = 5 +}; + +struct atl1_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmd_wrsr; + u8 cmd_read; + u8 cmd_program; + u8 cmd_wren; + u8 cmd_wrdi; + u8 cmd_rdsr; + u8 cmd_rdid; + u8 cmd_sector_erase; + u8 cmd_chip_erase; +}; + +#endif /* _ATL1_HW_H_ */ diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c new file mode 100644 index 000000000000..6655640eb4ca --- /dev/null +++ b/drivers/net/atl1/atl1_main.c @@ -0,0 +1,2468 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. 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. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + * + * Contact Information: + * Xiong Huang <xiong_huang@attansic.com> + * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei, + * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA + * + * Chris Snook <csnook@redhat.com> + * Jay Cliburn <jcliburn@gmail.com> + * + * This version is adapted from the Attansic reference driver for + * inclusion in the Linux kernel. It is currently under heavy development. + * A very incomplete list of things that need to be dealt with: + * + * TODO: + * Fix TSO; tx performance is horrible with TSO enabled. + * Wake on LAN. + * Add more ethtool functions, including set ring parameters. + * Fix abstruse irq enable/disable condition described here: + * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 + * + * NEEDS TESTING: + * VLAN + * multicast + * promiscuous mode + * interrupt coalescing + * SMP torture testing + */ + +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/if_vlan.h> +#include <linux/irqreturn.h> +#include <linux/workqueue.h> +#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h> +#include <linux/irqflags.h> +#include <linux/dma-mapping.h> +#include <linux/net.h> +#include <linux/pm.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/compiler.h> +#include <linux/delay.h> +#include <linux/mii.h> +#include <net/checksum.h> + +#include <asm/atomic.h> +#include <asm/byteorder.h> + +#include "atl1.h" + +#define RUN_REALTIME 0 +#define DRIVER_VERSION "2.0.6" + +char atl1_driver_name[] = "atl1"; +static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; +static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation."; +char atl1_driver_version[] = DRIVER_VERSION; + +MODULE_AUTHOR + ("Attansic Corporation <xiong_huang@attansic.com>, Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>"); +MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/* + * atl1_pci_tbl - PCI Device ID Table + */ +static const struct pci_device_id atl1_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, atl1_pci_tbl); + +/* + * atl1_sw_init - Initialize general software structures (struct atl1_adapter) + * @adapter: board private structure to initialize + * + * atl1_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + */ +static int __devinit atl1_sw_init(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + + hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; + + adapter->wol = 0; + adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7; + adapter->ict = 50000; /* 100ms */ + adapter->link_speed = SPEED_0; /* hardware init */ + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->rfd_burst = 8; + hw->rrd_burst = 8; + hw->rfd_fetch_gap = 1; + hw->rx_jumbo_th = adapter->rx_buffer_len / 8; + hw->rx_jumbo_lkah = 1; + hw->rrd_ret_timer = 16; + hw->tpd_burst = 4; + hw->tpd_fetch_th = 16; + hw->txf_burst = 0x100; + hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3; + hw->tpd_fetch_gap = 1; + hw->rcb_value = atl1_rcb_64; + hw->dma_ord = atl1_dma_ord_enh; + hw->dmar_block = atl1_dma_req_256; + hw->dmaw_block = atl1_dma_req_256; + hw->cmb_rrd = 4; + hw->cmb_tpd = 4; + hw->cmb_rx_timer = 1; /* about 2us */ + hw->cmb_tx_timer = 1; /* about 2us */ + hw->smb_timer = 100000; /* about 200ms */ + + atomic_set(&adapter->irq_sem, 0); + spin_lock_init(&adapter->lock); + spin_lock_init(&adapter->mb_lock); + + return 0; +} + +/* + * atl1_setup_mem_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count); + tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); + if (unlikely(!tpd_ring->buffer_info)) { + printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + rfd_ring->buffer_info = + (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + + /* real ring DMA buffer */ + ring_header->size = size = sizeof(struct tx_packet_desc) * + tpd_ring->count + + sizeof(struct rx_free_desc) * rfd_ring->count + + sizeof(struct rx_return_desc) * rrd_ring->count + + sizeof(struct coals_msg_block) + + sizeof(struct stats_msg_block) + + 40; /* "40: for 8 bytes align" huh? -- CHS */ + + ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, + &ring_header->dma); + if (unlikely(!ring_header->desc)) { + printk(KERN_WARNING + "%s: pci_alloc_consistent failed, size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + + memset(ring_header->desc, 0, ring_header->size); + + /* init TPD ring */ + tpd_ring->dma = ring_header->dma; + offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0; + tpd_ring->dma += offset; + tpd_ring->desc = (u8 *) ring_header->desc + offset; + tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count; + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); + + /* init RFD ring */ + rfd_ring->dma = tpd_ring->dma + tpd_ring->size; + offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0; + rfd_ring->dma += offset; + rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset); + rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count; + rfd_ring->next_to_clean = 0; + /* rfd_ring->next_to_use = rfd_ring->count - 1; */ + atomic_set(&rfd_ring->next_to_use, 0); + + /* init RRD ring */ + rrd_ring->dma = rfd_ring->dma + rfd_ring->size; + offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0; + rrd_ring->dma += offset; + rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset); + rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count; + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); + + /* init CMB */ + adapter->cmb.dma = rrd_ring->dma + rrd_ring->size; + offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0; + adapter->cmb.dma += offset; + adapter->cmb.cmb = + (struct coals_msg_block *) ((u8 *) rrd_ring->desc + + (rrd_ring->size + offset)); + + /* init SMB */ + adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block); + offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0; + adapter->smb.dma += offset; + adapter->smb.smb = (struct stats_msg_block *) + ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset)); + + return ATL1_SUCCESS; + +err_nomem: + kfree(tpd_ring->buffer_info); + return -ENOMEM; +} + +/* + * atl1_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void atl1_irq_enable(struct atl1_adapter *adapter) +{ + if (likely(!atomic_dec_and_test(&adapter->irq_sem))) + iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); +} + +static void atl1_clear_phy_int(struct atl1_adapter *adapter) +{ + u16 phy_data; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static void atl1_inc_smb(struct atl1_adapter *adapter) +{ + struct stats_msg_block *smb = adapter->smb.smb; + + /* Fill out the OS statistics structure */ + adapter->soft_stats.rx_packets += smb->rx_ok; + adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; + adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; + adapter->soft_stats.multicast += smb->rx_mcast; + adapter->soft_stats.collisions += (smb->tx_1_col + + smb->tx_2_col * 2 + + smb->tx_late_col + + smb->tx_abort_col * + adapter->hw.max_retry); + + /* Rx Errors */ + adapter->soft_stats.rx_errors += (smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; + adapter->soft_stats.rx_length_errors += smb->rx_len_err; + adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; + adapter->soft_stats.rx_frame_errors += smb->rx_align_err; + adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + + smb->rx_rxf_ov); + + adapter->soft_stats.rx_pause += smb->rx_pause; + adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; + adapter->soft_stats.rx_trunc += smb->rx_sz_ov; + + /* Tx Errors */ + adapter->soft_stats.tx_errors += (smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; + adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; + adapter->soft_stats.tx_window_errors += smb->tx_late_col; + + adapter->soft_stats.excecol += smb->tx_abort_col; + adapter->soft_stats.deffer += smb->tx_defer; + adapter->soft_stats.scc += smb->tx_1_col; + adapter->soft_stats.mcc += smb->tx_2_col; + adapter->soft_stats.latecol += smb->tx_late_col; + adapter->soft_stats.tx_underun += smb->tx_underrun; + adapter->soft_stats.tx_trunc += smb->tx_trunc; + adapter->soft_stats.tx_pause += smb->tx_pause; + + adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; + adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; + adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; + adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; + adapter->net_stats.multicast = adapter->soft_stats.multicast; + adapter->net_stats.collisions = adapter->soft_stats.collisions; + adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; + adapter->net_stats.rx_over_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.rx_length_errors = + adapter->soft_stats.rx_length_errors; + adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + adapter->net_stats.rx_frame_errors = + adapter->soft_stats.rx_frame_errors; + adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + adapter->net_stats.rx_missed_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; + adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + adapter->net_stats.tx_aborted_errors = + adapter->soft_stats.tx_aborted_errors; + adapter->net_stats.tx_window_errors = + adapter->soft_stats.tx_window_errors; + adapter->net_stats.tx_carrier_errors = + adapter->soft_stats.tx_carrier_errors; +} + +static void atl1_rx_checksum(struct atl1_adapter *adapter, + struct rx_return_desc *rrd, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | + ERR_FLAG_CODE | ERR_FLAG_OV)) { + adapter->hw_csum_err++; + printk(KERN_DEBUG "%s: rx checksum error\n", + atl1_driver_name); + return; + } + } + + /* not IPv4 */ + if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) + /* checksum is invalid, but it's not an IPv4 pkt, so ok */ + return; + + /* IPv4 packet */ + if (likely(!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + return; + } + + /* IPv4, but hardware thinks its checksum is wrong */ + printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n", + atl1_driver_name, rrd->pkt_flg, rrd->err_flg); + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); + adapter->hw_csum_err++; + return; +} + +/* + * atl1_alloc_rx_buffers - Replace used receive buffers + * @adapter: address of board private structure + */ +static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct page *page; + unsigned long offset; + struct atl1_buffer *buffer_info, *next_info; + struct sk_buff *skb; + u16 num_alloc = 0; + u16 rfd_next_to_use, next_next; + struct rx_free_desc *rfd_desc; + + next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use); + if (++next_next == rfd_ring->count) + next_next = 0; + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + + while (!buffer_info->alloced && !next_info->alloced) { + if (buffer_info->skb) { + buffer_info->alloced = 1; + goto next; + } + + rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); + + skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + if (unlikely(!skb)) { /* Better luck next round */ + adapter->net_stats.rx_dropped++; + break; + } + + /* + * Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + skb->dev = netdev; + + buffer_info->alloced = 1; + buffer_info->skb = skb; + buffer_info->length = (u16) adapter->rx_buffer_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(pdev, page, offset, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len); + rfd_desc->coalese = 0; + +next: + rfd_next_to_use = next_next; + if (unlikely(++next_next == rfd_ring->count)) + next_next = 0; + + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + num_alloc++; + } + + if (num_alloc) { + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use); + } + return num_alloc; +} + +static void atl1_intr_rx(struct atl1_adapter *adapter) +{ + int i, count; + u16 length; + u16 rrd_next_to_clean; + u32 value; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct rx_return_desc *rrd; + struct sk_buff *skb; + + count = 0; + + rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); + + while (1) { + rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); + i = 1; + if (likely(rrd->xsz.valid)) { /* packet valid */ +chk_rrd: + /* check rrd status */ + if (likely(rrd->num_buf == 1)) + goto rrd_ok; + + /* rrd seems to be bad */ + if (unlikely(i-- > 0)) { + /* rrd may not be DMAed completely */ + printk(KERN_DEBUG + "%s: RRD may not be DMAed completely\n", + atl1_driver_name); + udelay(1); + goto chk_rrd; + } + /* bad rrd */ + printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name); + /* see if update RFD index */ + if (rrd->num_buf > 1) { + u16 num_buf; + num_buf = + (rrd->xsz.xsum_sz.pkt_size + + adapter->rx_buffer_len - + 1) / adapter->rx_buffer_len; + if (rrd->num_buf == num_buf) { + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != + (rrd->buf_indx + num_buf)) { + rfd_ring->buffer_info[rfd_ring-> + next_to_clean].alloced = 0; + if (++rfd_ring->next_to_clean == + rfd_ring->count) { + rfd_ring-> + next_to_clean = 0; + } + } + } + } + + /* update rrd */ + rrd->xsz.valid = 0; + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + continue; + } else { /* current rrd still not be updated */ + + break; + } +rrd_ok: + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != rrd->buf_indx) { + rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = + 0; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + } + + buffer_info = &rfd_ring->buffer_info[rrd->buf_indx]; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + + /* update rrd next to clean */ + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM + | ERR_FLAG_LEN))) { + /* packet error, don't need upstream */ + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + continue; + } + } + + /* Good Receive */ + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); + skb = buffer_info->skb; + length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); + + skb_put(skb, length - ETHERNET_FCS_SIZE); + + /* Receive Checksum Offload */ + atl1_rx_checksum(adapter, rrd, skb); + skb->protocol = eth_type_trans(skb, adapter->netdev); + + if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) { + u16 vlan_tag = (rrd->vlan_tag >> 4) | + ((rrd->vlan_tag & 7) << 13) | + ((rrd->vlan_tag & 8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else + netif_rx(skb); + + /* let protocol layer free skb */ + buffer_info->skb = NULL; + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + + adapter->netdev->last_rx = jiffies; + } + + atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); + + atl1_alloc_rx_buffers(adapter); + + /* update mailbox ? */ + if (count) { + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + + spin_lock(&adapter->mb_lock); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = + atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = + atomic_read(&adapter->rrd_ring.next_to_clean); + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + spin_unlock(&adapter->mb_lock); + } +} + +static void atl1_intr_tx(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + u16 sw_tpd_next_to_clean; + u16 cmb_tpd_next_to_clean; + u8 update = 0; + + sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); + cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); + + while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { + struct tx_packet_desc *tpd; + update = 1; + tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); + buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->skb) { + dev_kfree_skb_irq(buffer_info->skb); + buffer_info->skb = NULL; + } + tpd->buffer_addr = 0; + tpd->desc.data = 0; + + if (++sw_tpd_next_to_clean == tpd_ring->count) + sw_tpd_next_to_clean = 0; + } + atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); + + if (netif_queue_stopped(adapter->netdev) + && netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); +} + +static void atl1_check_for_link(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->lock); + adapter->phy_timer_pending = false; + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->lock); + + /* notify upper layer link down ASAP */ + if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: %s link is down\n", + atl1_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +/* + * atl1_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + */ +static irqreturn_t atl1_intr(int irq, void *data) +{ + /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/ + struct atl1_adapter *adapter = netdev_priv(data); + u32 status; + u8 update_rx; + int max_ints = 10; + + status = adapter->cmb.cmb->int_stats; + if (!status) + return IRQ_NONE; + + update_rx = 0; + + do { + /* clear CMB interrupt status at once */ + adapter->cmb.cmb->int_stats = 0; + + if (status & ISR_GPHY) /* clear phy status */ + atl1_clear_phy_int(adapter); + + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); + + /* check if SMB intr */ + if (status & ISR_SMB) + atl1_inc_smb(adapter); + + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + printk(KERN_DEBUG "%s: pcie phy link down %x\n", + atl1_driver_name, status); + if (netif_running(adapter->netdev)) { /* reset MAC */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + } + + /* check if DMA read/write error ? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + printk(KERN_DEBUG + "%s: pcie DMA r/w error (status = 0x%x)\n", + atl1_driver_name, status); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + + /* link event */ + if (status & ISR_GPHY) { + adapter->soft_stats.tx_carrier_errors++; + atl1_check_for_link(adapter); + } + + /* transmit event */ + if (status & ISR_CMB_TX) + atl1_intr_tx(adapter); + + /* rx exception */ + if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV | ISR_CMB_RX))) { + if (status & + (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | + ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV)) + printk(KERN_INFO + "%s: rx exception: status = 0x%x\n", + atl1_driver_name, status); + atl1_intr_rx(adapter); + } + + if (--max_ints < 0) + break; + + } while ((status = adapter->cmb.cmb->int_stats)); + + /* re-enable Interrupt */ + iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); + return IRQ_HANDLED; +} + +/* + * atl1_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + */ +static void atl1_set_multi(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ioread32(hw->hw_addr + REG_MAC_CTRL); + if (netdev->flags & IFF_PROMISC) + rctl |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + + iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL); + + /* clear the old settings from the multicast hash table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + /* compute mc addresses' hash value ,and put it into hash table */ + for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl1_hash_set(hw, hash_value); + } +} + +static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter) +{ + u32 value; + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + /* duplex */ + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + /* speed */ + value |= ((u32) ((SPEED_1000 == adapter->link_speed) ? + MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) << + MAC_CTRL_SPEED_SHIFT); + /* flow control */ + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + /* PAD & CRC */ + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + /* preamble length */ + value |= (((u32) adapter->hw.preamble_len + & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + /* vlan */ + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + /* rx checksum + if (adapter->rx_csum) + value |= MAC_CTRL_RX_CHKSUM_EN; + */ + /* filter mode */ + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + /* value |= MAC_CTRL_LOOPBACK; */ + iowrite32(value, hw->hw_addr + REG_MAC_CTRL); +} + +static u32 atl1_check_link(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + /* MII_BMSR must read twice */ + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data & BMSR_LSTATUS)) { /* link down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: link is down\n", + atl1_driver_name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* Link Up */ + ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + + switch (hw->media_type) { + case MEDIA_TYPE_1000M_FULL: + if (speed != SPEED_1000 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + + /* link result is our setting */ + if (!reconfig) { + if (adapter->link_speed != speed + || adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl1_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s link is up %d Mbps %s\n", + atl1_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == + FULL_DUPLEX ? "full duplex" : "half duplex"); + } + if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* change orignal link status */ + if (netif_carrier_ok(netdev)) { + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR && + hw->media_type != MEDIA_TYPE_1000M_FULL) { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + return ATL1_SUCCESS; + } + + /* auto-neg, insert timer to re-config phy */ + if (!adapter->phy_timer_pending) { + adapter->phy_timer_pending = true; + mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + } + + return ATL1_SUCCESS; +} + +static void set_flow_ctrl_old(struct atl1_adapter *adapter) +{ + u32 hi, lo, value; + + /* RFD Flow Control */ + value = adapter->rfd_ring.count; + hi = value / 16; + if (hi < 2) + hi = 2; + lo = value * 7 / 8; + + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = adapter->rrd_ring.count; + lo = value / 16; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +static void set_flow_ctrl_new(struct atl1_hw *hw) +{ + u32 hi, lo, value; + + /* RXF Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN); + lo = value / 16; + if (lo < 192) + lo = 192; + hi = value * 7 / 8; + if (hi < lo) + hi = lo + 16; + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN); + lo = value / 8; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + if (hi < lo) + hi = lo + 3; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +/* + * atl1_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +static u32 atl1_configure(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + u32 value; + + /* clear interrupt status */ + iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR); + + /* set MAC Address */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | + (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + + /* tx / rx ring */ + + /* HI base address */ + iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32), + hw->hw_addr + REG_DESC_BASE_ADDR_HI); + /* LO base address */ + iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RFD_ADDR_LO); + iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RRD_ADDR_LO); + iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_TPD_ADDR_LO); + iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_CMB_ADDR_LO); + iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_SMB_ADDR_LO); + + /* element count */ + value = adapter->rrd_ring.count; + value <<= 16; + value += adapter->rfd_ring.count; + iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE); + iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE); + + /* Load Ptr */ + iowrite32(1, hw->hw_addr + REG_LOAD_PTR); + + /* config Mailbox */ + value = ((atomic_read(&adapter->tpd_ring.next_to_use) + & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) | + ((atomic_read(&adapter->rrd_ring.next_to_clean) + & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | + ((atomic_read(&adapter->rfd_ring.next_to_use) + & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAILBOX); + + /* config IPG/IFG */ + value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK) + << MAC_IPG_IFG_IPGT_SHIFT) | + (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) + << MAC_IPG_IFG_MIFG_SHIFT) | + (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) + << MAC_IPG_IFG_IPGR1_SHIFT) | + (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) + << MAC_IPG_IFG_IPGR2_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG); + + /* config Half-Duplex Control */ + value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) + << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) + << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL); + + /* set Interrupt Moderator Timer */ + iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT); + iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL); + + /* set Interrupt Clear Timer */ + iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); + + /* set MTU, 4 : VLAN */ + iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU); + + /* jumbo size & rrd retirement timer */ + value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) + << RXQ_JMBOSZ_TH_SHIFT) | + (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK) + << RXQ_JMBO_LKAH_SHIFT) | + (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK) + << RXQ_RRD_TIMER_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM); + + /* Flow Control */ + switch (hw->dev_rev) { + case 0x8001: + case 0x9001: + case 0x9002: + case 0x9003: + set_flow_ctrl_old(adapter); + break; + default: + set_flow_ctrl_new(hw); + break; + } + + /* config TXQ */ + value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK) + << TXQ_CTRL_TPD_BURST_NUM_SHIFT) | + (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK) + << TXQ_CTRL_TXF_BURST_NUM_SHIFT) | + (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK) + << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_TXQ_CTRL); + + /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */ + value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK) + << TX_JUMBO_TASK_TH_SHIFT) | + (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK) + << TX_TPD_MIN_IPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG); + + /* config RXQ */ + value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK) + << RXQ_CTRL_RFD_BURST_NUM_SHIFT) | + (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK) + << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) | + (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK) + << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) | + RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_RXQ_CTRL); + + /* config DMA Engine */ + value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN; + value |= (u32) hw->dma_ord; + if (atl1_rcb_128 == hw->rcb_value) + value |= DMA_CTRL_RCB_VALUE; + iowrite32(value, hw->hw_addr + REG_DMA_CTRL); + + /* config CMB / SMB */ + value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH); + value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER); + iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER); + + /* --- enable CMB / SMB */ + value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN; + iowrite32(value, hw->hw_addr + REG_CSMB_CTRL); + + value = ioread32(adapter->hw.hw_addr + REG_ISR); + if (unlikely((value & ISR_PHY_LINKDOWN) != 0)) + value = 1; /* config failed */ + else + value = 0; + + /* clear all interrupt status */ + iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR); + iowrite32(0, adapter->hw.hw_addr + REG_ISR); + return value; +} + +/* + * atl1_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void atl1_irq_disable(struct atl1_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + ioread32(adapter->hw.hw_addr + REG_IMR); + synchronize_irq(adapter->pdev->irq); +} + +static void atl1_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } + + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* FIXME: justify or remove -- CHS */ +static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + /* We don't do Vlan filtering */ + return; +} + +/* FIXME: this looks wrong too -- CHS */ +static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + if (adapter->vlgrp) + adapter->vlgrp->vlan_devices[vid] = NULL; + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); + /* We don't do Vlan filtering */ + return; +} + +static void atl1_restore_vlan(struct atl1_adapter *adapter) +{ + atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp); + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!adapter->vlgrp->vlan_devices[vid]) + continue; + atl1_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring) +{ + u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); + u16 next_to_use = atomic_read(&tpd_ring->next_to_use); + return ((next_to_clean > + next_to_use) ? next_to_clean - next_to_use - + 1 : tpd_ring->count + next_to_clean - next_to_use - 1); +} + +static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, + struct tso_param *tso) +{ + /* We enter this function holding a spinlock. */ + u8 ipofst; + int err; + + if (skb_shinfo(skb)->gso_size) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (unlikely(err)) + return err; + } + + if (skb->protocol == ntohs(ETH_P_IP)) { + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, 0, + IPPROTO_TCP, 0); + ipofst = skb->nh.raw - skb->data; + if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */ + tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT; + + tso->tsopl |= (skb->nh.iph->ihl & + CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT; + tso->tsopl |= ((skb->h.th->doff << 2) & + TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT; + tso->tsopl |= (skb_shinfo(skb)->gso_size & + TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT; + return true; + } + } + return false; +} + +static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, + struct csum_param *csum) +{ + u8 css, cso; + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + cso = skb->h.raw - skb->data; + css = (skb->h.raw + skb->csum) - skb->data; + if (unlikely(cso & 0x1)) { + printk(KERN_DEBUG "%s: payload offset != even number\n", + atl1_driver_name); + return -1; + } + csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) << + CSUM_PARAM_PLOADOFFSET_SHIFT; + csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) << + CSUM_PARAM_XSUMOFFSET_SHIFT; + csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT; + return true; + } + + return true; +} + +static void atl1_tx_map(struct atl1_adapter *adapter, + struct sk_buff *skb, bool tcp_seg) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct page *page; + int first_buf_len = skb->len; + unsigned long offset; + unsigned int nr_frags; + unsigned int f; + u16 tpd_next_to_use; + u16 proto_hdr_len; + u16 i, m, len12; + + first_buf_len -= skb->data_len; + nr_frags = skb_shinfo(skb)->nr_frags; + tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; /* put skb in last TPD */ + + if (tcp_seg) { + /* TSO/GSO */ + proto_hdr_len = + ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + buffer_info->length = proto_hdr_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, proto_hdr_len, + PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + + if (first_buf_len > proto_hdr_len) { + len12 = first_buf_len - proto_hdr_len; + m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = + &tpd_ring->buffer_info[tpd_next_to_use]; + buffer_info->skb = NULL; + buffer_info->length = + (MAX_TX_BUF_LEN >= + len12) ? MAX_TX_BUF_LEN : len12; + len12 -= buffer_info->length; + page = virt_to_page(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)); + offset = (unsigned long)(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)) & + ~PAGE_MASK; + buffer_info->dma = + pci_map_page(adapter->pdev, page, offset, + buffer_info->length, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + } else { + /* not TSO/GSO */ + buffer_info->length = first_buf_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, first_buf_len, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + u16 lenf, i, m; + + frag = &skb_shinfo(skb)->frags[f]; + lenf = frag->size; + + m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; + buffer_info->length = + (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf; + lenf -= buffer_info->length; + buffer_info->dma = + pci_map_page(adapter->pdev, frag->page, + frag->page_offset + i * MAX_TX_BUF_LEN, + buffer_info->length, PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + + /* last tpd's buffer-info */ + buffer_info->skb = skb; +} + +static void atl1_tx_queue(struct atl1_adapter *adapter, int count, + union tpd_descr *descr) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + int j; + u32 val; + struct atl1_buffer *buffer_info; + struct tx_packet_desc *tpd; + u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + + for (j = 0; j < count; j++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use); + tpd->desc.csum.csumpu = descr->csum.csumpu; + tpd->desc.csum.csumpl = descr->csum.csumpl; + tpd->desc.tso.tsopu = descr->tso.tsopu; + tpd->desc.tso.tsopl = descr->tso.tsopl; + tpd->buffer_addr = cpu_to_le64(buffer_info->dma); + tpd->desc.data = descr->data; + tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) & + CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT; + + val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) & + TSO_PARAM_SEGMENT_MASK; + if (val && !j) + tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT; + + if (j == (count - 1)) + tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT; + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + /* + * Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + + atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use); +} + +static void atl1_update_mailbox(struct atl1_adapter *adapter) +{ + unsigned long flags; + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + u32 value; + + spin_lock_irqsave(&adapter->mb_lock, flags); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean); + + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + + spin_unlock_irqrestore(&adapter->mb_lock, flags); +} + +static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + int tso; + int count = 1; + int ret_val; + u32 val; + union tpd_descr param; + u16 frag_size; + u16 vlan_tag; + unsigned long flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + unsigned int f; + unsigned int proto_hdr_len; + + len -= skb->data_len; + + if (unlikely(skb->len == 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + param.data = 0; + param.tso.tsopu = 0; + param.tso.tsopl = 0; + param.csum.csumpu = 0; + param.csum.csumpl = 0; + + /* nr_frags will be nonzero if we're doing scatter/gather (SG) */ + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_shinfo(skb)->frags[f].size; + if (frag_size) + count += + (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + + /* mss will be nonzero if we're doing segment offload (TSO/GSO) */ + mss = skb_shinfo(skb)->gso_size; + if (mss) { + if (skb->protocol == ntohs(ETH_P_IP)) { + proto_hdr_len = ((skb->h.raw - skb->data) + + (skb->h.th->doff << 2)); + if (unlikely(proto_hdr_len > len)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* need additional TPD ? */ + if (proto_hdr_len != len) + count += (len - proto_hdr_len + + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + } + + local_irq_save(flags); + if (!spin_trylock(&adapter->lock)) { + /* Can't get lock - tell upper layer to requeue */ + local_irq_restore(flags); + printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name); + return NETDEV_TX_LOCKED; + } + + if (tpd_avail(&adapter->tpd_ring) < count) { + /* not enough descriptors */ + netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->lock, flags); + printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name); + return NETDEV_TX_BUSY; + } + + param.data = 0; + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | + ((vlan_tag >> 9) & 0x8); + param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT; + param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) << + CSUM_PARAM_VALAN_SHIFT; + } + + tso = atl1_tso(adapter, skb, ¶m.tso); + if (tso < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (!tso) { + ret_val = atl1_tx_csum(adapter, skb, ¶m.csum); + if (ret_val < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + + val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) & + CSUM_PARAM_SEGMENT_MASK; + atl1_tx_map(adapter, skb, 1 == val); + atl1_tx_queue(adapter, count, ¶m); + netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->lock, flags); + atl1_update_mailbox(adapter); + return NETDEV_TX_OK; +} + +/* + * atl1_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + */ +static struct net_device_stats *atl1_get_stats(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + return &adapter->net_stats; +} + +/* + * atl1_clean_rx_ring - Free RFD Buffers + * @adapter: board private structure + */ +static void atl1_clean_rx_ring(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rfd_ring->count; i++) { + buffer_info = &rfd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * rfd_ring->count; + memset(rfd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); + + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); + + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); +} + +/* + * atl1_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + */ +static void atl1_clean_tx_ring(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + } + + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * tpd_ring->count; + memset(tpd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tpd_ring->desc, 0, tpd_ring->size); + + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); +} + +/* + * atl1_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + */ +void atl1_free_ring_resources(struct atl1_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); + + kfree(tpd_ring->buffer_info); + pci_free_consistent(pdev, ring_header->size, ring_header->desc, + ring_header->dma); + + tpd_ring->buffer_info = NULL; + tpd_ring->desc = NULL; + tpd_ring->dma = 0; + + rfd_ring->buffer_info = NULL; + rfd_ring->desc = NULL; + rfd_ring->dma = 0; + + rrd_ring->desc = NULL; + rrd_ring->dma = 0; +} + +s32 atl1_up(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err; + int irq_flags = IRQF_SAMPLE_RANDOM; + + /* hardware has been reset, we need to reload some things */ + atl1_set_multi(netdev); + atl1_restore_vlan(adapter); + err = atl1_alloc_rx_buffers(adapter); + if (unlikely(!err)) /* no RX BUFFER allocated */ + return -ENOMEM; + + if (unlikely(atl1_configure(adapter))) { + err = -EIO; + goto err_up; + } + + err = pci_enable_msi(adapter->pdev); + if (err) { + dev_info(&adapter->pdev->dev, + "Unable to enable MSI: %d\n", err); + irq_flags |= IRQF_SHARED; + } + + err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, + netdev->name, netdev); + if (unlikely(err)) + goto err_up; + + mod_timer(&adapter->watchdog_timer, jiffies); + atl1_irq_enable(adapter); + atl1_check_link(adapter); + return 0; + + /* FIXME: unreachable code! -- CHS */ + /* free irq disable any interrupt */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + free_irq(adapter->pdev->irq, netdev); + +err_up: + pci_disable_msi(adapter->pdev); + /* free rx_buffers */ + atl1_clean_rx_ring(adapter); + return err; +} + +void atl1_down(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + adapter->phy_timer_pending = false; + + atl1_irq_disable(adapter); + free_irq(adapter->pdev->irq, netdev); + pci_disable_msi(adapter->pdev); + atl1_reset_hw(&adapter->hw); + adapter->cmb.cmb->int_stats = 0; + + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); +} + +/* + * atl1_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + */ +static int atl1_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int old_mtu = netdev->mtu; + int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + + if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + printk(KERN_WARNING "%s: invalid MTU setting\n", + atl1_driver_name); + return -EINVAL; + } + + adapter->hw.max_frame_size = max_frame; + adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3; + adapter->rx_buffer_len = (max_frame + 7) & ~7; + adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8; + + netdev->mtu = new_mtu; + if ((old_mtu != new_mtu) && netif_running(netdev)) { + atl1_down(adapter); + atl1_up(adapter); + } + + return 0; +} + +/* + * atl1_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + */ +static int atl1_set_mac(struct net_device *netdev, void *p) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); + + atl1_set_mac_addr(&adapter->hw); + return 0; +} + +/* + * atl1_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_watchdog(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); +} + +static int mdio_read(struct net_device *netdev, int phy_id, int reg_num) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + u16 result; + + atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result); + + return result; +} + +static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_write_phy_reg(&adapter->hw, reg_num, val); +} + +/* + * atl1_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + int retval; + + if (!netif_running(netdev)) + return -EINVAL; + + spin_lock_irqsave(&adapter->lock, flags); + retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); + spin_unlock_irqrestore(&adapter->lock, flags); + + return retval; +} + +/* + * atl1_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl1_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +/* + * atl1_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void atl1_tx_timeout(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->tx_timeout_task); +} + +/* + * atl1_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_phy_config(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + struct atl1_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + adapter->phy_timer_pending = false; + atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg); + atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +int atl1_reset(struct atl1_adapter *adapter) +{ + int ret; + + ret = atl1_reset_hw(&adapter->hw); + if (ret != ATL1_SUCCESS) + return ret; + return atl1_init_hw(&adapter->hw); +} + +/* + * atl1_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + */ +static int atl1_open(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int err; + + /* allocate transmit descriptors */ + err = atl1_setup_ring_resources(adapter); + if (err) + return err; + + err = atl1_up(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + atl1_reset(adapter); + return err; +} + +/* + * atl1_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the drivers control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + */ +static int atl1_close(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + atl1_down(adapter); + atl1_free_ring_resources(adapter); + return 0; +} + +/* + * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT + * will assert. We do soft reset <0x1400=1> according + * with the SPEC. BUT, it seemes that PCIE or DMA + * state-machine will not be reset. DMAR_TO_INT will + * assert again and again. + */ +static void atl1_tx_timeout_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; + + netif_device_detach(netdev); + atl1_down(adapter); + atl1_up(adapter); + netif_device_attach(netdev); +} + +/* + * atl1_link_chg_task - deal with link change event Out of interrupt context + */ +static void atl1_link_chg_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, link_chg_task); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_check_link(adapter); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* + * atl1_pcie_patch - Patch for PCIE module + */ +static void atl1_pcie_patch(struct atl1_adapter *adapter) +{ + u32 value; + value = 0x6500; + iowrite32(value, adapter->hw.hw_addr + 0x12FC); + /* pcie flow control mode change */ + value = ioread32(adapter->hw.hw_addr + 0x1008); + value |= 0x8000; + iowrite32(value, adapter->hw.hw_addr + 0x1008); +} + +/* + * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400 + * on PCI Command register is disable. + * The function enable this bit. + * Brackett, 2006/03/15 + */ +static void atl1_via_workaround(struct atl1_adapter *adapter) +{ + unsigned long value; + + value = ioread16(adapter->hw.hw_addr + PCI_COMMAND); + if (value & PCI_COMMAND_INTX_DISABLE) + value &= ~PCI_COMMAND_INTX_DISABLE; + iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND); +} + +/* + * atl1_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl1_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl1_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + */ +static int __devinit atl1_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl1_adapter *adapter; + static int cards_found = 0; + bool pci_using_64 = true; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_DEBUG + "%s: no usable DMA configuration, aborting\n", + atl1_driver_name); + goto err_dma; + } + pci_using_64 = false; + } + /* Mark all PCI regions associated with PCI device + * pdev as being reserved by owner atl1_driver_name + */ + err = pci_request_regions(pdev, atl1_driver_name); + if (err) + goto err_request_regions; + + /* Enables bus-mastering on the device and calls + * pcibios_set_master to do the needed arch specific settings + */ + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct atl1_adapter)); + if (!netdev) { + err = -ENOMEM; + goto err_alloc_etherdev; + } + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + adapter->hw.back = adapter; + + adapter->hw.hw_addr = pci_iomap(pdev, 0, 0); + if (!adapter->hw.hw_addr) { + err = -EIO; + goto err_pci_iomap; + } + /* get device revision number */ + adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); + + /* set default ring resource counts */ + adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; + adapter->tpd_ring.count = ATL1_DEFAULT_TPD; + + adapter->mii.dev = netdev; + adapter->mii.mdio_read = mdio_read; + adapter->mii.mdio_write = mdio_write; + adapter->mii.phy_id_mask = 0x1f; + adapter->mii.reg_num_mask = 0x1f; + + netdev->open = &atl1_open; + netdev->stop = &atl1_close; + netdev->hard_start_xmit = &atl1_xmit_frame; + netdev->get_stats = &atl1_get_stats; + netdev->set_multicast_list = &atl1_set_multi; + netdev->set_mac_address = &atl1_set_mac; + netdev->change_mtu = &atl1_change_mtu; + netdev->do_ioctl = &atl1_ioctl; + netdev->tx_timeout = &atl1_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netdev->vlan_rx_register = atl1_vlan_rx_register; + netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid; + netdev->ethtool_ops = &atl1_ethtool_ops; + adapter->bd_number = cards_found; + adapter->pci_using_64 = pci_using_64; + + /* setup the private structure */ + err = atl1_sw_init(adapter); + if (err) + goto err_common; + + netdev->features = NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SG; + netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + + /* + * FIXME - Until tso performance gets fixed, disable the feature. + * Enable it with ethtool -K if desired. + */ + /* netdev->features |= NETIF_F_TSO; */ + + if (pci_using_64) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_LLTX; + + /* + * patch for some L1 of old version, + * the final version of L1 may not need these + * patches + */ + /* atl1_pcie_patch(adapter); */ + + /* really reset GPHY core */ + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + + /* + * reset the controller to + * put the device in a known good starting state + */ + if (atl1_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_common; + } + + /* copy the MAC address out of the EEPROM */ + atl1_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + err = -EIO; + goto err_common; + } + + atl1_check_options(adapter); + + /* pre-init the MAC, and setup link */ + err = atl1_init_hw(&adapter->hw); + if (err) { + err = -EIO; + goto err_common; + } + + atl1_pcie_patch(adapter); + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl1_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl1_phy_config; + adapter->phy_config_timer.data = (unsigned long)adapter; + adapter->phy_timer_pending = false; + + INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); + + INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task); + + INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task); + + err = register_netdev(netdev); + if (err) + goto err_common; + + cards_found++; + atl1_via_workaround(adapter); + return 0; + +err_common: + pci_iounmap(pdev, adapter->hw.hw_addr); +err_pci_iomap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_dma: +err_request_regions: + pci_disable_device(pdev); + return err; +} + +/* + * atl1_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl1_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + */ +static void __devexit atl1_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter; + /* Device not available. Return. */ + if (!netdev) + return; + + adapter = netdev_priv(netdev); + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + unregister_netdev(netdev); + pci_iounmap(pdev, adapter->hw.hw_addr); + pci_release_regions(pdev); + free_netdev(netdev); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u32 ctrl = 0; + u32 wufc = adapter->wol; + + netif_device_detach(netdev); + if (netif_running(netdev)) + atl1_down(adapter); + + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + if (ctrl & BMSR_LSTATUS) + wufc &= ~ATL1_WUFC_LNKC; + + /* reduce speed to 10/100M */ + if (wufc) { + atl1_phy_enter_power_saving(hw); + /* if resume, let driver to re- setup link */ + hw->phy_configured = false; + atl1_set_mac_addr(hw); + atl1_set_multi(netdev); + + ctrl = 0; + /* turn on magic packet wol */ + if (wufc & ATL1_WUFC_MAG) + ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; + + /* turn on Link change WOL */ + if (wufc & ATL1_WUFC_LNKC) + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); + + /* turn on all-multi mode if wake on multicast is enabled */ + ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_DBG; + ctrl &= ~MAC_CTRL_PROMIS_EN; + if (wufc & ATL1_WUFC_MC) + ctrl |= MAC_CTRL_MC_ALL_EN; + else + ctrl &= ~MAC_CTRL_MC_ALL_EN; + + /* turn on broadcast mode if wake on-BC is enabled */ + if (wufc & ATL1_WUFC_BC) + ctrl |= MAC_CTRL_BC_EN; + else + ctrl &= ~MAC_CTRL_BC_EN; + + /* enable RX */ + ctrl |= MAC_CTRL_RX_EN; + iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */ + } else { + iowrite32(0, hw->hw_addr + REG_WOL_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + } + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int atl1_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + u32 ret_val; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + + ret_val = pci_enable_device(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); + atl1_reset(adapter); + + if (netif_running(netdev)) + atl1_up(adapter); + netif_device_attach(netdev); + + atl1_via_workaround(adapter); + + return 0; +} +#else +#define atl1_suspend NULL +#define atl1_resume NULL +#endif + +static struct pci_driver atl1_driver = { + .name = atl1_driver_name, + .id_table = atl1_pci_tbl, + .probe = atl1_probe, + .remove = __devexit_p(atl1_remove), + /* Power Managment Hooks */ + /* probably broken right now -- CHS */ + .suspend = atl1_suspend, + .resume = atl1_resume +}; + +/* + * atl1_exit_module - Driver Exit Cleanup Routine + * + * atl1_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit atl1_exit_module(void) +{ + pci_unregister_driver(&atl1_driver); +} + +/* + * atl1_init_module - Driver Registration Routine + * + * atl1_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init atl1_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION); + printk(KERN_INFO "%s\n", atl1_copyright); + return pci_register_driver(&atl1_driver); +} + +module_init(atl1_init_module); +module_exit(atl1_exit_module); diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c new file mode 100644 index 000000000000..c407214339f6 --- /dev/null +++ b/drivers/net/atl1/atl1_param.c @@ -0,0 +1,206 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook <csnook@redhat.com> + * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com> + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. 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/types.h> +#include <linux/pci.h> +#include <linux/moduleparam.h> +#include "atl1.h" + +/* + * This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL1_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } + +/* + * Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 100 (200us) + */ +static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_int_mod_timer = 0; +module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0); +MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); + +/* + * flash_vendor + * + * Valid Range: 0-2 + * + * 0 - Atmel + * 1 - SST + * 2 - ST + * + * Default Value: 0 + */ +static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_flash_vendor = 0; +module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0); +MODULE_PARM_DESC(flash_vendor, "SPI flash vendor"); + +#define DEFAULT_INT_MOD_CNT 100 /* 200us */ +#define MAX_INT_MOD_CNT 65000 +#define MIN_INT_MOD_CNT 50 + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl1_option { + enum { enable_option, range_option, list_option } type; + char *name; + char *err; + int def; + union { + struct { /* range_option info */ + int min; + int max; + } r; + struct { /* list_option info */ + int nr; + struct atl1_opt_list { + int i; + char *str; + } *p; + } l; + } arg; +}; + +static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name, + opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name, + opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s: %s set to %i\n", + atl1_driver_name, opt->name, *value); + return 0; + } + break; + case list_option:{ + int i; + struct atl1_opt_list *ent; + + for (i = 0; i < opt->arg.l.nr; i++) { + ent = &opt->arg.l.p[i]; + if (*value == ent->i) { + if (ent->str[0] != '\0') + printk(KERN_INFO "%s: %s\n", + atl1_driver_name, ent->str); + return 0; + } + } + } + break; + + default: + break; + } + + printk(KERN_INFO "%s: invalid %s specified (%i) %s\n", + atl1_driver_name, opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/* + * atl1_check_options - Range Checking for Command Line Parameters + * @adapter: board private structure + * + * This routine checks all command line parameters for valid user + * input. If an invalid value is given, or if no user specified + * value exists, a default value is used. The final value is stored + * in a variable in the adapter structure. + */ +void __devinit atl1_check_options(struct atl1_adapter *adapter) +{ + int bd = adapter->bd_number; + if (bd >= ATL1_MAX_NIC) { + printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n", + atl1_driver_name, bd); + printk(KERN_NOTICE "%s: using defaults for all values\n", + atl1_driver_name); + } + { /* Interrupt Moderate Timer */ + struct atl1_option opt = { + .type = range_option, + .name = "Interrupt Moderator Timer", + .err = "using default of " + __MODULE_STRING(DEFAULT_INT_MOD_CNT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}} + }; + int val; + if (num_int_mod_timer > bd) { + val = int_mod_timer[bd]; + atl1_validate_option(&val, &opt); + adapter->imt = (u16) val; + } else + adapter->imt = (u16) (opt.def); + } + + { /* Flash Vendor */ + struct atl1_option opt = { + .type = range_option, + .name = "SPI Flash Vendor", + .err = "using default of " + __MODULE_STRING(FLASH_VENDOR_DEFAULT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = FLASH_VENDOR_MIN,.max = + FLASH_VENDOR_MAX}} + }; + int val; + if (num_flash_vendor > bd) { + val = flash_vendor[bd]; + atl1_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; + } else + adapter->hw.flash_vendor = (u8) (opt.def); + } +} diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 32923162179e..217a2eedee0a 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond) spin_lock_init(&(bond_info->tx_hashtbl_lock)); - new_hashtbl = kmalloc(size, GFP_KERNEL); + new_hashtbl = kzalloc(size, GFP_KERNEL); if (!new_hashtbl) { printk(KERN_ERR DRV_NAME ": %s: Error: Failed to allocate TLB hash table\n", @@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; - memset(bond_info->tx_hashtbl, 0, size); - for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d3801a00d3d5..8ce8fec615ba 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1343,14 +1343,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) "inaccurate.\n", bond_dev->name, slave_dev->name); } - new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); if (!new_slave) { res = -ENOMEM; goto err_undo_flags; } - memset(new_slave, 0, sizeof(struct slave)); - /* save slave's original flags before calling * netdev_set_master and dev_open */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index dfa035a1ad45..c67f7d3c2f92 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -74,8 +74,6 @@ enum { #define EEPROM_MAGIC 0x38E2F10C -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - #define CH_DEVICE(devid, ssid, idx) \ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } @@ -434,11 +432,12 @@ static int setup_sge_qsets(struct adapter *adap) return 0; } -static ssize_t attr_show(struct class_device *cd, char *buf, +static ssize_t attr_show(struct device *d, struct device_attribute *attr, + char *buf, ssize_t(*format) (struct adapter *, char *)) { ssize_t len; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; /* Synchronize with ioctls that may shut down the device */ rtnl_lock(); @@ -447,14 +446,15 @@ static ssize_t attr_show(struct class_device *cd, char *buf, return len; } -static ssize_t attr_store(struct class_device *cd, const char *buf, size_t len, +static ssize_t attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, ssize_t(*set) (struct adapter *, unsigned int), unsigned int min_val, unsigned int max_val) { char *endp; ssize_t ret; unsigned int val; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -476,9 +476,10 @@ static ssize_t format_##name(struct adapter *adap, char *buf) \ { \ return sprintf(buf, "%u\n", val_expr); \ } \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ { \ - return attr_show(cd, buf, format_##name); \ + return attr_show(d, attr, buf, format_##name); \ } static ssize_t set_nfilters(struct adapter *adap, unsigned int val) @@ -493,10 +494,10 @@ static ssize_t set_nfilters(struct adapter *adap, unsigned int val) return 0; } -static ssize_t store_nfilters(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return attr_store(cd, buf, len, set_nfilters, 0, ~0); + return attr_store(d, attr, buf, len, set_nfilters, 0, ~0); } static ssize_t set_nservers(struct adapter *adap, unsigned int val) @@ -509,38 +510,39 @@ static ssize_t set_nservers(struct adapter *adap, unsigned int val) return 0; } -static ssize_t store_nservers(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_nservers(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return attr_store(cd, buf, len, set_nservers, 0, ~0); + return attr_store(d, attr, buf, len, set_nservers, 0, ~0); } #define CXGB3_ATTR_R(name, val_expr) \ CXGB3_SHOW(name, val_expr) \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) #define CXGB3_ATTR_RW(name, val_expr, store_method) \ CXGB3_SHOW(name, val_expr) \ -static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); static struct attribute *cxgb3_attrs[] = { - &class_device_attr_cam_size.attr, - &class_device_attr_nfilters.attr, - &class_device_attr_nservers.attr, + &dev_attr_cam_size.attr, + &dev_attr_nfilters.attr, + &dev_attr_nservers.attr, NULL }; static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; -static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched) +static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr, + char *buf, int sched) { ssize_t len; unsigned int v, addr, bpt, cpt; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; rtnl_lock(); @@ -560,13 +562,13 @@ static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched) return len; } -static ssize_t tm_attr_store(struct class_device *cd, const char *buf, - size_t len, int sched) +static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t len, int sched) { char *endp; ssize_t ret; unsigned int val; - struct adapter *adap = to_net_dev(cd)->priv; + struct adapter *adap = to_net_dev(d)->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -584,15 +586,17 @@ static ssize_t tm_attr_store(struct class_device *cd, const char *buf, } #define TM_ATTR(name, sched) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ { \ - return tm_attr_show(cd, buf, sched); \ + return tm_attr_show(d, attr, buf, sched); \ } \ -static ssize_t store_##name(struct class_device *cd, const char *buf, size_t len) \ +static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ + const char *buf, size_t len) \ { \ - return tm_attr_store(cd, buf, len, sched); \ + return tm_attr_store(d, attr, buf, len, sched); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) TM_ATTR(sched0, 0); TM_ATTR(sched1, 1); @@ -604,14 +608,14 @@ TM_ATTR(sched6, 6); TM_ATTR(sched7, 7); static struct attribute *offload_attrs[] = { - &class_device_attr_sched0.attr, - &class_device_attr_sched1.attr, - &class_device_attr_sched2.attr, - &class_device_attr_sched3.attr, - &class_device_attr_sched4.attr, - &class_device_attr_sched5.attr, - &class_device_attr_sched6.attr, - &class_device_attr_sched7.attr, + &dev_attr_sched0.attr, + &dev_attr_sched1.attr, + &dev_attr_sched2.attr, + &dev_attr_sched3.attr, + &dev_attr_sched4.attr, + &dev_attr_sched5.attr, + &dev_attr_sched6.attr, + &dev_attr_sched7.attr, NULL }; @@ -836,7 +840,7 @@ static int offload_open(struct net_device *dev) init_smt(adapter); /* Never mind if the next step fails */ - sysfs_create_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group); /* Call back all registered clients */ cxgb3_add_clients(tdev); @@ -861,7 +865,7 @@ static int offload_close(struct t3cdev *tdev) /* Call back all registered clients */ cxgb3_remove_clients(tdev); - sysfs_remove_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group); tdev->lldev = NULL; cxgb3_set_dummy_ops(tdev); @@ -2420,7 +2424,7 @@ static int __devinit init_one(struct pci_dev *pdev, else if (msi > 0 && pci_enable_msi(pdev) == 0) adapter->flags |= USING_MSI; - err = sysfs_create_group(&adapter->port[0]->class_dev.kobj, + err = sysfs_create_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); print_port_info(adapter, ai); @@ -2452,7 +2456,7 @@ static void __devexit remove_one(struct pci_dev *pdev) struct adapter *adapter = dev->priv; t3_sge_stop(adapter); - sysfs_remove_group(&adapter->port[0]->class_dev.kobj, + sysfs_remove_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); for_each_port(adapter, i) diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index c3a02d613382..c6b726643185 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -396,7 +396,7 @@ static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, int n) { CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", - n, ntohl(*(u32 *)skbs[0]->data)); + n, ntohl(*(__be32 *)skbs[0]->data)); while (n--) dev_kfree_skb_any(skbs[n]); return 0; @@ -755,7 +755,7 @@ static int do_trace(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_trace_pkt *p = cplhdr(skb); - skb->protocol = 0xffff; + skb->protocol = htons(0xffff); skb->dev = dev->lldev; skb_pull(skb, sizeof(*p)); skb->mac.raw = skb->data; diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index c62d9c6363c6..b2b0a96218ca 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring mem_on(ioaddr, shared_mem, (ring_offset>>8)); - /* Packet is always in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0); + memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count); mem_off(ioaddr); } diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 2d2ea94a00bb..822e5bfd1a71 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -375,7 +375,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk memcpy_fromio(skb->data + semi_count, ei_status.mem, count); } else { /* Packet is in one chunk. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 24f6050fbf33..8ca57a0a4c11 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -49,6 +49,7 @@ #include <linux/skbuff.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/bitrev.h> #include <asm/bootinfo.h> #include <asm/system.h> diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b3bf86422734..d98e53efa2ef 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2780,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = { .get_link = mv643xx_eth_get_link, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, - .get_strings = mv643xx_get_strings, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, .get_strings = mv643xx_get_strings, diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 577babd4c938..5598d86380b4 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2016,7 +2016,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, if (!skb) goto err_out; - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); *sk_buff = skb; mapping = pci_map_single(pdev, skb->data, rx_buf_sz, @@ -2487,7 +2487,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, skb = dev_alloc_skb(pkt_size + align); if (skb) { - skb_reserve(skb, (align - 1) & (u32)skb->data); + skb_reserve(skb, (align - 1) & (unsigned long)skb->data); eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); *sk_buff = skb; rtl8169_mark_to_asic(desc, rx_buf_sz); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 639fbc0f16f3..8646b64994ab 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7298,7 +7298,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) { struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; - u16 nchk; + __sum16 nchk; struct stat_block *statinfo = sp->mac_control.stats_info; DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index a5e1a513deb5..0de0c65f945a 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -727,12 +727,12 @@ struct lro { struct iphdr *iph; struct tcphdr *tcph; u32 tcp_next_seq; - u32 tcp_ack; + __be32 tcp_ack; int total_len; int frags_len; int sg_num; int in_use; - u16 window; + __be16 window; u32 cur_tsval; u32 cur_tsecr; u8 saw_ts; @@ -1005,7 +1005,7 @@ static int s2io_set_swapper(struct s2io_nic * sp); static void s2io_card_down(struct s2io_nic *nic); static int s2io_card_up(struct s2io_nic *nic); static int get_xena_rev_id(struct pci_dev *pdev); -static int wait_for_cmd_complete(void *addr, u64 busy_bit); +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit); static int s2io_add_isr(struct s2io_nic * sp); static void s2io_rem_isr(struct s2io_nic * sp); diff --git a/drivers/net/slip.c b/drivers/net/slip.c index a0806d262fc6..2f4b1de7a2b4 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1343,15 +1343,12 @@ static int __init slip_init(void) printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); + slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); if (!slip_devs) { printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } - /* Clear the pointer array, we allocate devices when we need them */ - memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); - /* Fill in our line protocol discipline, and register it */ if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 7122932eac90..ae1ae343beed 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -482,8 +482,7 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index d70bc9795346..a52b22d7db65 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri count -= semi_count; memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */ diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 2c5319c62fa5..88a30e56c64c 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -395,8 +395,7 @@ static void ultra32_block_input(struct net_device *dev, memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } } else { - /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } } diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index bf6ff39e02bb..64ed8ff5b03a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1907,7 +1907,7 @@ spider_net_stop(struct net_device *netdev) spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); + free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 135c0987deae..e136bae61970 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3380,7 +3380,7 @@ next_pkt: } next_pkt_nopost: sw_idx++; - sw_idx %= TG3_RX_RCB_RING_SIZE(tp); + sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1); /* Refresh hw_idx to see if there is new work */ if (sw_idx == hw_idx) { diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index abb8611c5a91..31c97a6591a4 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1709,75 +1709,13 @@ static void adjust_link(struct net_device *dev) if (mii_info->speed != ugeth->oldspeed) { switch (mii_info->speed) { case 1000: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this when it is fixed!!! */ - if (ugeth->ug_info->enet_interface == - ENET_1000_GMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval |= 0x000f; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } else if (ugeth->ug_info->enet_interface == - ENET_1000_RGMII) - /* Run the commands which initialize the PHY */ - { - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth-> - dev, mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | BMCR_RESET)); - } - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + ugeth->ug_info->enet_interface = ENET_1000_RGMII; break; case 100: - case 10: -#ifdef CONFIG_PPC_MPC836x -/* FIXME: This code is for 100Mbs BUG fixing, -remove this lines when it will be fixed!!! */ ugeth->ug_info->enet_interface = ENET_100_RGMII; - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - 0x1b); - tempval = (tempval & ~0x000f) | 0x000b; - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, 0x1b, - (u16) tempval); - tempval = - (u32) mii_info->mdio_read(ugeth->dev, - mii_info->mii_id, - MII_BMCR); - mii_info->mdio_write(ugeth->dev, - mii_info->mii_id, MII_BMCR, - (u16) (tempval | - BMCR_RESET)); - msleep(4000); -#endif /* CONFIG_MPC8360 */ - adjust_enet_interface(ugeth); + break; + case 10: + ugeth->ug_info->enet_interface = ENET_10_RGMII; break; default: ugeth_warn @@ -1785,6 +1723,7 @@ remove this lines when it will be fixed!!! */ dev->name, mii_info->speed); break; } + adjust_enet_interface(ugeth); ugeth_info("%s: Speed %dBT", dev->name, mii_info->speed); @@ -4133,6 +4072,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma static int mii_mng_configured = 0; const phandle *ph; const unsigned int *prop; + const void *mac_addr; ugeth_vdbg("%s: IN", __FUNCTION__); @@ -4258,7 +4198,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ug_info = ug_info; ugeth->dev = dev; - memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6); + + mac_addr = get_property(np, "mac-address", NULL); + if (mac_addr == NULL) + mac_addr = get_property(np, "local-mac-address", NULL); + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, 6); return 0; } diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c index 3c86592ce03c..6fda6d88be49 100644 --- a/drivers/net/ucc_geth_phy.c +++ b/drivers/net/ucc_geth_phy.c @@ -376,6 +376,8 @@ static int marvell_init(struct ugeth_mii_info *mii_info) ugphy_vdbg("%s: IN", __FUNCTION__); ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); + ucc_geth_phy_write(mii_info, 0x1b, + (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); ucc_geth_phy_write(mii_info, MII_BMCR, ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); msleep(4000); diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index 79b2d5454d6b..bc156b51678a 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -101,8 +101,8 @@ typedef struct port_s { typedef struct card_s { int type; /* RSV, X21, etc. */ int n_ports; /* 1 or 2 ports */ - u8* __iomem rambase; /* buffer memory base (virtual) */ - u8* __iomem scabase; /* SCA memory base (virtual) */ + u8 __iomem *rambase; /* buffer memory base (virtual) */ + u8 __iomem *scabase; /* SCA memory base (virtual) */ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */ u16 rx_ring_buffers; /* number of buffers in a ring */ @@ -134,7 +134,7 @@ typedef struct card_s { static void pc300_set_iface(port_t *port) { card_t *card = port->card; - u32* init_ctrl = &card->plxbase->init_ctrl; + u32 __iomem * init_ctrl = &card->plxbase->init_ctrl; u16 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; @@ -393,7 +393,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, /* PLX PCI 9050 workaround for local configuration register read bug */ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys); - card->init_ctrl_value = readl(&((plx9050*)card->scabase)->init_ctrl); + card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl); pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); /* Reset PLX */ @@ -519,10 +519,10 @@ static struct pci_device_id pc300_pci_tbl[] __devinitdata = { static struct pci_driver pc300_pci_driver = { - name: "PC300", - id_table: pc300_pci_tbl, - probe: pc300_pci_init_one, - remove: pc300_pci_remove_one, + .name = "PC300", + .id_table = pc300_pci_tbl, + .probe = pc300_pci_init_one, + .remove = pc300_pci_remove_one, }; diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 7f38012b9c92..a0326818ff2f 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_ memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + memcpy_fromio(skb->data, xfer_start, count); } /* Turn off 16 bit access so that reboot works. ISA brain-damage */ diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index bbf025874d0c..4dbef0762376 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -722,7 +722,7 @@ static int __init init_m32r_pcc(void) /* Set up interrupt handler(s) */ for (i = 0 ; i < pcc_sockets ; i++) { - socket[i].socket.dev.dev = &pcc_device.dev; + socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; socket[i].socket.resource_ops = &pccard_static_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 94d3df62a5fa..82f2ac87ccd4 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, case RTC_IRQP_READ: if (ops->irq_set_freq) - err = put_user(rtc->irq_freq, (unsigned long *) arg); + err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); break; case RTC_IRQP_SET: diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index a138b1510093..3a1a958fb5f2 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -3,7 +3,7 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer <geraldsc@de.ibm.com> */ @@ -22,7 +22,7 @@ #include <asm/ebcdic.h> #include <asm/extmem.h> #include <linux/poll.h> -#include "../net/iucv.h" +#include <net/iucv/iucv.h> //#define MON_DEBUG /* Debug messages on/off */ @@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0"; struct mon_msg { u32 pos; u32 mca_offset; - iucv_MessagePending local_eib; + struct iucv_message msg; char msglim_reached; char replied_msglim; }; struct mon_private { - u16 pathid; - iucv_handle_t iucv_handle; + struct iucv_path *path; struct mon_msg *msg_array[MON_MSGLIM]; unsigned int write_index; unsigned int read_index; @@ -75,8 +74,6 @@ static unsigned long mon_dcss_end; static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); -static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static u8 user_data_connect[16] = { /* Version code, must be 0x01 for shared mode */ 0x01, @@ -100,8 +97,7 @@ static u8 user_data_sever[16] = { * Create the 8 bytes EBCDIC DCSS segment name from * an ASCII name, incl. padding */ -static inline void -dcss_mkname(char *ascii_name, char *ebcdic_name) +static inline void dcss_mkname(char *ascii_name, char *ebcdic_name) { int i; @@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name) * print appropriate error message for segment_load()/segment_type() * return code */ -static void -mon_segment_warn(int rc, char* seg_name) +static void mon_segment_warn(int rc, char* seg_name) { switch (rc) { case -ENOENT: @@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name) } } -static inline unsigned long -mon_mca_start(struct mon_msg *monmsg) +static inline unsigned long mon_mca_start(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg1.iprmmsg1_u32; + return *(u32 *) &monmsg->msg.rmmsg; } -static inline unsigned long -mon_mca_end(struct mon_msg *monmsg) +static inline unsigned long mon_mca_end(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg2.ipbfln1f; + return *(u32 *) &monmsg->msg.rmmsg[4]; } -static inline u8 -mon_mca_type(struct mon_msg *monmsg, u8 index) +static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index) { return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); } -static inline u32 -mon_mca_size(struct mon_msg *monmsg) +static inline u32 mon_mca_size(struct mon_msg *monmsg) { return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; } -static inline u32 -mon_rec_start(struct mon_msg *monmsg) +static inline u32 mon_rec_start(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); } -static inline u32 -mon_rec_end(struct mon_msg *monmsg) +static inline u32 mon_rec_end(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); } -static inline int -mon_check_mca(struct mon_msg *monmsg) +static inline int mon_check_mca(struct mon_msg *monmsg) { if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || @@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg) return 0; } -static inline int -mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline int mon_send_reply(struct mon_msg *monmsg, + struct mon_private *monpriv) { - u8 prmmsg[8]; int rc; P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " "0x%08X\n\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); - rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, - monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls, - 0, prmmsg); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + + rc = iucv_message_reply(monpriv->path, &monmsg->msg, + IUCV_IPRMDATA, NULL, 0); atomic_dec(&monpriv->msglim_count); if (likely(!monmsg->msglim_reached)) { monmsg->pos = 0; @@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) return 0; } -static inline struct mon_private * -mon_alloc_mem(void) +static inline void mon_free_mem(struct mon_private *monpriv) +{ + int i; + + for (i = 0; i < MON_MSGLIM; i++) + if (monpriv->msg_array[i]) + kfree(monpriv->msg_array[i]); + kfree(monpriv); +} + +static inline struct mon_private *mon_alloc_mem(void) { - int i,j; + int i; struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); @@ -267,16 +261,15 @@ mon_alloc_mem(void) GFP_KERNEL); if (!monpriv->msg_array[i]) { P_ERROR("open, no memory for msg_array\n"); - for (j = 0; j < i; j++) - kfree(monpriv->msg_array[j]); + mon_free_mem(monpriv); return NULL; } } return monpriv; } -static inline void -mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) { #ifdef MON_DEBUG u8 msg_type[2], mca_type; @@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; - memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); + memcpy(msg_type, &monmsg->msg.class, 2); EBCASC(msg_type, 2); mca_type = mon_mca_type(monmsg, 0); EBCASC(&mca_type, 1); @@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", monpriv->read_index, monpriv->write_index); P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", msg_type[0], msg_type[1], mca_type ? mca_type : 'X', mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); @@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) #endif } -static inline void -mon_next_mca(struct mon_msg *monmsg) +static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; @@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg) monmsg->pos = 0; } -static inline struct mon_msg * -mon_next_message(struct mon_private *monpriv) +static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) { struct mon_msg *monmsg; @@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv) /****************************************************************************** * IUCV handler * *****************************************************************************/ -static void -mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data) +static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV connection completed\n"); P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " "0x%02X, Sample = 0x%02X\n", - eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]); + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } -static void -mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data) +static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", - (u8) eib->ipuser[0]); + P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); wake_up_interruptible(&mon_read_wait_queue); } -static void -mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) +static void mon_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV message pending\n"); - memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib, - sizeof(iucv_MessagePending)); + memcpy(&monpriv->msg_array[monpriv->write_index]->msg, + msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { P_WARNING("IUCV message pending, message limit (%i) reached\n", MON_MSGLIM); @@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) wake_up_interruptible(&mon_read_wait_queue); } -static iucv_interrupt_ops_t mon_iucvops = { - .ConnectionComplete = mon_iucv_ConnectionComplete, - .ConnectionSevered = mon_iucv_ConnectionSevered, - .MessagePending = mon_iucv_MessagePending, +static struct iucv_handler monreader_iucv_handler = { + .path_complete = mon_iucv_path_complete, + .path_severed = mon_iucv_path_severed, + .message_pending = mon_iucv_message_pending, }; /****************************************************************************** * file operations * *****************************************************************************/ -static int -mon_open(struct inode *inode, struct file *filp) +static int mon_open(struct inode *inode, struct file *filp) { - int rc, i; struct mon_private *monpriv; + int rc; /* * only one user allowed */ + rc = -EBUSY; if (test_and_set_bit(MON_IN_USE, &mon_in_use)) - return -EBUSY; + goto out; + rc = -ENOMEM; monpriv = mon_alloc_mem(); if (!monpriv) - return -ENOMEM; + goto out_use; /* - * Register with IUCV and connect to *MONITOR service + * Connect to *MONITOR service */ - monpriv->iucv_handle = iucv_register_program("my_monreader ", - MON_SERVICE, - NULL, - &mon_iucvops, - monpriv); - if (!monpriv->iucv_handle) { - P_ERROR("failed to register with iucv driver\n"); - rc = -EIO; - goto out_error; - } - P_INFO("open, registered with IUCV\n"); - - rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect, - MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL, - monpriv->iucv_handle, NULL); + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out_priv; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { P_ERROR("iucv connection to *MONITOR failed with " "IPUSER SEVER code = %i\n", rc); rc = -EIO; - goto out_unregister; + goto out_path; } /* * Wait for connection confirmation @@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp) atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); rc = -EIO; - goto out_unregister; + goto out_path; } P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); -out_unregister: - iucv_unregister_program(monpriv->iucv_handle); -out_error: - for (i = 0; i < MON_MSGLIM; i++) - kfree(monpriv->msg_array[i]); - kfree(monpriv); +out_path: + kfree(monpriv->path); +out_priv: + mon_free_mem(monpriv); +out_use: clear_bit(MON_IN_USE, &mon_in_use); +out: return rc; } -static int -mon_close(struct inode *inode, struct file *filp) +static int mon_close(struct inode *inode, struct file *filp) { int rc, i; struct mon_private *monpriv = filp->private_data; @@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ - rc = iucv_sever(monpriv->pathid, user_data_sever); + rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) P_ERROR("close, iucv_sever failed with rc = %i\n", rc); else P_INFO("close, terminated connection to *MONITOR service\n"); - rc = iucv_unregister_program(monpriv->iucv_handle); - if (rc) - P_ERROR("close, iucv_unregister failed with rc = %i\n", rc); - else - P_INFO("close, unregistered with IUCV\n"); - atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); @@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp) return 0; } -static ssize_t -mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) +static ssize_t mon_read(struct file *filp, char __user *data, + size_t count, loff_t *ppos) { struct mon_private *monpriv = filp->private_data; struct mon_msg *monmsg; @@ -563,8 +535,7 @@ out_copy: return count; } -static unsigned int -mon_poll(struct file *filp, struct poll_table_struct *p) +static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) { struct mon_private *monpriv = filp->private_data; @@ -593,8 +564,7 @@ static struct miscdevice mon_dev = { /****************************************************************************** * module init/exit * *****************************************************************************/ -static int __init -mon_init(void) +static int __init mon_init(void) { int rc; @@ -603,22 +573,34 @@ mon_init(void) return -ENODEV; } + /* + * Register with IUCV and connect to *MONITOR service + */ + rc = iucv_register(&monreader_iucv_handler, 1); + if (rc) { + P_ERROR("failed to register with iucv driver\n"); + return rc; + } + P_INFO("open, registered with IUCV\n"); + rc = segment_type(mon_dcss_name); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return rc; + goto out_iucv; } if (rc != SEG_TYPE_SC) { P_ERROR("segment %s has unsupported type, should be SC\n", mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -634,14 +616,16 @@ mon_init(void) out: segment_unload(mon_dcss_name); +out_iucv: + iucv_unregister(&monreader_iucv_handler, 1); return rc; } -static void __exit -mon_exit(void) +static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + iucv_unregister(&monreader_iucv_handler, 1); return; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 4f894dc2373b..8432a76b961e 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright (C) 2004 IBM Corporation + * Copyright 2004 IBM Corporation * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow <xenia@us.ibm.com> @@ -21,7 +21,7 @@ #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/ebcdic.h> -#include "../net/iucv.h" +#include <net/iucv/iucv.h> #include <linux/kmod.h> #include <linux/cdev.h> #include <linux/device.h> @@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { char system_service[8]; char internal_name[8]; char recording_name[8]; - u16 pathid; + struct iucv_path *path; int connection_established; int iucv_path_severed; - iucv_MessagePending local_interrupt_buffer; + struct iucv_message local_interrupt_buffer; atomic_t receive_ready; - iucv_handle_t iucv_handle; int minor_num; char * buffer; char * current_position; @@ -97,37 +96,19 @@ static struct file_operations vmlogrdr_fops = { }; -static u8 iucvMagic[16] = { - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 -}; +static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_message_pending(struct iucv_path *, + struct iucv_message *); -static u8 mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +static struct iucv_handler vmlogrdr_iucv_handler = { + .path_complete = vmlogrdr_iucv_path_complete, + .path_severed = vmlogrdr_iucv_path_severed, + .message_pending = vmlogrdr_iucv_message_pending, }; -static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - -static void -vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); -static void -vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); -static void -vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); - - -static iucv_interrupt_ops_t vmlogrdr_iucvops = { - .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, - .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, - .MessagePending = vmlogrdr_iucv_MessagePending, -}; - static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); @@ -176,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL; static int recording_class_AB; -static void -vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, - void * pgm_data) +static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + spin_lock(&logptr->priv_lock); logptr->connection_established = 1; spin_unlock(&logptr->priv_lock); wake_up(&conn_wait_queue); - return; } -static void -vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) +static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - u8 reason = (u8) eib->ipuser[8]; - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + u8 reason = (u8) ipuser[8]; printk (KERN_ERR "vmlogrdr: connection severed with" " reason %i\n", reason); + iucv_path_sever(path, NULL); + kfree(path); + logptr->path = NULL; + spin_lock(&logptr->priv_lock); logptr->connection_established = 0; logptr->iucv_path_severed = 1; @@ -209,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) } -static void -vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) +static void vmlogrdr_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; /* * This function is the bottom half so it should be quick. @@ -220,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) * the usage count */ spin_lock(&logptr->priv_lock); - memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); + memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); atomic_inc(&logptr->receive_ready); spin_unlock(&logptr->priv_lock); wake_up_interruptible(&read_wait_queue); } -static int -vmlogrdr_get_recording_class_AB(void) { +static int vmlogrdr_get_recording_class_AB(void) +{ char cp_command[]="QUERY COMMAND RECORDING "; char cp_response[80]; char *tail; @@ -258,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { } -static int -vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { +static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, + int action, int purge) +{ char cp_command[80]; char cp_response[160]; @@ -317,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { } -static int -vmlogrdr_open (struct inode *inode, struct file *filp) +static int vmlogrdr_open (struct inode *inode, struct file *filp) { int dev_num = 0; struct vmlogrdr_priv_t * logptr = NULL; @@ -328,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp) dev_num = iminor(inode); if (dev_num > MAXMINOR) return -ENODEV; - logptr = &sys_ser[dev_num]; - if (logptr == NULL) - return -ENODEV; /* * only allow for blocking reads to be open @@ -344,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp) if (logptr->dev_in_use) { spin_unlock_bh(&logptr->priv_lock); return -EBUSY; - } else { - logptr->dev_in_use = 1; - spin_unlock_bh(&logptr->priv_lock); } - + logptr->dev_in_use = 1; + logptr->connection_established = 0; + logptr->iucv_path_severed = 0; atomic_set(&logptr->receive_ready, 0); logptr->buffer_free = 1; + spin_unlock_bh(&logptr->priv_lock); /* set the file options */ filp->private_data = logptr; filp->f_op = &vmlogrdr_fops; /* start recording for this service*/ - ret=0; - if (logptr->autorecording) + if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); - if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); - - /* Register with iucv driver */ - logptr->iucv_handle = iucv_register_program(iucvMagic, - logptr->system_service, mask, &vmlogrdr_iucvops, - logptr); - - if (logptr->iucv_handle == NULL) { - printk (KERN_ERR "vmlogrdr: failed to register with" - "iucv driver\n"); - goto not_registered; + if (ret) + printk (KERN_WARNING "vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ - spin_lock_bh(&logptr->priv_lock); - logptr->connection_established = 0; - logptr->iucv_path_severed = 0; - spin_unlock_bh(&logptr->priv_lock); - - connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, - logptr->system_service, iucv_host, 0, - NULL, NULL, - logptr->iucv_handle, NULL); + logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); + if (!logptr->path) + goto out_dev; + connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, + logptr->system_service, NULL, NULL, + logptr); if (connect_rc) { printk (KERN_ERR "vmlogrdr: iucv connection to %s " "failed with rc %i \n", logptr->system_service, connect_rc); - goto not_connected; + goto out_path; } /* We've issued the connect and now we must wait for a @@ -398,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp) */ wait_event(conn_wait_queue, (logptr->connection_established) || (logptr->iucv_path_severed)); - if (logptr->iucv_path_severed) { - goto not_connected; - } - + if (logptr->iucv_path_severed) + goto out_record; return nonseekable_open(inode, filp); -not_connected: - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; -not_registered: +out_record: if (logptr->autorecording) vmlogrdr_recording(logptr,0,logptr->autopurge); +out_path: + kfree(logptr->path); /* kfree(NULL) is ok. */ + logptr->path = NULL; +out_dev: logptr->dev_in_use = 0; return -EIO; - - } -static int -vmlogrdr_release (struct inode *inode, struct file *filp) +static int vmlogrdr_release (struct inode *inode, struct file *filp) { int ret; struct vmlogrdr_priv_t * logptr = filp->private_data; - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; - if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) @@ -439,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp) } -static int -vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) +{ int rc, *temp; /* we need to keep track of two data sizes here: * The number of bytes we need to receive from iucv and @@ -461,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { * We need to return the total length of the record * + size of FENCE in the first 4 bytes of the buffer. */ - iucv_data_count = - priv->local_interrupt_buffer.ln1msg2.ipbfln1f; + iucv_data_count = priv->local_interrupt_buffer.length; user_data_count = sizeof(int); temp = (int*)priv->buffer; *temp= iucv_data_count + sizeof(FENCE); @@ -474,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { */ if (iucv_data_count > NET_BUFFER_SIZE) iucv_data_count = NET_BUFFER_SIZE; - rc = iucv_receive(priv->pathid, - priv->local_interrupt_buffer.ipmsgid, - priv->local_interrupt_buffer.iptrgcls, - buffer, - iucv_data_count, - NULL, - NULL, - &priv->residual_length); + rc = iucv_message_receive(priv->path, + &priv->local_interrupt_buffer, + 0, buffer, iucv_data_count, + &priv->residual_length); spin_unlock_bh(&priv->priv_lock); /* An rc of 5 indicates that the record was bigger then * the buffer, which is OK for us. A 9 indicates that the @@ -513,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { } -static ssize_t -vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) +static ssize_t vmlogrdr_read(struct file *filp, char __user *data, + size_t count, loff_t * ppos) { int rc; struct vmlogrdr_priv_t * priv = filp->private_data; @@ -546,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) return count; } -static ssize_t -vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_autopurge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -565,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con } -static ssize_t -vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autopurge_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autopurge); } @@ -576,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, vmlogrdr_autopurge_store); -static ssize_t -vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_purge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ char cp_command[80]; char cp_response[80]; @@ -617,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); -static ssize_t -vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) { +static ssize_t vmlogrdr_autorecording_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -637,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, } -static ssize_t -vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autorecording_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autorecording); } @@ -648,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, vmlogrdr_autorecording_store); -static ssize_t -vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - +static ssize_t vmlogrdr_recording_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret; @@ -675,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); -static ssize_t -vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { +static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, + char *buf) +{ char cp_command[] = "QUERY RECORDING "; int len; @@ -709,52 +673,63 @@ static struct device_driver vmlogrdr_driver = { }; -static int -vmlogrdr_register_driver(void) { +static int vmlogrdr_register_driver(void) +{ int ret; + /* Register with iucv driver */ + ret = iucv_register(&vmlogrdr_iucv_handler, 1); + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with" + "iucv driver\n"); + goto out; + } + ret = driver_register(&vmlogrdr_driver); if (ret) { printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); - return ret; + goto out_iucv; } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); if (ret) { printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); - goto unregdriver; + goto out_driver; } vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { printk(KERN_ERR "vmlogrdr: failed to create class.\n"); - ret=PTR_ERR(vmlogrdr_class); - vmlogrdr_class=NULL; - goto unregattr; + ret = PTR_ERR(vmlogrdr_class); + vmlogrdr_class = NULL; + goto out_attr; } return 0; -unregattr: +out_attr: driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); -unregdriver: +out_driver: driver_unregister(&vmlogrdr_driver); +out_iucv: + iucv_unregister(&vmlogrdr_iucv_handler, 1); +out: return ret; } -static void -vmlogrdr_unregister_driver(void) { +static void vmlogrdr_unregister_driver(void) +{ class_destroy(vmlogrdr_class); vmlogrdr_class = NULL; driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); driver_unregister(&vmlogrdr_driver); - return; + iucv_unregister(&vmlogrdr_iucv_handler, 1); } -static int -vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) +{ struct device *dev; int ret; @@ -803,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { } -static int -vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { - class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); +static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) +{ + class_device_destroy(vmlogrdr_class, + MKDEV(vmlogrdr_major, priv->minor_num)); if (priv->device != NULL) { sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); device_unregister(priv->device); @@ -815,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { } -static int -vmlogrdr_register_cdev(dev_t dev) { +static int vmlogrdr_register_cdev(dev_t dev) +{ int rc = 0; vmlogrdr_cdev = cdev_alloc(); if (!vmlogrdr_cdev) { @@ -836,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { } -static void -vmlogrdr_cleanup(void) { +static void vmlogrdr_cleanup(void) +{ int i; + if (vmlogrdr_cdev) { cdev_del(vmlogrdr_cdev); vmlogrdr_cdev=NULL; @@ -855,8 +832,7 @@ vmlogrdr_cleanup(void) { } -static int -vmlogrdr_init(void) +static int vmlogrdr_init(void) { int rc; int i; @@ -906,8 +882,7 @@ cleanup: } -static void -vmlogrdr_exit(void) +static void vmlogrdr_exit(void) { vmlogrdr_cleanup(); printk (KERN_INFO "vmlogrdr: driver unloaded\n"); diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 52625153a4f0..f98fa465df0a 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -22,13 +22,6 @@ config CTC available. This option is also available as a module which will be called ctc.ko. If you do not know what it is, it's safe to say "Y". -config IUCV - tristate "IUCV support (VM only)" - help - Select this option if you want to use inter-user communication - under VM or VIF. If unsure, say "Y" to enable a fast communication - link between VM guests. - config NETIUCV tristate "IUCV network device support (VM only)" depends on IUCV && NETDEVICES diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 4777e36a922f..bbe3ab2e93d9 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -4,7 +4,6 @@ ctc-objs := ctcmain.o ctcdbug.o -obj-$(CONFIG_IUCV) += iucv.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c deleted file mode 100644 index 229aeb5fc399..000000000000 --- a/drivers/s390/net/iucv.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * IUCV network driver - * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): - * Original source: - * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 - * Xenia Tkatschow (xenia@us.ibm.com) - * 2Gb awareness and general cleanup: - * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) - * - * Documentation used: - * The original source - * CP Programming Service, IBM document # SC24-5760 - * - * 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. - * - */ - -/* #define DEBUG */ - -#include <linux/module.h> -#include <linux/moduleparam.h> - -#include <linux/spinlock.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/device.h> -#include <asm/atomic.h> -#include "iucv.h" -#include <asm/io.h> -#include <asm/s390_ext.h> -#include <asm/ebcdic.h> -#include <asm/smp.h> -#include <asm/s390_rdev.h> - -/* FLAGS: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPSRCCLS - Indicates you have specified a source class - * IPFGMCL - Indicates you have specified a target class - * IPFGPID - Indicates you have specified a pathid - * IPFGMID - Indicates you have specified a message ID - * IPANSLST - Indicates that you are using an address list for - * reply data - * IPBUFLST - Indicates that you are using an address list for - * message data - */ - -#define IPSRCCLS 0x01 -#define IPFGMCL 0x01 -#define IPFGPID 0x02 -#define IPFGMID 0x04 -#define IPANSLST 0x08 -#define IPBUFLST 0x40 - -static int -iucv_bus_match (struct device *dev, struct device_driver *drv) -{ - return 0; -} - -struct bus_type iucv_bus = { - .name = "iucv", - .match = iucv_bus_match, -}; - -struct device *iucv_root; - -/* General IUCV interrupt structure */ -typedef struct { - __u16 ippathid; - __u8 res1; - __u8 iptype; - __u32 res2; - __u8 ipvmid[8]; - __u8 res3[24]; -} iucv_GeneralInterrupt; - -static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL; - -/* Spin Lock declaration */ - -static DEFINE_SPINLOCK(iucv_lock); - -static int messagesDisabled = 0; - -/***************INTERRUPT HANDLING ***************/ - -typedef struct { - struct list_head queue; - iucv_GeneralInterrupt data; -} iucv_irqdata; - -static struct list_head iucv_irq_queue; -static DEFINE_SPINLOCK(iucv_irq_queue_lock); - -/* - *Internal function prototypes - */ -static void iucv_tasklet_handler(unsigned long); -static void iucv_irq_handler(__u16); - -static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); - -/************ FUNCTION ID'S ****************************/ - -#define ACCEPT 10 -#define CONNECT 11 -#define DECLARE_BUFFER 12 -#define PURGE 9 -#define QUERY 0 -#define QUIESCE 13 -#define RECEIVE 5 -#define REJECT 8 -#define REPLY 6 -#define RESUME 14 -#define RETRIEVE_BUFFER 2 -#define SEND 4 -#define SETMASK 16 -#define SEVER 15 - -/** - * Structure: handler - * members: list - list management. - * structure: id - * userid - 8 char array of machine identification - * user_data - 16 char array for user identification - * mask - 24 char array used to compare the 2 previous - * interrupt_table - vector of interrupt functions. - * pgm_data - ulong, application data that is passed - * to the interrupt handlers -*/ -typedef struct handler_t { - struct list_head list; - struct { - __u8 userid[8]; - __u8 user_data[16]; - __u8 mask[24]; - } id; - iucv_interrupt_ops_t *interrupt_table; - void *pgm_data; -} handler; - -/** - * iucv_handler_table: List of registered handlers. - */ -static struct list_head iucv_handler_table; - -/** - * iucv_pathid_table: an array of *handler pointing into - * iucv_handler_table for fast indexing by pathid; - */ -static handler **iucv_pathid_table; - -static unsigned long max_connections; - -/** - * iucv_cpuid: contains the logical cpu number of the cpu which - * has declared the iucv buffer by issuing DECLARE_BUFFER. - * If no cpu has done the initialization iucv_cpuid contains -1. - */ -static int iucv_cpuid = -1; -/** - * register_flag: is 0 when external interrupt has not been registered - */ -static int register_flag; - -/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ -/* Data struct 1: iparml_control - * Used for iucv_accept - * iucv_connect - * iucv_quiesce - * iucv_resume - * iucv_sever - * iucv_retrieve_buffer - * Data struct 2: iparml_dpl (data in parameter list) - * Used for iucv_send_prmmsg - * iucv_send2way_prmmsg - * iucv_send2way_prmmsg_array - * iucv_reply_prmmsg - * Data struct 3: iparml_db (data in a buffer) - * Used for iucv_receive - * iucv_receive_array - * iucv_reject - * iucv_reply - * iucv_reply_array - * iucv_send - * iucv_send_array - * iucv_send2way - * iucv_send2way_array - * iucv_declare_buffer - * Data struct 4: iparml_purge - * Used for iucv_purge - * iucv_query - * Data struct 5: iparml_set_mask - * Used for iucv_set_mask - */ - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u16 ipmsglim; - __u16 res1; - __u8 ipvmid[8]; - __u8 ipuser[16]; - __u8 iptarget[8]; -} iparml_control; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u8 iprmmsg[8]; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_dpl; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u32 ipbfadr1; - __u32 ipbfln1f; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_db; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u8 ipaudit[3]; - __u8 res1[5]; - __u32 res2; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 res3[3]; -} iparml_purge; - -typedef struct { - __u8 ipmask; - __u8 res1[2]; - __u8 iprcode; - __u32 res2[9]; -} iparml_set_mask; - -typedef struct { - union { - iparml_control p_ctrl; - iparml_dpl p_dpl; - iparml_db p_db; - iparml_purge p_purge; - iparml_set_mask p_set_mask; - } param; - atomic_t in_use; - __u32 res; -} __attribute__ ((aligned(8))) iucv_param; -#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) - -static iucv_param * iucv_param_pool; - -MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); -MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); -MODULE_LICENSE("GPL"); - -/* - * Debugging stuff - *******************************************************************************/ - - -#ifdef DEBUG -static int debuglevel = 0; - -module_param(debuglevel, int, 0); -MODULE_PARM_DESC(debuglevel, - "Specifies the debug level (0=off ... 3=all)"); - -static void -iucv_dumpit(char *title, void *buf, int len) -{ - int i; - __u8 *p = (__u8 *)buf; - - if (debuglevel < 3) - return; - - printk(KERN_DEBUG "%s\n", title); - printk(" "); - for (i = 0; i < len; i++) { - if (!(i % 16) && i != 0) - printk ("\n "); - else if (!(i % 4) && i != 0) - printk(" "); - printk("%02X", *p++); - } - if (len % 16) - printk ("\n"); - return; -} -#define iucv_debug(lvl, fmt, args...) \ -do { \ - if (debuglevel >= lvl) \ - printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \ -} while (0) - -#else - -#define iucv_debug(lvl, fmt, args...) do { } while (0) -#define iucv_dumpit(title, buf, len) do { } while (0) - -#endif - -/* - * Internal functions - *******************************************************************************/ - -/** - * print start banner - */ -static void -iucv_banner(void) -{ - printk(KERN_INFO "IUCV lowlevel driver initialized\n"); -} - -/** - * iucv_init - Initialization - * - * Allocates and initializes various data structures. - */ -static int -iucv_init(void) -{ - int ret; - - if (iucv_external_int_buffer) - return 0; - - if (!MACHINE_IS_VM) { - printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); - return -EPROTONOSUPPORT; - } - - ret = bus_register(&iucv_bus); - if (ret) { - printk(KERN_ERR "IUCV: failed to register bus.\n"); - return ret; - } - - iucv_root = s390_root_dev_register("iucv"); - if (IS_ERR(iucv_root)) { - printk(KERN_ERR "IUCV: failed to register iucv root.\n"); - bus_unregister(&iucv_bus); - return PTR_ERR(iucv_root); - } - - /* Note: GFP_DMA used used to get memory below 2G */ - iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt), - GFP_KERNEL|GFP_DMA); - if (!iucv_external_int_buffer) { - printk(KERN_WARNING - "%s: Could not allocate external interrupt buffer\n", - __FUNCTION__); - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize parameter pool */ - iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, - GFP_KERNEL|GFP_DMA); - if (!iucv_param_pool) { - printk(KERN_WARNING "%s: Could not allocate param pool\n", - __FUNCTION__); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize irq queue */ - INIT_LIST_HEAD(&iucv_irq_queue); - - /* Initialize handler table */ - INIT_LIST_HEAD(&iucv_handler_table); - - iucv_banner(); - return 0; -} - -/** - * iucv_exit - De-Initialization - * - * Frees everything allocated from iucv_init. - */ -static int iucv_retrieve_buffer (void); - -static void -iucv_exit(void) -{ - iucv_retrieve_buffer(); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - kfree(iucv_param_pool); - iucv_param_pool = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); -} - -/** - * grab_param: - Get a parameter buffer from the pre-allocated pool. - * - * This function searches for an unused element in the pre-allocated pool - * of parameter buffers. If one is found, it marks it "in use" and returns - * a pointer to it. The calling function is responsible for releasing it - * when it has finished its usage. - * - * Returns: A pointer to iucv_param. - */ -static __inline__ iucv_param * -grab_param(void) -{ - iucv_param *ptr; - static int hint = 0; - - ptr = iucv_param_pool + hint; - do { - ptr++; - if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) - ptr = iucv_param_pool; - } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0); - hint = ptr - iucv_param_pool; - - memset(&ptr->param, 0, sizeof(ptr->param)); - return ptr; -} - -/** - * release_param - Release a parameter buffer. - * @p: A pointer to a struct iucv_param, previously obtained by calling - * grab_param(). - * - * This function marks the specified parameter buffer "unused". - */ -static __inline__ void -release_param(void *p) -{ - atomic_set(&((iucv_param *)p)->in_use, 0); -} - -/** - * iucv_add_handler: - Add a new handler - * @new_handler: handle that is being entered into chain. - * - * Places new handle on iucv_handler_table, if identical handler is not - * found. - * - * Returns: 0 on success, !0 on failure (handler already in chain). - */ -static int -iucv_add_handler (handler *new) -{ - ulong flags; - - iucv_debug(1, "entering"); - iucv_dumpit("handler:", new, sizeof(handler)); - - spin_lock_irqsave (&iucv_lock, flags); - if (!list_empty(&iucv_handler_table)) { - struct list_head *lh; - - /** - * Search list for handler with identical id. If one - * is found, the new handler is _not_ added. - */ - list_for_each(lh, &iucv_handler_table) { - handler *h = list_entry(lh, handler, list); - if (!memcmp(&new->id, &h->id, sizeof(h->id))) { - iucv_debug(1, "ret 1"); - spin_unlock_irqrestore (&iucv_lock, flags); - return 1; - } - } - } - /** - * If we get here, no handler was found. - */ - INIT_LIST_HEAD(&new->list); - list_add(&new->list, &iucv_handler_table); - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * b2f0: - * @code: identifier of IUCV call to CP. - * @parm: pointer to 40 byte iparml area passed to CP - * - * Calls CP to execute IUCV commands. - * - * Returns: return code from CP's IUCV call - */ -static inline ulong b2f0(__u32 code, void *parm) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); - - reg0 = code; - reg1 = virt_to_phys(parm); - asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1)); - - iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); - - return (unsigned long)*((__u8 *)(parm + 3)); -} - -/* - * Name: iucv_add_pathid - * Purpose: Adds a path id to the system. - * Input: pathid - pathid that is going to be entered into system - * handle - address of handler that the pathid will be associated - * with. - * pgm_data - token passed in by application. - * Output: 0: successful addition of pathid - * - EINVAL - pathid entry is being used by another application - * - ENOMEM - storage allocation for a new pathid table failed -*/ -static int -__iucv_add_pathid(__u16 pathid, handler *handler) -{ - - iucv_debug(1, "entering"); - - iucv_debug(1, "handler is pointing to %p", handler); - - if (pathid > (max_connections - 1)) - return -EINVAL; - - if (iucv_pathid_table[pathid]) { - iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); - printk(KERN_WARNING - "%s: Pathid being used, error.\n", __FUNCTION__); - return -EINVAL; - } - iucv_pathid_table[pathid] = handler; - - iucv_debug(1, "exiting"); - return 0; -} /* end of add_pathid function */ - -static int -iucv_add_pathid(__u16 pathid, handler *handler) -{ - ulong flags; - int rc; - - spin_lock_irqsave (&iucv_lock, flags); - rc = __iucv_add_pathid(pathid, handler); - spin_unlock_irqrestore (&iucv_lock, flags); - return rc; -} - -static void -iucv_remove_pathid(__u16 pathid) -{ - ulong flags; - - if (pathid > (max_connections - 1)) - return; - - spin_lock_irqsave (&iucv_lock, flags); - iucv_pathid_table[pathid] = NULL; - spin_unlock_irqrestore (&iucv_lock, flags); -} - -/** - * iucv_declare_buffer_cpuid - * Register at VM for subsequent IUCV operations. This is executed - * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). - */ -static void -iucv_declare_buffer_cpuid (void *result) -{ - iparml_db *parm; - - parm = (iparml_db *)grab_param(); - parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); - if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) - *((ulong *)result) = parm->iprcode; - release_param(parm); -} - -/** - * iucv_retrieve_buffer_cpuid: - * Unregister IUCV usage at VM. This is always executed on the same - * cpu that registered the buffer to VM. - * Called from iucv_retrieve_buffer(). - */ -static void -iucv_retrieve_buffer_cpuid (void *cpu) -{ - iparml_control *parm; - - parm = (iparml_control *)grab_param(); - b2f0(RETRIEVE_BUFFER, parm); - release_param(parm); -} - -/** - * Name: iucv_declare_buffer - * Purpose: Specifies the guests real address of an external - * interrupt. - * Input: void - * Output: iprcode - return code from b2f0 call - */ -static int -iucv_declare_buffer (void) -{ - unsigned long flags; - ulong b2f0_result; - - iucv_debug(1, "entering"); - b2f0_result = -ENODEV; - spin_lock_irqsave (&iucv_lock, flags); - if (iucv_cpuid == -1) { - /* Reserve any cpu for use by iucv. */ - iucv_cpuid = smp_get_cpu(CPU_MASK_ALL); - spin_unlock_irqrestore (&iucv_lock, flags); - smp_call_function_on(iucv_declare_buffer_cpuid, - &b2f0_result, 0, 1, iucv_cpuid); - if (b2f0_result) { - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); - } else { - spin_unlock_irqrestore (&iucv_lock, flags); - b2f0_result = 0; - } - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_retrieve_buffer: - * - * Terminates all use of IUCV. - * Returns: return code from CP - */ -static int -iucv_retrieve_buffer (void) -{ - iucv_debug(1, "entering"); - if (iucv_cpuid != -1) { - smp_call_function_on(iucv_retrieve_buffer_cpuid, - NULL, 0, 1, iucv_cpuid); - /* Release the cpu reserved by iucv_declare_buffer. */ - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_remove_handler: - * @users_handler: handler to be removed - * - * Remove handler when application unregisters. - */ -static void -iucv_remove_handler(handler *handler) -{ - unsigned long flags; - - if ((!iucv_pathid_table) || (!handler)) - return; - - iucv_debug(1, "entering"); - - spin_lock_irqsave (&iucv_lock, flags); - list_del(&handler->list); - if (list_empty(&iucv_handler_table)) { - if (register_flag) { - unregister_external_interrupt(0x4000, iucv_irq_handler); - register_flag = 0; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return; -} - -/** - * iucv_register_program: - * @pgmname: user identification - * @userid: machine identification - * @pgmmask: Indicates which bits in the pgmname and userid combined will be - * used to determine who is given control. - * @ops: Address of interrupt handler table. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * Registers an application with IUCV. - * Returns: - * The address of handler, or NULL on failure. - * NOTE on pgmmask: - * If pgmname, userid and pgmmask are provided, pgmmask is entered into the - * handler as is. - * If pgmmask is NULL, the internal mask is set to all 0xff's - * When userid is NULL, the first 8 bytes of the internal mask are forced - * to 0x00. - * If pgmmask and userid are NULL, the first 8 bytes of the internal mask - * are forced to 0x00 and the last 16 bytes to 0xff. - */ - -iucv_handle_t -iucv_register_program (__u8 pgmname[16], - __u8 userid[8], - __u8 pgmmask[24], - iucv_interrupt_ops_t * ops, void *pgm_data) -{ - ulong rc = 0; /* return code from function calls */ - handler *new_handler; - - iucv_debug(1, "entering"); - - if (ops == NULL) { - /* interrupt table is not defined */ - printk(KERN_WARNING "%s: Interrupt table is not defined, " - "exiting\n", __FUNCTION__); - return NULL; - } - if (!pgmname) { - printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); - return NULL; - } - - /* Allocate handler entry */ - new_handler = kmalloc(sizeof(handler), GFP_ATOMIC); - if (new_handler == NULL) { - printk(KERN_WARNING "%s: storage allocation for new handler " - "failed.\n", __FUNCTION__); - return NULL; - } - - if (!iucv_pathid_table) { - if (iucv_init()) { - kfree(new_handler); - return NULL; - } - - max_connections = iucv_query_maxconn(); - iucv_pathid_table = kcalloc(max_connections, sizeof(handler *), - GFP_ATOMIC); - if (iucv_pathid_table == NULL) { - printk(KERN_WARNING "%s: iucv_pathid_table storage " - "allocation failed\n", __FUNCTION__); - kfree(new_handler); - return NULL; - } - } - memset(new_handler, 0, sizeof (handler)); - memcpy(new_handler->id.user_data, pgmname, - sizeof (new_handler->id.user_data)); - if (userid) { - memcpy (new_handler->id.userid, userid, - sizeof (new_handler->id.userid)); - ASCEBC (new_handler->id.userid, - sizeof (new_handler->id.userid)); - EBC_TOUPPER (new_handler->id.userid, - sizeof (new_handler->id.userid)); - - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - } else { - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - memset (new_handler->id.userid, 0x00, - sizeof (new_handler->id.userid)); - } - /* fill in the rest of handler */ - new_handler->pgm_data = pgm_data; - new_handler->interrupt_table = ops; - - /* - * Check if someone else is registered with same pgmname, userid - * and mask. If someone is already registered with same pgmname, - * userid and mask, registration will fail and NULL will be returned - * to the application. - * If identical handler not found, then handler is added to list. - */ - rc = iucv_add_handler(new_handler); - if (rc) { - printk(KERN_WARNING "%s: Someone already registered with same " - "pgmname, userid, pgmmask\n", __FUNCTION__); - kfree (new_handler); - return NULL; - } - - rc = iucv_declare_buffer(); - if (rc) { - char *err = "Unknown"; - iucv_remove_handler(new_handler); - kfree(new_handler); - switch(rc) { - case 0x03: - err = "Directory error"; - break; - case 0x0a: - err = "Invalid length"; - break; - case 0x13: - err = "Buffer already exists"; - break; - case 0x3e: - err = "Buffer overlap"; - break; - case 0x5c: - err = "Paging or storage error"; - break; - } - printk(KERN_WARNING "%s: iucv_declare_buffer " - "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err); - return NULL; - } - if (!register_flag) { - /* request the 0x4000 external interrupt */ - rc = register_external_interrupt (0x4000, iucv_irq_handler); - if (rc) { - iucv_remove_handler(new_handler); - kfree (new_handler); - printk(KERN_WARNING "%s: " - "register_external_interrupt returned %ld\n", - __FUNCTION__, rc); - return NULL; - - } - register_flag = 1; - } - iucv_debug(1, "exiting"); - return new_handler; -} /* end of register function */ - -/** - * iucv_unregister_program: - * @handle: address of handler - * - * Unregister application with IUCV. - * Returns: - * 0 on success, -EINVAL, if specified handle is invalid. - */ - -int -iucv_unregister_program (iucv_handle_t handle) -{ - handler *h = NULL; - struct list_head *lh; - int i; - ulong flags; - - iucv_debug(1, "entering"); - iucv_debug(1, "address of handler is %p", h); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - if (!h) { - spin_unlock_irqrestore (&iucv_lock, flags); - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - /** - * First, walk thru iucv_pathid_table and sever any pathid which is - * still pointing to the handler to be removed. - */ - for (i = 0; i < max_connections; i++) - if (iucv_pathid_table[i] == h) { - spin_unlock_irqrestore (&iucv_lock, flags); - iucv_sever(i, h->id.user_data); - spin_lock_irqsave(&iucv_lock, flags); - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_remove_handler(h); - kfree(h); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_accept: - * @pathid: Path identification number - * @msglim_reqstd: The number of outstanding messages requested. - * @user_data: Data specified by the iucv_connect function. - * @flags1: Contains options for this path. - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * @handle: Address of handler. - * @pgm_data: Application data passed to interrupt handlers. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * - * This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Returns: - * return code from CP - */ -int -iucv_accept(__u16 pathid, __u16 msglim_reqstd, - __u8 user_data[16], int flags1, - iucv_handle_t handle, void *pgm_data, - int *flags1_out, __u16 * msglim) -{ - ulong b2f0_result = 0; - ulong flags; - struct list_head *lh; - handler *h = NULL; - iparml_control *parm; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsglim = msglim_reqstd; - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(ACCEPT, parm); - - if (!b2f0_result) { - if (msglim) - *msglim = parm->ipmsglim; - if (pgm_data) - h->pgm_data = pgm_data; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - } - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_connect: - * @pathid: Path identification number - * @msglim_reqstd: Number of outstanding messages requested - * @user_data: 16-byte user data - * @userid: 8-byte of user identification - * @system_name: 8-byte identifying the system name - * @flags1: Specifies options for this path: - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * - IPLOCAL (0x01) Allows an application to force the partner to be on the - * local system. If local is specified then target class - * cannot be specified. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * @handle: Address of handler. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Returns: return code from CP, or one of the following - * - ENOMEM - * - return code from iucv_declare_buffer - * - EINVAL - invalid handle passed by application - * - EINVAL - pathid address is NULL - * - ENOMEM - pathid table storage allocation failed - * - return code from internal function add_pathid - */ -int -iucv_connect (__u16 *pathid, __u16 msglim_reqstd, - __u8 user_data[16], __u8 userid[8], - __u8 system_name[8], int flags1, - int *flags1_out, __u16 * msglim, - iucv_handle_t handle, void *pgm_data) -{ - iparml_control *parm; - iparml_control local_parm; - struct list_head *lh; - ulong b2f0_result = 0; - ulong flags; - int add_pathid_result = 0; - handler *h = NULL; - __u8 no_memory[16] = "NO MEMORY"; - - iucv_debug(1, "entering"); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - if (pathid == NULL) { - printk(KERN_WARNING "%s: NULL pathid pointer\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ipmsglim = msglim_reqstd; - - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - if (userid) { - memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); - ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); - EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); - } - - if (system_name) { - memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); - ASCEBC(parm->iptarget, sizeof(parm->iptarget)); - EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); - } - - /* In order to establish an IUCV connection, the procedure is: - * - * b2f0(CONNECT) - * take the ippathid from the b2f0 call - * register the handler to the ippathid - * - * Unfortunately, the ConnectionEstablished message gets sent after the - * b2f0(CONNECT) call but before the register is handled. - * - * In order for this race condition to be eliminated, the IUCV Control - * Interrupts must be disabled for the above procedure. - * - * David Kennedy <dkennedy@linuxcare.com> - */ - - /* Enable everything but IUCV Control messages */ - iucv_setmask(~(AllInterrupts)); - messagesDisabled = 1; - - spin_lock_irqsave (&iucv_lock, flags); - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(CONNECT, parm); - memcpy(&local_parm, parm, sizeof(local_parm)); - release_param(parm); - parm = &local_parm; - if (!b2f0_result) - add_pathid_result = __iucv_add_pathid(parm->ippathid, h); - spin_unlock_irqrestore (&iucv_lock, flags); - - if (b2f0_result) { - iucv_setmask(~0); - messagesDisabled = 0; - return b2f0_result; - } - - *pathid = parm->ippathid; - - /* Enable everything again */ - iucv_setmask(IUCVControlInterruptsFlag); - - if (msglim) - *msglim = parm->ipmsglim; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - - if (add_pathid_result) { - iucv_sever(*pathid, no_memory); - printk(KERN_WARNING "%s: add_pathid failed with rc =" - " %d\n", __FUNCTION__, add_pathid_result); - return(add_pathid_result); - } - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_purge: - * @pathid: Path identification number - * @msgid: Message ID of message to purge. - * @srccls: Message class of the message to purge. - * @audit: Pointer to an __u32. If not NULL, on return, information about - * asynchronous errors that may have affected the normal completion - * of this message ist stored at the given location. - * - * Cancels a message you have sent. - * Returns: return code from CP - */ -int -iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit) -{ - iparml_purge *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_purge *)grab_param(); - - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->ipsrccls = srccls; - parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); - b2f0_result = b2f0(PURGE, parm); - - if (!b2f0_result && audit) { - memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); - /* parm->ipaudit has only 3 bytes */ - *audit >>= 8; - } - - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_query_generic: - * @want_maxconn: Flag, describing which value is to be returned. - * - * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). - * - * Returns: The buffersize, if want_maxconn is 0; the maximum number of - * connections, if want_maxconn is 1 or an error-code < 0 on failure. - */ -static int -iucv_query_generic(int want_maxconn) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iparml_purge *parm = (iparml_purge *)grab_param(); - int bufsize, maxconn; - int ccode; - - /** - * Call b2f0 and store R0 (max buffer size), - * R1 (max connections) and CC. - */ - reg0 = QUERY; - reg1 = virt_to_phys(parm); - asm volatile( - " .long 0xb2f01000\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); - bufsize = reg0; - maxconn = reg1; - release_param(parm); - - if (ccode) - return -EPERM; - if (want_maxconn) - return maxconn; - return bufsize; -} - -/** - * iucv_query_maxconn: - * - * Determines the maximum number of connections thay may be established. - * - * Returns: Maximum number of connections that can be. - */ -ulong -iucv_query_maxconn(void) -{ - return iucv_query_generic(1); -} - -/** - * iucv_query_bufsize: - * - * Determines the size of the external interrupt buffer. - * - * Returns: Size of external interrupt buffer. - */ -ulong -iucv_query_bufsize (void) -{ - return iucv_query_generic(0); -} - -/** - * iucv_quiesce: - * @pathid: Path identification number - * @user_data: 16-byte user data - * - * Temporarily suspends incoming messages on an IUCV path. - * You can later reactivate the path by invoking the iucv_resume function. - * Returns: return code from CP - */ -int -iucv_quiesce (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(QUIESCE, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/** - * iucv_receive: - * @pathid: Path identification number. - * @buffer: Address of buffer to receive. Must be below 2G. - * @buflen: Length of buffer to receive. - * @msgid: Specifies the message ID. - * @trgcls: Specifies target class. - * @flags1_out: Receives options for path on return. - * - IPNORPY (0x10) Specifies whether a reply is required - * - IPPRTY (0x20) Specifies if you want to send priority message - * - IPRMDATA (0x80) Specifies the data is contained in the parameter list - * @residual_buffer: Receives the address of buffer updated by the number - * of bytes you have received on return. - * @residual_length: On return, receives one of the following values: - * - 0 If the receive buffer is the same length as - * the message. - * - Remaining bytes in buffer If the receive buffer is longer than the - * message. - * - Remaining bytes in message If the receive buffer is shorter than the - * message. - * - * This function receives messages that are being sent to you over established - * paths. - * Returns: return code from CP IUCV call; If the receive buffer is shorter - * than the message, always 5 - * -EINVAL - buffer address is pointing to NULL - */ -int -iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, - void *buffer, ulong buflen, - int *flags1_out, ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int moved = 0; /* number of bytes moved from parmlist to buffer */ - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) (addr_t) buffer; - parm->ipbfln1f = (__u32) ((ulong) buflen); - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - } else { - moved = min_t (unsigned long, buflen, 8); - - memcpy ((char *) buffer, - (char *) &parm->ipbfadr1, moved); - - if (buflen < 8) - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) - *residual_buffer = (ulong) (buffer + moved); - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. - * Input: pathid - path identification number - * buffer - address of array of buffers - * buflen - total length of buffers - * msgid - specifies the message ID. - * trgcls - specifies target class - * Output: - * flags1_out: Options for path. - * IPNORPY - 0x10 specifies whether a reply is required - * IPPRTY - 0x20 specifies if you want to send priority message - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this case - * b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_receive_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - iucv_array_t * buffer, ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int i = 0, moved = 0, need_to_move = 8, dyn_len; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - - } else { - /* copy msg from parmlist to users array. */ - - while ((moved < 8) && (moved < buflen)) { - dyn_len = - min_t (unsigned int, - (buffer + i)->length, need_to_move); - - memcpy ((char *)((ulong)((buffer + i)->address)), - ((char *) &parm->ipbfadr1) + moved, - dyn_len); - - moved += dyn_len; - need_to_move -= dyn_len; - - (buffer + i)->address = - (__u32) - ((ulong)(__u8 *) ((ulong)(buffer + i)->address) - + dyn_len); - - (buffer + i)->length -= dyn_len; - i++; - } - - if (need_to_move) /* buflen < 8 bytes */ - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) { - if (!moved) - *residual_buffer = (ulong) buffer; - else - *residual_buffer = - (ulong) (buffer + (i - 1)); - } - - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/** - * iucv_reject: - * @pathid: Path identification number. - * @msgid: Message ID of the message to reject. - * @trgcls: Target class of the message to reject. - * Returns: return code from CP - * - * Refuses a specified message. Between the time you are notified of a - * message and the time that you complete the message, the message may - * be rejected. - */ -int -iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls) -{ - iparml_db *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID); - - b2f0_result = b2f0(REJECT, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- 0x20 - specifies if you want to send priority message - * buffer - address of reply buffer - * buflen - length of reply buffer - * Output: ipbfadr2 - Address of buffer updated by the number - * of bytes you have moved. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_reply (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = (__u32) buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (__u8) flags1; /* priority message */ - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of reply buffers - * buflen - total length of reply buffers - * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_reply_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPANSLST | flags1); - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter - * list. - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_reply_prmmsg (__u16 pathid, - __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg)); - parm->ipflags1 = (IPRMDATA | flags1); - - b2f0_result = b2f0(REPLY, parm); - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/** - * iucv_resume: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function restores communication over a quiesced path. - * Returns: return code from CP - */ -int -iucv_resume (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy (parm->ipuser, user_data, sizeof (*user_data)); - parm->ippathid = pathid; - - b2f0_result = b2f0(RESUME, parm); - release_param(parm); - - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send - * Purpose: sends messages - * Input: pathid - ushort, pathid - * msgid - ulong *, id of message returned to caller - * trgcls - ulong, target message class - * srccls - ulong, source message class - * msgtag - ulong, message tag - * flags1 - Contains options for this path. - * IPPRTY - Ox20 - specifies if you want to send a priority message. - * buffer - pointer to buffer - * buflen - ulong, length of buffer - * Output: b2f0_result - return code from b2f0 call - * msgid - returns message id - */ -int -iucv_send (__u16 pathid, __u32 * msgid, - __u32 trgcls, __u32 srccls, - __u32 msgtag, int flags1, void *buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated witht the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | IPBUFLST | flags1); - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into parameter list - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP -*/ -int -iucv_send_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of send buffer - * buflen - length of send buffer - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer or ansbuf address is NULL - */ -int -iucv_send2way (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = flags1; /* priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - spcifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send2way_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPBUFLST | IPANSLST | flags1); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed in parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_send2way_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */ - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - ansbuf address is NULL - */ -int -iucv_send2way_prmmsg_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - __u8 prmmsg[8], - iucv_array_t * ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | IPANSLST | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -void -iucv_setmask_cpuid (void *result) -{ - iparml_set_mask *parm; - - iucv_debug(1, "entering"); - parm = (iparml_set_mask *)grab_param(); - parm->ipmask = *((__u8*)result); - *((ulong *)result) = b2f0(SETMASK, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", *((ulong *)result)); - iucv_debug(1, "exiting"); -} - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_setmask (int SetMaskFlag) -{ - union { - ulong result; - __u8 param; - } u; - int cpu; - - u.param = SetMaskFlag; - cpu = get_cpu(); - smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid); - put_cpu(); - - return u.result; -} - -/** - * iucv_sever: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function terminates an iucv path. - * Returns: return code from CP - */ -int -iucv_sever(__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(SEVER, parm); - - if (!b2f0_result) - iucv_remove_pathid(pathid); - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/* - * Interrupt Handlers - *******************************************************************************/ - -/** - * iucv_irq_handler: - * @regs: Current registers - * @code: irq code - * - * Handles external interrupts coming in from CP. - * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). - */ -static void -iucv_irq_handler(__u16 code) -{ - iucv_irqdata *irqdata; - - irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC); - if (!irqdata) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - return; - } - - memcpy(&irqdata->data, iucv_external_int_buffer, - sizeof(iucv_GeneralInterrupt)); - - spin_lock(&iucv_irq_queue_lock); - list_add_tail(&irqdata->queue, &iucv_irq_queue); - spin_unlock(&iucv_irq_queue_lock); - - tasklet_schedule(&iucv_tasklet); -} - -/** - * iucv_do_int: - * @int_buf: Pointer to copy of external interrupt buffer - * - * The workhorse for handling interrupts queued by iucv_irq_handler(). - * This function is called from the bottom half iucv_tasklet_handler(). - */ -static void -iucv_do_int(iucv_GeneralInterrupt * int_buf) -{ - handler *h = NULL; - struct list_head *lh; - ulong flags; - iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */ - __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */ - int rc = 0, j = 0; - __u8 no_listener[16] = "NO LISTENER"; - - iucv_debug(2, "entering, pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - iucv_dumpit("External Interrupt Buffer:", - int_buf, sizeof(iucv_GeneralInterrupt)); - - ASCEBC (no_listener, 16); - - if (int_buf->iptype != 01) { - if ((int_buf->ippathid) > (max_connections - 1)) { - printk(KERN_WARNING "%s: Got interrupt with pathid %d" - " > max_connections (%ld)\n", __FUNCTION__, - int_buf->ippathid, max_connections - 1); - } else { - h = iucv_pathid_table[int_buf->ippathid]; - interrupt = h->interrupt_table; - iucv_dumpit("Handler:", h, sizeof(handler)); - } - } - - /* end of if statement */ - switch (int_buf->iptype) { - case 0x01: /* connection pending */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - spin_lock_irqsave(&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - h = list_entry(lh, handler, list); - memcpy(temp_buff1, &(int_buf->ipvmid), 24); - memcpy(temp_buff2, &(h->id.userid), 24); - for (j = 0; j < 24; j++) { - temp_buff1[j] &= (h->id.mask)[j]; - temp_buff2[j] &= (h->id.mask)[j]; - } - - iucv_dumpit("temp_buff1:", - temp_buff1, sizeof(temp_buff1)); - iucv_dumpit("temp_buff2", - temp_buff2, sizeof(temp_buff2)); - - if (!memcmp (temp_buff1, temp_buff2, 24)) { - - iucv_debug(2, - "found a matching handler"); - break; - } else - h = NULL; - } - spin_unlock_irqrestore (&iucv_lock, flags); - if (h) { - /* ADD PATH TO PATHID TABLE */ - rc = iucv_add_pathid(int_buf->ippathid, h); - if (rc) { - iucv_sever (int_buf->ippathid, - no_listener); - iucv_debug(1, - "add_pathid failed, rc = %d", - rc); - } else { - interrupt = h->interrupt_table; - if (interrupt->ConnectionPending) { - EBCASC (int_buf->ipvmid, 8); - interrupt->ConnectionPending( - (iucv_ConnectionPending *)int_buf, - h->pgm_data); - } else - iucv_sever(int_buf->ippathid, - no_listener); - } - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x02: /*connection complete */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionComplete) - { - interrupt->ConnectionComplete( - (iucv_ConnectionComplete *)int_buf, - h->pgm_data); - } - else - iucv_debug(1, - "ConnectionComplete not called"); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x03: /* connection severed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionSevered) - interrupt->ConnectionSevered( - (iucv_ConnectionSevered *)int_buf, - h->pgm_data); - - else - iucv_sever (int_buf->ippathid, no_listener); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x04: /* connection quiesced */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionQuiesced) - interrupt->ConnectionQuiesced( - (iucv_ConnectionQuiesced *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionQuiesced not called"); - } - break; - - case 0x05: /* connection resumed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionResumed) - interrupt->ConnectionResumed( - (iucv_ConnectionResumed *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionResumed not called"); - } - break; - - case 0x06: /* priority message complete */ - case 0x07: /* nonpriority message complete */ - if (h) { - if (interrupt->MessageComplete) - interrupt->MessageComplete( - (iucv_MessageComplete *)int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessageComplete not called"); - } - break; - - case 0x08: /* priority message pending */ - case 0x09: /* nonpriority message pending */ - if (h) { - if (interrupt->MessagePending) - interrupt->MessagePending( - (iucv_MessagePending *) int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessagePending not called"); - } - break; - default: /* unknown iucv type */ - printk(KERN_WARNING "%s: unknown iucv interrupt\n", - __FUNCTION__); - break; - } /* end switch */ - - iucv_debug(2, "exiting pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - - return; -} - -/** - * iucv_tasklet_handler: - * - * This function loops over the queue of irq buffers and runs iucv_do_int() - * on every queue element. - */ -static void -iucv_tasklet_handler(unsigned long ignored) -{ - struct list_head head; - struct list_head *next; - ulong flags; - - spin_lock_irqsave(&iucv_irq_queue_lock, flags); - list_add(&head, &iucv_irq_queue); - list_del_init(&iucv_irq_queue); - spin_unlock_irqrestore (&iucv_irq_queue_lock, flags); - - next = head.next; - while (next != &head) { - iucv_irqdata *p = list_entry(next, iucv_irqdata, queue); - - next = next->next; - iucv_do_int(&p->data); - kfree(p); - } - - return; -} - -subsys_initcall(iucv_init); -module_exit(iucv_exit); - -/** - * Export all public stuff - */ -EXPORT_SYMBOL (iucv_bus); -EXPORT_SYMBOL (iucv_root); -EXPORT_SYMBOL (iucv_accept); -EXPORT_SYMBOL (iucv_connect); -#if 0 -EXPORT_SYMBOL (iucv_purge); -EXPORT_SYMBOL (iucv_query_maxconn); -EXPORT_SYMBOL (iucv_query_bufsize); -EXPORT_SYMBOL (iucv_quiesce); -#endif -EXPORT_SYMBOL (iucv_receive); -#if 0 -EXPORT_SYMBOL (iucv_receive_array); -#endif -EXPORT_SYMBOL (iucv_reject); -#if 0 -EXPORT_SYMBOL (iucv_reply); -EXPORT_SYMBOL (iucv_reply_array); -EXPORT_SYMBOL (iucv_resume); -#endif -EXPORT_SYMBOL (iucv_reply_prmmsg); -EXPORT_SYMBOL (iucv_send); -EXPORT_SYMBOL (iucv_send2way); -EXPORT_SYMBOL (iucv_send2way_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 -EXPORT_SYMBOL (iucv_sever); -EXPORT_SYMBOL (iucv_register_program); -EXPORT_SYMBOL (iucv_unregister_program); diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h deleted file mode 100644 index 5b6b1b7241c9..000000000000 --- a/drivers/s390/net/iucv.h +++ /dev/null @@ -1,849 +0,0 @@ -/* - * drivers/s390/net/iucv.h - * IUCV base support. - * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) - * Xenia Tkatschow (xenia@us.ibm.com) - * - * - * Functionality: - * To explore any of the IUCV functions, one must first register - * their program using iucv_register_program(). Once your program has - * successfully completed a register, it can exploit the other functions. - * For furthur reference on all IUCV functionality, refer to the - * CP Programming Services book, also available on the web - * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - * Definition of Return Codes - * -All positive return codes including zero are reflected back - * from CP except for iucv_register_program. The definition of each - * return code can be found in CP Programming Services book. - * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - Return Code of: - * (-EINVAL) Invalid value - * (-ENOMEM) storage allocation failed - * pgmask defined in iucv_register_program will be set depending on input - * paramters. - * - */ - -#include <linux/types.h> -#include <asm/debug.h> - -/** - * Debug Facility stuff - */ -#define IUCV_DBF_SETUP_NAME "iucv_setup" -#define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_PAGES 2 -#define IUCV_DBF_SETUP_NR_AREAS 1 -#define IUCV_DBF_SETUP_LEVEL 3 - -#define IUCV_DBF_DATA_NAME "iucv_data" -#define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_PAGES 2 -#define IUCV_DBF_DATA_NR_AREAS 1 -#define IUCV_DBF_DATA_LEVEL 2 - -#define IUCV_DBF_TRACE_NAME "iucv_trace" -#define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_PAGES 4 -#define IUCV_DBF_TRACE_NR_AREAS 1 -#define IUCV_DBF_TRACE_LEVEL 3 - -#define IUCV_DBF_TEXT(name,level,text) \ - do { \ - debug_text_event(iucv_dbf_##name,level,text); \ - } while (0) - -#define IUCV_DBF_HEX(name,level,addr,len) \ - do { \ - debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ - } while (0) - -DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); - -#define IUCV_DBF_TEXT_(name,level,text...) \ - do { \ - char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ - sprintf(iucv_dbf_txt_buf, text); \ - debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ - put_cpu_var(iucv_dbf_txt_buf); \ - } while (0) - -#define IUCV_DBF_SPRINTF(name,level,text...) \ - do { \ - debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ - debug_sprintf_event(iucv_dbf_trace, level, text ); \ - } while (0) - -/** - * some more debug stuff - */ -#define IUCV_HEXDUMP16(importance,header,ptr) \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ - *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ - *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ - *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ - *(((char*)ptr)+12),*(((char*)ptr)+13), \ - *(((char*)ptr)+14),*(((char*)ptr)+15)); \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)+16),*(((char*)ptr)+17), \ - *(((char*)ptr)+18),*(((char*)ptr)+19), \ - *(((char*)ptr)+20),*(((char*)ptr)+21), \ - *(((char*)ptr)+22),*(((char*)ptr)+23), \ - *(((char*)ptr)+24),*(((char*)ptr)+25), \ - *(((char*)ptr)+26),*(((char*)ptr)+27), \ - *(((char*)ptr)+28),*(((char*)ptr)+29), \ - *(((char*)ptr)+30),*(((char*)ptr)+31)); - -static inline void -iucv_hex_dump(unsigned char *buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (i && !(i % 16)) - printk("\n"); - printk("%02x ", *(buf + i)); - } - printk("\n"); -} -/** - * end of debug stuff - */ - -#define uchar unsigned char -#define ushort unsigned short -#define ulong unsigned long -#define iucv_handle_t void * - -/* flags1: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPLOCAL - Indicates the connect can only be satisfied on the - * local system - * IPPRTY - Indicates a priority message - * IPQUSCE - Indicates you do not want to receive messages on a - * path until an iucv_resume is issued - * IPRMDATA - Indicates that the message is in the parameter list - */ -#define IPLOCAL 0x01 -#define IPPRTY 0x20 -#define IPQUSCE 0x40 -#define IPRMDATA 0x80 - -/* flags1_out: - * All flags are defined in the output field of IPFLAGS1 for each function - * and can be found in CP Programming Services. - * IPNORPY - Specifies this is a one-way message and no reply is expected. - * IPPRTY - Indicates a priority message is permitted. Defined in flags1. - */ -#define IPNORPY 0x10 - -#define Nonpriority_MessagePendingInterruptsFlag 0x80 -#define Priority_MessagePendingInterruptsFlag 0x40 -#define Nonpriority_MessageCompletionInterruptsFlag 0x20 -#define Priority_MessageCompletionInterruptsFlag 0x10 -#define IUCVControlInterruptsFlag 0x08 -#define AllInterrupts 0xf8 -/* - * Mapping of external interrupt buffers should be used with the corresponding - * interrupt types. - * Names: iucv_ConnectionPending -> connection pending - * iucv_ConnectionComplete -> connection complete - * iucv_ConnectionSevered -> connection severed - * iucv_ConnectionQuiesced -> connection quiesced - * iucv_ConnectionResumed -> connection resumed - * iucv_MessagePending -> message pending - * iucv_MessageComplete -> message complete - */ -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar ipvmid[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionPending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar res2[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionComplete; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionSevered; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionQuiesced; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionResumed; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 iptrgcls; - union u2 { - u32 iprmmsg1_u32; - uchar iprmmsg1[4]; - } ln1msg1; - union u1 { - u32 ipbfln1f; - uchar iprmmsg2[4]; - } ln1msg2; - u32 res1[3]; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessagePending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 ipaudit; - uchar iprmmsg[8]; - u32 ipsrccls; - u32 ipmsgtag; - u32 res; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessageComplete; - -/* - * iucv_interrupt_ops_t: Is a vector of functions that handle - * IUCV interrupts. - * Parameter list: - * eib - is a pointer to a 40-byte area described - * with one of the structures above. - * pgm_data - this data is strictly for the - * interrupt handler that is passed by - * the application. This may be an address - * or token. -*/ -typedef struct { - void (*ConnectionPending) (iucv_ConnectionPending * eib, - void *pgm_data); - void (*ConnectionComplete) (iucv_ConnectionComplete * eib, - void *pgm_data); - void (*ConnectionSevered) (iucv_ConnectionSevered * eib, - void *pgm_data); - void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, - void *pgm_data); - void (*ConnectionResumed) (iucv_ConnectionResumed * eib, - void *pgm_data); - void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data); - void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data); -} iucv_interrupt_ops_t; - -/* - *iucv_array_t : Defines buffer array. - * Inside the array may be 31- bit addresses and 31-bit lengths. -*/ -typedef struct { - u32 address; - u32 length; -} iucv_array_t __attribute__ ((aligned (8))); - -extern struct bus_type iucv_bus; -extern struct device *iucv_root; - -/* -prototypes- */ -/* - * Name: iucv_register_program - * Purpose: Registers an application with IUCV - * Input: prmname - user identification - * userid - machine identification - * pgmmask - indicates which bits in the prmname and userid combined will be - * used to determine who is given control - * ops - address of vector of interrupt handlers - * pgm_data- application data passed to interrupt handlers - * Output: NA - * Return: address of handler - * (0) - Error occurred, registration not completed. - * NOTE: Exact cause of failure will be recorded in syslog. -*/ -iucv_handle_t iucv_register_program (uchar pgmname[16], - uchar userid[8], - uchar pgmmask[24], - iucv_interrupt_ops_t * ops, - void *pgm_data); - -/* - * Name: iucv_unregister_program - * Purpose: Unregister application with IUCV - * Input: address of handler - * Output: NA - * Return: (0) - Normal return - * (-EINVAL) - Internal error, wild pointer -*/ -int iucv_unregister_program (iucv_handle_t handle); - -/* - * Name: iucv_accept - * Purpose: This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Input: pathid - u16 , Path identification number - * msglim_reqstd - u16, The number of outstanding messages requested. - * user_data - uchar[16], Data specified by the iucv_connect function. - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20- Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * handle - iucv_handle_t, Address of handler. - * pgm_data - void *, Application data passed to interrupt handlers. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - *u16, Number of outstanding messages. - * Output: return code from CP IUCV call. -*/ - -int iucv_accept (u16 pathid, - u16 msglim_reqstd, - uchar user_data[16], - int flags1, - iucv_handle_t handle, - void *pgm_data, int *flags1_out, u16 * msglim); - -/* - * Name: iucv_connect - * Purpose: This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Input: pathid - u16 *, Path identification number - * msglim_reqstd - u16, Number of outstanding messages requested - * user_data - uchar[16], 16-byte user data - * userid - uchar[8], User identification - * system_name - uchar[8], 8-byte identifying the system name - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20, Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * -IPLOCAL - 0X01, Allows an application to force the partner to be on - * the local system. If local is specified then target class cannot be - * specified. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - * u16, Number of outstanding messages - * handle - iucv_handle_t, Address of handler - * pgm_data - void *, Application data passed to interrupt handlers - * Output: return code from CP IUCV call - * rc - return code from iucv_declare_buffer - * -EINVAL - Invalid handle passed by application - * -EINVAL - Pathid address is NULL - * add_pathid_result - Return code from internal function add_pathid -*/ -int - iucv_connect (u16 * pathid, - u16 msglim_reqstd, - uchar user_data[16], - uchar userid[8], - uchar system_name[8], - int flags1, - int *flags1_out, - u16 * msglim, iucv_handle_t handle, void *pgm_data); - -/* - * Name: iucv_purge - * Purpose: This function cancels a message that you have sent. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID of the message to be purged. - * srccls - Specifies the source message class. - * Output: audit - Contains information about asynchronous error - * that may have affected the normal completion - * of this message. - * Return: Return code from CP IUCV call. -*/ -int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit); -/* - * Name: iucv_query_maxconn - * Purpose: This function determines the maximum number of communication paths you - * may establish. - * Return: maxconn - ulong, Maximum number of connection the virtual machine may - * establish. -*/ -ulong iucv_query_maxconn (void); - -/* - * Name: iucv_query_bufsize - * Purpose: This function determines how large an external interrupt - * buffer IUCV requires to store information. - * Return: bufsize - ulong, Size of external interrupt buffer. - */ -ulong iucv_query_bufsize (void); - -/* - * Name: iucv_quiesce - * Purpose: This function temporarily suspends incoming messages on an - * IUCV path. You can later reactivate the path by invoking - * the iucv_resume function. - * Input: pathid - Path identification number - * user_data - 16-bytes of user data - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_quiesce (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_receive - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in buffer for length of - * buflen. - * Input: - * pathid - Path identification number. - * buffer - Address of buffer to receive. - * buflen - Length of buffer to receive. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address of buffer updated by the number - * of bytes you have received. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - buffer address is pointing to NULL -*/ -int iucv_receive (u16 pathid, - u32 msgid, - u32 trgcls, - void *buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - - /* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in first buffer for - * length of first buffer. - * Input: pathid - Path identification number. - * msgid - specifies the message ID. - * trgcls - Specifies target class. - * buffer - Address of array of buffers. - * buflen - Total length of buffers. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. - */ -int iucv_receive_array (u16 pathid, - u32 msgid, - u32 trgcls, - iucv_array_t * buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - -/* - * Name: iucv_reject - * Purpose: The reject function refuses a specified message. Between the - * time you are notified of a message and the time that you - * complete the message, the message may be rejected. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reject (u16 pathid, u32 msgid, u32 trgcls); - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of reply buffer. - * buflen - Length of reply buffer. - * Output: residual_buffer - Address of buffer updated by the number - * of bytes you have moved. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * residual_buffer, - ulong * residual_length); - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - Path identification number - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of array of reply buffers. - * buflen - Total length of reply buffers. - * Output: residual_buffer - Address of buffer which IUCV is currently working on. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply_array (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * residual_address, - ulong * residual_length); - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter. - * list. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reply_prmmsg (u16 pathid, - u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_resume - * Purpose: This function restores communications over a quiesced path - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_resume (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_send - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer and this is a - * one-way message and the receiver will not reply to the - * message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen); - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated witht the message. - * flags1 - Option for path. - * IPPRTY- specifies if you want to send priority message. - * buffer - Address of array of send buffers. - * buflen - Total length of send buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, iucv_array_t * buffer, ulong buflen); - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into parameter list. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. -*/ -int iucv_send_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer or ansbuf address is NULL. -*/ -int iucv_send2way (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Sddress of array of send buffers. - * buflen - Total length of send buffers. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - Rath identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed in parameter list. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - ulong flags1, - uchar prmmsg[8], void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter list. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length of reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Ansbuf address is NULL. -*/ -int iucv_send2way_prmmsg_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - uchar prmmsg[8], - iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_setmask (int SetMaskFlag); - -/* - * Name: iucv_sever - * Purpose: This function terminates an IUCV path. - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. - * (-EINVAL) - Interal error, wild pointer. -*/ -int iucv_sever (u16 pathid, uchar user_data[16]); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3346088f47e0..6387b483f2bf 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,7 +1,7 @@ /* * IUCV network driver * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Sysfs integration and all bugs therein by Cornelia Huck @@ -58,13 +58,94 @@ #include <asm/io.h> #include <asm/uaccess.h> -#include "iucv.h" +#include <net/iucv/iucv.h> #include "fsm.h" MODULE_AUTHOR ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); +/** + * Debug Facility stuff + */ +#define IUCV_DBF_SETUP_NAME "iucv_setup" +#define IUCV_DBF_SETUP_LEN 32 +#define IUCV_DBF_SETUP_PAGES 2 +#define IUCV_DBF_SETUP_NR_AREAS 1 +#define IUCV_DBF_SETUP_LEVEL 3 + +#define IUCV_DBF_DATA_NAME "iucv_data" +#define IUCV_DBF_DATA_LEN 128 +#define IUCV_DBF_DATA_PAGES 2 +#define IUCV_DBF_DATA_NR_AREAS 1 +#define IUCV_DBF_DATA_LEVEL 2 + +#define IUCV_DBF_TRACE_NAME "iucv_trace" +#define IUCV_DBF_TRACE_LEN 16 +#define IUCV_DBF_TRACE_PAGES 4 +#define IUCV_DBF_TRACE_NR_AREAS 1 +#define IUCV_DBF_TRACE_LEVEL 3 + +#define IUCV_DBF_TEXT(name,level,text) \ + do { \ + debug_text_event(iucv_dbf_##name,level,text); \ + } while (0) + +#define IUCV_DBF_HEX(name,level,addr,len) \ + do { \ + debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ + } while (0) + +DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); + +#define IUCV_DBF_TEXT_(name,level,text...) \ + do { \ + char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ + sprintf(iucv_dbf_txt_buf, text); \ + debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ + put_cpu_var(iucv_dbf_txt_buf); \ + } while (0) + +#define IUCV_DBF_SPRINTF(name,level,text...) \ + do { \ + debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ + debug_sprintf_event(iucv_dbf_trace, level, text ); \ + } while (0) + +/** + * some more debug stuff + */ +#define IUCV_HEXDUMP16(importance,header,ptr) \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ + *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ + *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ + *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ + *(((char*)ptr)+12),*(((char*)ptr)+13), \ + *(((char*)ptr)+14),*(((char*)ptr)+15)); \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)+16),*(((char*)ptr)+17), \ + *(((char*)ptr)+18),*(((char*)ptr)+19), \ + *(((char*)ptr)+20),*(((char*)ptr)+21), \ + *(((char*)ptr)+22),*(((char*)ptr)+23), \ + *(((char*)ptr)+24),*(((char*)ptr)+25), \ + *(((char*)ptr)+26),*(((char*)ptr)+27), \ + *(((char*)ptr)+28),*(((char*)ptr)+29), \ + *(((char*)ptr)+30),*(((char*)ptr)+31)); + +static inline void iucv_hex_dump(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + printk("\n"); + printk("%02x ", *(buf + i)); + } + printk("\n"); +} #define PRINTK_HEADER " iucv: " /* for debugging */ @@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = { .bus = &iucv_bus, }; +static int netiucv_callback_connreq(struct iucv_path *, + u8 ipvmid[8], u8 ipuser[16]); +static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); +static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler netiucv_handler = { + .path_pending = netiucv_callback_connreq, + .path_complete = netiucv_callback_connack, + .path_severed = netiucv_callback_connrej, + .path_quiesced = netiucv_callback_connsusp, + .path_resumed = netiucv_callback_connres, + .message_pending = netiucv_callback_rx, + .message_complete = netiucv_callback_txdone +}; + /** * Per connection profiling data */ @@ -92,9 +192,8 @@ struct connection_profile { * Representation of one iucv connection */ struct iucv_connection { - struct iucv_connection *next; - iucv_handle_t handle; - __u16 pathid; + struct list_head list; + struct iucv_path *path; struct sk_buff *rx_buff; struct sk_buff *tx_buff; struct sk_buff_head collect_queue; @@ -112,12 +211,9 @@ struct iucv_connection { /** * Linked list of all connection structs. */ -struct iucv_connection_struct { - struct iucv_connection *iucv_connections; - rwlock_t iucv_rwlock; -}; - -static struct iucv_connection_struct iucv_conns; +static struct list_head iucv_connection_list = + LIST_HEAD_INIT(iucv_connection_list); +static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; /** * Representation of event-data for the @@ -142,11 +238,11 @@ struct netiucv_priv { /** * Link level header for a packet. */ -typedef struct ll_header_t { - __u16 next; -} ll_header; +struct ll_header { + u16 next; +}; -#define NETIUCV_HDRLEN (sizeof(ll_header)) +#define NETIUCV_HDRLEN (sizeof(struct ll_header)) #define NETIUCV_BUFSIZE_MAX 32768 #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) @@ -158,36 +254,26 @@ typedef struct ll_header_t { * Compatibility macros for busy handling * of network devices. */ -static __inline__ void netiucv_clear_busy(struct net_device *dev) +static inline void netiucv_clear_busy(struct net_device *dev) { - clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); + struct netiucv_priv *priv = netdev_priv(dev); + clear_bit(0, &priv->tbusy); netif_wake_queue(dev); } -static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) +static inline int netiucv_test_and_set_busy(struct net_device *dev) { + struct netiucv_priv *priv = netdev_priv(dev); netif_stop_queue(dev); - return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); + return test_and_set_bit(0, &priv->tbusy); } -static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static __u8 iucvMagic[16] = { +static u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; /** - * This mask means the 16-byte IUCV "magic" and the origin userid must - * match exactly as specified in order to give connection_pending() - * control. - */ -static __u8 netiucv_mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -/** * Convert an iucv userId to its printable * form (strip whitespace at end). * @@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = { * * @returns The printable string (static data!!) */ -static __inline__ char * -netiucv_printname(char *name) +static inline char *netiucv_printname(char *name) { static char tmp[9]; char *p = tmp; @@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL; DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); -static void -iucv_unregister_dbf_views(void) +static void iucv_unregister_dbf_views(void) { if (iucv_dbf_setup) debug_unregister(iucv_dbf_setup); @@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void) if (iucv_dbf_trace) debug_unregister(iucv_dbf_trace); } -static int -iucv_register_dbf_views(void) +static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, IUCV_DBF_SETUP_PAGES, @@ -422,125 +505,111 @@ iucv_register_dbf_views(void) return 0; } -/** +/* * Callback-wrappers, called from lowlevel iucv layer. - *****************************************************************************/ + */ -static void -netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) +static void netiucv_callback_rx(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; - + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_RX, &ev); } -static void -netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) +static void netiucv_callback_txdone(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); } -static void -netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) +static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); } -static void -netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) +static int netiucv_callback_connreq(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; + int rc; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) + /* ipuser must match iucvMagic. */ + return -EINVAL; + rc = -EINVAL; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(conn, &iucv_connection_list, list) { + if (strncmp(ipvmid, conn->userid, 8)) + continue; + /* Found a matching connection for this path. */ + conn->path = path; + ev.conn = conn; + ev.data = path; + fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + rc = 0; + } + read_unlock_bh(&iucv_connection_rwlock); + return rc; } -static void -netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) +static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); } -static void -netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) +static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); } -static void -netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) +static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); -} - -static iucv_interrupt_ops_t netiucv_ops = { - .ConnectionPending = netiucv_callback_connreq, - .ConnectionComplete = netiucv_callback_connack, - .ConnectionSevered = netiucv_callback_connrej, - .ConnectionQuiesced = netiucv_callback_connsusp, - .ConnectionResumed = netiucv_callback_connres, - .MessagePending = netiucv_callback_rx, - .MessageComplete = netiucv_callback_txdone -}; + fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); +} /** * Dummy NOP action for all statemachines */ -static void -fsm_action_nop(fsm_instance *fi, int event, void *arg) +static void fsm_action_nop(fsm_instance *fi, int event, void *arg) { } -/** +/* * Actions of the connection statemachine - *****************************************************************************/ + */ /** - * Helper function for conn_action_rx() - * Unpack a just received skb and hand it over to - * upper layers. + * netiucv_unpack_skb + * @conn: The connection where this skb has been received. + * @pskb: The received skb. * - * @param conn The connection where this skb has been received. - * @param pskb The received skb. + * Unpack a just received skb and hand it over to upper layers. + * Helper function for conn_action_rx. */ -//static __inline__ void -static void -netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) +static void netiucv_unpack_skb(struct iucv_connection *conn, + struct sk_buff *pskb) { struct net_device *dev = conn->netdev; - struct netiucv_priv *privptr = dev->priv; - __u16 offset = 0; + struct netiucv_priv *privptr = netdev_priv(dev); + u16 offset = 0; skb_put(pskb, NETIUCV_HDRLEN); pskb->dev = dev; @@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) while (1) { struct sk_buff *skb; - ll_header *header = (ll_header *)pskb->data; + struct ll_header *header = (struct ll_header *) pskb->data; if (!header->next) break; @@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) } } -static void -conn_action_rx(fsm_instance *fi, int event, void *arg) +static void conn_action_rx(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; - struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; - - __u32 msglen = eib->ln1msg2.ipbfln1f; + struct iucv_message *msg = ev->data; + struct netiucv_priv *privptr = netdev_priv(conn->netdev); int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (!conn->netdev) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + iucv_message_reject(conn->path, msg); PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, - "Received data for unlinked connection\n"); + "Received data for unlinked connection\n"); return; } - if (msglen > conn->max_buffsize) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + if (msg->length > conn->max_buffsize) { + iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; PRINT_WARN("msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); return; } conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; - rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, - conn->rx_buff->data, msglen, NULL, NULL, NULL); - if (rc || msglen < 5) { + rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, + msg->length, NULL); + if (rc || msg->length < 5) { privptr->stats.rx_errors++; PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); @@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg) netiucv_unpack_skb(conn, conn->rx_buff); } -static void -conn_action_txdone(fsm_instance *fi, int event, void *arg) +static void conn_action_txdone(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; + struct iucv_message *msg = ev->data; + struct iucv_message txmsg; struct netiucv_priv *privptr = NULL; - /* Shut up, gcc! skb is always below 2G. */ - __u32 single_flag = eib->ipmsgtag; - __u32 txbytes = 0; - __u32 txpackets = 0; - __u32 stat_maxcq = 0; + u32 single_flag = msg->tag; + u32 txbytes = 0; + u32 txpackets = 0; + u32 stat_maxcq = 0; struct sk_buff *skb; unsigned long saveflags; - ll_header header; + struct ll_header header; + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); - if (conn && conn->netdev && conn->netdev->priv) - privptr = (struct netiucv_priv *)conn->netdev->priv; + if (conn && conn->netdev) + privptr = netdev_priv(conn->netdev); conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { @@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) conn->prof.maxmulti = conn->collect_len; conn->collect_len = 0; spin_unlock_irqrestore(&conn->collect_lock, saveflags); - if (conn->tx_buff->len) { - int rc; - - header.next = 0; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, - NETIUCV_HDRLEN); + if (conn->tx_buff->len == 0) { + fsm_newstate(fi, CONN_STATE_IDLE); + return; + } - conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, + header.next = 0; + memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + conn->prof.send_stamp = xtime; + txmsg.class = 0; + txmsg.tag = 0; + rc = iucv_message_send(conn->path, &txmsg, 0, 0, conn->tx_buff->data, conn->tx_buff->len); - conn->prof.doios_multi++; - conn->prof.txlen += conn->tx_buff->len; - conn->prof.tx_pending++; - if (conn->prof.tx_pending > conn->prof.tx_max_pending) - conn->prof.tx_max_pending = conn->prof.tx_pending; - if (rc) { - conn->prof.tx_pending--; - fsm_newstate(fi, CONN_STATE_IDLE); - if (privptr) - privptr->stats.tx_errors += txpackets; - PRINT_WARN("iucv_send returned %08x\n", rc); - IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); - } else { - if (privptr) { - privptr->stats.tx_packets += txpackets; - privptr->stats.tx_bytes += txbytes; - } - if (stat_maxcq > conn->prof.maxcqueue) - conn->prof.maxcqueue = stat_maxcq; - } - } else + conn->prof.doios_multi++; + conn->prof.txlen += conn->tx_buff->len; + conn->prof.tx_pending++; + if (conn->prof.tx_pending > conn->prof.tx_max_pending) + conn->prof.tx_max_pending = conn->prof.tx_pending; + if (rc) { + conn->prof.tx_pending--; fsm_newstate(fi, CONN_STATE_IDLE); + if (privptr) + privptr->stats.tx_errors += txpackets; + PRINT_WARN("iucv_send returned %08x\n", rc); + IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); + } else { + if (privptr) { + privptr->stats.tx_packets += txpackets; + privptr->stats.tx_bytes += txbytes; + } + if (stat_maxcq > conn->prof.maxcqueue) + conn->prof.maxcqueue = stat_maxcq; + } } -static void -conn_action_connaccept(fsm_instance *fi, int event, void *arg) +static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; + struct iucv_path *path = ev->data; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; - __u16 msglimit; - __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, - conn->handle, conn, NULL, &msglimit); + conn->path = path; + path->msglim = NETIUCV_QUEUELEN_DEFAULT; + path->flags = 0; + rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); if (rc) { PRINT_WARN("%s: IUCV accept failed with error %d\n", netdev->name, rc); @@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg) return; } fsm_newstate(fi, CONN_STATE_IDLE); - conn->pathid = eib->ippathid; - netdev->tx_queue_len = msglimit; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_connreject(fsm_instance *fi, int event, void *arg) +static void conn_action_connreject(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - struct net_device *netdev = conn->netdev; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; - __u8 udata[16]; + struct iucv_event *ev = arg; + struct iucv_path *path = ev->data; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - - iucv_sever(eib->ippathid, udata); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Pending; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connreject: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - iucv_sever(conn->pathid, udata); - } + iucv_path_sever(path, NULL); } -static void -conn_action_connack(fsm_instance *fi, int event, void *arg) +static void conn_action_connack(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Complete; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connack: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - conn->pathid = eib->ippathid; - } - netdev->tx_queue_len = eib->ipmsglim; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_conntimsev(fsm_instance *fi, int event, void *arg) +static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) { - struct iucv_connection *conn = (struct iucv_connection *)arg; - __u8 udata[16]; + struct iucv_connection *conn = arg; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); fsm_newstate(fi, CONN_STATE_STARTWAIT); } -static void -conn_action_connsever(fsm_instance *fi, int event, void *arg) +static void conn_action_connsever(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; - __u8 udata[16]; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); PRINT_INFO("%s: Remote dropped connection\n", netdev->name); IUCV_DBF_TEXT(data, 2, - "conn_action_connsever: Remote dropped connection\n"); + "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_start(fsm_instance *fi, int event, void *arg) +static void conn_action_start(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - __u16 msglimit; + struct iucv_connection *conn = arg; int rc; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (!conn->handle) { - IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); - conn->handle = - iucv_register_program(iucvMagic, conn->userid, - netiucv_mask, - &netiucv_ops, conn); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - if (!conn->handle) { - fsm_newstate(fi, CONN_STATE_REGERR); - conn->handle = NULL; - IUCV_DBF_TEXT(setup, 2, - "NULL from iucv_register_program\n"); - return; - } - - PRINT_DEBUG("%s('%s'): registered successfully\n", - conn->netdev->name, conn->userid); - } - + fsm_newstate(fi, CONN_STATE_STARTWAIT); PRINT_DEBUG("%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + conn->netdev->name, conn->userid); - /* We must set the state before calling iucv_connect because the callback - * handler could be called at any point after the connection request is - * sent */ + /* + * We must set the state before calling iucv_connect because the + * callback handler could be called at any point after the connection + * request is sent + */ fsm_newstate(fi, CONN_STATE_SETUPWAIT); - rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, &msglimit, - conn->handle, conn); + conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); + rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, + NULL, iucvMagic, conn); switch (rc) { - case 0: - conn->netdev->tx_queue_len = msglimit; - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); - return; - case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 14: - PRINT_WARN( - "%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 15: - PRINT_WARN( - "%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; + case 0: + conn->netdev->tx_queue_len = conn->path->msglim; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); + return; + case 11: + PRINT_INFO("%s: User %s is currently not available.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 12: + PRINT_INFO("%s: User %s is currently not ready.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 13: + PRINT_WARN("%s: Too many IUCV connections.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 14: + PRINT_WARN("%s: User %s has too many IUCV connections.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 15: + PRINT_WARN("%s: No IUCV authorization in CP directory.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + default: + PRINT_WARN("%s: iucv_connect returned error %d\n", + conn->netdev->name, rc); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; } IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + kfree(conn->path); + conn->path = NULL; } -static void -netiucv_purge_skb_queue(struct sk_buff_head *q) +static void netiucv_purge_skb_queue(struct sk_buff_head *q) { struct sk_buff *skb; @@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q) } } -static void -conn_action_stop(fsm_instance *fi, int event, void *arg) +static void conn_action_stop(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); - if (conn->handle) - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + if (conn->path) { + IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; + } netiucv_purge_skb_queue(&conn->commit_queue); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_inval(fsm_instance *fi, int event, void *arg) +static void conn_action_inval(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - PRINT_WARN("%s: Cannot connect without username\n", - netdev->name); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } @@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = { static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); -/** +/* * Actions for interface - statemachine. - *****************************************************************************/ + */ /** - * Startup connection by sending CONN_EVENT_START to it. + * dev_action_start + * @fi: An instance of an interface statemachine. + * @event: The event, just happened. + * @arg: Generic pointer, casted from struct net_device * upon call. * - * @param fi An instance of an interface statemachine. - * @param event The event, just happened. - * @param arg Generic pointer, casted from struct net_device * upon call. + * Startup connection by sending CONN_EVENT_START to it. */ -static void -dev_action_start(fsm_instance *fi, int event, void *arg) +static void dev_action_start(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; - struct iucv_event ev; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STARTWAIT); - fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); + fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); } /** @@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg) static void dev_action_stop(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) static void dev_action_connup(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { +static int netiucv_transmit_skb(struct iucv_connection *conn, + struct sk_buff *skb) +{ + struct iucv_message msg; unsigned long saveflags; - ll_header header; - int rc = 0; + struct ll_header header; + int rc; if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { int l = skb->len + NETIUCV_HDRLEN; @@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { (conn->max_buffsize - NETIUCV_HDRLEN)) { rc = -EBUSY; IUCV_DBF_TEXT(data, 2, - "EBUSY from netiucv_transmit_skb\n"); + "EBUSY from netiucv_transmit_skb\n"); } else { atomic_inc(&skb->users); skb_queue_tail(&conn->collect_queue, skb); conn->collect_len += l; + rc = 0; } spin_unlock_irqrestore(&conn->collect_lock, saveflags); } else { @@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { fsm_newstate(conn->fsm, CONN_STATE_TX); conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, - 0, nskb->data, nskb->len); - /* Shut up, gcc! nskb is always below 2G. */ + msg.tag = 1; + msg.class = 0; + rc = iucv_message_send(conn->path, &msg, 0, 0, + nskb->data, nskb->len); conn->prof.doios_single++; conn->prof.txlen += skb->len; conn->prof.tx_pending++; @@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { struct netiucv_priv *privptr; fsm_newstate(conn->fsm, CONN_STATE_IDLE); conn->prof.tx_pending--; - privptr = (struct netiucv_priv *)conn->netdev->priv; + privptr = netdev_priv(conn->netdev); if (privptr) privptr->stats.tx_errors++; if (copied) @@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { return rc; } -/** +/* * Interface API for upper network layers - *****************************************************************************/ + */ /** * Open an interface. @@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_open(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); +static int netiucv_open(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_START, dev); return 0; } @@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_close(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); +static int netiucv_close(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_STOP, dev); return 0; } @@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) { */ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) { - int rc = 0; - struct netiucv_priv *privptr = dev->priv; + struct netiucv_priv *privptr = netdev_priv(dev); + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); /** @@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return -EBUSY; } dev->trans_start = jiffies; - if (netiucv_transmit_skb(privptr->conn, skb)) - rc = 1; + rc = netiucv_transmit_skb(privptr->conn, skb) != 0; netiucv_clear_busy(dev); return rc; } /** - * Returns interface statistics of a device. + * netiucv_stats + * @dev: Pointer to interface struct. * - * @param dev Pointer to interface struct. + * Returns interface statistics of a device. * - * @return Pointer to stats struct of this interface. + * Returns pointer to stats struct of this interface. */ -static struct net_device_stats * -netiucv_stats (struct net_device * dev) +static struct net_device_stats *netiucv_stats (struct net_device * dev) { + struct netiucv_priv *priv = netdev_priv(dev); + IUCV_DBF_TEXT(trace, 5, __FUNCTION__); - return &((struct netiucv_priv *)dev->priv)->stats; + return &priv->stats; } /** - * Sets MTU of an interface. + * netiucv_change_mtu + * @dev: Pointer to interface struct. + * @new_mtu: The new MTU to use for this interface. * - * @param dev Pointer to interface struct. - * @param new_mtu The new MTU to use for this interface. + * Sets MTU of an interface. * - * @return 0 on success, -EINVAL if MTU is out of valid range. + * Returns 0 on success, -EINVAL if MTU is out of valid range. * (valid range is 576 .. NETIUCV_MTU_MAX). */ -static int -netiucv_change_mtu (struct net_device * dev, int new_mtu) +static int netiucv_change_mtu(struct net_device * dev, int new_mtu) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { + if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); return -EINVAL; } @@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) return 0; } -/** +/* * attributes in sysfs - *****************************************************************************/ + */ -static ssize_t -user_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t user_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } -static ssize_t -user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t user_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, char *tmp; char username[9]; int i; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (count>9) { - PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); + if (count > 9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, - "%d is length of username\n", (int)count); + "%d is length of username\n", (int) count); return -EINVAL; } tmp = strsep((char **) &buf, "\n"); - for (i=0, p=tmp; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) + for (i = 0, p = tmp; i < 8 && *p; i++, p++) { + if (isalnum(*p) || (*p == '$')) { username[i]= toupper(*p); - else if (*p == '\n') { + continue; + } + if (*p == '\n') { /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid char %c in username!\n", - *p); - IUCV_DBF_TEXT_(setup, 2, - "username: invalid character %c\n", - *p); - return -EINVAL; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); + IUCV_DBF_TEXT_(setup, 2, + "username: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - if (memcmp(username, priv->conn->userid, 9)) { - /* username changed */ - if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: device %s active, connected to %s\n", - dev->bus_id, priv->conn->userid); - PRINT_WARN("netiucv: user cannot be updated\n"); - IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); - return -EBUSY; + if (memcmp(username, priv->conn->userid, 9) && + (ndev->flags & (IFF_UP | IFF_RUNNING))) { + /* username changed while the interface is active. */ + PRINT_WARN("netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + PRINT_WARN("netiucv: user cannot be updated\n"); + IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); + return -EBUSY; + } + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; } } - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9) || - ((*clist)->netdev != ndev)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; - } + read_unlock_bh(&iucv_connection_rwlock); memcpy(priv->conn->userid, username, 9); - return count; - } static DEVICE_ATTR(user, 0644, user_show, user_write); -static ssize_t -buffer_show (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct netiucv_priv *priv = dev->driver_data; +static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, + char *buf) +{ struct netiucv_priv *priv = dev->driver_data; IUCV_DBF_TEXT(trace, 5, __FUNCTION__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); } -static ssize_t -buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); -static ssize_t -dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); -static ssize_t -conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t conn_fsm_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); -static ssize_t -maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxmulti_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); } -static ssize_t -maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxmulti_write (struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); -static ssize_t -maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); } -static ssize_t -maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); -static ssize_t -sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); } -static ssize_t -sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); -static ssize_t -mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); } -static ssize_t -mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); -static ssize_t -txlen_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.txlen); } -static ssize_t -txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); -static ssize_t -txtime_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); } -static ssize_t -txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); -static ssize_t -txpend_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); } -static ssize_t -txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); -static ssize_t -txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); } -static ssize_t -txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = { .attrs = netiucv_stat_attrs, }; -static inline int -netiucv_add_files(struct device *dev) +static inline int netiucv_add_files(struct device *dev) { int ret; @@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev) return ret; } -static inline void -netiucv_remove_files(struct device *dev) +static inline void netiucv_remove_files(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } -static int -netiucv_register_device(struct net_device *ndev) +static int netiucv_register_device(struct net_device *ndev) { - struct netiucv_priv *priv = ndev->priv; + struct netiucv_priv *priv = netdev_priv(ndev); struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; @@ -1786,8 +1787,7 @@ out_unreg: return ret; } -static void -netiucv_unregister_device(struct device *dev) +static void netiucv_unregister_device(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); netiucv_remove_files(dev); @@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev) * Allocate and initialize a new connection structure. * Add it to the list of netiucv connections; */ -static struct iucv_connection * -netiucv_new_connection(struct net_device *dev, char *username) -{ - unsigned long flags; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - struct iucv_connection *conn = - kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); - - if (conn) { - skb_queue_head_init(&conn->collect_queue); - skb_queue_head_init(&conn->commit_queue); - spin_lock_init(&conn->collect_lock); - conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; - conn->netdev = dev; - - conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->rx_buff) { - kfree(conn); - return NULL; - } - conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->tx_buff) { - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - conn->fsm = init_fsm("netiucvconn", conn_state_names, - conn_event_names, NR_CONN_STATES, - NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, - GFP_KERNEL); - if (!conn->fsm) { - kfree_skb(conn->tx_buff); - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - fsm_settimer(conn->fsm, &conn->timer); - fsm_newstate(conn->fsm, CONN_STATE_INVALID); - - if (username) { - memcpy(conn->userid, username, 9); - fsm_newstate(conn->fsm, CONN_STATE_STOPPED); - } +static struct iucv_connection *netiucv_new_connection(struct net_device *dev, + char *username) +{ + struct iucv_connection *conn; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - conn->next = *clist; - *clist = conn; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + goto out; + skb_queue_head_init(&conn->collect_queue); + skb_queue_head_init(&conn->commit_queue); + spin_lock_init(&conn->collect_lock); + conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; + conn->netdev = dev; + + conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->rx_buff) + goto out_conn; + conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->tx_buff) + goto out_rx; + conn->fsm = init_fsm("netiucvconn", conn_state_names, + conn_event_names, NR_CONN_STATES, + NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, + GFP_KERNEL); + if (!conn->fsm) + goto out_tx; + + fsm_settimer(conn->fsm, &conn->timer); + fsm_newstate(conn->fsm, CONN_STATE_INVALID); + + if (username) { + memcpy(conn->userid, username, 9); + fsm_newstate(conn->fsm, CONN_STATE_STOPPED); } + + write_lock_bh(&iucv_connection_rwlock); + list_add_tail(&conn->list, &iucv_connection_list); + write_unlock_bh(&iucv_connection_rwlock); return conn; + +out_tx: + kfree_skb(conn->tx_buff); +out_rx: + kfree_skb(conn->rx_buff); +out_conn: + kfree(conn); +out: + return NULL; } /** * Release a connection structure and remove it from the * list of netiucv connections. */ -static void -netiucv_remove_connection(struct iucv_connection *conn) +static void netiucv_remove_connection(struct iucv_connection *conn) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (conn == NULL) - return; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (*clist == conn) { - *clist = conn->next; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (conn->handle) { - iucv_unregister_program(conn->handle); - conn->handle = NULL; - } - fsm_deltimer(&conn->timer); - kfree_fsm(conn->fsm); - kfree_skb(conn->rx_buff); - kfree_skb(conn->tx_buff); - return; - } - clist = &((*clist)->next); + write_lock_bh(&iucv_connection_rwlock); + list_del_init(&conn->list); + write_unlock_bh(&iucv_connection_rwlock); + if (conn->path) { + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; } - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + fsm_deltimer(&conn->timer); + kfree_fsm(conn->fsm); + kfree_skb(conn->rx_buff); + kfree_skb(conn->tx_buff); } /** * Release everything of a net device. */ -static void -netiucv_free_netdevice(struct net_device *dev) +static void netiucv_free_netdevice(struct net_device *dev) { - struct netiucv_priv *privptr; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (!dev) return; - privptr = (struct netiucv_priv *)dev->priv; if (privptr) { if (privptr->conn) netiucv_remove_connection(privptr->conn); @@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev) /** * Initialize a net device. (Called from kernel in alloc_netdev()) */ -static void -netiucv_setup_netdevice(struct net_device *dev) +static void netiucv_setup_netdevice(struct net_device *dev) { - memset(dev->priv, 0, sizeof(struct netiucv_priv)); - dev->mtu = NETIUCV_MTU_DEFAULT; dev->hard_start_xmit = netiucv_tx; dev->open = netiucv_open; @@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev) /** * Allocate and initialize everything of a net device. */ -static struct net_device * -netiucv_init_netdevice(char *username) +static struct net_device *netiucv_init_netdevice(char *username) { struct netiucv_priv *privptr; struct net_device *dev; @@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) { - free_netdev(dev); - return NULL; - } + if (dev_alloc_name(dev, dev->name) < 0) + goto out_netdev; - privptr = (struct netiucv_priv *)dev->priv; + privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, dev_fsm, DEV_FSM_LEN, GFP_KERNEL); - if (!privptr->fsm) { - free_netdev(dev); - return NULL; - } + if (!privptr->fsm) + goto out_netdev; + privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { - kfree_fsm(privptr->fsm); - free_netdev(dev); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); - return NULL; + goto out_fsm; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); - return dev; + +out_fsm: + kfree_fsm(privptr->fsm); +out_netdev: + free_netdev(dev); + return NULL; } -static ssize_t -conn_write(struct device_driver *drv, const char *buf, size_t count) +static ssize_t conn_write(struct device_driver *drv, + const char *buf, size_t count) { - char *p; + const char *p; char username[9]; - int i, ret; + int i, rc; struct net_device *dev; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct netiucv_priv *priv; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (count>9) { @@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) return -EINVAL; } - for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) - username[i]= toupper(*p); - else if (*p == '\n') { + for (i = 0, p = buf; i < 8 && *p; i++, p++) { + if (isalnum(*p) || *p == '$') { + username[i] = toupper(*p); + continue; + } + if (*p == '\n') /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid character in username!\n"); - IUCV_DBF_TEXT_(setup, 2, - "conn_write: invalid character %c\n", *p); - return -EINVAL; - } + PRINT_WARN("netiucv: Invalid character in username!\n"); + IUCV_DBF_TEXT_(setup, 2, + "conn_write: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9)) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; + } } + read_unlock_bh(&iucv_connection_rwlock); + dev = netiucv_init_netdevice(username); if (!dev) { - PRINT_WARN( - "netiucv: Could not allocate network device structure " - "for user '%s'\n", netiucv_printname(username)); + PRINT_WARN("netiucv: Could not allocate network device " + "structure for user '%s'\n", + netiucv_printname(username)); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); return -ENODEV; } - if ((ret = netiucv_register_device(dev))) { + rc = netiucv_register_device(dev); + if (rc) { IUCV_DBF_TEXT_(setup, 2, - "ret %d from netiucv_register_device\n", ret); + "ret %d from netiucv_register_device\n", rc); goto out_free_ndev; } /* sysfs magic */ - SET_NETDEV_DEV(dev, - (struct device*)((struct netiucv_priv*)dev->priv)->dev); + priv = netdev_priv(dev); + SET_NETDEV_DEV(dev, priv->dev); - if ((ret = register_netdev(dev))) { - netiucv_unregister_device((struct device*) - ((struct netiucv_priv*)dev->priv)->dev); - goto out_free_ndev; - } + rc = register_netdev(dev); + if (rc) + goto out_unreg; PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); return count; +out_unreg: + netiucv_unregister_device(priv->dev); out_free_ndev: PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); netiucv_free_netdevice(dev); - return ret; + return rc; } static DRIVER_ATTR(connection, 0200, NULL, conn_write); -static ssize_t -remove_write (struct device_driver *drv, const char *buf, size_t count) +static ssize_t remove_write (struct device_driver *drv, + const char *buf, size_t count) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; struct net_device *ndev; struct netiucv_priv *priv; struct device *dev; char name[IFNAMSIZ]; - char *p; + const char *p; int i; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) if (count >= IFNAMSIZ) count = IFNAMSIZ - 1;; - for (i=0, p=(char *)buf; i<count && *p; i++, p++) { - if ((*p == '\n') || (*p == ' ')) { + for (i = 0, p = buf; i < count && *p; i++, p++) { + if (*p == '\n' || *p == ' ') /* trailing lf, grr */ break; - } else { - name[i]=*p; - } + name[i] = *p; } name[i] = '\0'; - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - ndev = (*clist)->netdev; - priv = (struct netiucv_priv*)ndev->priv; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + ndev = cp->netdev; + priv = netdev_priv(ndev); dev = priv->dev; - - if (strncmp(name, ndev->name, count)) { - clist = &((*clist)->next); - continue; - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + if (strncmp(name, ndev->name, count)) + continue; + read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: net device %s active with peer %s\n", - ndev->name, priv->conn->userid); + PRINT_WARN("netiucv: net device %s active with peer " + "%s\n", ndev->name, priv->conn->userid); PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EBUSY; } @@ -2106,7 +2077,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) netiucv_unregister_device(dev); return count; } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + read_unlock_bh(&iucv_connection_rwlock); PRINT_WARN("netiucv: net device %s unknown\n", name); IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); return -EINVAL; @@ -2114,67 +2085,86 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) static DRIVER_ATTR(remove, 0200, NULL, remove_write); -static void -netiucv_banner(void) +static struct attribute * netiucv_drv_attrs[] = { + &driver_attr_connection.attr, + &driver_attr_remove.attr, + NULL, +}; + +static struct attribute_group netiucv_drv_attr_group = { + .attrs = netiucv_drv_attrs, +}; + +static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); } -static void __exit -netiucv_exit(void) +static void __exit netiucv_exit(void) { + struct iucv_connection *cp; + struct net_device *ndev; + struct netiucv_priv *priv; + struct device *dev; + IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - while (iucv_conns.iucv_connections) { - struct net_device *ndev = iucv_conns.iucv_connections->netdev; - struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; - struct device *dev = priv->dev; + while (!list_empty(&iucv_connection_list)) { + cp = list_entry(iucv_connection_list.next, + struct iucv_connection, list); + list_del(&cp->list); + ndev = cp->netdev; + priv = netdev_priv(ndev); + dev = priv->dev; unregister_netdev(ndev); netiucv_unregister_device(dev); } - driver_remove_file(&netiucv_driver, &driver_attr_connection); - driver_remove_file(&netiucv_driver, &driver_attr_remove); + sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); + iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); PRINT_INFO("NETIUCV driver unloaded\n"); return; } -static int __init -netiucv_init(void) +static int __init netiucv_init(void) { - int ret; + int rc; - ret = iucv_register_dbf_views(); - if (ret) { - PRINT_WARN("netiucv_init failed, " - "iucv_register_dbf_views rc = %d\n", ret); - return ret; - } + rc = iucv_register_dbf_views(); + if (rc) + goto out; + rc = iucv_register(&netiucv_handler, 1); + if (rc) + goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ret = driver_register(&netiucv_driver); - if (ret) { + rc = driver_register(&netiucv_driver); + if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret); - iucv_unregister_dbf_views(); - return ret; + IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); + goto out_iucv; } - /* Add entry for specifying connections. */ - ret = driver_create_file(&netiucv_driver, &driver_attr_connection); - if (!ret) { - ret = driver_create_file(&netiucv_driver, &driver_attr_remove); - netiucv_banner(); - rwlock_init(&iucv_conns.iucv_rwlock); - } else { - PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); - driver_unregister(&netiucv_driver); - iucv_unregister_dbf_views(); + rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); + if (rc) { + PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); + IUCV_DBF_TEXT_(setup, 2, + "ret %d - netiucv_drv_attr_group\n", rc); + goto out_driver; } - return ret; + netiucv_banner(); + return rc; + +out_driver: + driver_unregister(&netiucv_driver); +out_iucv: + iucv_unregister(&netiucv_handler, 1); +out_dbf: + iucv_unregister_dbf_views(); +out: + return rc; } module_init(netiucv_init); diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index b8179c27ceb6..3ccca5871fdf 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -1,7 +1,7 @@ /* * IUCV special message driver * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -23,10 +23,10 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/device.h> +#include <net/iucv/iucv.h> #include <asm/cpcmd.h> #include <asm/ebcdic.h> - -#include "iucv.h" +#include "smsgiucv.h" struct smsg_callback { struct list_head list; @@ -39,38 +39,46 @@ MODULE_AUTHOR ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); -static iucv_handle_t smsg_handle; -static unsigned short smsg_pathid; +static struct iucv_path *smsg_path; + static DEFINE_SPINLOCK(smsg_list_lock); static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); -static void -smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data) +static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); +static void smsg_message_pending(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler smsg_handler = { + .path_pending = smsg_path_pending, + .message_pending = smsg_message_pending, +}; + +static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8], + u8 ipuser[16]) { + if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0) + return -EINVAL; + /* Path pending from *MSG. */ + return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL); } - -static void -smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) +static void smsg_message_pending(struct iucv_path *path, + struct iucv_message *msg) { struct smsg_callback *cb; - unsigned char *msg; + unsigned char *buffer; unsigned char sender[9]; - unsigned short len; int rc, i; - len = eib->ln1msg2.ipbfln1f; - msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); - if (!msg) { - iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls); + buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA); + if (!buffer) { + iucv_message_reject(path, msg); return; } - rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls, - msg, len, NULL, NULL, NULL); + rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL); if (rc == 0) { - msg[len] = 0; - EBCASC(msg, len); - memcpy(sender, msg, 8); + buffer[msg->length] = 0; + EBCASC(buffer, msg->length); + memcpy(sender, buffer, 8); sender[8] = 0; /* Remove trailing whitespace from the sender name. */ for (i = 7; i >= 0; i--) { @@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) } spin_lock(&smsg_list_lock); list_for_each_entry(cb, &smsg_list, list) - if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { - cb->callback(sender, msg + 8); + if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) { + cb->callback(sender, buffer + 8); break; } spin_unlock(&smsg_list_lock); } - kfree(msg); + kfree(buffer); } -static iucv_interrupt_ops_t smsg_ops = { - .ConnectionComplete = smsg_connection_complete, - .MessagePending = smsg_message_pending, -}; - -static struct device_driver smsg_driver = { - .name = "SMSGIUCV", - .bus = &iucv_bus, -}; - -int -smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) +int smsg_register_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb; @@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) cb->prefix = prefix; cb->len = strlen(prefix); cb->callback = callback; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); list_add_tail(&cb->list, &smsg_list); - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); return 0; } -void -smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) +void smsg_unregister_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb, *tmp; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); cb = NULL; list_for_each_entry(tmp, &smsg_list, list) if (tmp->callback == callback && @@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) list_del(&cb->list); break; } - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); kfree(cb); } -static void __exit -smsg_exit(void) +static struct device_driver smsg_driver = { + .name = "SMSGIUCV", + .bus = &iucv_bus, +}; + +static void __exit smsg_exit(void) { - if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", NULL, 0, NULL); - iucv_sever(smsg_pathid, NULL); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - } - return; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); + iucv_unregister(&smsg_handler, 1); + driver_unregister(&smsg_driver); } -static int __init -smsg_init(void) +static int __init smsg_init(void) { - static unsigned char pgmmask[24] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; int rc; rc = driver_register(&smsg_driver); - if (rc != 0) { - printk(KERN_ERR "SMSGIUCV: failed to register driver.\n"); - return rc; - } - smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ", - pgmmask, &smsg_ops, NULL); - if (!smsg_handle) { + if (rc != 0) + goto out; + rc = iucv_register(&smsg_handler, 1); + if (rc) { printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); - driver_unregister(&smsg_driver); - return -EIO; /* better errno ? */ + rc = -EIO; /* better errno ? */ + goto out_driver; + } + smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); + if (!smsg_path) { + rc = -ENOMEM; + goto out_register; } - rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0, - NULL, NULL, smsg_handle, NULL); + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); if (rc) { printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - smsg_handle = NULL; - return -EIO; + rc = -EIO; /* better errno ? */ + goto out_free; } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; + +out_free: + iucv_path_free(smsg_path); +out_register: + iucv_unregister(&smsg_handler, 1); +out_driver: + driver_unregister(&smsg_driver); +out: + return rc; } module_init(smsg_init); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 437684084377..8f55e1431433 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) } BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE); - if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) { + if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock_bh(&session->lock); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d37048c96eab..7c75771c77ff 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); hdr->data_length = cpu_to_be32(sc->request_bufflen); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; @@ -270,7 +269,7 @@ invalid_datalen: goto out; } - senselen = be16_to_cpu(*(uint16_t *)data); + senselen = be16_to_cpu(*(__be16 *)data); if (datalen < senselen) goto invalid_datalen; @@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - itt = rejected_pdu.itt & ISCSI_ITT_MASK; + itt = get_itt(rejected_pdu.itt); printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " "due to DataDigest error.\n", itt, rejected_pdu.opcode); @@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_mgmt_task *mtask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) - itt = hdr->itt & ISCSI_ITT_MASK; + if (hdr->itt != RESERVED_ITT) + itt = get_itt(hdr->itt); else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { + if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { rc = ISCSI_ERR_PROTO; break; } @@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, rc = ISCSI_ERR_BAD_OPCODE; break; } - } else if (itt == ISCSI_RESERVED_TAG) { + } else if (itt == ~0U) { rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)hdr); if (rc) @@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, break; } - if (hdr->ttt == ISCSI_RESERVED_TAG) + if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) break; if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) @@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_cmd_task *ctask; uint32_t itt; - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - if ((hdr->itt & ISCSI_AGE_MASK) != + if (hdr->itt != RESERVED_ITT) { + if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != (session->age << ISCSI_AGE_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x expected " - "session age (%x)\n", hdr->itt, + "session age (%x)\n", (__force u32)hdr->itt, session->age & ISCSI_AGE_MASK); return ISCSI_ERR_BAD_ITT; } - if ((hdr->itt & ISCSI_CID_MASK) != + if (((__force u32)hdr->itt & ISCSI_CID_MASK) != (conn->id << ISCSI_CID_SHIFT)) { printk(KERN_ERR "iscsi: received itt %x, expected " - "CID (%x)\n", hdr->itt, conn->id); + "CID (%x)\n", (__force u32)hdr->itt, conn->id); return ISCSI_ERR_BAD_ITT; } - itt = hdr->itt & ISCSI_ITT_MASK; + itt = get_itt(hdr->itt); } else - itt = hdr->itt; + itt = ~0U; if (itt < session->cmds_max) { ctask = session->cmds[itt]; @@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, /* * pre-format CmdSN for outgoing PDU. */ - if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) { - hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) | - (session->age << ISCSI_AGE_SHIFT); + if (hdr->itt != RESERVED_ITT) { + hdr->itt = build_itt(mtask->itt, conn->id, session->age); nop->cmdsn = cpu_to_be32(session->cmdsn); if (conn->c_stage == ISCSI_CONN_STARTED && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) @@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, spin_lock_bh(&session->lock); ctask->mtask = (struct iscsi_mgmt_task *) - session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) - + session->mgmt_cmds[get_itt(hdr->itt) - ISCSI_MGMT_ITT_OFFSET]; if (conn->tmabort_state == TMABORT_INITIAL) { diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 7d2311067903..bd6bbf61adb8 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_ break; default: ; /* probably FILL */ } - aux->filemark_cnt = ntohl(STp->filemark_cnt); - aux->phys_fm = ntohl(0xffffffff); - aux->last_mark_ppos = ntohl(STp->last_mark_ppos); - aux->last_mark_lbn = ntohl(STp->last_mark_lbn); + aux->filemark_cnt = htonl(STp->filemark_cnt); + aux->phys_fm = htonl(0xffffffff); + aux->last_mark_ppos = htonl(STp->last_mark_ppos); + aux->last_mark_lbn = htonl(STp->last_mark_lbn); } /* diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 1e426f5d0ed8..2cc7b5a1606a 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h @@ -288,11 +288,11 @@ typedef struct { #else #error "Please fix <asm/byteorder.h>" #endif - u16 max_speed; /* Maximum speed supported in KBps */ + __be16 max_speed; /* Maximum speed supported in KBps */ u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ + __be16 ctl; /* Continuous Transfer Limit in blocks */ + __be16 speed; /* Current Speed, in KBps */ + __be16 buffer_size; /* Buffer Size, in 512 bytes */ u8 reserved18, reserved19; } osst_capabilities_page_t; @@ -352,8 +352,8 @@ typedef struct { u8 reserved2; u8 density; u8 reserved3,reserved4; - u16 segtrk; - u16 trks; + __be16 segtrk; + __be16 trks; u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; } osst_tape_paramtr_page_t; @@ -369,18 +369,18 @@ typedef struct { typedef struct os_partition_s { __u8 partition_num; __u8 par_desc_ver; - __u16 wrt_pass_cntr; - __u32 first_frame_ppos; - __u32 last_frame_ppos; - __u32 eod_frame_ppos; + __be16 wrt_pass_cntr; + __be32 first_frame_ppos; + __be32 last_frame_ppos; + __be32 eod_frame_ppos; } os_partition_t; /* * DAT entry */ typedef struct os_dat_entry_s { - __u32 blk_sz; - __u16 blk_cnt; + __be32 blk_sz; + __be16 blk_cnt; __u8 flags; __u8 reserved; } os_dat_entry_t; @@ -412,23 +412,23 @@ typedef struct os_dat_s { * AUX */ typedef struct os_aux_s { - __u32 format_id; /* hardware compability AUX is based on */ + __be32 format_id; /* hardware compability AUX is based on */ char application_sig[4]; /* driver used to write this media */ - __u32 hdwr; /* reserved */ - __u32 update_frame_cntr; /* for configuration frame */ + __be32 hdwr; /* reserved */ + __be32 update_frame_cntr; /* for configuration frame */ __u8 frame_type; __u8 frame_type_reserved; __u8 reserved_18_19[2]; os_partition_t partition; __u8 reserved_36_43[8]; - __u32 frame_seq_num; - __u32 logical_blk_num_high; - __u32 logical_blk_num; + __be32 frame_seq_num; + __be32 logical_blk_num_high; + __be32 logical_blk_num; os_dat_t dat; __u8 reserved188_191[4]; - __u32 filemark_cnt; - __u32 phys_fm; - __u32 last_mark_ppos; + __be32 filemark_cnt; + __be32 phys_fm; + __be32 last_mark_ppos; __u8 reserved204_223[20]; /* @@ -436,8 +436,8 @@ typedef struct os_aux_s { * * Linux specific fields: */ - __u32 next_mark_ppos; /* when known, points to next marker */ - __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ + __be32 next_mark_ppos; /* when known, points to next marker */ + __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ __u8 linux_specific[24]; __u8 reserved_256_511[256]; @@ -450,19 +450,19 @@ typedef struct os_fm_tab_s { __u8 reserved_1; __u8 fm_tab_ent_sz; __u8 reserved_3; - __u16 fm_tab_ent_cnt; + __be16 fm_tab_ent_cnt; __u8 reserved6_15[10]; - __u32 fm_tab_ent[OS_FM_TAB_MAX]; + __be32 fm_tab_ent[OS_FM_TAB_MAX]; } os_fm_tab_t; typedef struct os_ext_trk_ey_s { __u8 et_part_num; __u8 fmt; - __u16 fm_tab_off; + __be16 fm_tab_off; __u8 reserved4_7[4]; - __u32 last_hlb_hi; - __u32 last_hlb; - __u32 last_pp; + __be32 last_hlb_hi; + __be32 last_hlb; + __be32 last_pp; __u8 reserved20_31[12]; } os_ext_trk_ey_t; @@ -479,17 +479,17 @@ typedef struct os_header_s { char ident_str[8]; __u8 major_rev; __u8 minor_rev; - __u16 ext_trk_tb_off; + __be16 ext_trk_tb_off; __u8 reserved12_15[4]; __u8 pt_par_num; __u8 pt_reserved1_3[3]; os_partition_t partition[16]; - __u32 cfg_col_width; - __u32 dat_col_width; - __u32 qfa_col_width; + __be32 cfg_col_width; + __be32 dat_col_width; + __be32 qfa_col_width; __u8 cartridge[16]; __u8 reserved304_511[208]; - __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ + __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ os_ext_trk_tb_t ext_track_tb; __u8 reserved17272_17735[464]; os_fm_tab_t dat_fm_tab; diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index db8607e3d531..f5051cf1a0c8 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -256,7 +256,7 @@ static void ulite_release_port(struct uart_port *port) { release_mem_region(port->mapbase, ULITE_REGION); iounmap(port->membase); - port->membase = 0; + port->membase = NULL; } static int ulite_request_port(struct uart_port *port) @@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) port->iotype = UPIO_MEM; port->iobase = 1; /* mark port in use */ port->mapbase = res->start; - port->membase = 0; + port->membase = NULL; port->ops = &ulite_ops; port->irq = res2->start; port->flags = UPF_BOOT_AUTOCONF; @@ -462,7 +462,7 @@ static int ulite_remove(struct platform_device *pdev) uart_remove_one_port(&ulite_uart_driver, port); /* mark port as free */ - port->membase = 0; + port->membase = NULL; return 0; } diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 371f194a9d39..4d781a2a9807 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -104,7 +104,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index ec0da0343be4..46fa57a520d0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -677,10 +677,10 @@ static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO return ehci_big_endian_mmio(ehci) ? - readl_be((__force u32 *)regs) : - readl((__force u32 *)regs); + readl_be(regs) : + readl(regs); #else - return readl((__force u32 *)regs); + return readl(regs); #endif } @@ -689,10 +689,10 @@ static inline void ehci_writel (const struct ehci_hcd *ehci, { #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO ehci_big_endian_mmio(ehci) ? - writel_be(val, (__force u32 *)regs) : - writel(val, (__force u32 *)regs); + writel_be(val, regs) : + writel(val, regs); #else - writel(val, (__force u32 *)regs); + writel(val, regs); #endif } diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 69d948b4a701..62283a3926de 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -107,7 +107,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, __LINE__, dev->m_region->lpar_addr); - result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 0dafcda37291..c2b5ecfe5e9f 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -507,10 +507,10 @@ static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO return big_endian_mmio(ohci) ? - readl_be ((__force u32 *)regs) : - readl ((__force u32 *)regs); + readl_be (regs) : + readl (regs); #else - return readl ((__force u32 *)regs); + return readl (regs); #endif } @@ -519,10 +519,10 @@ static inline void _ohci_writel (const struct ohci_hcd *ohci, { #ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO big_endian_mmio(ohci) ? - writel_be (val, (__force u32 *)regs) : - writel (val, (__force u32 *)regs); + writel_be (val, regs) : + writel (val, regs); #else - writel (val, (__force u32 *)regs); + writel (val, regs); #endif } diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c index a6f0f4d934df..31e5fe363fdc 100644 --- a/drivers/usb/net/gl620a.c +++ b/drivers/usb/net/gl620a.c @@ -70,12 +70,12 @@ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) struct gl_packet { - u32 packet_length; + __le32 packet_length; char packet_data [1]; }; struct gl_header { - u32 packet_count; + __le32 packet_count; struct gl_packet packets; }; @@ -85,15 +85,14 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) struct gl_packet *packet; struct sk_buff *gl_skb; u32 size; + u32 count; header = (struct gl_header *) skb->data; // get the packet count of the received skb - le32_to_cpus(&header->packet_count); - if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) - || (header->packet_count < 0)) { - dbg("genelink: invalid received packet count %d", - header->packet_count); + count = le32_to_cpu(header->packet_count); + if (count > GL_MAX_TRANSMIT_PACKETS) { + dbg("genelink: invalid received packet count %u", count); return 0; } @@ -103,7 +102,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) // decrement the length for the packet count size 4 bytes skb_pull(skb, 4); - while (header->packet_count > 1) { + while (count > 1) { // get the packet length size = le32_to_cpu(packet->packet_length); @@ -124,9 +123,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } // advance to the next packet - packet = (struct gl_packet *) - &packet->packet_data [size]; - header->packet_count--; + packet = (struct gl_packet *)&packet->packet_data[size]; + count--; // shift the data pointer to the next gl_packet skb_pull(skb, size + 4); @@ -149,8 +147,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) int length = skb->len; int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); - u32 *packet_count; - u32 *packet_len; + __le32 *packet_count; + __le32 *packet_len; // FIXME: magic numbers, bleech padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; @@ -172,7 +170,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) } // attach the packet count to the header - packet_count = (u32 *) skb_push(skb, (4 + 4*1)); + packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); packet_len = packet_count + 1; *packet_count = cpu_to_le32(1); diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 06b4fffc189c..3ec24870bca9 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -170,13 +170,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kcalloc(length, sizeof(u32), GFP_KERNEL); + buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; @@ -216,13 +216,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request, unsigned int *data, int size) { struct usb_serial *serial = port->serial; - u32 *buf; + __le32 *buf; int result, i, length; /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kmalloc(length * sizeof(u32), GFP_KERNEL); + buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); |