diff options
| author | Andy Grover <agrover@groveronline.com> | 2003-03-20 18:45:08 -0800 |
|---|---|---|
| committer | Andy Grover <agrover@groveronline.com> | 2003-03-20 18:45:08 -0800 |
| commit | ff6e14381a7c1597c4ffbeb760e9802f3ebaebb2 (patch) | |
| tree | f5463b22c7b9b67342cde9e46f1d3a3068019ec8 /drivers | |
| parent | ecabd7d2dd8117b1ec4cc4b7303a7e8198843684 (diff) | |
| parent | aa43a933c82fe96479cd5e260a221b69409a553b (diff) | |
Merge groveronline.com:/root/bk/linux-2.5
into groveronline.com:/root/bk/linux-acpi
Diffstat (limited to 'drivers')
113 files changed, 7315 insertions, 3564 deletions
diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c index 8f06514adce0..4630bb66434d 100644 --- a/drivers/acpi/processor.c +++ b/drivers/acpi/processor.c @@ -1356,7 +1356,8 @@ acpi_processor_write_throttling ( loff_t *data) { int result = 0; - struct acpi_processor *pr = (struct acpi_processor *) data; + struct seq_file *m = (struct seq_file *)file->private_data; + struct acpi_processor *pr = (struct acpi_processor *)m->private; char state_string[12] = {'\0'}; ACPI_FUNCTION_TRACE("acpi_processor_write_throttling"); @@ -1418,7 +1419,8 @@ acpi_processor_write_limit ( loff_t *data) { int result = 0; - struct acpi_processor *pr = (struct acpi_processor *) data; + struct seq_file *m = (struct seq_file *)file->private_data; + struct acpi_processor *pr = (struct acpi_processor *)m->private; char limit_string[25] = {'\0'}; int px = 0; int tx = 0; diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index e337c9e68ed4..3a59d3d3833c 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -730,7 +730,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb) struct atm_vcc *vcc = vc->tx_vcc; vc->estimator->cells += (skb->len + 47) / 48; - if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) { + if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) { u32 cps = vc->estimator->maxcps; vc->estimator->cps = cps; @@ -2025,7 +2025,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } - atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse); + atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc); ATM_SKB(skb)->iovcnt = 0; memcpy(skb_put(skb, 52), cell, 52); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 924212464123..b473e3b08ce1 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -353,10 +353,8 @@ static int fd_motor_on(int nr) unit[nr].motor = 1; fd_select(nr); - del_timer(&motor_on_timer); motor_on_timer.data = nr; - motor_on_timer.expires = jiffies + HZ/2; - add_timer(&motor_on_timer); + mod_timer(&motor_on_timer, jiffies + HZ/2); on_attempts = 10; sleep_on (&motor_wait); @@ -414,11 +412,9 @@ static void floppy_off (unsigned int nr) int drive; drive = nr & 3; - del_timer(motor_off_timer + drive); - motor_off_timer[drive].expires = jiffies + 3*HZ; /* called this way it is always from interrupt */ motor_off_timer[drive].data = nr | 0x80000000; - add_timer(motor_off_timer + nr); + mod_timer(motor_off_timer + drive, jiffies + 3*HZ); } static int fd_calibrate(int drive) @@ -1429,10 +1425,7 @@ static void redo_fd_request(void) floppy->dirty = 1; /* reset the timer */ - del_timer (flush_track_timer + drive); - - flush_track_timer[drive].expires = jiffies + 1; - add_timer (flush_track_timer + drive); + mod_timer (flush_track_timer + drive, jiffies + 1); local_irq_restore(flags); break; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 734ae3817430..642920295653 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2623,12 +2623,8 @@ int __init cciss_init(void) { printk(KERN_INFO DRIVER_NAME "\n"); - /* Register for out PCI devices */ - if (pci_register_driver(&cciss_pci_driver) > 0 ) - return 0; - else - return -ENODEV; - + /* Register for our PCI devices */ + return pci_register_driver(&cciss_pci_driver); } static int __init init_cciss_module(void) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index d3d20c946e30..c8b909229c5d 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3649,6 +3649,8 @@ static void __init config_types(void) name = default_drive_params[type].name; allowed_drive_mask |= 1 << drive; } + else + allowed_drive_mask &= ~(1 << drive); } else { params = &default_drive_params[0].params; sprintf(temparea, "unknown type %d (usb?)", type); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 001b2f98267e..08298857a712 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -76,22 +76,15 @@ static void nbd_end_request(struct request *req) { int uptodate = (req->errors == 0) ? 1 : 0; request_queue_t *q = req->q; - struct bio *bio; - unsigned nsect; unsigned long flags; #ifdef PARANOIA requests_out++; #endif spin_lock_irqsave(q->queue_lock, flags); - while((bio = req->bio) != NULL) { - nsect = bio_sectors(bio); - blk_finished_io(nsect); - req->bio = bio->bi_next; - bio->bi_next = NULL; - bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO); + if (!end_that_request_first(req, uptodate, req->nr_sectors)) { + end_that_request_last(req); } - blk_put_request(req); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -243,7 +236,7 @@ static struct request *nbd_find_request(struct nbd_device *lo, char *handle) req = list_entry(tmp, struct request, queuelist); if (req != xreq) continue; - list_del(&req->queuelist); + list_del_init(&req->queuelist); spin_unlock(&lo->queue_lock); return req; } @@ -322,7 +315,7 @@ void nbd_clear_que(struct nbd_device *lo) spin_lock(&lo->queue_lock); if (!list_empty(&lo->queue_head)) { req = list_entry(lo->queue_head.next, struct request, queuelist); - list_del(&req->queuelist); + list_del_init(&req->queuelist); } spin_unlock(&lo->queue_lock); if (req) { @@ -387,7 +380,7 @@ static void do_nbd_request(request_queue_t * q) if (req->errors) { printk(KERN_ERR "nbd: nbd_send_req failed\n"); spin_lock(&lo->queue_lock); - list_del(&req->queuelist); + list_del_init(&req->queuelist); spin_unlock(&lo->queue_lock); nbd_end_request(req); spin_lock_irq(q->queue_lock); @@ -590,6 +583,7 @@ static int __init nbd_init(void) disk->first_minor = i; disk->fops = &nbd_fops; disk->private_data = &nbd_dev[i]; + disk->queue = &nbd_queue; sprintf(disk->disk_name, "nbd%d", i); set_capacity(disk, 0x3ffffe); add_disk(disk); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index aea2bdce51b5..c2774d5224cc 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1125,7 +1125,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) { - unsigned char buf[20], *base; + unsigned char buf[21], *base; struct dvd_layer *layer; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index f25d9ff0fda2..915afe6dfe71 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -1375,9 +1375,9 @@ read_data_block(char *buffer, readahead_buffer + (2048 - readahead_dataleft), readahead_dataleft); - readahead_dataleft = 0; bytesleft -= readahead_dataleft; offset += readahead_dataleft; + readahead_dataleft = 0; } else { /* The readahead will fill the whole buffer, get the data and return. */ diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 9978844a3bc4..187b8434fb69 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -102,8 +102,6 @@ static char *serial_version = "4.30"; static char *serial_name = "Amiga-builtin serial driver"; -static DECLARE_TASK_QUEUE(tq_serial); - static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -276,8 +274,7 @@ static _INLINE_ void rs_sched_event(struct async_struct *info, int event) { info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); + tasklet_schedule(&info->tlet); } static _INLINE_ void receive_chars(struct async_struct *info) @@ -560,12 +557,8 @@ static void ser_tx_int(int irq, void *dev_id, struct pt_regs * regs) * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} -static void do_softint(void *private_) +static void do_softint(unsigned long private_) { struct async_struct *info = (struct async_struct *) private_; struct tty_struct *tty; @@ -1878,8 +1871,7 @@ static int get_async_struct(int line, struct async_struct **ret_info) info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; - info->tqueue.routine = do_softint; - info->tqueue.data = info; + tasklet_init(&info->tlet, do_softint, (unsigned long)info); info->state = sstate; if (sstate->info) { kfree(info); @@ -2117,8 +2109,6 @@ static int __init rs_init(void) if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]")) return -EBUSY; - init_bh(SERIAL_BH, do_serial_bh); - IRQ_ports = NULL; show_serial_version(); @@ -2234,23 +2224,18 @@ static int __init rs_init(void) static __exit void rs_exit(void) { - unsigned long flags; int e1, e2; - struct async_struct *info; + struct async_struct *info = rs_table[0].info; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - save_flags(flags); - cli(); - remove_bh(SERIAL_BH); + tasklet_kill(&info->tlet); if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); if ((e2 = tty_unregister_driver(&callout_driver))) printk("SERIAL: failed to unregister callout driver (%d)\n", e2); - restore_flags(flags); - info = rs_table[0].info; if (info) { rs_table[0].info = NULL; kfree(info); @@ -2320,9 +2305,10 @@ static struct console sercons = { /* * Register console. */ -static void __init amiserial_console_init(void) +static int __init amiserial_console_init(void) { register_console(&sercons); + return 0; } console_initcall(amiserial_console_init); #endif diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c index cd01044afd9d..aa1440934e95 100644 --- a/drivers/char/decserial.c +++ b/drivers/char/decserial.c @@ -75,7 +75,7 @@ __initcall(rs_init); /* serial_console_init handles the special case of starting * up the console on the serial port */ -static void __init decserial_console_init(void) +static int __init decserial_console_init(void) { #if defined(CONFIG_ZS) && defined(CONFIG_DZ) if (IOASIC) @@ -93,6 +93,7 @@ static void __init decserial_console_init(void) #endif #endif + return 0; } console_initcall(decserial_console_init); diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index dbffc3ced84a..0f65f959c0dd 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -40,12 +40,6 @@ #include <linux/interrupt.h> /* For task queue support */ #include <linux/delay.h> -#ifdef DO_MUNMAP_4_ARGS -#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1) -#else -#define DO_MUNMAP(m, a, l) do_munmap(m, a, l) -#endif - #define I830_BUF_FREE 2 #define I830_BUF_CLIENT 1 #define I830_BUF_HARDWARE 0 @@ -230,7 +224,7 @@ static int i830_unmap_buffer(drm_buf_t *buf) return -EINVAL; down_write(¤t->mm->mmap_sem); - retcode = DO_MUNMAP(current->mm, + retcode = do_munmap(current->mm, (unsigned long)buf_priv->virtual, (size_t) buf->total); up_write(¤t->mm->mmap_sem); diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 6be546513a3c..0de5b2d8e51d 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -1,5 +1,8 @@ /* - * Real Time Clock interface for q40 and other m68k machines + * Real Time Clock interface for + * - q40 and other m68k machines, + * - HP PARISC machines + * - PowerPC machines * emulate some RTC irq capabilities in software * * Copyright (C) 1999 Richard Zidlicky @@ -13,7 +16,7 @@ * pseudo-file for status information. * * The ioctls can be used to set the interrupt behaviour where - * supported. + * supported. * * The /dev/rtc interface will block on reads until an interrupt * has been received. If a RTC interrupt has already happened, @@ -34,9 +37,10 @@ * 1.04 removed useless timer code rz@linux-m68k.org * 1.05 portable RTC_UIE emulation rz@linux-m68k.org * 1.06 set_rtc_time can return an error trini@kernel.crashing.org + * 1.07 ported to HP PARISC (hppa) Helge Deller <deller@gmx.de> */ -#define RTC_VERSION "1.06" +#define RTC_VERSION "1.07" #include <linux/module.h> #include <linux/config.h> @@ -63,20 +67,17 @@ static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait); -static int gen_rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - /* * Bits in gen_rtc_status. */ #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ -unsigned char gen_rtc_status; /* bitmapped status byte. */ -unsigned long gen_rtc_irq_data; /* our output to the world */ +static unsigned char gen_rtc_status; /* bitmapped status byte. */ +static unsigned long gen_rtc_irq_data; /* our output to the world */ /* months start at 0 now */ -unsigned char days_in_mo[] = +static unsigned char days_in_mo[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static int irq_active; @@ -89,18 +90,20 @@ static unsigned int oldsecs; static int lostint; static int tt_exp; -void gen_rtc_timer(unsigned long data); +static void gen_rtc_timer(unsigned long data); static volatile int stask_active; /* schedule_work */ static volatile int ttask_active; /* timer_task */ static int stop_rtc_timers; /* don't requeue tasks */ static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED; +static void gen_rtc_interrupt(unsigned long arg); + /* * Routine to poll RTC seconds field for change as often as possible, * after first RTC_UIE use timer to reduce polling */ -void genrtc_troutine(void *data) +static void genrtc_troutine(void *data) { unsigned int tmp = get_rtc_ss(); @@ -124,7 +127,7 @@ void genrtc_troutine(void *data) stask_active = 0; } -void gen_rtc_timer(unsigned long data) +static void gen_rtc_timer(unsigned long data) { lostint = get_rtc_ss() - oldsecs ; if (lostint<0) @@ -145,7 +148,7 @@ void gen_rtc_timer(unsigned long data) * from some routine that periodically (eg 100HZ) monitors * whether RTC_SECS changed */ -void gen_rtc_interrupt(unsigned long arg) +static void gen_rtc_interrupt(unsigned long arg) { /* We store the status in the low byte and the number of * interrupts received since the last read in the remainder @@ -175,7 +178,7 @@ static ssize_t gen_rtc_read(struct file *file, char *buf, unsigned long data; ssize_t retval; - if (count != sizeof (unsigned int) && count != sizeof (unsigned long)) + if (count != sizeof (unsigned int) && count != sizeof (unsigned long)) return -EINVAL; if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data) @@ -385,24 +388,24 @@ static int gen_rtc_read_proc(char *page, char **start, off_t off, */ static struct file_operations gen_rtc_fops = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, #ifdef CONFIG_GEN_RTC_X - .read = gen_rtc_read, - .poll = gen_rtc_poll, + .read = gen_rtc_read, + .poll = gen_rtc_poll, #endif - .ioctl = gen_rtc_ioctl, - .open = gen_rtc_open, - .release = gen_rtc_release + .ioctl = gen_rtc_ioctl, + .open = gen_rtc_open, + .release = gen_rtc_release, }; static struct miscdevice rtc_gen_dev = { - RTC_MINOR, - "rtc", - &gen_rtc_fops + .minor = RTC_MINOR, + .name = "rtc", + .fops = &gen_rtc_fops, }; -int __init rtc_generic_init(void) +static int __init rtc_generic_init(void) { int retval; @@ -436,16 +439,18 @@ module_exit(rtc_generic_exit); * Info exported via "/proc/rtc". */ -int gen_rtc_proc_output(char *buf) +#ifdef CONFIG_PROC_FS + +static int gen_rtc_proc_output(char *buf) { char *p; struct rtc_time tm; - unsigned tmp; + unsigned int flags; struct rtc_pll_info pll; p = buf; - get_rtc_time(&tm); + flags = get_rtc_time(&tm); p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" @@ -454,7 +459,7 @@ int gen_rtc_proc_output(char *buf) tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900); - tm.tm_hour=0;tm.tm_min=0;tm.tm_sec=0; + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; p += sprintf(p, "alarm\t\t: "); if (tm.tm_hour <= 24) @@ -472,7 +477,6 @@ int gen_rtc_proc_output(char *buf) else p += sprintf(p, "**\n"); - tmp= RTC_24H ; p += sprintf(p, "DST_enable\t: %s\n" "BCD\t\t: %s\n" @@ -483,15 +487,15 @@ int gen_rtc_proc_output(char *buf) "periodic_IRQ\t: %s\n" "periodic_freq\t: %ld\n" "batt_status\t: %s\n", - (tmp & RTC_DST_EN) ? "yes" : "no", - (tmp & RTC_DM_BINARY) ? "no" : "yes", - (tmp & RTC_24H) ? "yes" : "no", - (tmp & RTC_SQWE) ? "yes" : "no", - (tmp & RTC_AIE) ? "yes" : "no", + (flags & RTC_DST_EN) ? "yes" : "no", + (flags & RTC_DM_BINARY) ? "no" : "yes", + (flags & RTC_24H) ? "yes" : "no", + (flags & RTC_SQWE) ? "yes" : "no", + (flags & RTC_AIE) ? "yes" : "no", irq_active ? "yes" : "no", - (tmp & RTC_PIE) ? "yes" : "no", + (flags & RTC_PIE) ? "yes" : "no", 0L /* freq */, - "okay" ); + (flags & RTC_BATT_BAD) ? "bad" : "okay"); if (!get_rtc_pll(&pll)) p += sprintf(p, "PLL adjustment\t: %d\n" @@ -506,7 +510,7 @@ int gen_rtc_proc_output(char *buf) pll.pll_posmult, pll.pll_negmult, pll.pll_clock); - return p - buf; + return p - buf; } static int gen_rtc_read_proc(char *page, char **start, off_t off, @@ -521,6 +525,9 @@ static int gen_rtc_read_proc(char *page, char **start, off_t off, return len; } +#endif /* CONFIG_PROC_FS */ + MODULE_AUTHOR("Richard Zidlicky"); MODULE_LICENSE("GPL"); + diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index c80d79a80bd0..d4991bac9437 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1029,7 +1029,10 @@ do_it_again: break; cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; - put_user(cs, b++); + if (put_user(cs, b++)) { + retval = -EFAULT; + break; + } nr--; break; } @@ -1068,7 +1071,10 @@ do_it_again: /* Deal with packet mode. */ if (tty->packet && b == buf) { - put_user(TIOCPKT_DATA, b++); + if (put_user(TIOCPKT_DATA, b++)) { + retval = -EFAULT; + break; + } nr--; } @@ -1095,12 +1101,17 @@ do_it_again: spin_unlock_irqrestore(&tty->read_lock, flags); if (!eol || (c != __DISABLED_CHAR)) { - put_user(c, b++); + if (put_user(c, b++)) { + retval = -EFAULT; + break; + } nr--; } if (eol) break; } + if (retval) + break; } else { int uncopied; uncopied = copy_from_read_buf(tty, &b, &nr); @@ -1135,7 +1146,7 @@ do_it_again: current->state = TASK_RUNNING; size = b - buf; - if (size) { + if (!retval && size) { retval = size; if (nr) clear_bit(TTY_PUSH, &tty->flags); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index ac5f3c0f6041..08fd00d4fce4 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -50,7 +50,7 @@ static int raw_open(struct inode *inode, struct file *filp) filp->f_op = &raw_ctl_fops; return 0; } - + down(&raw_mutex); /* @@ -70,10 +70,10 @@ static int raw_open(struct inode *inode, struct file *filp) } else { err = set_blocksize(bdev, bdev_hardsect_size(bdev)); if (err == 0) { - raw_devices[minor].inuse++; - filp->f_dentry->d_inode->i_mapping = - bdev->bd_inode->i_mapping; filp->f_flags |= O_DIRECT; + if (++raw_devices[minor].inuse == 1) + filp->f_dentry->d_inode->i_mapping = + bdev->bd_inode->i_mapping; } } } @@ -83,6 +83,10 @@ out: return err; } +/* + * When the final fd which refers to this character-special node is closed, we + * make its ->mapping point back at its own i_data. + */ static int raw_release(struct inode *inode, struct file *filp) { const int minor= minor(inode->i_rdev); @@ -90,13 +94,13 @@ static int raw_release(struct inode *inode, struct file *filp) down(&raw_mutex); bdev = raw_devices[minor].binding; - raw_devices[minor].inuse--; + if (--raw_devices[minor].inuse == 0) { + /* Here inode->i_mapping == bdev->bd_inode->i_mapping */ + inode->i_mapping = &inode->i_data; + inode->i_mapping->backing_dev_info = &default_backing_dev_info; + } up(&raw_mutex); - /* Here inode->i_mapping == bdev->bd_inode->i_mapping */ - inode->i_mapping = &inode->i_data; - inode->i_mapping->backing_dev_info = &default_backing_dev_info; - bd_release(bdev); blkdev_put(bdev, BDEV_RAW); return 0; @@ -118,27 +122,28 @@ raw_ioctl(struct inode *inode, struct file *filp, * Deal with ioctls against the raw-device control interface, to bind * and unbind other raw devices. */ -static int -raw_ctl_ioctl(struct inode *inode, struct file *filp, - unsigned int command, unsigned long arg) +static int raw_ctl_ioctl(struct inode *inode, struct file *filp, + unsigned int command, unsigned long arg) { struct raw_config_request rq; struct raw_device_data *rawdev; - int err; - + int err = 0; + switch (command) { case RAW_SETBIND: case RAW_GETBIND: /* First, find out which raw minor we want */ - err = -EFAULT; - if (copy_from_user(&rq, (void *) arg, sizeof(rq))) + if (copy_from_user(&rq, (void *) arg, sizeof(rq))) { + err = -EFAULT; goto out; - - err = -EINVAL; - if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) + } + + if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) { + err = -EINVAL; goto out; + } rawdev = &raw_devices[rq.raw_minor]; if (command == RAW_SETBIND) { @@ -148,9 +153,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, * This is like making block devices, so demand the * same capability */ - err = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; goto out; + } /* * For now, we don't need to check that the underlying @@ -159,17 +165,18 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, * major/minor numbers make sense. */ - err = -EINVAL; dev = MKDEV(rq.block_major, rq.block_minor); if ((rq.block_major == 0 && rq.block_minor != 0) || - MAJOR(dev) != rq.block_major || - MINOR(dev) != rq.block_minor) + MAJOR(dev) != rq.block_major || + MINOR(dev) != rq.block_minor) { + err = -EINVAL; goto out; - + } + down(&raw_mutex); - err = -EBUSY; if (rawdev->inuse) { up(&raw_mutex); + err = -EBUSY; goto out; } if (rawdev->binding) { @@ -181,7 +188,10 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, rawdev->binding = NULL; } else { rawdev->binding = bdget(dev); - MOD_INC_USE_COUNT; + if (rawdev->binding == NULL) + err = -ENOMEM; + else + try_module_get(THIS_MODULE); } up(&raw_mutex); } else { @@ -196,13 +206,12 @@ raw_ctl_ioctl(struct inode *inode, struct file *filp, rq.block_major = rq.block_minor = 0; } up(&raw_mutex); - err = -EFAULT; - if (copy_to_user((void *)arg, &rq, sizeof(rq))) + if (copy_to_user((void *)arg, &rq, sizeof(rq))) { + err = -EFAULT; goto out; + } } - err = 0; break; - default: err = -EINVAL; break; diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index dcd2d72c2579..1800ea9984dd 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2836,7 +2836,7 @@ static struct console sercons = { }; -static void __init serial167_console_init(void) +static int __init serial167_console_init(void) { if (vme_brdtype == VME_TYPE_MVME166 || vme_brdtype == VME_TYPE_MVME167 || @@ -2844,6 +2844,7 @@ static void __init serial167_console_init(void) mvme167_serial_console_setup(0); register_console(&sercons); } + return 0; } console_initcall(serial167_console_init); diff --git a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c index 394b0564aec9..ded61de976d2 100644 --- a/drivers/char/serial_tx3912.c +++ b/drivers/char/serial_tx3912.c @@ -1054,9 +1054,10 @@ static struct console sercons = { .index = -1 }; -static void __init tx3912_console_init(void) +static int __init tx3912_console_init(void) { register_console(&sercons); + return 0; } console_initcall(tx3912_console_init); diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c index 5c2463b13eb6..8126a71d0b0b 100644 --- a/drivers/char/sh-sci.c +++ b/drivers/char/sh-sci.c @@ -1275,7 +1275,7 @@ static struct console sercons = { extern void sh_console_unregister (void); #endif -static void __init sci_console_init(void) +static int __init sci_console_init(void) { register_console(&sercons); #ifdef CONFIG_SH_EARLY_PRINTK @@ -1284,6 +1284,7 @@ static void __init sci_console_init(void) */ sh_console_unregister(); #endif + return 0; } console_initcall(sci_console_init); diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 3eb52370b48a..95cc54d04ed4 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -1091,7 +1091,7 @@ static struct console sercons = { }; -static void __init vme_scc_console_init(void) +static int __init vme_scc_console_init(void) { if (vme_brdtype == VME_TYPE_MVME147 || vme_brdtype == VME_TYPE_MVME162 || @@ -1099,5 +1099,6 @@ static void __init vme_scc_console_init(void) vme_brdtype == VME_TYPE_BVME4000 || vme_brdtype == VME_TYPE_BVME6000) register_console(&sercons); + return 0; } console_initcall(vme_scc_console_init); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 67abe170a8de..a2c20584f7f9 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -76,6 +76,24 @@ config I2C_I801 in the lm_sensors package, which you can download at http://www.lm-sensors.nu +config I2C_ISA + tristate " ISA Bus support" + depends on I2C && I2C_PROC && ISA && EXPERIMENTAL + help + If you say yes to this option, support will be included for i2c + interfaces that are on the ISA bus. + + This can also be built as a module which can be inserted and removed + while the kernel is running. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + The module will be called i2c-isa. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + + config I2C_PIIX4 tristate " Intel PIIX4" depends on I2C && I2C_PROC && PCI && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index c8e61d4a6f88..b6b6ace36f1b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_I801) += i2c-i801.o +obj-$(CONFIG_I2C_ISA) += i2c-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 8d7f372e109f..cd4569ed952f 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -60,6 +60,8 @@ /* Note: we assume there can only be one ALI15X3, with one SMBus interface */ +/* #define DEBUG 1 */ + #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> @@ -71,46 +73,46 @@ #include <asm/io.h> /* ALI15X3 SMBus address offsets */ -#define SMBHSTSTS (0 + ali15x3_smba) -#define SMBHSTCNT (1 + ali15x3_smba) -#define SMBHSTSTART (2 + ali15x3_smba) -#define SMBHSTCMD (7 + ali15x3_smba) -#define SMBHSTADD (3 + ali15x3_smba) -#define SMBHSTDAT0 (4 + ali15x3_smba) -#define SMBHSTDAT1 (5 + ali15x3_smba) -#define SMBBLKDAT (6 + ali15x3_smba) +#define SMBHSTSTS (0 + ali15x3_smba) +#define SMBHSTCNT (1 + ali15x3_smba) +#define SMBHSTSTART (2 + ali15x3_smba) +#define SMBHSTCMD (7 + ali15x3_smba) +#define SMBHSTADD (3 + ali15x3_smba) +#define SMBHSTDAT0 (4 + ali15x3_smba) +#define SMBHSTDAT1 (5 + ali15x3_smba) +#define SMBBLKDAT (6 + ali15x3_smba) /* PCI Address Constants */ -#define SMBCOM 0x004 -#define SMBBA 0x014 -#define SMBATPC 0x05B /* used to unlock xxxBA registers */ -#define SMBHSTCFG 0x0E0 -#define SMBSLVC 0x0E1 -#define SMBCLK 0x0E2 -#define SMBREV 0x008 +#define SMBCOM 0x004 +#define SMBBA 0x014 +#define SMBATPC 0x05B /* used to unlock xxxBA registers */ +#define SMBHSTCFG 0x0E0 +#define SMBSLVC 0x0E1 +#define SMBCLK 0x0E2 +#define SMBREV 0x008 /* Other settings */ -#define MAX_TIMEOUT 200 /* times 1/100 sec */ -#define ALI15X3_SMB_IOSIZE 32 +#define MAX_TIMEOUT 200 /* times 1/100 sec */ +#define ALI15X3_SMB_IOSIZE 32 /* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB. We don't use these here. If the bases aren't set to some value we tell user to upgrade BIOS and we fail. */ -#define ALI15X3_SMB_DEFAULTBASE 0xE800 +#define ALI15X3_SMB_DEFAULTBASE 0xE800 /* ALI15X3 address lock bits */ -#define ALI15X3_LOCK 0x06 +#define ALI15X3_LOCK 0x06 /* ALI15X3 command constants */ -#define ALI15X3_ABORT 0x02 -#define ALI15X3_T_OUT 0x04 -#define ALI15X3_QUICK 0x00 -#define ALI15X3_BYTE 0x10 -#define ALI15X3_BYTE_DATA 0x20 -#define ALI15X3_WORD_DATA 0x30 -#define ALI15X3_BLOCK_DATA 0x40 -#define ALI15X3_BLOCK_CLR 0x80 +#define ALI15X3_ABORT 0x02 +#define ALI15X3_T_OUT 0x04 +#define ALI15X3_QUICK 0x00 +#define ALI15X3_BYTE 0x10 +#define ALI15X3_BYTE_DATA 0x20 +#define ALI15X3_WORD_DATA 0x30 +#define ALI15X3_BLOCK_DATA 0x40 +#define ALI15X3_BLOCK_CLR 0x80 /* ALI15X3 status register bits */ #define ALI15X3_STS_IDLE 0x04 @@ -129,55 +131,52 @@ MODULE_PARM(force_addr, "i"); MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"); - -static void ali15x3_do_pause(unsigned int amount); -static int ali15x3_transaction(void); - static unsigned short ali15x3_smba = 0; -int ali15x3_setup(struct pci_dev *ALI15X3_dev) +static int ali15x3_setup(struct pci_dev *ALI15X3_dev) { u16 a; unsigned char temp; -/* Check the following things: - - SMB I/O address is initialized - - Device is enabled - - We can use the addresses -*/ - -/* Unlock the register. - The data sheet says that the address registers are read-only - if the lock bits are 1, but in fact the address registers - are zero unless you clear the lock bits. -*/ + /* Check the following things: + - SMB I/O address is initialized + - Device is enabled + - We can use the addresses + */ + + /* Unlock the register. + The data sheet says that the address registers are read-only + if the lock bits are 1, but in fact the address registers + are zero unless you clear the lock bits. + */ pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp); if (temp & ALI15X3_LOCK) { temp &= ~ALI15X3_LOCK; pci_write_config_byte(ALI15X3_dev, SMBATPC, temp); } -/* Determine the address of the SMBus area */ + /* Determine the address of the SMBus area */ pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba); ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1)); if (ali15x3_smba == 0 && force_addr == 0) { - printk - ("i2c-ali15x3.o: ALI15X3_smb region uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized " + "- upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } if(force_addr) ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); - if (check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE)) { - printk - ("i2c-ali15x3.o: ALI15X3_smb region 0x%x already in use!\n", - ali15x3_smba); + if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb")) { + dev_err(&ALI15X3_dev->dev, + "ALI15X3_smb region 0x%x already in use!\n", + ali15x3_smba); return -ENODEV; } if(force_addr) { - printk("i2c-ali15x3.o: forcing ISA address 0x%04X\n", ali15x3_smba); + dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n", + ali15x3_smba); if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba)) return -ENODEV; @@ -186,68 +185,60 @@ int ali15x3_setup(struct pci_dev *ALI15X3_dev) return -ENODEV; if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { /* make sure it works */ - printk("i2c-ali15x3.o: force address failed - not supported?\n"); + dev_err(&ALI15X3_dev->dev, + "force address failed - not supported?\n"); return -ENODEV; } } -/* check if whole device is enabled */ + /* check if whole device is enabled */ pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp); if ((temp & 1) == 0) { - printk("i2c-ali15x3: enabling SMBus device\n"); + dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n"); pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01); } -/* Is SMB Host controller enabled? */ + /* Is SMB Host controller enabled? */ pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { - printk("i2c-ali15x3: enabling SMBus controller\n"); + dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n"); pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01); } -/* set SMB clock to 74KHz as recommended in data sheet */ + /* set SMB clock to 74KHz as recommended in data sheet */ pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20); - /* Everything is happy, let's grab the memory and set things up. */ - request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, "ali15x3-smb"); - -#ifdef DEBUG -/* - The interrupt routing for SMB is set up in register 0x77 in the - 1533 ISA Bridge device, NOT in the 7101 device. - Don't bother with finding the 1533 device and reading the register. - if ((....... & 0x0F) == 1) - printk("i2c-ali15x3.o: ALI15X3 using Interrupt 9 for SMBus.\n"); -*/ + /* + The interrupt routing for SMB is set up in register 0x77 in the + 1533 ISA Bridge device, NOT in the 7101 device. + Don't bother with finding the 1533 device and reading the register. + if ((....... & 0x0F) == 1) + dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n"); + */ pci_read_config_byte(ALI15X3_dev, SMBREV, &temp); - printk("i2c-ali15x3.o: SMBREV = 0x%X\n", temp); - printk("i2c-ali15x3.o: ALI15X3_smba = 0x%X\n", ali15x3_smba); -#endif /* DEBUG */ + dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp); + dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); return 0; } - /* Internally used pause function */ -void ali15x3_do_pause(unsigned int amount) +static void ali15x3_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); } /* Another internally used function */ -int ali15x3_transaction(void) +static int ali15x3_transaction(struct i2c_adapter *adap) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); /* get status */ temp = inb_p(SMBHSTSTS); @@ -255,43 +246,32 @@ int ali15x3_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ /* Check the busy bit first */ if (temp & ALI15X3_STS_BUSY) { -/* - If the host controller is still busy, it may have timed out in the previous transaction, - resulting in a "SMBus Timeout" printk. - I've tried the following to reset a stuck busy bit. - 1. Reset the controller with an ABORT command. - (this doesn't seem to clear the controller if an external device is hung) - 2. Reset the controller and the other SMBus devices with a T_OUT command. - (this clears the host busy bit if an external device is hung, - but it comes back upon a new access to a device) - 3. Disable and reenable the controller in SMBHSTCFG - Worst case, nothing seems to work except power reset. -*/ -/* Abort - reset the host controller */ -/* -#ifdef DEBUG - printk("i2c-ali15x3.o: Resetting host controller to clear busy condition\n",temp); -#endif - outb_p(ALI15X3_ABORT, SMBHSTCNT); - temp = inb_p(SMBHSTSTS); - if (temp & ALI15X3_STS_BUSY) { -*/ - -/* - Try resetting entire SMB bus, including other devices - - This may not work either - it clears the BUSY bit but - then the BUSY bit may come back on when you try and use the chip again. - If that's the case you are stuck. -*/ - printk - ("i2c-ali15x3.o: Resetting entire SMB Bus to clear busy condition (%02x)\n", - temp); + /* + If the host controller is still busy, it may have timed out in the + previous transaction, resulting in a "SMBus Timeout" Dev. + I've tried the following to reset a stuck busy bit. + 1. Reset the controller with an ABORT command. + (this doesn't seem to clear the controller if an external + device is hung) + 2. Reset the controller and the other SMBus devices with a + T_OUT command. (this clears the host busy bit if an + external device is hung, but it comes back upon a new access + to a device) + 3. Disable and reenable the controller in SMBHSTCFG + Worst case, nothing seems to work except power reset. + */ + /* Abort - reset the host controller */ + /* + Try resetting entire SMB bus, including other devices - + This may not work either - it clears the BUSY bit but + then the BUSY bit may come back on when you try and use the chip again. + If that's the case you are stuck. + */ + dev_info(&adap->dev, "Resetting entire SMB Bus to " + "clear busy condition (%02x)\n", temp); outb_p(ALI15X3_T_OUT, SMBHSTCNT); temp = inb_p(SMBHSTSTS); } -/* - } -*/ /* now check the error bits and the busy bit */ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { @@ -302,9 +282,9 @@ int ali15x3_transaction(void) /* this is probably going to be correctable only by a power reset as one of the bits now appears to be stuck */ /* This may be a bus or device with electrical problems. */ - printk - ("i2c-ali15x3.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung\n", - temp); + dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - " + "controller or device on bus is probably hung\n", + temp); return -1; } } else { @@ -328,48 +308,41 @@ int ali15x3_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; - printk("i2c-ali15x3.o: SMBus Timeout!\n"); + dev_err(&adap->dev, "SMBus Timeout!\n"); } if (temp & ALI15X3_STS_TERM) { result = -1; -#ifdef DEBUG - printk("i2c-ali15x3.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); } -/* - Unfortunately the ALI SMB controller maps "no response" and "bus collision" - into a single bit. No reponse is the usual case so don't - do a printk. - This means that bus collisions go unreported. -*/ + /* + Unfortunately the ALI SMB controller maps "no response" and "bus + collision" into a single bit. No reponse is the usual case so don't + do a printk. + This means that bus collisions go unreported. + */ if (temp & ALI15X3_STS_COLL) { result = -1; -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Error: no response or bus collision ADD=%02x\n", - inb_p(SMBHSTADD)); -#endif + dev_dbg(&adap->dev, + "Error: no response or bus collision ADD=%02x\n", + inb_p(SMBHSTADD)); } -/* haven't ever seen this */ + /* haven't ever seen this */ if (temp & ALI15X3_STS_DEV) { result = -1; - printk("i2c-ali15x3.o: Error: device error\n"); + dev_err(&adap->dev, "Error: device error\n"); } -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); return result; } /* Return -1 on error. */ -s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, +static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { @@ -377,9 +350,9 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, int temp; int timeout; -/* clear all the bits (clear-on-write) */ + /* clear all the bits (clear-on-write) */ outb_p(0xFF, SMBHSTSTS); -/* make sure SMBus is idle */ + /* make sure SMBus is idle */ temp = inb_p(SMBHSTSTS); for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); @@ -388,14 +361,12 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, temp = inb_p(SMBHSTSTS); } if (timeout >= MAX_TIMEOUT) { - printk("i2c-ali15x3.o: Idle wait Timeout! STS=0x%02x\n", - temp); + dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp); } switch (size) { case I2C_SMBUS_PROC_CALL: - printk - ("i2c-ali15x3.o: I2C_SMBUS_PROC_CALL not supported!\n"); + dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), @@ -442,7 +413,8 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, data->block[0] = len; } outb_p(len, SMBHSTDAT0); - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */ + /* Reset SMBBLKDAT */ + outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } @@ -452,7 +424,7 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, outb_p(size, SMBHSTCNT); /* output command */ - if (ali15x3_transaction()) /* Error in transaction */ + if (ali15x3_transaction(adap)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK)) @@ -474,22 +446,19 @@ s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, if (len > 32) len = 32; data->block[0] = len; - outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); /* Reset SMBBLKDAT */ + /* Reset SMBBLKDAT */ + outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= data->block[0]; i++) { data->block[i] = inb_p(SMBBLKDAT); -#ifdef DEBUG - printk - ("i2c-ali15x3.o: Blk: len=%d, i=%d, data=%02x\n", - len, i, data->block[i]); -#endif /* DEBUG */ + dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n", + len, i, data->block[i]); } break; } return 0; } - -u32 ali15x3_func(struct i2c_adapter *adapter) +static u32 ali15x3_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | @@ -510,8 +479,6 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; - - static struct pci_device_id ali15x3_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_AL, @@ -525,9 +492,8 @@ static struct pci_device_id ali15x3_ids[] __devinitdata = { static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) { if (ali15x3_setup(dev)) { - printk - ("i2c-ali15x3.o: ALI15X3 not detected, module not inserted.\n"); - + dev_err(&dev->dev, + "ALI15X3 not detected, module not inserted.\n"); return -ENODEV; } @@ -557,17 +523,15 @@ static int __init i2c_ali15x3_init(void) return pci_module_init(&ali15x3_driver); } - static void __exit i2c_ali15x3_exit(void) { pci_unregister_driver(&ali15x3_driver); release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); } - - -MODULE_AUTHOR - ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>"); +MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " + "Philip Edelbrock <phil@netroedge.com>, " + "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); MODULE_DESCRIPTION("ALI15X3 SMBus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index d4bc60ebac3d..86ae2dce1423 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -35,6 +35,8 @@ Note: we assume there can only be one device, with one SMBus interface. */ +/* #define DEBUG 1 */ + #include <linux/version.h> #include <linux/module.h> #include <linux/pci.h> @@ -46,44 +48,42 @@ #include <linux/init.h> #include <asm/io.h> -#define DRV_NAME "i2c-amd756" - /* AMD756 SMBus address offsets */ -#define SMB_ADDR_OFFSET 0xE0 -#define SMB_IOSIZE 16 -#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) -#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) -#define SMB_HOST_ADDRESS (0x4 + amd756_ioport) -#define SMB_HOST_DATA (0x6 + amd756_ioport) -#define SMB_HOST_COMMAND (0x8 + amd756_ioport) -#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) -#define SMB_HAS_DATA (0xA + amd756_ioport) -#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) -#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) -#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) +#define SMB_ADDR_OFFSET 0xE0 +#define SMB_IOSIZE 16 +#define SMB_GLOBAL_STATUS (0x0 + amd756_ioport) +#define SMB_GLOBAL_ENABLE (0x2 + amd756_ioport) +#define SMB_HOST_ADDRESS (0x4 + amd756_ioport) +#define SMB_HOST_DATA (0x6 + amd756_ioport) +#define SMB_HOST_COMMAND (0x8 + amd756_ioport) +#define SMB_HOST_BLOCK_DATA (0x9 + amd756_ioport) +#define SMB_HAS_DATA (0xA + amd756_ioport) +#define SMB_HAS_DEVICE_ADDRESS (0xC + amd756_ioport) +#define SMB_HAS_HOST_ADDRESS (0xE + amd756_ioport) +#define SMB_SNOOP_ADDRESS (0xF + amd756_ioport) /* PCI Address Constants */ /* address of I/O space */ -#define SMBBA 0x058 /* mh */ -#define SMBBANFORCE 0x014 +#define SMBBA 0x058 /* mh */ +#define SMBBANFORCE 0x014 /* general configuration */ -#define SMBGCFG 0x041 /* mh */ +#define SMBGCFG 0x041 /* mh */ /* silicon revision code */ -#define SMBREV 0x008 +#define SMBREV 0x008 /* Other settings */ -#define MAX_TIMEOUT 500 +#define MAX_TIMEOUT 500 /* AMD756 constants */ -#define AMD756_QUICK 0x00 -#define AMD756_BYTE 0x01 -#define AMD756_BYTE_DATA 0x02 -#define AMD756_WORD_DATA 0x03 -#define AMD756_PROCESS_CALL 0x04 -#define AMD756_BLOCK_DATA 0x05 +#define AMD756_QUICK 0x00 +#define AMD756_BYTE 0x01 +#define AMD756_BYTE_DATA 0x02 +#define AMD756_WORD_DATA 0x03 +#define AMD756_PROCESS_CALL 0x04 +#define AMD756_BLOCK_DATA 0x05 static unsigned short amd756_ioport = 0; @@ -101,36 +101,36 @@ static void amd756_do_pause(unsigned int amount) schedule_timeout(amount); } -#define GS_ABRT_STS (1 << 0) -#define GS_COL_STS (1 << 1) -#define GS_PRERR_STS (1 << 2) -#define GS_HST_STS (1 << 3) -#define GS_HCYC_STS (1 << 4) -#define GS_TO_STS (1 << 5) -#define GS_SMB_STS (1 << 11) +#define GS_ABRT_STS (1 << 0) +#define GS_COL_STS (1 << 1) +#define GS_PRERR_STS (1 << 2) +#define GS_HST_STS (1 << 3) +#define GS_HCYC_STS (1 << 4) +#define GS_TO_STS (1 << 5) +#define GS_SMB_STS (1 << 11) -#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ - GS_HCYC_STS | GS_TO_STS ) +#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \ + GS_HCYC_STS | GS_TO_STS ) -#define GE_CYC_TYPE_MASK (7) -#define GE_HOST_STC (1 << 3) -#define GE_ABORT (1 << 5) +#define GE_CYC_TYPE_MASK (7) +#define GE_HOST_STC (1 << 3) +#define GE_ABORT (1 << 5) -static int amd756_transaction(void) +static int amd756_transaction(struct i2c_adapter *adap) { int temp; int result = 0; int timeout = 0; - pr_debug(DRV_NAME - ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); + dev_dbg(&adap->dev, ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, " + "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS), + inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS), + inb_p(SMB_HOST_DATA)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) { - pr_debug(DRV_NAME ": SMBus busy (%04x). Waiting... \n", temp); + dev_dbg(&adap->dev, ": SMBus busy (%04x). Waiting... \n", temp); do { amd756_do_pause(1); temp = inw_p(SMB_GLOBAL_STATUS); @@ -138,7 +138,7 @@ static int amd756_transaction(void) (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - pr_debug(DRV_NAME ": Busy wait timeout (%04x)\n", temp); + dev_dbg(&adap->dev, ": Busy wait timeout (%04x)\n", temp); goto abort; } timeout = 0; @@ -155,46 +155,46 @@ static int amd756_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - pr_debug(DRV_NAME ": Completion timeout!\n"); + dev_dbg(&adap->dev, ": Completion timeout!\n"); goto abort; } if (temp & GS_PRERR_STS) { result = -1; - pr_debug(DRV_NAME ": SMBus Protocol error (no response)!\n"); + dev_dbg(&adap->dev, ": SMBus Protocol error (no response)!\n"); } if (temp & GS_COL_STS) { result = -1; - printk(KERN_WARNING DRV_NAME " SMBus collision!\n"); + dev_warn(&adap->dev, " SMBus collision!\n"); } if (temp & GS_TO_STS) { result = -1; - pr_debug(DRV_NAME ": SMBus protocol timeout!\n"); + dev_dbg(&adap->dev, ": SMBus protocol timeout!\n"); } if (temp & GS_HCYC_STS) - pr_debug(DRV_NAME " SMBus protocol success!\n"); + dev_dbg(&adap->dev, " SMBus protocol success!\n"); outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); #ifdef DEBUG if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) { - pr_debug(DRV_NAME - ": Failed reset at end of transaction (%04x)\n", temp); + dev_dbg(&adap->dev, + ": Failed reset at end of transaction (%04x)\n", temp); } - - pr_debug(DRV_NAME - ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", - inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), - inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); #endif + dev_dbg(&adap->dev, + ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n", + inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE), + inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA)); + return result; abort: - printk(KERN_WARNING DRV_NAME ": Sending abort.\n"); + dev_warn(&adap->dev, ": Sending abort.\n"); outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE); amd756_do_pause(100); outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS); @@ -211,7 +211,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr, /** TODO: Should I supporte the 10-bit transfers? */ switch (size) { case I2C_SMBUS_PROC_CALL: - pr_debug(DRV_NAME ": I2C_SMBUS_PROC_CALL not supported!\n"); + dev_dbg(&adap->dev, ": I2C_SMBUS_PROC_CALL not supported!\n"); /* TODO: Well... It is supported, I'm just not sure what to do here... */ return -1; case I2C_SMBUS_QUICK: @@ -266,7 +266,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr, /* How about enabling interrupts... */ outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE); - if (amd756_transaction()) /* Error in transaction */ + if (amd756_transaction(adap)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK)) @@ -334,7 +334,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev, u8 temp; if (amd756_ioport) { - printk(KERN_ERR DRV_NAME ": Only one device supported. " + dev_err(&pdev->dev, ": Only one device supported. " "(you have a strange motherboard, btw..)\n"); return -ENODEV; } @@ -351,8 +351,8 @@ static int __devinit amd756_probe(struct pci_dev *pdev, pci_read_config_byte(pdev, SMBGCFG, &temp); if ((temp & 128) == 0) { - printk(KERN_ERR DRV_NAME - ": Error: SMBus controller I/O not enabled!\n"); + dev_err(&pdev->dev, + ": Error: SMBus controller I/O not enabled!\n"); return -ENODEV; } @@ -364,16 +364,14 @@ static int __devinit amd756_probe(struct pci_dev *pdev, } if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) { - printk(KERN_ERR DRV_NAME - ": SMB region 0x%x already in use!\n", amd756_ioport); + dev_err(&pdev->dev, ": SMB region 0x%x already in use!\n", + amd756_ioport); return -ENODEV; } -#ifdef DEBUG pci_read_config_byte(pdev, SMBREV, &temp); - printk(KERN_DEBUG DRV_NAME ": SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG DRV_NAME ": AMD756_smba = 0x%X\n", amd756_ioport); -#endif + dev_dbg(&pdev->dev, ": SMBREV = 0x%X\n", temp); + dev_dbg(&pdev->dev, ": AMD756_smba = 0x%X\n", amd756_ioport); /* set up the driverfs linkage to our parent device */ amd756_adapter.dev.parent = &pdev->dev; @@ -383,8 +381,8 @@ static int __devinit amd756_probe(struct pci_dev *pdev, error = i2c_add_adapter(&amd756_adapter); if (error) { - printk(KERN_ERR DRV_NAME - ": Adapter registration failed, module not inserted.\n"); + dev_err(&pdev->dev, + ": Adapter registration failed, module not inserted.\n"); goto out_err; } diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 07f22e6e8495..e83bbf9ffd0e 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -74,7 +74,7 @@ unsigned int amd_ec_wait_write(struct amd_smbus *smbus) udelay(1); if (!timeout) { - printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n"); + dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n"); return -1; } @@ -89,7 +89,7 @@ unsigned int amd_ec_wait_read(struct amd_smbus *smbus) udelay(1); if (!timeout) { - printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for OBF to set\n"); + dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n"); return -1; } @@ -256,11 +256,11 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BLOCK_DATA_PEC: case I2C_SMBUS_PROC_CALL_PEC: case I2C_SMBUS_BLOCK_PROC_CALL_PEC: - printk(KERN_WARNING "i2c-amd8111.c: Unexpected software PEC transaction %d\n.", size); + dev_warn(&adap->dev, "Unexpected software PEC transaction %d\n.", size); return -1; default: - printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size); + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; } @@ -392,7 +392,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev) } static struct pci_driver amd8111_driver = { - .name = "amd8111 smbus", + .name = "amd8111 smbus 2", .id_table = amd8111_ids, .probe = amd8111_probe, .remove = __devexit_p(amd8111_remove), diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index b1556e08ce54..9f70bc88e1c5 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -49,65 +49,48 @@ #include <linux/i2c.h> #include <asm/io.h> -MODULE_LICENSE("GPL"); - #ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC #define HAVE_PEC #endif -#ifndef PCI_DEVICE_ID_INTEL_82801CA_SMBUS -#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS 0x2483 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_82801DB_SMBUS -#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS 0x24C3 -#endif - -static int supported[] = {PCI_DEVICE_ID_INTEL_82801AA_3, - PCI_DEVICE_ID_INTEL_82801AB_3, - PCI_DEVICE_ID_INTEL_82801BA_2, - PCI_DEVICE_ID_INTEL_82801CA_SMBUS, - PCI_DEVICE_ID_INTEL_82801DB_SMBUS, - 0 }; - /* I801 SMBus address offsets */ -#define SMBHSTSTS (0 + i801_smba) -#define SMBHSTCNT (2 + i801_smba) -#define SMBHSTCMD (3 + i801_smba) -#define SMBHSTADD (4 + i801_smba) -#define SMBHSTDAT0 (5 + i801_smba) -#define SMBHSTDAT1 (6 + i801_smba) -#define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ +#define SMBHSTSTS (0 + i801_smba) +#define SMBHSTCNT (2 + i801_smba) +#define SMBHSTCMD (3 + i801_smba) +#define SMBHSTADD (4 + i801_smba) +#define SMBHSTDAT0 (5 + i801_smba) +#define SMBHSTDAT1 (6 + i801_smba) +#define SMBBLKDAT (7 + i801_smba) +#define SMBPEC (8 + i801_smba) /* ICH4 only */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ /* PCI Address Constants */ -#define SMBBA 0x020 -#define SMBHSTCFG 0x040 -#define SMBREV 0x008 +#define SMBBA 0x020 +#define SMBHSTCFG 0x040 +#define SMBREV 0x008 /* Host configuration bits for SMBHSTCFG */ -#define SMBHSTCFG_HST_EN 1 -#define SMBHSTCFG_SMB_SMI_EN 2 -#define SMBHSTCFG_I2C_EN 4 +#define SMBHSTCFG_HST_EN 1 +#define SMBHSTCFG_SMB_SMI_EN 2 +#define SMBHSTCFG_I2C_EN 4 /* Other settings */ -#define MAX_TIMEOUT 100 -#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ +#define MAX_TIMEOUT 100 +#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ /* I801 command constants */ -#define I801_QUICK 0x00 -#define I801_BYTE 0x04 -#define I801_BYTE_DATA 0x08 -#define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ -#define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ -#define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ -#define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_QUICK 0x00 +#define I801_BYTE 0x04 +#define I801_BYTE_DATA 0x08 +#define I801_WORD_DATA 0x0C +#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ +#define I801_BLOCK_DATA 0x14 +#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_BLOCK_LAST 0x34 +#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ +#define I801_START 0x40 +#define I801_PEC_EN 0x80 /* ICH4 only */ /* insmod parameters */ @@ -119,10 +102,6 @@ MODULE_PARM_DESC(force_addr, "Forcibly enable the I801 at the given address. " "EXTREMELY DANGEROUS!"); - - - - static void i801_do_pause(unsigned int amount); static int i801_transaction(void); static int i801_block_transaction(union i2c_smbus_data *data, @@ -135,7 +114,6 @@ static int isich4; static int i801_setup(struct pci_dev *dev) { int error_return = 0; - int *num = supported; unsigned char temp; /* Note: we keep on searching until we have found 'function 3' */ @@ -143,101 +121,90 @@ static int i801_setup(struct pci_dev *dev) return -ENODEV; I801_dev = dev; - isich4 = *num == PCI_DEVICE_ID_INTEL_82801DB_SMBUS; + if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) + isich4 = 1; + else + isich4 = 0; -/* Determine the address of the SMBus areas */ + /* Determine the address of the SMBus areas */ if (force_addr) { i801_smba = force_addr & 0xfff0; } else { pci_read_config_word(I801_dev, SMBBA, &i801_smba); i801_smba &= 0xfff0; if(i801_smba == 0) { - printk(KERN_ERR "i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(&dev->dev, "SMB base address uninitialized" + "- upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } } - if (check_region(i801_smba, (isich4 ? 16 : 8))) { - printk - (KERN_ERR "i2c-i801.o: I801_smb region 0x%x already in use!\n", - i801_smba); - error_return = -ENODEV; + if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) { + dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n", + i801_smba); + error_return = -EBUSY; goto END; } pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ pci_write_config_byte(I801_dev, SMBHSTCFG, temp); -/* If force_addr is set, we program the new address here. Just to make - sure, we disable the device first. */ + + /* If force_addr is set, we program the new address here. Just to make + sure, we disable the device first. */ if (force_addr) { pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe); pci_write_config_word(I801_dev, SMBBA, i801_smba); pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01); - printk - (KERN_WARNING "i2c-i801.o: WARNING: I801 SMBus interface set to new " - "address %04x!\n", i801_smba); + dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to " + "new address %04x!\n", i801_smba); } else if ((temp & 1) == 0) { pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1); - printk(KERN_WARNING "i2c-i801.o: enabling SMBus device\n"); + dev_warn(&dev->dev, "enabling SMBus device\n"); } - request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus"); - -#ifdef DEBUG if (temp & 0x02) - printk - (KERN_DEBUG "i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n"); + dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n"); else - printk - (KERN_DEBUG "i2c-i801.o: I801 using PCI Interrupt for SMBus.\n"); + dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n"); pci_read_config_byte(I801_dev, SMBREV, &temp); - printk(KERN_DEBUG "i2c-i801.o: SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG "i2c-i801.o: I801_smba = 0x%X\n", i801_smba); -#endif /* DEBUG */ + dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); + dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba); - END: +END: return error_return; } -void i801_do_pause(unsigned int amount) +static void i801_do_pause(unsigned int amount) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(amount); } -int i801_transaction(void) +static int i801_transaction(void) { int temp; int result = 0; int timeout = 0; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x," + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n", - temp); -#endif + dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n", + temp); outb_p(temp, SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Failed! (%02x)\n", temp); -#endif + dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp); return -1; } else { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Successfull!\n"); -#endif + dev_dbg(&I801_dev->dev, "Successfull!\n"); } } @@ -251,76 +218,64 @@ int i801_transaction(void) /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n"); + dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); result = -1; -#endif } if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); } if (temp & 0x08) { result = -1; - printk - (KERN_ERR "i2c-i801.o: Bus collision! SMBus may be locked until next hard\n" - "reset. (sorry!)\n"); + dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked " + "until next hard reset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n"); -#endif + dev_dbg(&I801_dev->dev, "Error: no response!\n"); } if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00) outb_p(inb(SMBHSTSTS), SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Failed reset at end of transaction (%02x)\n", - temp); -#endif + dev_dbg(&I801_dev->dev, "Failed reset at end of transaction" + "(%02x)\n", temp); } -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); return result; } /* All-inclusive block transaction function */ -int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command) +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command) { int i, len; int smbcmd; int temp; int result = 0; int timeout; - unsigned char hostc, errmask; - - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(I801_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else { - printk("i2c-i801.o: " - "I2C_SMBUS_I2C_BLOCK_READ not supported!\n"); - return -1; - } - } + unsigned char hostc, errmask; + + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(I801_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else { + dev_err(&I801_dev->dev, + "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + return -1; + } + } if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; @@ -343,60 +298,43 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write, smbcmd = I801_BLOCK_LAST; else smbcmd = I801_BLOCK_DATA; -#if 0 /* now using HW PEC */ - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) - smbcmd |= I801_PEC_EN; -#endif outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBBLKDAT)); -#endif + dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); - if (i == 1) { - /* Erronenous conditions before transaction: - * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ - errmask=0x9f; - } else { - /* Erronenous conditions during transaction: - * Failed, Bus_Err, Dev_Err, Intr */ - errmask=0x1e; - } + if (i == 1) { + /* Erronenous conditions before transaction: + * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ + errmask=0x9f; + } else { + /* Erronenous conditions during transaction: + * Failed, Bus_Err, Dev_Err, Intr */ + errmask=0x1e; + } if (temp & errmask) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n", - temp); -#endif + dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " + "Resetting... \n", temp); outb_p(temp, SMBHSTSTS); if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { - printk - (KERN_ERR "i2c-i801.o: Reset failed! (%02x)\n", - temp); + dev_err(&I801_dev->dev, + "Reset failed! (%02x)\n", temp); result = -1; goto END; } if (i != 1) { - result = -1; /* if die in middle of block transaction, fail */ - goto END; - } + /* if die in middle of block transaction, fail */ + result = -1; + goto END; + } } - if (i == 1) { -#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */ - if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { - if(read_write == I2C_SMBUS_WRITE) - outb_p(data->block[len + 1], SMBPEC); - } -#endif + if (i == 1) outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); - } /* We will always wait for a fraction of a second! */ timeout = 0; @@ -410,25 +348,19 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write, /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n"); -#endif + dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); } if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n"); -#endif + dev_dbg(&I801_dev->dev, + "Error: Failed bus transaction\n"); } else if (temp & 0x08) { result = -1; - printk(KERN_ERR "i2c-i801.o: Bus collision!\n"); + dev_err(&I801_dev->dev, "Bus collision!\n"); } else if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n"); -#endif + dev_dbg(&I801_dev->dev, "Error: no response!\n"); } if (i == 1 && read_write == I2C_SMBUS_READ) { @@ -440,7 +372,7 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write, data->block[0] = len; } - /* Retrieve/store value in SMBBLKDAT */ + /* Retrieve/store value in SMBBLKDAT */ if (read_write == I2C_SMBUS_READ) data->block[i] = inb_p(SMBBLKDAT); if (read_write == I2C_SMBUS_WRITE && i+1 <= len) @@ -448,18 +380,15 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write, if ((temp & 0x9e) != 0x00) outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */ -#ifdef DEBUG if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { - printk - (KERN_DEBUG "i2c-i801.o: Bad status (%02x) at end of transaction\n", - temp); + dev_dbg(&I801_dev->dev, + "Bad status (%02x) at end of transaction\n", + temp); } - printk - (KERN_DEBUG "i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), - inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), - inb_p(SMBBLKDAT)); -#endif + dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), + inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); if (result < 0) goto END; @@ -476,29 +405,24 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write, && (timeout++ < MAX_TIMEOUT)); if (timeout >= MAX_TIMEOUT) { - printk(KERN_DEBUG "i2c-i801.o: PEC Timeout!\n"); - } -#if 0 /* now using HW PEC */ - if(read_write == I2C_SMBUS_READ) { - data->block[len + 1] = inb_p(SMBPEC); + dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); } -#endif outb_p(temp, SMBHSTSTS); } #endif - result = 0; + result = 0; END: - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - /* restore saved configuration register value */ + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); - } + } return result; } /* Return -1 on error. */ -s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, - union i2c_smbus_data * data) +static s32 i801_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data * data) { int hwpec = 0; int block = 0; @@ -554,7 +478,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, break; case I2C_SMBUS_PROC_CALL: default: - printk(KERN_ERR "i2c-i801.o: Unsupported transaction %d\n", size); + dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); return -1; } @@ -600,7 +524,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, } -u32 i801_func(struct i2c_adapter *adapter) +static u32 i801_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | @@ -627,8 +551,6 @@ static struct i2c_adapter i801_adapter = { .algo = &smbus_algorithm, }; - - static struct pci_device_id i801_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_INTEL, @@ -650,13 +572,13 @@ static struct pci_device_id i801_ids[] __devinitdata = { }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801CA_SMBUS, + .device = PCI_DEVICE_ID_INTEL_82801CA_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_82801DB_SMBUS, + .device = PCI_DEVICE_ID_INTEL_82801DB_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, @@ -667,8 +589,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id { if (i801_setup(dev)) { - printk - (KERN_WARNING "i2c-i801.o: I801 not detected, module not inserted.\n"); + dev_warn(&dev->dev, + "I801 not detected, module not inserted.\n"); return -ENODEV; } @@ -694,22 +616,21 @@ static struct pci_driver i801_driver = { static int __init i2c_i801_init(void) { - printk(KERN_INFO "i2c-i801.o version %s (%s)\n", I2C_VERSION, I2C_DATE); + printk(KERN_INFO "i2c-i801 version %s (%s)\n", I2C_VERSION, I2C_DATE); return pci_module_init(&i801_driver); } - static void __exit i2c_i801_exit(void) { pci_unregister_driver(&i801_driver); release_region(i801_smba, (isich4 ? 16 : 8)); } - - -MODULE_AUTHOR - ("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>"); +MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " + "Philip Edelbrock <phil@netroedge.com>, " + "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); MODULE_DESCRIPTION("I801 SMBus driver"); +MODULE_LICENSE("GPL"); module_init(i2c_i801_init); module_exit(i2c_i801_exit); diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c new file mode 100644 index 000000000000..73612de6e96c --- /dev/null +++ b/drivers/i2c/busses/i2c-isa.c @@ -0,0 +1,62 @@ +/* + i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* This implements an i2c algorithm/adapter for ISA bus. Not that this is + on first sight very useful; almost no functionality is preserved. + Except that it makes writing drivers for chips which can be on both + the SMBus and the ISA bus very much easier. See lm78.c for an example + of this. */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/i2c.h> + +/* This is the actual algorithm we define */ +static struct i2c_algorithm isa_algorithm = { + .name = "ISA bus algorithm", + .id = I2C_ALGO_ISA, +}; + +/* There can only be one... */ +static struct i2c_adapter isa_adapter = { + .owner = THIS_MODULE, + .name = "ISA main adapter", + .id = I2C_ALGO_ISA | I2C_HW_ISA, + .algo = &isa_algorithm, +}; + +static int __init i2c_isa_init(void) +{ + return i2c_add_adapter(&isa_adapter); +} + +static void __exit i2c_isa_exit(void) +{ + i2c_del_adapter(&isa_adapter); +} + +MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); +MODULE_DESCRIPTION("ISA bus access through i2c"); +MODULE_LICENSE("GPL"); + +module_init(i2c_isa_init); +module_exit(i2c_isa_exit); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 5acd8211b1d6..a1048f7b5cbe 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -28,6 +28,8 @@ Note: we assume there can only be one device, with one SMBus interface. */ +/* #define DEBUG 1 */ + #include <linux/module.h> #include <linux/config.h> #include <linux/pci.h> @@ -49,37 +51,37 @@ struct sd { }; /* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) +#define SMBHSTSTS (0 + piix4_smba) +#define SMBHSLVSTS (1 + piix4_smba) +#define SMBHSTCNT (2 + piix4_smba) +#define SMBHSTCMD (3 + piix4_smba) +#define SMBHSTADD (4 + piix4_smba) +#define SMBHSTDAT0 (5 + piix4_smba) +#define SMBHSTDAT1 (6 + piix4_smba) +#define SMBBLKDAT (7 + piix4_smba) +#define SMBSLVCNT (8 + piix4_smba) +#define SMBSHDWCMD (9 + piix4_smba) +#define SMBSLVEVT (0xA + piix4_smba) +#define SMBSLVDAT (0xC + piix4_smba) /* PCI Address Constants */ -#define SMBBA 0x090 -#define SMBHSTCFG 0x0D2 -#define SMBSLVC 0x0D3 -#define SMBSHDW1 0x0D4 -#define SMBSHDW2 0x0D5 -#define SMBREV 0x0D6 +#define SMBBA 0x090 +#define SMBHSTCFG 0x0D2 +#define SMBSLVC 0x0D3 +#define SMBSHDW1 0x0D4 +#define SMBSHDW2 0x0D5 +#define SMBREV 0x0D6 /* Other settings */ -#define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 +#define MAX_TIMEOUT 500 +#define ENABLE_INT9 0 /* PIIX4 constants */ -#define PIIX4_QUICK 0x00 -#define PIIX4_BYTE 0x04 -#define PIIX4_BYTE_DATA 0x08 -#define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 +#define PIIX4_QUICK 0x00 +#define PIIX4_BYTE 0x04 +#define PIIX4_BYTE_DATA 0x08 +#define PIIX4_WORD_DATA 0x0C +#define PIIX4_BLOCK_DATA 0x14 /* insmod parameters */ @@ -102,6 +104,7 @@ static int piix4_transaction(void); static unsigned short piix4_smba = 0; +static struct i2c_adapter piix4_adapter; /* * Get DMI information. @@ -125,18 +128,17 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) return -ENODEV; - printk(KERN_INFO "i2c-piix4.o: Found %s device\n", PIIX4_dev->dev.name); + dev_info(&PIIX4_dev->dev, "Found %s device\n", PIIX4_dev->dev.name); if(ibm_dmi_probe()) { - printk - (KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module may corrupt\n"); - printk - (KERN_ERR " your serial eeprom! Refusing to load module!\n"); - error_return = -EPERM; - goto END; + dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module " + "may corrupt your serial eeprom! Refusing to load " + "module!\n"); + error_return = -EPERM; + goto END; } -/* Determine the address of the SMBus areas */ + /* Determine the address of the SMBus areas */ if (force_addr) { piix4_smba = force_addr & 0xfff0; force = 0; @@ -144,75 +146,68 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); piix4_smba &= 0xfff0; if(piix4_smba == 0) { - printk(KERN_ERR "i2c-piix4.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(&PIIX4_dev->dev, "SMB base address " + "uninitialized - upgrade BIOS or use " + "force_addr=0xaddr\n"); return -ENODEV; } } - if (check_region(piix4_smba, 8)) { - printk - (KERN_ERR "i2c-piix4.o: SMB region 0x%x already in use!\n", - piix4_smba); + if (!request_region(piix4_smba, 8, "piix4-smbus")) { + dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", + piix4_smba); error_return = -ENODEV; goto END; } pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); -/* If force_addr is set, we program the new address here. Just to make - sure, we disable the PIIX4 first. */ + /* If force_addr is set, we program the new address here. Just to make + sure, we disable the PIIX4 first. */ if (force_addr) { pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe); pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba); pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01); - printk - (KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to new " - "address %04x!\n", piix4_smba); + dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to " + "new address %04x!\n", piix4_smba); } else if ((temp & 1) == 0) { if (force) { -/* This should never need to be done, but has been noted that - many Dell machines have the SMBus interface on the PIIX4 - disabled!? NOTE: This assumes I/O space and other allocations WERE - done by the Bios! Don't complain if your hardware does weird - things after enabling this. :') Check for Bios updates before - resorting to this. */ + /* This should never need to be done, but has been + * noted that many Dell machines have the SMBus + * interface on the PIIX4 disabled!? NOTE: This assumes + * I/O space and other allocations WERE done by the + * Bios! Don't complain if your hardware does weird + * things after enabling this. :') Check for Bios + * updates before resorting to this. + */ pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 1); - printk - (KERN_NOTICE "i2c-piix4.o: WARNING: SMBus interface has been FORCEFULLY " - "ENABLED!\n"); + dev_printk(KERN_NOTICE, &PIIX4_dev->dev, + "WARNING: SMBus interface has been " + "FORCEFULLY ENABLED!\n"); } else { - printk - (KERN_ERR "i2c-piix4.o: Host SMBus controller not enabled!\n"); + dev_err(&PIIX4_dev->dev, + "Host SMBus controller not enabled!\n"); error_return = -ENODEV; goto END; } } - /* Everything is happy, let's grab the memory and set things up. */ - request_region(piix4_smba, 8, "piix4-smbus"); - -#ifdef DEBUG if ((temp & 0x0E) == 8) - printk - (KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for SMBus.\n"); + dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n"); else if ((temp & 0x0E) == 0) - printk - (KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# for SMBus.\n"); + dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n"); else - printk - (KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration (or code out " - "of date)!\n"); + dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration " + "(or code out of date)!\n"); pci_read_config_byte(PIIX4_dev, SMBREV, &temp); - printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp); - printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba); -#endif /* DEBUG */ + dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp); + dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba); - END: +END: return error_return; } - /* Internally used pause function */ static void piix4_do_pause(unsigned int amount) { @@ -227,29 +222,21 @@ static int piix4_transaction(void) int result = 0; int timeout = 0; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting... \n", - temp); -#endif + dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " + "Resetting... \n", temp); outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp); -#endif + dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); return -1; } else { -#ifdef DEBUG - printk(KERN_DEBUG "i2c-piix4.o: Successfull!\n"); -#endif + dev_dbg(&piix4_adapter.dev, "Successfull!\n"); } } @@ -262,50 +249,40 @@ static int piix4_transaction(void) temp = inb_p(SMBHSTSTS); } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); -#ifdef DEBUG /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { - printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n"); + dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); result = -1; } -#endif if (temp & 0x10) { result = -1; -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n"); -#endif + dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); } if (temp & 0x08) { result = -1; - printk - (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n" - "reset. (sorry!)\n"); + dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " + "locked until next hard reset. (sorry!)\n"); /* Clock stops and slave is stuck in mid-transmission */ } if (temp & 0x04) { result = -1; -#ifdef DEBUG - printk(KERN_ERR "i2c-piix4.o: Error: no response!\n"); -#endif + dev_err(&piix4_adapter.dev, "Error: no response!\n"); } if (inb_p(SMBHSTSTS) != 0x00) outb_p(inb(SMBHSTSTS), SMBHSTSTS); -#ifdef DEBUG if ((temp = inb_p(SMBHSTSTS)) != 0x00) { - printk - (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n", - temp); + dev_err(&piix4_adapter.dev, "Failed reset at end of " + "transaction (%02x)\n", temp); } - printk - (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), - inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); -#endif + dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " + "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), + inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), + inb_p(SMBHSTDAT1)); return result; } @@ -318,8 +295,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, switch (size) { case I2C_SMBUS_PROC_CALL: - printk - (KERN_ERR "i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!\n"); + dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), @@ -402,7 +378,6 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, return 0; } - static u32 piix4_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | @@ -424,8 +399,6 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; - - static struct pci_device_id piix4_ids[] __devinitdata = { { .vendor = PCI_VENDOR_ID_INTEL, @@ -468,7 +441,7 @@ static struct pci_device_id piix4_ids[] __devinitdata = { static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; - + retval = piix4_setup(dev, id); if (retval) return retval; @@ -499,7 +472,7 @@ static struct pci_driver piix4_driver = { static int __init i2c_piix4_init(void) { - printk("i2c-piix4.o version %s (%s)\n", I2C_VERSION, I2C_DATE); + printk(KERN_INFO "i2c-piix4 version %s (%s)\n", I2C_VERSION, I2C_DATE); return pci_module_init(&piix4_driver); } @@ -510,8 +483,6 @@ static void __exit i2c_piix4_exit(void) release_region(piix4_smba, 8); } - - MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>"); MODULE_DESCRIPTION("PIIX4 SMBus driver"); diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index 5c15c7b4be1f..c4370afc01e1 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -93,9 +93,9 @@ SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1 /* Initial values */ -/* Note: Eventhough I left the low and high limits named os and hyst, +/* Note: Even though I left the low and high limits named os and hyst, they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actuall triggers an alarm instead of +a lower temp than THYST actually triggers an alarm instead of clearing it. Weird, ey? --Phil */ #define adm1021_INIT_TOS 60 #define adm1021_INIT_THYST 20 diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c index e625528e7b3a..da1e4d2c2c28 100644 --- a/drivers/i2c/chips/lm75.c +++ b/drivers/i2c/chips/lm75.c @@ -25,7 +25,7 @@ #include <linux/i2c-proc.h> -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ +#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c index 874d37827954..c7383b281a34 100644 --- a/drivers/i2c/i2c-algo-pcf.c +++ b/drivers/i2c/i2c-algo-pcf.c @@ -152,7 +152,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) /* load own address in S0, effective address is (own << 1) */ i2c_outb(adap, get_own(adap)); - /* check it's realy writen */ + /* check it's really written */ if ((temp = i2c_inb(adap)) != get_own(adap)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); return -ENXIO; @@ -168,7 +168,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) /* load clock register S2 */ i2c_outb(adap, get_clock(adap)); - /* check it's realy writen, the only 5 lowest bits does matter */ + /* check it's really written, the only 5 lowest bits does matter */ if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); return -ENXIO; @@ -177,7 +177,7 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) /* Enable serial interface, idle, S0 selected */ set_pcf(adap, 1, I2C_PCF_IDLE); - /* check to see PCF is realy idled and we can access status register */ + /* check to see PCF is really idled and we can access status register */ if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); return -ENXIO; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 28cc3ec02277..52355c190120 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -53,6 +53,16 @@ static void i2cproc_remove(int bus); #endif /* CONFIG_PROC_FS */ +int i2c_device_probe(struct device *dev) +{ + return -ENODEV; +} + +int i2c_device_remove(struct device *dev) +{ + return 0; +} + /* --------------------------------------------------- * registering functions * --------------------------------------------------- @@ -204,6 +214,16 @@ int i2c_add_driver(struct i2c_driver *driver) drivers[i] = driver; DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); + + /* add the driver to the list of i2c drivers in the driver core */ + driver->driver.name = driver->name; + driver->driver.bus = &i2c_bus_type; + driver->driver.probe = i2c_device_probe; + driver->driver.remove = i2c_device_remove; + + res = driver_register(&driver->driver); + if (res) + goto out_unlock; /* now look for instances of driver on our adapters */ @@ -236,6 +256,8 @@ int i2c_del_driver(struct i2c_driver *driver) goto out_unlock; } + driver_unregister(&driver->driver); + /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver * afterwards. diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c index 73bb33815907..313b5b5c4d7c 100644 --- a/drivers/i2c/i2c-proc.c +++ b/drivers/i2c/i2c-proc.c @@ -270,7 +270,7 @@ static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, } -/* This funcion reads or writes a 'real' value (encoded by the combination +/* This function reads or writes a 'real' value (encoded by the combination of an integer and a magnitude, the last is the power of ten the value should be divided with) to a /proc/sys directory. To use this function, you must (before registering the ctl_table) set the extra2 field to the diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index a67b113cbce2..2fe946fce0aa 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -106,6 +106,7 @@ #include "ide_modes.h" #include "piix.h" +static int no_piix_dma; #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) #include <linux/stat.h> #include <linux/proc_fs.h> @@ -114,7 +115,6 @@ static u8 piix_proc = 0; #define PIIX_MAX_DEVS 5 static struct pci_dev *piix_devs[PIIX_MAX_DEVS]; static int n_piix_devs; -static int no_piix_dma = 0; /** * piix_get_info - fill in /proc for PIIX ide diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index a5a983fdbede..0f791c59ee52 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -249,7 +249,7 @@ adb_probe_task(void *x) strcpy(current->comm, "kadbprobe"); sigfillset(&blocked); - sicprocmask(SIG_BLOCK, &blocked, NULL); + sigprocmask(SIG_BLOCK, &blocked, NULL); flush_signals(current); printk(KERN_INFO "adb: starting probe task...\n"); diff --git a/drivers/md/md.c b/drivers/md/md.c index cefd2423f1c7..3de804ebdfee 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1735,7 +1735,6 @@ static int do_md_run(mddev_t * mddev) mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */ mddev->in_sync = 1; - md_update_sb(mddev); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); set_capacity(disk, md_size[mdidx(mddev)]<<1); @@ -1763,7 +1762,6 @@ static int restart_array(mddev_t *mddev) goto out; mddev->safemode = 0; - md_update_sb(mddev); mddev->ro = 0; set_disk_ro(disk, 0); @@ -3247,7 +3245,7 @@ static void md_do_sync(mddev_t *mddev) { mddev_t *mddev2; unsigned int max_sectors, currspeed = 0, - j, window, err; + j, window; unsigned long mark[SYNC_MARKS]; unsigned long mark_cnt[SYNC_MARKS]; int last_mark,m; @@ -3283,7 +3281,6 @@ static void md_do_sync(mddev_t *mddev) if (wait_event_interruptible(resync_wait, mddev2->curr_resync < mddev->curr_resync)) { flush_signals(current); - err = -EINTR; mddev_put(mddev2); goto skip; } @@ -3335,7 +3332,7 @@ static void md_do_sync(mddev_t *mddev) sectors = mddev->pers->sync_request(mddev, j, currspeed < sysctl_speed_limit_min); if (sectors < 0) { - err = sectors; + set_bit(MD_RECOVERY_ERR, &mddev->recovery); goto out; } atomic_add(sectors, &mddev->recovery_active); @@ -3372,7 +3369,7 @@ static void md_do_sync(mddev_t *mddev) */ printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n"); flush_signals(current); - err = -EINTR; + set_bit(MD_RECOVERY_INTR, &mddev->recovery); goto out; } @@ -3398,7 +3395,6 @@ static void md_do_sync(mddev_t *mddev) } } printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); - err = 0; /* * this also signals 'finished resyncing' to md_stop */ @@ -3408,8 +3404,6 @@ static void md_do_sync(mddev_t *mddev) /* tell personality that we are finished */ mddev->pers->sync_request(mddev, max_sectors, 1); - if (err) - set_bit(MD_RECOVERY_ERR, &mddev->recovery); if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) && mddev->curr_resync > 2 && mddev->curr_resync > mddev->recovery_cp) { diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0dd391e3d3b1..4921992134bf 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -840,7 +840,8 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) * we read from here, no need to write */ continue; - if (conf->mirrors[i].rdev->in_sync && mddev->in_sync) + if (conf->mirrors[i].rdev->in_sync && + r1_bio->sector + (bio->bi_size>>9) <= mddev->recovery_cp) /* * don't need to write this we are just rebuilding */ diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 29289ef75d1b..d9e2735afddf 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -221,7 +221,7 @@ dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *dvbdmxfeed, return 0; neq|=f->maskandnotmode[i]&xor; } - if (f->doneq & !neq) + if (f->doneq && !neq) return 0; return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen, diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index fa7af13f3ed4..2f1d8eda388f 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -56,6 +56,10 @@ v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org> - Introduce driver model for EISA cards. */ +/* + FIXES for PC-9800: + Shu Iwanaga: 3c569B(PC-9801 C-bus) support +*/ #define DRV_NAME "3c509" #define DRV_VERSION "1.19b" @@ -257,7 +261,7 @@ static struct mca_driver el3_mca_driver = { }; #endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), @@ -350,7 +354,7 @@ static void el3_common_remove (struct net_device *dev) if (lp->pmdev) pm_unregister(lp->pmdev); #endif -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) if (lp->type == EL3_PNP) pnp_device_detach(to_pnp_dev(lp->dev)); #endif @@ -368,12 +372,12 @@ static int __init el3_probe(int card_idx) int ioaddr, irq, if_port; u16 phys_addr[3]; static int current_tag; -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) static int pnp_cards; struct pnp_dev *idev = NULL; #endif /* __ISAPNP__ */ -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) if (nopnp == 1) goto no_pnp; @@ -421,6 +425,9 @@ static int __init el3_probe(int card_idx) no_pnp: #endif /* __ISAPNP__ */ +#ifdef CONFIG_X86_PC9800 + id_port = 0x71d0; +#else /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { if (check_region(id_port, 1)) @@ -435,6 +442,7 @@ no_pnp: printk(" WARNING: No I/O port available for 3c509 activation.\n"); return -ENODEV; } +#endif /* CONFIG_X86_PC9800 */ /* Next check for all ISA bus boards by sending the ID sequence to the ID_PORT. We find cards past the first by setting the 'current_tag' on cards as they are found. Cards with their tag set will not @@ -465,7 +473,7 @@ no_pnp: phys_addr[i] = htons(id_read_eeprom(i)); } -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) if (nopnp == 0) { /* The ISA PnP 3c509 cards respond to the ID sequence. This check is needed in order not to register them twice. */ @@ -490,9 +498,19 @@ no_pnp: { unsigned int iobase = id_read_eeprom(8); if_port = iobase >> 14; +#ifdef CONFIG_X86_PC9800 + ioaddr = 0x40d0 + ((iobase & 0x1f) << 8); +#else ioaddr = 0x200 + ((iobase & 0x1f) << 4); +#endif } irq = id_read_eeprom(9) >> 12; +#ifdef CONFIG_X86_PC9800 + if (irq == 7) + irq = 6; + else if (irq == 15) + irq = 13; +#endif if (!(dev = init_etherdev(NULL, sizeof(struct el3_private)))) return -ENOMEM; @@ -522,7 +540,11 @@ no_pnp: outb(0xd0 + ++current_tag, id_port); /* Activate the adaptor at the EEPROM location. */ +#ifdef CONFIG_X86_PC9800 + outb((ioaddr >> 8) | 0xe0, id_port); +#else outb((ioaddr >> 4) | 0xe0, id_port); +#endif EL3WINDOW(0); if (inw(ioaddr) != 0x6d50) { @@ -534,7 +556,7 @@ no_pnp: /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) found: /* PNP jumps here... */ #endif /* __ISAPNP__ */ @@ -543,7 +565,7 @@ no_pnp: dev->irq = irq; dev->if_port = if_port; lp = dev->priv; -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) lp->dev = &idev->dev; #endif @@ -1388,6 +1410,12 @@ el3_up(struct net_device *dev) outw(0x0001, ioaddr + 4); /* Set the IRQ line. */ +#ifdef CONFIG_X86_PC9800 + if (dev->irq == 6) + dev->irq = 7; + else if (dev->irq == 13) + dev->irq = 15; +#endif outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); /* Set the station address in window 2 each time opened. */ @@ -1550,7 +1578,7 @@ MODULE_PARM_DESC(debug, "debug level (0-6)"); MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)"); MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); -#ifdef __ISAPNP__ +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) MODULE_PARM(nopnp, "i"); MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)"); MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters); diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 76bf501617bd..28001ae6c1b3 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -646,7 +646,7 @@ static int init_i596_mem(struct net_device *dev) /* change the scp address */ - MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp)); + MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp)); #elif defined(ENABLE_APRICOT) @@ -677,8 +677,8 @@ static int init_i596_mem(struct net_device *dev) lp->scp.sysbus = 0x00440000; #endif - lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp))); - lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb))); + lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp)); + lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb)); lp->iscp.stat = ISCP_BUSY; lp->cmd_backlog = 0; diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 4debea1fd190..b9a61079dc5d 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -123,7 +123,8 @@ struct ei_device { #define inb_p(port) in_8(port) #define outb_p(val,port) out_8(port,val) -#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) +#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) || \ + defined(CONFIG_NET_CBUS) #define EI_SHIFT(x) (ei_local->reg_offset[x]) #else #define EI_SHIFT(x) (x) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d770d320577f..7d9ab385a1ab 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -663,7 +663,7 @@ config EL16 as <file:Documentation/networking/net-modules.txt>. config EL3 - tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support" + tristate "3c509/3c529 (MCA)/3c569B (98)/3c579 \"EtherLink III\" support" depends on NET_VENDOR_3COM && (ISA || EISA || MCA) ---help--- If you have a network (Ethernet) card belonging to the 3Com @@ -932,7 +932,7 @@ config NI65 source "drivers/net/tulip/Kconfig" config AT1700 - tristate "AT1700/1720 support (EXPERIMENTAL)" + tristate "AT1700/1720/RE1000Plus(C-Bus) support (EXPERIMENTAL)" depends on NET_ETHERNET && (ISA || MCA) && EXPERIMENTAL ---help--- If you have a network (Ethernet) card of this type, say Y and read @@ -978,7 +978,7 @@ config HP100 config NET_ISA bool "Other ISA cards" - depends on NET_ETHERNET && ISA + depends on NET_ETHERNET && ISA && !X86_PC9800 ---help--- If your network (Ethernet) card hasn't been mentioned yet and its bus system (that's the way the cards talks to the other components @@ -1176,6 +1176,55 @@ config SK_G16 the Ethernet-HOWTO, available from <http://www.linuxdoc.org/docs.html#howto>. +config NET_CBUS + bool "NEC PC-9800 C-bus cards" + depends on NET_ETHERNET && ISA && X86_PC9800 + ---help--- + If your network (Ethernet) card hasn't been mentioned yet and its + bus system (that's the way the cards talks to the other components + of your computer) is NEC PC-9800 C-Bus, say Y. + +config NE2K_CBUS + tristate "Most NE2000-based Ethernet support" + depends on NET_CBUS + +config NE2K_CBUS_EGY98 + bool "Melco EGY-98 support" + depends on NE2K_CBUS + +config NE2K_CBUS_LGY98 + bool "Melco LGY-98 support" + depends on NE2K_CBUS + +config NE2K_CBUS_ICM + bool "ICM IF-27xxET support" + depends on NE2K_CBUS + +config NE2K_CBUS_IOLA98 + bool "I-O DATA LA-98 support" + depends on NE2K_CBUS + +config NE2K_CBUS_CNET98EL + bool "Contec C-NET(98)E/L support" + depends on NE2K_CBUS + +config NE2K_CBUS_CNET98EL_IO_BASE + hex "C-NET(98)E/L I/O base address (0xaaed or 0x55ed)" + depends on NE2K_CBUS_CNET98EL + default "0xaaed" + +config NE2K_CBUS_ATLA98 + bool "Allied Telesis LA-98 Support" + depends on NE2K_CBUS + +config NE2K_CBUS_BDN + bool "ELECOM Laneed LD-BDN[123]A Support" + depends on NE2K_CBUS + +config NE2K_CBUS_NEC108 + bool "NEC PC-9801-108 Support" + depends on NE2K_CBUS + config SKMC tristate "SKnet MCA support" depends on NET_ETHERNET && MCA @@ -1904,6 +1953,7 @@ config E1000 82544 PRO/1000 XF Server Adapter A50484-xxx 82544 PRO/1000 T Desktop Adapter A62947-xxx 82540 PRO/1000 MT Desktop Adapter A78408-xxx + 82541 PRO/1000 MT Desktop Adapter C91016-xxx 82545 PRO/1000 MT Server Adapter A92165-xxx 82546 PRO/1000 MT Dual Port Server Adapter A92111-xxx 82545 PRO/1000 MF Server Adapter A91622-xxx diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b0b65d9cdbd8..9ad7798d4b1f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_ARM_ETHERH) += 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o obj-$(CONFIG_EL2) += 3c503.o 8390.o obj-$(CONFIG_NE2000) += ne.o 8390.o +obj-$(CONFIG_NE2K_CBUS) += ne2k_cbus.o 8390.o obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o obj-$(CONFIG_HPLAN) += hp.o 8390.o obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o diff --git a/drivers/net/Makefile.lib b/drivers/net/Makefile.lib index c918d456d1b3..44e3b9b329e9 100644 --- a/drivers/net/Makefile.lib +++ b/drivers/net/Makefile.lib @@ -19,6 +19,7 @@ obj-$(CONFIG_MACE) += crc32.o obj-$(CONFIG_MACMACE) += crc32.o obj-$(CONFIG_MIPS_AU1000_ENET) += crc32.o obj-$(CONFIG_NATSEMI) += crc32.o +obj-$(CONFIG_NE2K_CBUS) += crc32.o obj-$(CONFIG_PCMCIA_FMVJ18X) += crc32.o obj-$(CONFIG_PCMCIA_SMC91C92) += crc32.o obj-$(CONFIG_PCMCIA_XIRTULIP) += crc32.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 134b45257a5c..b09a14ceae14 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -233,7 +233,7 @@ static struct devprobe isa_probes[] __initdata = { #ifdef CONFIG_E2100 /* Cabletron E21xx series. */ {e2100_probe, 0}, #endif -#ifdef CONFIG_NE2000 /* ISA (use ne2k-pci for PCI cards) */ +#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS) /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */ {ne_probe, 0}, #endif #ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */ diff --git a/drivers/net/apne.c b/drivers/net/apne.c index b34302abf92b..7d9f45f7e2d9 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -111,9 +111,6 @@ static int init_pcmcia(void); #define MANUAL_HWADDR5 0x9a */ -#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) ) - - static const char version[] = "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n"; @@ -402,10 +399,9 @@ apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pa } outb(ENISR_RDC, nic_base + NE_EN0_ISR); /* Ack intr. */ - - hdr->count = WORDSWAP(hdr->count); - ei_status.dmaing &= ~0x01; + + le16_to_cpus(&hdr->count); } /* Block input and output, similar to the Crynwr packet driver. If you diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 0c21dc3db762..d98c1e8f55bd 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -34,6 +34,10 @@ only is it difficult to detect, it also moves around in I/O space in response to inb()s from other device probes! */ +/* + 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa + 99/12/30 port to 2.3.35 by K.Takai +*/ #include <linux/config.h> #include <linux/errno.h> @@ -76,10 +80,17 @@ static int fmv18x_probe_list[] __initdata = { * ISA */ +#ifndef CONFIG_X86_PC9800 static int at1700_probe_list[] __initdata = { 0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; +#else /* CONFIG_X86_PC9800 */ +static int at1700_probe_list[] __initdata = { + 0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0 +}; + +#endif /* CONFIG_X86_PC9800 */ /* * MCA */ @@ -122,6 +133,7 @@ struct net_local { /* Offsets from the base address. */ +#ifndef CONFIG_X86_PC9800 #define STATUS 0 #define TX_STATUS 0 #define RX_STATUS 1 @@ -136,6 +148,7 @@ struct net_local { #define TX_START 10 #define COL16CNTL 11 /* Controll Reg for 16 collisions */ #define MODE13 13 +#define RX_CTRL 14 /* Configuration registers only on the '865A/B chips. */ #define EEPROM_Ctrl 16 #define EEPROM_Data 17 @@ -144,8 +157,39 @@ struct net_local { #define IOCONFIG 18 /* Either read the jumper, or move the I/O. */ #define IOCONFIG1 19 #define SAPROM 20 /* The station address PROM, if no EEPROM. */ +#define MODE24 24 #define RESET 31 /* Write to reset some parts of the chip. */ #define AT1700_IO_EXTENT 32 +#define PORT_OFFSET(o) (o) +#else /* CONFIG_X86_PC9800 */ +#define STATUS (0x0000) +#define TX_STATUS (0x0000) +#define RX_STATUS (0x0001) +#define TX_INTR (0x0200)/* Bit-mapped interrupt enable registers. */ +#define RX_INTR (0x0201) +#define TX_MODE (0x0400) +#define RX_MODE (0x0401) +#define CONFIG_0 (0x0600)/* Misc. configuration settings. */ +#define CONFIG_1 (0x0601) +/* Run-time register bank 2 definitions. */ +#define DATAPORT (0x0800)/* Word-wide DMA or programmed-I/O dataport. */ +#define TX_START (0x0a00) +#define COL16CNTL (0x0a01)/* Controll Reg for 16 collisions */ +#define MODE13 (0x0c01) +#define RX_CTRL (0x0e00) +/* Configuration registers only on the '865A/B chips. */ +#define EEPROM_Ctrl (0x1000) +#define EEPROM_Data (0x1200) +#define CARDSTATUS 16 /* FMV-18x Card Status */ +#define CARDSTATUS1 17 /* FMV-18x Card Status */ +#define IOCONFIG (0x1400)/* Either read the jumper, or move the I/O. */ +#define IOCONFIG1 (0x1600) +#define SAPROM 20 /* The station address PROM, if no EEPROM. */ +#define MODE24 (0x1800)/* The station address PROM, if no EEPROM. */ +#define RESET (0x1e01)/* Write to reset some parts of the chip. */ +#define PORT_OFFSET(o) ({ int _o_ = (o); (_o_ & ~1) * 0x100 + (_o_ & 1); }) +#endif /* CONFIG_X86_PC9800 */ + #define TX_TIMEOUT 10 @@ -225,8 +269,20 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) int slot, ret = -ENODEV; struct net_local *lp; +#ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) return -EBUSY; +#else + for (i = 0; i < 0x2000; i += 0x0200) { + if (!request_region(ioaddr + i, 2, dev->name)) { + while (i > 0) { + i -= 0x0200; + release_region(ioaddr + i, 2); + } + return -EBUSY; + } + } +#endif /* Resetting the chip doesn't reset the ISA interface, so don't bother. That means we have to be careful with the register values we probe for. @@ -317,10 +373,17 @@ found: /* Reset the internal state machines. */ outb(0, ioaddr + RESET); - if (is_at1700) + if (is_at1700) { +#ifndef CONFIG_X86_PC9800 irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04) | (read_eeprom(ioaddr, 0)>>14)]; - else { +#else + { + char re1000plus_irqmap[4] = {3, 5, 6, 12}; + irq = re1000plus_irqmap[inb(ioaddr + IOCONFIG1) >> 6]; + } +#endif + } else { /* Check PnP mode for FMV-183/184/183A/184A. */ /* This PnP routine is very poor. IO and IRQ should be known. */ if (inb(ioaddr + CARDSTATUS1) & 0x20) { @@ -392,18 +455,22 @@ found: /* Set the station address in bank zero. */ outb(0x00, ioaddr + CONFIG_1); for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + 8 + i); + outb(dev->dev_addr[i], ioaddr + PORT_OFFSET(8 + i)); /* Switch to bank 1 and set the multicast table to accept none. */ outb(0x04, ioaddr + CONFIG_1); for (i = 0; i < 8; i++) - outb(0x00, ioaddr + 8 + i); + outb(0x00, ioaddr + PORT_OFFSET(8 + i)); /* Switch to bank 2 */ /* Lock our I/O address, and set manual processing mode for 16 collisions. */ outb(0x08, ioaddr + CONFIG_1); +#ifndef CONFIG_X86_PC9800 outb(dev->if_port, ioaddr + MODE13); +#else + outb(0, ioaddr + MODE13); +#endif outb(0x00, ioaddr + COL16CNTL); if (net_debug) @@ -447,7 +514,12 @@ err_out_priv: kfree(dev->priv); dev->priv = NULL; err_out: +#ifndef CONFIG_X86_PC9800 release_region(ioaddr, AT1700_IO_EXTENT); +#else + for (i = 0; i < 0x2000; i += 0x0200) + release_region(ioaddr + i, 2); +#endif return ret; } @@ -459,7 +531,11 @@ err_out: #define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ /* Delay between EEPROM clock transitions. */ +#ifndef CONFIG_X86_PC9800 #define eeprom_delay() do { } while (0) +#else +#define eeprom_delay() __asm__ ("out%B0 %%al,%0" :: "N"(0x5f)) +#endif /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5 << 6) @@ -542,12 +618,12 @@ static void net_tx_timeout (struct net_device *dev) inw (ioaddr + STATUS), inb (ioaddr + TX_STATUS) & 0x80 ? "IRQ conflict" : "network cable problem"); printk ("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n", - dev->name, inw (ioaddr + 0), inw (ioaddr + 2), inw (ioaddr + 4), - inw (ioaddr + 6), inw (ioaddr + 8), inw (ioaddr + 10), - inw (ioaddr + 12), inw (ioaddr + 14)); + dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE), + inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START), + inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL)); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ - outw (0xffff, ioaddr + 24); + outw(0xffff, ioaddr + MODE24); outw (0xffff, ioaddr + TX_STATUS); outb (0x5a, ioaddr + CONFIG_0); outb (0xe8, ioaddr + CONFIG_1); @@ -704,7 +780,7 @@ net_rx(struct net_device *dev) dev->name, inb(ioaddr + RX_MODE), status); #ifndef final_version if (status == 0) { - outb(0x05, ioaddr + 14); + outb(0x05, ioaddr + RX_CTRL); break; } #endif @@ -724,7 +800,7 @@ net_rx(struct net_device *dev) dev->name, pkt_len); /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); - outb(0x05, ioaddr + 14); + outb(0x05, ioaddr + RX_CTRL); lp->stats.rx_errors++; break; } @@ -734,7 +810,7 @@ net_rx(struct net_device *dev) dev->name, pkt_len); /* Prime the FIFO and then flush the packet. */ inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT); - outb(0x05, ioaddr + 14); + outb(0x05, ioaddr + RX_CTRL); lp->stats.rx_dropped++; break; } @@ -761,7 +837,7 @@ net_rx(struct net_device *dev) if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40) break; inw(ioaddr + DATAPORT); /* dummy status read */ - outb(0x05, ioaddr + 14); + outb(0x05, ioaddr + RX_CTRL); } if (net_debug > 5) @@ -844,24 +920,28 @@ set_rx_mode(struct net_device *dev) outb(0x02, ioaddr + RX_MODE); /* Use normal mode. */ } - save_flags(flags); - cli(); + spin_lock_irqsave (&lp->lock, flags); if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { int saved_bank = inw(ioaddr + CONFIG_0); /* Switch to bank 1 and set the multicast table. */ outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0); for (i = 0; i < 8; i++) - outb(mc_filter[i], ioaddr + 8 + i); + outb(mc_filter[i], ioaddr + PORT_OFFSET(8 + i)); memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); outw(saved_bank, ioaddr + CONFIG_0); } - restore_flags(flags); + spin_unlock_irqrestore (&lp->lock, flags); return; } #ifdef MODULE static struct net_device dev_at1700; +#ifndef CONFIG_X86_PC9800 static int io = 0x260; +#else +static int io = 0xd0; +#endif + static int irq; MODULE_PARM(io, "i"); @@ -901,7 +981,15 @@ cleanup_module(void) /* If we don't do this, we can't re-insmod it later. */ free_irq(dev_at1700.irq, NULL); +#ifndef CONFIG_X86_PC9800 release_region(dev_at1700.base_addr, AT1700_IO_EXTENT); +#else + { + int i; + for (i = 0; i < 0x2000; i += 0x200) + release_region(dev_at1700.base_addr + i, 2); + } +#endif } #endif /* MODULE */ MODULE_LICENSE("GPL"); diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h index 761628d8b586..aa58407de02d 100644 --- a/drivers/net/e100/e100.h +++ b/drivers/net/e100/e100.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -57,6 +57,8 @@ #include <linux/if.h> #include <asm/uaccess.h> #include <linux/ip.h> +#include <linux/if_vlan.h> +#include <linux/mii.h> #define E100_REGS_LEN 1 /* @@ -301,6 +303,9 @@ struct driver_stats { /* EEPROM bit definitions */ /*- EEPROM control register bits */ +#define EEPROM_FLAG_ASF 0x8000 +#define EEPROM_FLAG_GCL 0x4000 + #define EN_TRNF 0x10 /* Enable turnoff */ #define EEDO 0x08 /* EEPROM data out */ #define EEDI 0x04 /* EEPROM data in (set for writing data) */ @@ -319,6 +324,8 @@ struct driver_stats { #define EEPROM_COMPATIBILITY_WORD 3 #define EEPROM_PWA_NO 8 #define EEPROM_ID_WORD 0x0A +#define EEPROM_CONFIG_ASF 0x0D +#define EEPROM_SMBUS_ADDR 0x90 #define EEPROM_SUM 0xbaba @@ -358,7 +365,7 @@ struct driver_stats { #define CB_STATUS_MASK BIT_12_15 /* CB Status Mask (4-bits) */ #define CB_STATUS_COMPLETE BIT_15 /* CB Complete Bit */ #define CB_STATUS_OK BIT_13 /* CB OK Bit */ -#define CB_STATUS_UNDERRUN BIT_12 /* CB A Bit */ +#define CB_STATUS_VLAN BIT_12 /* CB Valn detected Bit */ #define CB_STATUS_FAIL BIT_11 /* CB Fail (F) Bit */ /*misc command bits */ @@ -851,6 +858,7 @@ struct ethtool_lpbk_data{ }; struct e100_private { + struct vlan_group *vlgrp; u32 flags; /* board management flags */ u32 tx_per_underrun; /* number of good tx frames per underrun */ unsigned int tx_count; /* count of tx frames, so we can request an interrupt */ @@ -886,7 +894,6 @@ struct e100_private { struct driver_stats drv_stats; u8 rev_id; /* adapter PCI revision ID */ - unsigned long device_type; /* device type from e100_vendor.h */ unsigned int phy_addr; /* address of PHY component */ unsigned int PhyId; /* ID of PHY component */ @@ -923,8 +930,6 @@ struct e100_private { struct cfg_params params; /* adapter's command line parameters */ - char *id_string; - u32 speed_duplex_caps; /* adapter's speed/duplex capabilities */ /* WOL params for ethtool */ diff --git a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c index bff330628916..d9df35677a7c 100644 --- a/drivers/net/e100/e100_config.c +++ b/drivers/net/e100/e100_config.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -521,6 +521,25 @@ e100_config_wol(struct e100_private *bdp) spin_unlock_bh(&(bdp->config_lock)); } +void +e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable) +{ + spin_lock_bh(&(bdp->config_lock)); + if (enable) { + if (!(bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { + bdp->config[22] |= CB_CFIG_VLAN_DROP_ENABLE; + E100_CONFIG(bdp, 22); + } + + } else { + if ((bdp->config[22] & CB_CFIG_VLAN_DROP_ENABLE)) { + bdp->config[22] &= ~CB_CFIG_VLAN_DROP_ENABLE; + E100_CONFIG(bdp, 22); + } + } + spin_unlock_bh(&(bdp->config_lock)); +} + /** * e100_config_loopback_mode * @bdp: atapter's private data struct diff --git a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h index 5bc88f6849b6..5d1e194ff25b 100644 --- a/drivers/net/e100/e100_config.h +++ b/drivers/net/e100/e100_config.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -163,5 +163,5 @@ extern void e100_config_force_dplx(struct e100_private *bdp); extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode); extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable); extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable); - +extern void e100_config_vlan_drop(struct e100_private *bdp, unsigned char enable); #endif /* _E100_CONFIG_INC_ */ diff --git a/drivers/net/e100/e100_eeprom.c b/drivers/net/e100/e100_eeprom.c index c5618c1a2ca4..ff843e161b76 100644 --- a/drivers/net/e100/e100_eeprom.c +++ b/drivers/net/e100/e100_eeprom.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c index 1f1f70caca21..d241eaa64e2e 100644 --- a/drivers/net/e100/e100_main.c +++ b/drivers/net/e100/e100_main.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -45,8 +45,22 @@ **********************************************************************/ /* Change Log - * - * 2.1.29 12/20/02 + * + * 2.2.21 02/11/03 + * o Removed marketing brand strings. Instead, Using generic string + * "Intel(R) PRO/100 Network Connection" for all adapters. + * o Implemented ethtool -S option + * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver + * o Bug fix: Read wrong byte in EEPROM when offset is odd number + * o Bug fix: PHY loopback test fails on ICH devices + * o Bug fix: System panic on e100_close when repeating Hot Remove and + * Add in a team + * o Bug fix: Linux Bonding driver claims adapter's link loss because of + * not updating last_rx field + * o Bug fix: e100 does not check validity of MAC address + * o New feature: added ICH5 support + * + * 2.1.27 11/20/02 * o Bug fix: Device command timeout due to SMBus processing during init * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly * o Bug fix: Not using EEPROM WoL setting as default in ethtool @@ -62,15 +76,6 @@ * ifconfig down, rmmod and insmod * * 2.1.24 10/7/02 - * o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface - * name is changed - * o Bug fix: Rx skb corruption when Rx polling code and Rx interrupt code - * are executing during stress traffic at shared interrupt system. - * Removed Rx polling code - * o Added detailed printk if selftest failed when insmod - * o Removed misleading printks - * - * 2.1.12 8/2/02 */ #include <linux/config.h> @@ -81,7 +86,8 @@ #include "e100_ucode.h" #include "e100_config.h" #include "e100_phy.h" -#include "e100_vendor.h" + +extern void e100_force_speed_duplex_to_phy(struct e100_private *bdp); static char e100_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", @@ -127,7 +133,6 @@ static char *test_strings[] = { static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); -#include <linux/mii.h> static int e100_mii_ioctl(struct net_device *, struct ifreq *, int); static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *, @@ -136,11 +141,15 @@ static void e100_free_nontx_list(struct e100_private *); static void e100_non_tx_background(unsigned long); /* Global Data structures and variables */ -char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation"; -char e100_driver_version[]="2.1.29-k4"; +char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation"; +char e100_driver_version[]="2.2.21-k1"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; char e100_short_driver_name[] = "e100"; static int e100nics = 0; +static void e100_vlan_rx_register(struct net_device *netdev, struct vlan_group + *grp); +static void e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid); +static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); #ifdef CONFIG_PM static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); @@ -186,7 +195,6 @@ static void e100_print_brd_conf(struct e100_private *); static void e100_set_multi(struct net_device *); void e100_set_speed_duplex(struct e100_private *); -char *e100_get_brand_msg(struct e100_private *); static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); static u8 e100_sw_init(struct e100_private *); static void e100_tco_workaround(struct e100_private *); @@ -220,6 +228,7 @@ static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, char *); unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); void e100_exec_cmplx(struct e100_private *, u32, u8); +static unsigned char e100_asf_enabled(struct e100_private *bdp); /** * e100_get_rx_struct - retrieve cell to hold skb buff from the pool @@ -607,7 +616,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) } if (((bdp->pdev->device > 0x1030) - && (bdp->pdev->device < 0x103F)) + && (bdp->pdev->device < 0x103F)) + || ((bdp->pdev->device >= 0x1050) + && (bdp->pdev->device <= 0x1057)) || (bdp->pdev->device == 0x2449) || (bdp->pdev->device == 0x2459) || (bdp->pdev->device == 0x245D)) { @@ -646,6 +657,9 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) goto err_pci; } + dev->vlan_rx_register = e100_vlan_rx_register; + dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; dev->irq = pcid->irq; dev->open = &e100_open; dev->hard_start_xmit = &e100_xmit_frame; @@ -655,9 +669,11 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) dev->set_multicast_list = &e100_set_multi; dev->set_mac_address = &e100_set_mac; dev->do_ioctl = &e100_ioctl; - if (bdp->flags & USE_IPCB) { - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; - } + + if (bdp->flags & USE_IPCB) + dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + e100nics++; e100_get_speed_duplex_caps(bdp); @@ -668,25 +684,24 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent) memcpy(bdp->ifname, dev->name, IFNAMSIZ); bdp->ifname[IFNAMSIZ-1] = 0; - bdp->device_type = ent->driver_data; printk(KERN_NOTICE "e100: %s: %s\n", - bdp->device->name, e100_get_brand_msg(bdp)); + bdp->device->name, "Intel(R) PRO/100 Network Connection"); e100_print_brd_conf(bdp); - bdp->id_string = e100_get_brand_msg(bdp); bdp->wolsupported = 0; bdp->wolopts = 0; /* Check if WoL is enabled on EEPROM */ if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) { + /* Magic Packet WoL is enabled on device by default */ + /* if EEPROM WoL bit is TRUE */ + bdp->wolsupported = WAKE_MAGIC; + bdp->wolopts = WAKE_MAGIC; if (bdp->rev_id >= D101A4_REV_ID) bdp->wolsupported = WAKE_PHY | WAKE_MAGIC; if (bdp->rev_id >= D101MA_REV_ID) bdp->wolsupported |= WAKE_UCAST | WAKE_ARP; - /* Magic Packet WoL is enabled on device by default */ - /* if EEPROM WoL bit is TRUE */ - bdp->wolopts = WAKE_MAGIC; } printk(KERN_NOTICE "\n"); @@ -752,6 +767,34 @@ e100_remove1(struct pci_dev *pcid) --e100nics; } +static struct pci_device_id e100_id_table[] __devinitdata = { + {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + {0,} /* This has to be the last entry*/ +}; MODULE_DEVICE_TABLE(pci, e100_id_table); static struct pci_driver e100_driver = { @@ -994,13 +1037,14 @@ e100_close(struct net_device *dev) { struct e100_private *bdp = dev->priv; + e100_disable_clear_intr(bdp); + free_irq(dev->irq, dev); bdp->intr_mask = SCB_INT_MASK; e100_isolate_driver(bdp); netif_carrier_off(bdp->device); bdp->cur_line_speed = 0; bdp->cur_dplx_mode = 0; - free_irq(dev->irq, dev); e100_clear_pools(bdp); return 0; @@ -1097,6 +1141,8 @@ e100_set_mac(struct net_device *dev, void *addr) int rc = -1; struct sockaddr *p_sockaddr = (struct sockaddr *) addr; + if (!is_valid_ether_addr(p_sockaddr->sa_data)) + return -EADDRNOTAVAIL; bdp = dev->priv; if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { @@ -1231,6 +1277,10 @@ e100_init(struct e100_private *bdp) /* read the MAC address from the eprom */ e100_rd_eaddr(bdp); + if (!is_valid_ether_addr(bdp->device->dev_addr)) { + printk(KERN_ERR "e100: Invalid Ethernet address\n"); + return false; + } /* read NIC's part number */ e100_rd_pwa_no(bdp); @@ -1670,6 +1720,11 @@ e100_watchdog(struct net_device *dev) } else { if (netif_running(dev)) netif_stop_queue(dev); + /* When changing to non-autoneg, device may lose */ + /* link with some switches. e100 will try to */ + /* revover link by sending command to PHY layer */ + if (bdp->params.e100_speed_duplex != E100_AUTONEG) + e100_force_speed_duplex_to_phy(bdp); } rmb(); @@ -1793,7 +1848,8 @@ e100intr(int irq, void *dev_inst, struct pt_regs *regs) bdp = dev->priv; intr_status = readw(&bdp->scb->scb_status); - if (!intr_status || (intr_status == 0xffff)) { + /* If not my interrupt, just return */ + if (!(intr_status & SCB_STATUS_ACK_MASK) || (intr_status == 0xffff)) { return; } @@ -1993,17 +2049,15 @@ e100_rx_srv(struct e100_private *bdp) } else { skb->ip_summed = CHECKSUM_NONE; } - switch (netif_rx(skb)) { - case NET_RX_BAD: - case NET_RX_DROP: - case NET_RX_CN_MOD: - case NET_RX_CN_HIGH: - break; - default: - bdp->drv_stats.net_stats.rx_bytes += skb->len; - break; - } + if(bdp->vlgrp && (rfd_status & CB_STATUS_VLAN)) { + vlan_hwaccel_rx(skb, bdp->vlgrp, be16_to_cpu(rfd->vlanid)); + } else { + netif_rx(skb); + } + dev->last_rx = jiffies; + bdp->drv_stats.net_stats.rx_bytes += skb->len; + rfd_cnt++; } /* end of rfd loop */ @@ -2096,6 +2150,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCPUDP_CHECKSUM_ENABLE; } + if(bdp->vlgrp && vlan_tx_tag_present(skb)) { + (tcb->tcbu).ipcb.ip_activation_high |= IPCB_INSERTVLAN_ENABLE; + (tcb->tcbu).ipcb.vlan = cpu_to_be16(vlan_tx_tag_get(skb)); + } + tcb->tcb_hdr.cb_status = 0; tcb->tcb_thrshld = bdp->tx_thld; tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT); @@ -2114,7 +2173,8 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) if ((ip->protocol == IPPROTO_TCP) || (ip->protocol == IPPROTO_UDP)) { - tcb->tcbu.ipcb.ip_activation_high = + + tcb->tcbu.ipcb.ip_activation_high |= IPCB_HARDWAREPARSING_ENABLE; tcb->tcbu.ipcb.ip_schedule |= IPCB_TCPUDP_CHECKSUM_ENABLE; @@ -2682,13 +2742,12 @@ e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) udelay(20); } - /* Mask off our interrupt line -- its unmasked after reset */ + /* Mask off our interrupt line -- it is unmasked after reset */ e100_disable_clear_intr(bdp); #ifdef E100_CU_DEBUG bdp->last_cmd = 0; bdp->last_sub_cmd = 0; #endif - } /** @@ -2901,27 +2960,6 @@ e100_print_brd_conf(struct e100_private *bdp) } /** - * e100_get_brand_msg - * @bdp: atapter's private data struct - * - * This routine checks if there is specified branding message for a given board - * type and returns a pointer to the string containing the branding message. - */ -char * -e100_get_brand_msg(struct e100_private *bdp) -{ - int i; - - for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) { - if (e100_vendor_info_array[i].device_type == bdp->device_type) { - return e100_vendor_info_array[i].idstr; - } - } - - return e100_vendor_info_array[E100_ALL_BOARDS].idstr; -} - -/** * e100_pci_setup - setup the adapter's PCI information * @pcid: adapter's pci_dev struct * @bdp: atapter's private data struct @@ -3004,12 +3042,17 @@ e100_isolate_driver(struct e100_private *bdp) void e100_set_speed_duplex(struct e100_private *bdp) { - if (netif_carrier_ok(bdp->device)) + int carrier_ok; + /* Device may lose link with some siwtches when */ + /* changing speed/duplex to non-autoneg. e100 */ + /* needs to remember carrier state in order to */ + /* start watchdog timer for recovering link */ + if ((carrier_ok = netif_carrier_ok(bdp->device))) e100_isolate_driver(bdp); e100_phy_set_speed_duplex(bdp, true); e100_config_fc(bdp); /* re-config flow-control if necessary */ e100_config(bdp); - if (netif_carrier_ok(bdp->device)) + if (carrier_ok) e100_deisolate_driver(bdp, false); } @@ -3426,6 +3469,7 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) u16 first_word, last_word; int i, max_len; void *ptr; + u8 *eeprom_data_bytes = (u8 *)eeprom_data; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -3461,7 +3505,9 @@ e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr) if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) return -EFAULT; - if (copy_to_user(usr_eeprom_ptr, eeprom_data, ecmd.len)) + if(ecmd.offset & 1) + eeprom_data_bytes++; + if (copy_to_user(usr_eeprom_ptr, eeprom_data_bytes, ecmd.len)) return -EFAULT; } else { if (ecmd.magic != E100_EEPROM_MAGIC) @@ -3754,7 +3800,8 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) return -EFAULT; switch (info.string_set) { - case ETH_SS_TEST: + case ETH_SS_TEST: { + int ret = 0; if (info.len > E100_MAX_TEST_RES) info.len = E100_MAX_TEST_RES; strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); @@ -3766,7 +3813,13 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) sprintf(strings + i * ETH_GSTRING_LEN, "%-31s", test_strings[i]); } - break; + if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) + ret = -EFAULT; + if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) + ret = -EFAULT; + kfree(strings); + return ret; + } case ETH_SS_STATS: { char *strings = NULL; void *addr = ifr->ifr_data; @@ -3783,19 +3836,6 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr) default: return -EOPNOTSUPP; } - - if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) { - kfree(strings); - return -EFAULT; - } - - if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN)) { - kfree(strings); - return -EFAULT; - } - - kfree(strings); - return 0; } static int @@ -4022,6 +4062,45 @@ exit: spin_unlock_bh(&(bdp->bd_non_tx_lock)); } +static void +e100_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) +{ + struct e100_private *bdp = netdev->priv; + + e100_disable_clear_intr(bdp); + bdp->vlgrp = grp; + + if(grp) { + /* enable VLAN tag insert/strip */ + e100_config_vlan_drop(bdp, true); + + } else { + /* disable VLAN tag insert/strip */ + e100_config_vlan_drop(bdp, false); + } + + e100_config(bdp); + e100_set_intr_mask(bdp); +} + +static void +e100_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + /* We don't do Vlan filtering */ + return; +} + +static void +e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct e100_private *bdp = netdev->priv; + + if(bdp->vlgrp) + bdp->vlgrp->vlan_devices[vid] = NULL; + /* We don't do Vlan filtering */ + return; +} + #ifdef CONFIG_PM static int e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) @@ -4057,7 +4136,7 @@ e100_suspend(struct pci_dev *pcid, u32 state) e100_do_wol(pcid, bdp); /* If wol is enabled */ - if (bdp->wolopts) { + if (bdp->wolopts || e100_asf_enabled(bdp)) { pci_enable_wake(pcid, 3, 1); /* Enable PME for power state D3 */ pci_set_power_state(pcid, 3); /* Set power state to D3. */ } else { @@ -4085,6 +4164,31 @@ e100_resume(struct pci_dev *pcid) } #endif /* CONFIG_PM */ +/** + * e100_asf_enabled - checks if ASF is configured on the current adaper + * by reading registers 0xD and 0x90 in the EEPROM + * @bdp: atapter's private data struct + * + * Returns: true if ASF is enabled + */ +static unsigned char +e100_asf_enabled(struct e100_private *bdp) +{ + u16 asf_reg; + u16 smbus_addr_reg; + if ((bdp->pdev->device >= 0x1050) && (bdp->pdev->device <= 0x1055)) { + asf_reg = e100_eeprom_read(bdp, EEPROM_CONFIG_ASF); + if ((asf_reg & EEPROM_FLAG_ASF) + && !(asf_reg & EEPROM_FLAG_GCL)) { + smbus_addr_reg = + e100_eeprom_read(bdp, EEPROM_SMBUS_ADDR); + if ((smbus_addr_reg & 0xFF) != 0xFE) + return true; + } + } + return false; +} + #ifdef E100_CU_DEBUG unsigned char e100_cu_unknown_state(struct e100_private *bdp) diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c index c8f9053992e1..08782934bdf6 100644 --- a/drivers/net/e100/e100_phy.c +++ b/drivers/net/e100/e100_phy.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -636,7 +636,6 @@ e100_force_speed_duplex(struct e100_private *bdp) control &= ~BMCR_ANENABLE; control &= ~BMCR_LOOPBACK; - /* Check e100.c values */ switch (bdp->params.e100_speed_duplex) { case E100_SPEED_10_HALF: control &= ~BMCR_SPEED100; @@ -682,6 +681,41 @@ e100_force_speed_duplex(struct e100_private *bdp) } while (true); } +void +e100_force_speed_duplex_to_phy(struct e100_private *bdp) +{ + u16 control; + + e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); + control &= ~BMCR_ANENABLE; + control &= ~BMCR_LOOPBACK; + + switch (bdp->params.e100_speed_duplex) { + case E100_SPEED_10_HALF: + control &= ~BMCR_SPEED100; + control &= ~BMCR_FULLDPLX; + break; + + case E100_SPEED_10_FULL: + control &= ~BMCR_SPEED100; + control |= BMCR_FULLDPLX; + break; + + case E100_SPEED_100_HALF: + control |= BMCR_SPEED100; + control &= ~BMCR_FULLDPLX; + break; + + case E100_SPEED_100_FULL: + control |= BMCR_SPEED100; + control |= BMCR_FULLDPLX; + break; + } + + /* Send speed/duplex command to PHY layer. */ + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); +} + /* * Procedure: e100_set_fc * diff --git a/drivers/net/e100/e100_phy.h b/drivers/net/e100/e100_phy.h index 51d5ff192700..df2d483e67f8 100644 --- a/drivers/net/e100/e100_phy.h +++ b/drivers/net/e100/e100_phy.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -30,8 +30,6 @@ #include "e100.h" -#include <linux/mii.h> - /* * Auto-polarity enable/disable * e100_autopolarity = 0 => disable auto-polarity diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c index 27ff5af00bfd..0ff7266ef8e2 100644 --- a/drivers/net/e100/e100_test.c +++ b/drivers/net/e100/e100_test.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -242,6 +242,9 @@ e100_diag_config_loopback(struct e100_private* bdp, *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd); if (set_loopback) { + /* ICH PHY loopback is broken */ + if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK) + loopback_mode = MAC_LOOPBACK; /* Configure loopback on MAC */ e100_config_loopback_mode(bdp,loopback_mode); } else { diff --git a/drivers/net/e100/e100_ucode.h b/drivers/net/e100/e100_ucode.h index 1c6b88c7fac3..ccbcd05583aa 100644 --- a/drivers/net/e100/e100_ucode.h +++ b/drivers/net/e100/e100_ucode.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 diff --git a/drivers/net/e100/e100_vendor.h b/drivers/net/e100/e100_vendor.h deleted file mode 100644 index 01be2d41b9cd..000000000000 --- a/drivers/net/e100/e100_vendor.h +++ /dev/null @@ -1,311 +0,0 @@ -/******************************************************************************* - - - Copyright(c) 1999 - 2002 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 LICENSE. - - Contact Information: - Linux NICS <linux.nics@intel.com> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 -*******************************************************************************/ - -#ifndef E100_VENDOR_ID_INFO -#define E100_VENDOR_ID_INFO -/* ====================================================================== */ -/* vendor_info */ -/* ====================================================================== */ - -struct e100_vendor_info { - unsigned long device_type; - char *idstr; -}; - -enum e100_device_type { - E100_BRD_100TX = 1, - E100_BRD_100T4, - E100_BRD_10T, - E100_BRD_100WFM, - E100_BRD_82557, - E100_BRD_82557_WOL, - E100_BRD_82558, - E100_BRD_82558_WOL, - E100_BRD_100, - E100_BRD_100M, - E100_BRD_AOL2, - E100_BRD_AOL, - E100_PROS_M, - E100_PROS_AM, - E100_PROS_AM_AOL, - E100_PROS_DT, - E100_PRO_DT, - E100_PROM_DT, - E100_PRO_SRV, - E100_PRO_SRVP, - E100_PROS_SRV, - E100_PRO_DUAL, - E100_PROS_DUAL, - E100_PROP_DUAL, - E100_PROP_WOL, - E100_PROS_MOB, - E100_PRO_CB, - E100_PRO_CB_M, - E100_PROSR_MOB, - E100_PROS_MC, - E100_PROSR_MC, - E100_PROP_MC, - E100_PROSP_MC, - E100_PROP_MOB, - E100_PROSP_MOB, - E100_PRO_MINI, - E100_PRO_NET, - E100_PROS_NET, - E100_PROVM_NET, - E100_PROVE_D, - E100_82559_LOM, - E100_82559_LOM_AOL, - E100_82559_LOM_AOL2, - E100_82559_LOM_DELL, - E100_IBM_MDS, - E100_CMPQ_S, - E100_PROVE_DA, - E100_PROVM_DA, - E100_PROVE_LOM, - E100_PROVE_NET, - E100_82562, - E100_82551QM, - E100_ALL_BOARDS -}; - -struct e100_vendor_info e100_vendor_info_array[] = { - { E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"}, - { E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"}, - { E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"}, - { E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"}, - { E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"}, - { E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"}, - { E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"}, - { E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"}, - { E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"}, - { E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"}, - { E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"}, - { E100_82559_LOM_DELL, "Intel(R) 8255x Based Network Connection"}, - { E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"}, - { E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"}, - { E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"}, - { E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"}, - { E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"}, - { E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"}, - { E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"}, - { E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"}, - { E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"}, - { E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"}, - { E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"}, - { E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"}, - { E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"}, - { E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"}, - { E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"}, - { E100_PRO_CB, "Intel(R) PRO/100 CardBus II"}, - { E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"}, - { E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"}, - { E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"}, - { E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"}, - { E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"}, - { E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"}, - { E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"}, - { E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"}, - { E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"}, - { E100_PRO_NET, "Intel(R) PRO/100 Network Connection" }, - { E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" }, - { E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"}, - { E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"}, - { E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"}, - { E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" }, - { E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" }, - { E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"}, - { E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" }, - { E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"}, - { E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"}, - { E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" }, - { E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"}, - { E100_82562, "Intel(R)82562 based Fast Ethernet Connection"}, - { E100_82551QM, "Intel(R) PRO/100 M Mobile Connection"}, - { E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"}, - {0,NULL} -}; - -static struct pci_device_id e100_id_table[] __devinitdata = { - {0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX}, - {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4}, - {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T}, - {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM}, - {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557}, - {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL}, - {0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4}, - {0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T}, - {0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM}, - {0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557}, - {0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL}, - {0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558}, - {0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL}, - {0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100}, - {0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M}, - {0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100}, - {0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M}, - {0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2}, - {0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL}, - {0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M}, - {0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M}, - {0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM}, - {0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM}, - {0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL}, - {0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT}, - {0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT}, - {0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT}, - {0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT}, - {0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT}, - {0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV}, - {0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP}, - {0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV}, - {0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV}, - {0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL}, - {0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL}, - {0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL}, - {0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL}, - {0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL}, - {0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV}, - {0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV}, - {0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV}, - {0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV}, - {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, - {0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, - {0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB}, - {0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB}, - {0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M}, - {0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB}, - {0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC}, - {0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC}, - {0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB}, - {0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC}, - {0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB}, - {0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC}, - {0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB}, - {0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC}, - {0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC}, - {0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC}, - {0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI}, - {0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI}, - {0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC}, - {0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC}, - {0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC}, - {0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC}, - {0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI}, - {0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI}, - {0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI}, - {0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM}, - {0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM}, - {0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL}, - {0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2}, - {0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET}, - {0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET}, - {0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET}, - {0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET}, - {0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS}, - {0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET}, - {0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S}, - {0x8086, 0x1229, 0x1028, PCI_ANY_ID, 0, 0, E100_82559_LOM_DELL}, - {0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS}, - - {0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D}, - {0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D}, - {0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D}, - {0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA}, - {0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA}, - {0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET}, - {0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET}, - {0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC}, - {0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB}, - {0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET}, - {0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D}, - {0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS}, - - {0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM}, - {0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM}, - {0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM}, - - {0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS}, - {0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS}, - {0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS}, - {0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, - {0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, - {0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, - {0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, - {0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, - {0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, - {0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562}, - {0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562}, - {0,} /* This has to be the last entry*/ -}; - -#endif /* E100_VENDOR_ID_INFO */ diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 18d0c2b5e471..2b81e45e641f 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -65,6 +65,7 @@ #include <linux/reboot.h> #include <net/checksum.h> #include <linux/workqueue.h> +#include <linux/mii.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> @@ -95,6 +96,15 @@ struct e1000_adapter; #define E1000_RXBUFFER_8192 8192 #define E1000_RXBUFFER_16384 16384 +/* SmartSpeed delimiters */ +#define E1000_SMARTSPEED_DOWNSHIFT 3 +#define E1000_SMARTSPEED_MAX 15 + +/* Packet Buffer allocations */ +#define E1000_TX_FIFO_SIZE_SHIFT 0xA +#define E1000_TX_HEAD_ADDR_SHIFT 7 +#define E1000_PBA_TX_MASK 0xFFFF0000 + /* Flow Control High-Watermark: 43464 bytes */ #define E1000_FC_HIGH_THRESH 0xA9C8 @@ -107,10 +117,7 @@ struct e1000_adapter; /* How many Tx Descriptors do we need to call netif_wake_queue ? */ #define E1000_TX_QUEUE_WAKE 16 /* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define E1000_RX_BUFFER_WRITE 16 - -#define E1000_JUMBO_PBA 0x00000028 -#define E1000_DEFAULT_PBA 0x00000030 +#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ #define AUTO_ALL_MODES 0 #define E1000_EEPROM_APME 4 @@ -145,7 +152,8 @@ struct e1000_desc_ring { }; #define E1000_DESC_UNUSED(R) \ -((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count)) + ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ + (R)->next_to_clean - (R)->next_to_use - 1) #define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) #define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) @@ -155,6 +163,7 @@ struct e1000_desc_ring { /* board specific private data structure */ struct e1000_adapter { + struct timer_list tx_fifo_stall_timer; struct timer_list watchdog_timer; struct timer_list phy_info_timer; struct vlan_group *vlgrp; @@ -163,6 +172,7 @@ struct e1000_adapter { uint32_t rx_buffer_len; uint32_t part_num; uint32_t wol; + uint32_t smartspeed; uint16_t link_speed; uint16_t link_duplex; spinlock_t stats_lock; @@ -177,7 +187,11 @@ struct e1000_adapter { uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; - int max_data_per_txd; + uint32_t gotcl; + uint32_t tx_fifo_head; + uint32_t tx_head_addr; + uint32_t tx_fifo_size; + atomic_t tx_fifo_stall; /* RX */ struct e1000_desc_ring rx_ring; @@ -186,6 +200,10 @@ struct e1000_adapter { uint32_t rx_int_delay; uint32_t rx_abs_int_delay; boolean_t rx_csum; + uint32_t gorcl; + + /* Interrupt Throttle Rate */ + uint32_t itr; /* OS defined structs */ struct net_device *netdev; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index d06ef79c6e29..c64530107467 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -38,6 +38,7 @@ extern char e1000_driver_version[]; extern int e1000_up(struct e1000_adapter *adapter); extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); +extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", @@ -129,30 +130,9 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) hw->autoneg = 1; hw->autoneg_advertised = 0x002F; ecmd->advertising = 0x002F; - } else { - hw->autoneg = 0; - switch(ecmd->speed + ecmd->duplex) { - case SPEED_10 + DUPLEX_HALF: - hw->forced_speed_duplex = e1000_10_half; - break; - case SPEED_10 + DUPLEX_FULL: - hw->forced_speed_duplex = e1000_10_full; - break; - case SPEED_100 + DUPLEX_HALF: - hw->forced_speed_duplex = e1000_100_half; - break; - case SPEED_100 + DUPLEX_FULL: - hw->forced_speed_duplex = e1000_100_full; - break; - case SPEED_1000 + DUPLEX_FULL: - hw->autoneg = 1; - hw->autoneg_advertised = ADVERTISE_1000_FULL; - break; - case SPEED_1000 + DUPLEX_HALF: /* not supported */ - default: + } else + if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) return -EINVAL; - } - } /* reset the link */ @@ -165,16 +145,6 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) return 0; } -static inline int -e1000_eeprom_size(struct e1000_hw *hw) -{ - if((hw->mac_type > e1000_82544) && - (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE)) - return 512; - else - return 128; -} - static void e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, struct ethtool_drvinfo *drvinfo) @@ -186,7 +156,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter, drvinfo->n_stats = E1000_STATS_LEN; #define E1000_REGS_LEN 32 drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t); - drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw); + drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2; } static void @@ -220,9 +190,8 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter, struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff) { struct e1000_hw *hw = &adapter->hw; - int max_len, first_word, last_word; + int first_word, last_word; int ret_val = 0; - int i; if(eeprom->len == 0) { ret_val = -EINVAL; @@ -231,22 +200,28 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter, eeprom->magic = hw->vendor_id | (hw->device_id << 16); - max_len = e1000_eeprom_size(hw); - if(eeprom->offset > eeprom->offset + eeprom->len) { ret_val = -EINVAL; goto geeprom_error; } - if((eeprom->offset + eeprom->len) > max_len) - eeprom->len = (max_len - eeprom->offset); + if((eeprom->offset + eeprom->len) > (hw->eeprom.word_size * 2)) + eeprom->len = ((hw->eeprom.word_size * 2) - eeprom->offset); first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; - for(i = 0; i <= (last_word - first_word); i++) - e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]); - + if(hw->eeprom.type == e1000_eeprom_spi) + ret_val = e1000_read_eeprom(hw, first_word, + last_word - first_word + 1, + eeprom_buff); + else { + uint16_t i; + for (i = 0; i < last_word - first_word + 1; i++) + if((ret_val = e1000_read_eeprom(hw, first_word + i, 1, + &eeprom_buff[i]))) + break; + } geeprom_error: return ret_val; } @@ -257,9 +232,8 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter, { struct e1000_hw *hw = &adapter->hw; uint16_t *eeprom_buff; - int max_len, first_word, last_word; void *ptr; - int i; + int max_len, first_word, last_word, ret_val = 0; if(eeprom->len == 0) return -EOPNOTSUPP; @@ -267,7 +241,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter, if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; - max_len = e1000_eeprom_size(hw); + max_len = hw->eeprom.word_size * 2; if((eeprom->offset + eeprom->len) > max_len) eeprom->len = (max_len - eeprom->offset); @@ -283,30 +257,31 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter, if(eeprom->offset & 1) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ - e1000_read_eeprom(hw, first_word, &eeprom_buff[0]); + ret_val = e1000_read_eeprom(hw, first_word, 1, + &eeprom_buff[0]); ptr++; } - if((eeprom->offset + eeprom->len) & 1) { + if(((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { /* need read/modify/write of last changed EEPROM word */ /* only the first byte of the word is being modified */ - e1000_read_eeprom(hw, last_word, + ret_val = e1000_read_eeprom(hw, last_word, 1, &eeprom_buff[last_word - first_word]); } - if(copy_from_user(ptr, user_data, eeprom->len)) { - kfree(eeprom_buff); - return -EFAULT; + if((ret_val != 0) || copy_from_user(ptr, user_data, eeprom->len)) { + ret_val = -EFAULT; + goto seeprom_error; } - for(i = 0; i <= (last_word - first_word); i++) - e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]); + ret_val = e1000_write_eeprom(hw, first_word, + last_word - first_word + 1, eeprom_buff); /* Update the checksum over the first part of the EEPROM if needed */ - if(first_word <= EEPROM_CHECKSUM_REG) + if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG) e1000_update_eeprom_checksum(hw); +seeprom_error: kfree(eeprom_buff); - - return 0; + return ret_val; } static void @@ -333,8 +308,8 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) /* Fall Through */ default: - wol->supported = WAKE_UCAST | WAKE_MCAST - | WAKE_BCAST | WAKE_MAGIC; + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC; wol->wolopts = 0; if(adapter->wol & E1000_WUFC_EX) @@ -368,7 +343,7 @@ e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) /* Fall Through */ default: - if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY)) + if(wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; adapter->wol = 0; @@ -542,13 +517,12 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr) } case ETHTOOL_GEEPROM: { struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM}; + struct e1000_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; - int max_len, err = 0; - - max_len = e1000_eeprom_size(&adapter->hw); + int err = 0; - eeprom_buff = kmalloc(max_len, GFP_KERNEL); + eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL); if(eeprom_buff == NULL) return -ENOMEM; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 8ead5c6544c8..3527e7794635 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -32,6 +32,8 @@ #include "e1000_hw.h" +static int32_t e1000_set_phy_type(struct e1000_hw *hw); +static void e1000_phy_init_script(struct e1000_hw *hw); static int32_t e1000_setup_fiber_link(struct e1000_hw *hw); static int32_t e1000_setup_copper_link(struct e1000_hw *hw); static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw); @@ -42,19 +44,103 @@ static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl); static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count); static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw); static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw); +static int32_t e1000_write_eeprom_spi(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_write_eeprom_microwire(struct e1000_hw *hw, + uint16_t offset, uint16_t words, + uint16_t *data); +static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw); static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd); static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd); static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count); -static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw); -static void e1000_setup_eeprom(struct e1000_hw *hw); -static void e1000_clock_eeprom(struct e1000_hw *hw); -static void e1000_cleanup_eeprom(struct e1000_hw *hw); +static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count); +static int32_t e1000_acquire_eeprom(struct e1000_hw *hw); +static void e1000_release_eeprom(struct e1000_hw *hw); static void e1000_standby_eeprom(struct e1000_hw *hw); static int32_t e1000_id_led_init(struct e1000_hw * hw); + + +/****************************************************************************** + * Set the phy type member in the hw struct. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +int32_t +e1000_set_phy_type(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_set_phy_type"); + + switch(hw->phy_id) { + case M88E1000_E_PHY_ID: + case M88E1000_I_PHY_ID: + case M88E1011_I_PHY_ID: + hw->phy_type = e1000_phy_m88; + break; + case IGP01E1000_I_PHY_ID: + hw->phy_type = e1000_phy_igp; + break; + default: + /* Should never have loaded on this device */ + hw->phy_type = e1000_phy_undefined; + return -E1000_ERR_PHY_TYPE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * IGP phy init script - initializes the GbE PHY + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +static void +e1000_phy_init_script(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_phy_init_script"); + + if(hw->phy_init_script) { + msec_delay(10); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); + e1000_write_phy_reg(hw,0x0000,0x0140); + + msec_delay(5); + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95); + e1000_write_phy_reg(hw,0x0015,0x0001); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71); + e1000_write_phy_reg(hw,0x0011,0xBD21); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79); + e1000_write_phy_reg(hw,0x0019,0x0018); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30); + e1000_write_phy_reg(hw,0x0010,0x1600); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31); + e1000_write_phy_reg(hw,0x0011,0x0014); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32); + e1000_write_phy_reg(hw,0x0012,0x161C); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94); + e1000_write_phy_reg(hw,0x0014,0x0003); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96); + e1000_write_phy_reg(hw,0x0016,0x003F); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010); + e1000_write_phy_reg(hw,0x0010,0x0008); + + e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); + e1000_write_phy_reg(hw,0x0000,0x3300); + } +} + /****************************************************************************** * Set the mac type member in the hw struct. - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ int32_t @@ -101,10 +187,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82546EB_FIBER: hw->mac_type = e1000_82546; break; + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + hw->mac_type = e1000_82541; + break; + case E1000_DEV_ID_82547EI: + hw->mac_type = e1000_82547; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } + + return E1000_SUCCESS; } /****************************************************************************** @@ -119,9 +214,10 @@ e1000_reset_hw(struct e1000_hw *hw) uint32_t ctrl_ext; uint32_t icr; uint32_t manc; + uint32_t led_ctrl; DEBUGFUNC("e1000_reset_hw"); - + /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ if(hw->mac_type == e1000_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); @@ -145,7 +241,7 @@ e1000_reset_hw(struct e1000_hw *hw) /* Delay to allow any outstanding PCI transactions to complete before * resetting the device - */ + */ msec_delay(10); /* Issue a global reset to the MAC. This will reset the chip's @@ -156,6 +252,12 @@ e1000_reset_hw(struct e1000_hw *hw) DEBUGOUT("Issuing a global reset to MAC\n"); ctrl = E1000_READ_REG(hw, CTRL); + /* Must reset the PHY before resetting the MAC */ + if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { + E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST)); + msec_delay(5); + } + if(hw->mac_type > e1000_82543) E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); else @@ -173,13 +275,25 @@ e1000_reset_hw(struct e1000_hw *hw) msec_delay(2); } else { /* Wait for EEPROM reload (it happens automatically) */ - msec_delay(4); + msec_delay(5); /* Dissable HW ARPs on ASF enabled adapters */ manc = E1000_READ_REG(hw, MANC); manc &= ~(E1000_MANC_ARP_EN); E1000_WRITE_REG(hw, MANC, manc); } - + + if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { + e1000_phy_init_script(hw); + + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == e1000_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } + /* Clear interrupt mask to stop board from generating interrupts */ DEBUGOUT("Masking off all interrupts\n"); E1000_WRITE_REG(hw, IMC, 0xffffffff); @@ -198,8 +312,8 @@ e1000_reset_hw(struct e1000_hw *hw) * 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 + * + * Assumes that the controller has previously been reset and is in a * post-reset uninitialized state. Initializes the receive address registers, * multicast table, and VLAN filter table. Calls routines to setup link * configuration and flow control settings. Clears all on-chip counters. Leaves @@ -224,7 +338,7 @@ e1000_init_hw(struct e1000_hw *hw) DEBUGOUT("Error Initializing Identification LED\n"); return ret_val; } - + /* Set the Media Type and exit with error if it is not valid. */ if(hw->mac_type != e1000_82543) { /* tbi_compatibility is only valid on 82543 */ @@ -327,13 +441,13 @@ e1000_init_hw(struct e1000_hw *hw) /****************************************************************************** * Configures flow control and link settings. - * + * * hw - Struct containing variables accessed by shared code - * + * * Determines which flow control settings to use. Calls the apropriate media- * specific link configuration function. Configures the flow control settings. * Assuming the adapter has a valid link partner, a valid link should be - * established. Assumes the hardware has previously been reset and the + * established. Assumes the hardware has previously been reset and the * transmitter and receiver are not enabled. *****************************************************************************/ int32_t @@ -353,7 +467,7 @@ e1000_setup_link(struct e1000_hw *hw) * control setting, then the variable hw->fc will * be initialized based on a value in the EEPROM. */ - if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -361,7 +475,7 @@ e1000_setup_link(struct e1000_hw *hw) if(hw->fc == e1000_fc_default) { if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0) hw->fc = e1000_fc_none; - else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == + else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR) hw->fc = e1000_fc_tx_pause; else @@ -390,7 +504,7 @@ e1000_setup_link(struct e1000_hw *hw) * or e1000_phy_setup() is called. */ if(hw->mac_type == e1000_82543) { - ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << + ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); } @@ -416,7 +530,7 @@ e1000_setup_link(struct e1000_hw *hw) * these registers will be set to a default threshold that may be * adjusted later by the driver's runtime code. However, if the * ability to transmit pause frames in not enabled, then these - * registers will be set to 0. + * registers will be set to 0. */ if(!(hw->fc & e1000_fc_tx_pause)) { E1000_WRITE_REG(hw, FCRTL, 0); @@ -445,7 +559,7 @@ e1000_setup_link(struct e1000_hw *hw) * link. Assumes the hardware has been previously reset and the transmitter * and receiver are not enabled. *****************************************************************************/ -static int32_t +static int32_t e1000_setup_fiber_link(struct e1000_hw *hw) { uint32_t ctrl; @@ -457,29 +571,29 @@ e1000_setup_fiber_link(struct e1000_hw *hw) DEBUGFUNC("e1000_setup_fiber_link"); - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal */ ctrl = E1000_READ_REG(hw, CTRL); if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1; else signal = 0; - + /* Take the link out of reset */ ctrl &= ~(E1000_CTRL_LRST); - + e1000_config_collision_dist(hw); /* Check for a software override of the flow control settings, and setup * the device accordingly. If auto-negotiation is enabled, then software * will have to set the "PAUSE" bits to the correct value in the Tranmsit * Config Word Register (TXCW) and re-start auto-negotiation. However, if - * auto-negotiation is disabled, then software will have to manually + * auto-negotiation is disabled, then software will have to manually * configure the two flow control enable bits in the CTRL register. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, but + * 1: Rx flow control is enabled (we can receive pause frames, but * not send pause frames). * 2: Tx flow control is enabled (we can send pause frames but we do * not support receiving pause frames). @@ -491,8 +605,8 @@ e1000_setup_fiber_link(struct e1000_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); break; case e1000_fc_rx_pause: - /* RX Flow control is enabled and TX Flow control is disabled by a - * software over-ride. Since there really isn't a way to advertise + /* RX Flow control is enabled and TX Flow control is disabled by a + * software over-ride. Since there really isn't a way to advertise * that we are capable of RX Pause ONLY, we will advertise that we * support both symmetric and asymmetric RX PAUSE. Later, we will * disable the adapter's ability to send PAUSE frames. @@ -500,7 +614,7 @@ e1000_setup_fiber_link(struct e1000_hw *hw) txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); break; case e1000_fc_tx_pause: - /* TX Flow control is enabled, and RX Flow control is disabled, by a + /* TX Flow control is enabled, and RX Flow control is disabled, by a * software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); @@ -531,8 +645,8 @@ e1000_setup_fiber_link(struct e1000_hw *hw) msec_delay(1); /* If we have a signal (the cable is plugged in) then poll for a "Link-Up" - * indication in the Device Status Register. Time-out if a link isn't - * seen in 500 milliseconds seconds (Auto-negotiation should complete in + * indication in the Device Status Register. Time-out if a link isn't + * seen in 500 milliseconds seconds (Auto-negotiation should complete in * less than 500 milliseconds even if the other end is doing it in SW). */ if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) { @@ -543,7 +657,7 @@ e1000_setup_fiber_link(struct e1000_hw *hw) if(status & E1000_STATUS_LU) break; } if(i == (LINK_UP_TIMEOUT / 10)) { - /* AutoNeg failed to achieve a link, so we'll call + /* AutoNeg failed to achieve a link, so we'll call * e1000_check_for_link. This routine will force the link up if we * detect a signal. This will allow us to communicate with * non-autonegotiating link partners. @@ -571,10 +685,10 @@ e1000_setup_fiber_link(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -static int32_t +static int32_t e1000_setup_copper_link(struct e1000_hw *hw) { - uint32_t ctrl; + uint32_t ctrl, led_ctrl; int32_t ret_val; uint16_t i; uint16_t phy_data; @@ -604,80 +718,148 @@ e1000_setup_copper_link(struct e1000_hw *hw) } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); - /* Enable CRS on TX. This must be set for half-duplex operation. */ - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + if (hw->phy_type == e1000_phy_igp) { - /* Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = e1000_phy_reset(hw); + if(ret_val < 0) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } - switch (hw->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } + /* Wait 10ms for MAC to configure PHY from eeprom settings */ + msec_delay(15); - /* Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if(hw->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } - /* Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_EPSCR_TX_CLK_25; + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == e1000_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + + if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, + phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + /* Set auto Master/Slave resolution process */ + if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data &= ~CR_1000T_MS_ENABLE; + if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + } - if (hw->phy_revision < M88E1011_I_REV_4) { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + + /* Force MDI for IGP PHY */ + phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | + IGP01E1000_PSCR_FORCE_MDI_MDIX); + + hw->mdix = 1; + + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } - } - /* SW Reset the PHY so all changes take effect */ - ret_val = e1000_phy_reset(hw); - if(ret_val < 0) { - DEBUGOUT("Error Resetting the PHY\n"); - return ret_val; + } else { + /* Enable CRS on TX. This must be set for half-duplex operation. */ + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (hw->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if(hw->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + + /* Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if (hw->phy_revision < M88E1011_I_REV_4) { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + } + + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000_phy_reset(hw); + if(ret_val < 0) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } } - + /* Options: * autoneg = 1 (default) * PHY will advertise value(s) parsed from @@ -736,6 +918,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) return ret_val; } } + hw->get_link_status = TRUE; } else { DEBUGOUT("Forcing speed and duplex\n"); ret_val = e1000_phy_force_speed_duplex(hw); @@ -1014,23 +1197,41 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } + if (hw->phy_type == e1000_phy_m88) { + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } - /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed are duplex are forced. - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } - DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); + /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed are duplex are forced. + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); - /* Need to reset the PHY or these changes will be ignored */ - mii_ctrl_reg |= MII_CR_RESET; + /* Need to reset the PHY or these changes will be ignored */ + mii_ctrl_reg |= MII_CR_RESET; + } else { + /* Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed or duplex are forced. + */ + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + } /* Write back the modified PHY MII control register. */ if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) { @@ -1069,7 +1270,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) } if(i == 0) { /* We didn't get link */ /* Reset the DSP and wait again for link. */ - + ret_val = e1000_phy_reset_dsp(hw); if(ret_val < 0) { DEBUGOUT("Error Resetting PHY DSP\n"); @@ -1093,32 +1294,34 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) } } } - - /* Because we reset the PHY above, we need to re-force TX_CLK in the - * Extended PHY Specific Control Register to 25MHz clock. This value - * defaults back to a 2.5MHz clock when the PHY is reset. - */ - if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_EPSCR_TX_CLK_25; - if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; - } - /* In addition, because of the s/w reset above, we need to enable CRS on - * TX. This must be set for both full and half duplex operation. - */ - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { - DEBUGOUT("PHY Write Error\n"); - return -E1000_ERR_PHY; + if (hw->phy_type == e1000_phy_m88) { + /* Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This value + * defaults back to a 2.5MHz clock when the PHY is reset. + */ + if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data |= M88E1000_EPSCR_TX_CLK_25; + if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } + + /* In addition, because of the s/w reset above, we need to enable CRS on + * TX. This must be set for both full and half duplex operation. + */ + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { + DEBUGOUT("PHY Write Error\n"); + return -E1000_ERR_PHY; + } } return 0; } @@ -1136,6 +1339,8 @@ e1000_config_collision_dist(struct e1000_hw *hw) { uint32_t tctl; + DEBUGFUNC("e1000_config_collision_dist"); + tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; @@ -1172,22 +1377,43 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) /* Set up duplex in the Device Control and Transmit Control * registers depending on negotiated values. */ - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { - DEBUGOUT("PHY Read Error\n"); - return -E1000_ERR_PHY; - } - if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; - else ctrl &= ~E1000_CTRL_FD; + if (hw->phy_type == e1000_phy_igp) { + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; + else ctrl &= ~E1000_CTRL_FD; - e1000_config_collision_dist(hw); + e1000_config_collision_dist(hw); - /* Set up speed in the Device Control register depending on - * negotiated values. - */ - if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) - ctrl |= E1000_CTRL_SPD_1000; - else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) - ctrl |= E1000_CTRL_SPD_100; + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_100MBPS) + ctrl |= E1000_CTRL_SPD_100; + } else { + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; + else ctrl &= ~E1000_CTRL_FD; + + e1000_config_collision_dist(hw); + + /* Set up speed in the Device Control register depending on + * negotiated values. + */ + if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) + ctrl |= E1000_CTRL_SPD_1000; + else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) + ctrl |= E1000_CTRL_SPD_100; + } /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return 0; @@ -1195,7 +1421,7 @@ e1000_config_mac_to_phy(struct e1000_hw *hw) /****************************************************************************** * Forces the MAC's flow control settings. - * + * * hw - Struct containing variables accessed by shared code * * Sets the TFCE and RFCE bits in the device control register to reflect @@ -1262,7 +1488,7 @@ e1000_force_mac_fc(struct e1000_hw *hw) /****************************************************************************** * Configures flow control settings after link is established - * + * * hw - Struct containing variables accessed by shared code * * Should be called immediately after a valid link has been established. @@ -1484,9 +1710,9 @@ e1000_check_for_link(struct e1000_hw *hw) uint16_t lp_capability; DEBUGFUNC("e1000_check_for_link"); - - /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be - * set when the optics detect a signal. On older adapters, it will be + + /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be + * set when the optics detect a signal. On older adapters, it will be * cleared when there is a signal */ if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1; @@ -1519,6 +1745,10 @@ e1000_check_for_link(struct e1000_hw *hw) if(phy_data & MII_SR_LINK_STATUS) { hw->get_link_status = FALSE; + /* Check if there was DownShift, must be checked immediately after + * link-up */ + e1000_check_downshift(hw); + } else { /* No link detected */ return 0; @@ -1547,7 +1777,7 @@ e1000_check_for_link(struct e1000_hw *hw) } } - /* Configure Flow Control now that Auto-Neg has completed. First, we + /* Configure Flow Control now that Auto-Neg has completed. First, we * need to restore the desired flow control settings because we may * have had to re-autoneg with a different link partner. */ @@ -1576,7 +1806,7 @@ e1000_check_for_link(struct e1000_hw *hw) NWAY_LPAR_100TX_HD_CAPS | NWAY_LPAR_100TX_FD_CAPS | NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to + /* If our link partner advertises anything in addition to * gigabit, we do not need to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { @@ -1780,7 +2010,7 @@ e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t mask; /* We need to shift "count" number of bits out to the PHY. So, the value - * in the "data" parameter will be shifted out to the PHY one bit at a + * in the "data" parameter will be shifted out to the PHY one bit at a * time. In order to do this, "data" must be broken down into bits. */ mask = 0x01; @@ -1817,7 +2047,7 @@ e1000_shift_out_mdi_bits(struct e1000_hw *hw, * * hw - Struct containing variables accessed by shared code * -* Bits are shifted in in MSB to LSB order. +* Bits are shifted in in MSB to LSB order. ******************************************************************************/ static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw) @@ -1832,7 +2062,7 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw) * These two bits are ignored by us and thrown away. Bits are "shifted in" * by raising the input to the Management Data Clock (setting the MDC bit), * and then reading the value of the MDIO bit. - */ + */ ctrl = E1000_READ_REG(hw, CTRL); /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */ @@ -1892,7 +2122,7 @@ e1000_read_phy_reg(struct e1000_hw *hw, * PHY to retrieve the desired data. */ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_READ)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -1930,7 +2160,7 @@ e1000_read_phy_reg(struct e1000_hw *hw, * READ operation is performed. These two bits are thrown away * followed by a shift in of 16 bits which contains the desired data. */ - mdic = ((reg_addr) | (phy_addr << 5) | + mdic = ((reg_addr) | (phy_addr << 5) | (PHY_OP_READ << 10) | (PHY_SOF << 12)); e1000_shift_out_mdi_bits(hw, mdic, 14); @@ -1974,7 +2204,7 @@ e1000_write_phy_reg(struct e1000_hw *hw, */ mdic = (((uint32_t) phy_data) | (reg_addr << E1000_MDIC_REG_SHIFT) | - (phy_addr << E1000_MDIC_PHY_SHIFT) | + (phy_addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_WRITE)); E1000_WRITE_REG(hw, MDIC, mdic); @@ -1992,12 +2222,12 @@ e1000_write_phy_reg(struct e1000_hw *hw, } else { /* We'll need to use the SW defined pins to shift the write command * out to the PHY. We first send a preamble to the PHY to signal the - * beginning of the MII instruction. This is done by sending 32 + * beginning of the MII instruction. This is done by sending 32 * consecutive "1" bits. */ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); - /* Now combine the remaining required fields that will indicate a + /* Now combine the remaining required fields that will indicate a * write operation. We use this method instead of calling the * e1000_shift_out_mdi_bits routine for each field in the command. The * format of a MII write instruction is as follows: @@ -2010,6 +2240,7 @@ e1000_write_phy_reg(struct e1000_hw *hw, e1000_shift_out_mdi_bits(hw, mdic, 32); } + return 0; } @@ -2021,8 +2252,7 @@ e1000_write_phy_reg(struct e1000_hw *hw, void e1000_phy_hw_reset(struct e1000_hw *hw) { - uint32_t ctrl; - uint32_t ctrl_ext; + uint32_t ctrl, ctrl_ext, led_ctrl; DEBUGFUNC("e1000_phy_hw_reset"); @@ -2053,6 +2283,21 @@ e1000_phy_hw_reset(struct e1000_hw *hw) E1000_WRITE_FLUSH(hw); } udelay(150); + + if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { + DEBUGOUT("PHY Write Error\n"); + return; + } + + /* Configure activity LED after PHY reset */ + led_ctrl = E1000_READ_REG(hw, LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= IGP_ACTIVITY_LED_ENABLE; + if(hw->mac_type == e1000_82547) + led_ctrl |= IGP_LED3_MODE; + E1000_WRITE_REG(hw, LEDCTL, led_ctrl); + } } /****************************************************************************** @@ -2079,6 +2324,9 @@ e1000_phy_reset(struct e1000_hw *hw) return -E1000_ERR_PHY; } udelay(1); + if (hw->phy_type == e1000_phy_igp) { + e1000_phy_init_script(hw); + } return 0; } @@ -2092,6 +2340,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw) { uint16_t phy_id_high, phy_id_low; boolean_t match = FALSE; + int32_t phy_init_status; DEBUGFUNC("e1000_detect_gig_phy"); @@ -2101,7 +2350,7 @@ e1000_detect_gig_phy(struct e1000_hw *hw) return -E1000_ERR_PHY; } hw->phy_id = (uint32_t) (phy_id_high << 16); - udelay(2); + udelay(20); if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; @@ -2121,11 +2370,17 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_82546: if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE; break; + case e1000_82541: + case e1000_82547: + if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; } - if(match) { + phy_init_status = e1000_set_phy_type(hw); + + if ((match) && (phy_init_status == E1000_SUCCESS)) { DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id); return 0; } @@ -2143,7 +2398,7 @@ e1000_phy_reset_dsp(struct e1000_hw *hw) { int32_t ret_val = -E1000_ERR_PHY; DEBUGFUNC("e1000_phy_reset_dsp"); - + do { if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break; if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break; @@ -2156,6 +2411,133 @@ e1000_phy_reset_dsp(struct e1000_hw *hw) } /****************************************************************************** +* Get PHY information from various PHY registers for igp PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) +{ + uint16_t phy_data, polarity, min_length, max_length, average; + + DEBUGFUNC("e1000_phy_igp_get_info"); + + /* The downshift status is checked only once, after link is established, + * and it stored in the hw->speed_downgraded parameter. */ + phy_info->downshift = hw->speed_downgraded; + + /* IGP01E1000 does not need to support it. */ + phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal; + + /* IGP01E1000 always correct polarity reversal */ + phy_info->polarity_correction = e1000_polarity_reversal_enabled; + + /* Check polarity status */ + if(e1000_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >> + IGP01E1000_PSSR_MDIX_SHIFT; + + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + /* Local/Remote Receiver Information are only valid at 1000 Mbps */ + if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + + /* Get cable length */ + if(e1000_get_cable_length(hw, &min_length, &max_length) < 0) + return -E1000_ERR_PHY; + + /* transalte to old method */ + average = (max_length + min_length) / 2; + + if(average <= e1000_igp_cable_length_50) + phy_info->cable_length = e1000_cable_length_50; + else if(average <= e1000_igp_cable_length_80) + phy_info->cable_length = e1000_cable_length_50_80; + else if(average <= e1000_igp_cable_length_110) + phy_info->cable_length = e1000_cable_length_80_110; + else if(average <= e1000_igp_cable_length_140) + phy_info->cable_length = e1000_cable_length_110_140; + else + phy_info->cable_length = e1000_cable_length_140; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** +* Get PHY information from various PHY registers fot m88 PHY only. +* +* hw - Struct containing variables accessed by shared code +* phy_info - PHY information structure +******************************************************************************/ +int32_t +e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) +{ + uint16_t phy_data, polarity; + + DEBUGFUNC("e1000_phy_m88_get_info"); + + /* The downshift status is checked only once, after link is established, + * and it stored in the hw->speed_downgraded parameter. */ + phy_info->downshift = hw->speed_downgraded; + + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->extended_10bt_distance = + (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> + M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; + phy_info->polarity_correction = + (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> + M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; + + /* Check polarity status */ + if(e1000_check_polarity(hw, &polarity) < 0) + return -E1000_ERR_PHY; + + phy_info->cable_polarity = polarity; + + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> + M88E1000_PSSR_MDIX_SHIFT; + + if(phy_data & M88E1000_PSSR_1000MBS) { + /* Cable Length Estimation and Local/Remote Receiver Informatoion + * are only valid at 1000 Mbps + */ + phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + + if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> + SR_1000T_LOCAL_RX_STATUS_SHIFT; + + phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> + SR_1000T_REMOTE_RX_STATUS_SHIFT; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** * Get PHY information from various PHY registers * * hw - Struct containing variables accessed by shared code @@ -2165,7 +2547,6 @@ int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) { - int32_t ret_val = -E1000_ERR_PHY; uint16_t phy_data; DEBUGFUNC("e1000_phy_get_info"); @@ -2173,6 +2554,7 @@ e1000_phy_get_info(struct e1000_hw *hw, phy_info->cable_length = e1000_cable_length_undefined; phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined; phy_info->cable_polarity = e1000_rev_polarity_undefined; + phy_info->downshift = e1000_downshift_undefined; phy_info->polarity_correction = e1000_polarity_reversal_undefined; phy_info->mdix_mode = e1000_auto_x_mode_undefined; phy_info->local_rx = e1000_1000t_rx_status_undefined; @@ -2183,47 +2565,23 @@ e1000_phy_get_info(struct e1000_hw *hw, return -E1000_ERR_CONFIG; } - do { - if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break; - if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { - DEBUGOUT("PHY info is only valid if link is up\n"); - return -E1000_ERR_CONFIG; - } - - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) - break; - phy_info->extended_10bt_distance = - (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >> - M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT; - phy_info->polarity_correction = - (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >> - M88E1000_PSCR_POLARITY_REVERSAL_SHIFT; - - if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) - break; - phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> - M88E1000_PSSR_REV_POLARITY_SHIFT; - phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >> - M88E1000_PSSR_MDIX_SHIFT; - if(phy_data & M88E1000_PSSR_1000MBS) { - /* Cable Length Estimation and Local/Remote Receiver Informatoion - * are only valid at 1000 Mbps - */ - phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT); - if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) - break; - phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >> - SR_1000T_LOCAL_RX_STATUS_SHIFT; - phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >> - SR_1000T_REMOTE_RX_STATUS_SHIFT; - } - ret_val = 0; - } while(0); + if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) { + DEBUGOUT("PHY info is only valid if link is up\n"); + return -E1000_ERR_CONFIG; + } - if(ret_val < 0) DEBUGOUT("PHY Read Error\n"); - return ret_val; + if (hw->phy_type == e1000_phy_igp) + return e1000_phy_igp_get_info(hw, phy_info); + else + return e1000_phy_m88_get_info(hw, phy_info); } int32_t @@ -2239,6 +2597,109 @@ e1000_validate_mdi_setting(struct e1000_hw *hw) return 0; } + +/****************************************************************************** + * Sets up eeprom variables in the hw struct. Must be called after mac_type + * is configured. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ +void +e1000_init_eeprom_params(struct e1000_hw *hw) +{ + struct e1000_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd = E1000_READ_REG(hw, EECD); + uint16_t eeprom_size; + + DEBUGFUNC("e1000_init_eeprom_params"); + + switch (hw->mac_type) { + case e1000_82542_rev2_0: + case e1000_82542_rev2_1: + case e1000_82543: + case e1000_82544: + eeprom->type = e1000_eeprom_microwire; + eeprom->word_size = 64; + eeprom->opcode_bits = 3; + eeprom->address_bits = 6; + eeprom->delay_usec = 50; + break; + case e1000_82540: + case e1000_82545: + case e1000_82546: + eeprom->type = e1000_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if(eecd & E1000_EECD_SIZE) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + break; + case e1000_82541: + case e1000_82547: + default: + if (eecd & E1000_EECD_TYPE) { + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + } else { + eeprom->type = e1000_eeprom_microwire; + eeprom->opcode_bits = 3; + eeprom->delay_usec = 50; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->word_size = 256; + eeprom->address_bits = 8; + } else { + eeprom->word_size = 64; + eeprom->address_bits = 6; + } + } + break; + } + + if (eeprom->type == e1000_eeprom_spi) { + eeprom->word_size = 64; + if (e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) { + eeprom_size &= EEPROM_SIZE_MASK; + + switch (eeprom_size) { + case EEPROM_SIZE_16KB: + eeprom->word_size = 8192; + break; + case EEPROM_SIZE_8KB: + eeprom->word_size = 4096; + break; + case EEPROM_SIZE_4KB: + eeprom->word_size = 2048; + break; + case EEPROM_SIZE_2KB: + eeprom->word_size = 1024; + break; + case EEPROM_SIZE_1KB: + eeprom->word_size = 512; + break; + case EEPROM_SIZE_512B: + eeprom->word_size = 256; + break; + case EEPROM_SIZE_128B: + default: + eeprom->word_size = 64; + break; + } + } + } +} + /****************************************************************************** * Raises the EEPROM's clock input. * @@ -2255,26 +2716,26 @@ e1000_raise_ee_clk(struct e1000_hw *hw, *eecd = *eecd | E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - udelay(50); + udelay(hw->eeprom.delay_usec); } /****************************************************************************** * Lowers the EEPROM's clock input. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * eecd - EECD's current value *****************************************************************************/ static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd) { - /* Lower the clock input to the EEPROM (by clearing the SK bit), and then - * wait 50 microseconds. + /* Lower the clock input to the EEPROM (by clearing the SK bit), and then + * wait 50 microseconds. */ *eecd = *eecd & ~E1000_EECD_SK; E1000_WRITE_REG(hw, EECD, *eecd); E1000_WRITE_FLUSH(hw); - udelay(50); + udelay(hw->eeprom.delay_usec); } /****************************************************************************** @@ -2289,16 +2750,21 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count) { + struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; uint32_t mask; /* We need to shift "count" bits out to the EEPROM. So, value in the * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. + * In order to do this, "data" must be broken down into bits. */ mask = 0x01 << (count - 1); eecd = E1000_READ_REG(hw, EECD); - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + if (eeprom->type == e1000_eeprom_microwire) { + eecd &= ~E1000_EECD_DO; + } else if (eeprom->type == e1000_eeprom_spi) { + eecd |= E1000_EECD_DO; + } do { /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1", * and then raising and then lowering the clock (the SK bit controls @@ -2313,7 +2779,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw, E1000_WRITE_REG(hw, EECD, eecd); E1000_WRITE_FLUSH(hw); - udelay(50); + udelay(eeprom->delay_usec); e1000_raise_ee_clk(hw, &eecd); e1000_lower_ee_clk(hw, &eecd); @@ -2333,7 +2799,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw, * hw - Struct containing variables accessed by shared code *****************************************************************************/ static uint16_t -e1000_shift_in_ee_bits(struct e1000_hw *hw) +e1000_shift_in_ee_bits(struct e1000_hw *hw, uint16_t count) { uint32_t eecd; uint32_t i; @@ -2351,7 +2817,7 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw) eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); data = 0; - for(i = 0; i < 16; i++) { + for(i = 0; i < count; i++) { data = data << 1; e1000_raise_ee_clk(hw, &eecd); @@ -2372,104 +2838,196 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code * - * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This + * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This * function should be called before issuing a command to the EEPROM. *****************************************************************************/ -static void -e1000_setup_eeprom(struct e1000_hw *hw) +static int32_t +e1000_acquire_eeprom(struct e1000_hw *hw) { - uint32_t eecd; + struct e1000_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd, i=0; + + DEBUGFUNC("e1000_acquire_eeprom"); eecd = E1000_READ_REG(hw, EECD); - /* Clear SK and DI */ - eecd &= ~(E1000_EECD_SK | E1000_EECD_DI); - E1000_WRITE_REG(hw, EECD, eecd); + /* Request EEPROM Access */ + if(hw->mac_type > e1000_82544) { + eecd |= E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + eecd = E1000_READ_REG(hw, EECD); + while((!(eecd & E1000_EECD_GNT)) && + (i < E1000_EEPROM_GRANT_ATTEMPTS)) { + i++; + udelay(5); + eecd = E1000_READ_REG(hw, EECD); + } + if(!(eecd & E1000_EECD_GNT)) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + DEBUGOUT("Could not acquire EEPROM grant\n"); + return -E1000_ERR_EEPROM; + } + } - /* Set CS */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); + /* Setup EEPROM for Read/Write */ + + if (eeprom->type == e1000_eeprom_microwire) { + /* Clear SK and DI */ + eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + + /* Set CS */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + } else if (eeprom->type == e1000_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + udelay(1); + } + + return E1000_SUCCESS; } /****************************************************************************** * Returns EEPROM to a "standby" state - * + * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void e1000_standby_eeprom(struct e1000_hw *hw) { + struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t eecd; eecd = E1000_READ_REG(hw, EECD); - /* Deselct EEPROM */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + if(eeprom->type == e1000_eeprom_microwire) { + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); - /* Clock high */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + /* Clock high */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); - /* Select EEPROM */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + /* Select EEPROM */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); - /* Clock low */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + /* Clock low */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); + } else if(eeprom->type == e1000_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); + eecd &= ~E1000_EECD_CS; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(eeprom->delay_usec); + } } /****************************************************************************** - * Raises then lowers the EEPROM's clock pin + * Terminates a command by inverting the EEPROM's chip select pin * * hw - Struct containing variables accessed by shared code *****************************************************************************/ static void -e1000_clock_eeprom(struct e1000_hw *hw) +e1000_release_eeprom(struct e1000_hw *hw) { uint32_t eecd; + DEBUGFUNC("e1000_release_eeprom"); + eecd = E1000_READ_REG(hw, EECD); - /* Rising edge of clock */ - eecd |= E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + if (hw->eeprom.type == e1000_eeprom_spi) { + eecd |= E1000_EECD_CS; /* Pull CS high */ + eecd &= ~E1000_EECD_SK; /* Lower SCK */ - /* Falling edge of clock */ - eecd &= ~E1000_EECD_SK; - E1000_WRITE_REG(hw, EECD, eecd); - E1000_WRITE_FLUSH(hw); - udelay(50); + E1000_WRITE_REG(hw, EECD, eecd); + + udelay(hw->eeprom.delay_usec); + } else if(hw->eeprom.type == e1000_eeprom_microwire) { + /* cleanup eeprom */ + + /* CS on Microwire is active-high */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + + E1000_WRITE_REG(hw, EECD, eecd); + + /* Rising edge of clock */ + eecd |= E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(hw->eeprom.delay_usec); + + /* Falling edge of clock */ + eecd &= ~E1000_EECD_SK; + E1000_WRITE_REG(hw, EECD, eecd); + E1000_WRITE_FLUSH(hw); + udelay(hw->eeprom.delay_usec); + } + + /* Stop requesting EEPROM access */ + if(hw->mac_type > e1000_82544) { + eecd &= ~E1000_EECD_REQ; + E1000_WRITE_REG(hw, EECD, eecd); + } } /****************************************************************************** - * Terminates a command by lowering the EEPROM's chip select pin + * Reads a 16 bit word from the EEPROM. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -static void -e1000_cleanup_eeprom(struct e1000_hw *hw) +int32_t +e1000_spi_eeprom_ready(struct e1000_hw *hw) { - uint32_t eecd; + uint16_t retry_count = 0; + uint8_t spi_stat_reg; - eecd = E1000_READ_REG(hw, EECD); + DEBUGFUNC("e1000_spi_eeprom_ready"); + + /* Read "Status Register" repeatedly until the LSB is cleared. The + * EEPROM will signal that the command has been completed by clearing + * bit 0 of the internal status register. If it's not cleared within + * 5 milliseconds, then error out. + */ + retry_count = 0; + do { + e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI, + hw->eeprom.opcode_bits); + spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8); + if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI)) + break; - eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + udelay(5); + retry_count += 5; - E1000_WRITE_REG(hw, EECD, eecd); + } while(retry_count < EEPROM_MAX_RETRY_SPI); - e1000_clock_eeprom(hw); + /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and + * only 0-5mSec on 5V devices) + */ + if(retry_count >= EEPROM_MAX_RETRY_SPI) { + DEBUGOUT("SPI EEPROM Status error\n"); + return -E1000_ERR_EEPROM; + } + + return E1000_SUCCESS; } /****************************************************************************** @@ -2477,71 +3035,76 @@ e1000_cleanup_eeprom(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code * offset - offset of word in the EEPROM to read - * data - word read from the EEPROM + * data - word read from the EEPROM + * words - number of words to read *****************************************************************************/ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data) { - uint32_t eecd; + struct e1000_eeprom_info *eeprom = &hw->eeprom; uint32_t i = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("e1000_read_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > e1000_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - udelay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } - /* Prepare the EEPROM for reading */ - e1000_setup_eeprom(hw); + /* Prepare the EEPROM for reading */ + if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the READ command (opcode + addr) */ - e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3); - if(large_eeprom) { - /* If we have a 256 word EEPROM, there are 8 address bits */ - e1000_shift_out_ee_bits(hw, offset, 8); - } else { - /* If we have a 64 word EEPROM, there are 6 address bits */ - e1000_shift_out_ee_bits(hw, offset, 6); - } + if(eeprom->type == e1000_eeprom_spi) { + uint8_t read_opcode = EEPROM_READ_OPCODE_SPI; - /* Read the data */ - *data = e1000_shift_in_ee_bits(hw); + if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; - /* End this read operation */ - e1000_standby_eeprom(hw); + e1000_standby_eeprom(hw); - /* Stop requesting EEPROM access */ - if(hw->mac_type > e1000_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + read_opcode |= EEPROM_A8_OPCODE_SPI; + + /* Send the READ command (opcode + addr) */ + e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits); + e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits); + } + else if(eeprom->type == e1000_eeprom_microwire) { + /* Send the READ command (opcode + addr) */ + e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE, + eeprom->opcode_bits); + e1000_shift_out_ee_bits(hw, offset, eeprom->address_bits); } + /* Read the data. The address of the eeprom internally increments with + * each word (microwire) or byte (spi) being read, saving on the overhead + * of eeprom setup and tear-down. The address counter will roll over if + * reading beyond the size of the eeprom, thus allowing the entire memory + * to be read starting from any offset. */ + for (i = 0; i < words; i++) { + uint16_t word_in = e1000_shift_in_ee_bits(hw, 16); + if (eeprom->type == e1000_eeprom_spi) + word_in = (word_in >> 8) | (word_in << 8); + data[i] = word_in; + } + + /* End this read operation */ + e1000_release_eeprom(hw); + return 0; } /****************************************************************************** * Verifies that the EEPROM has a valid checksum - * + * * hw - Struct containing variables accessed by shared code * * Reads the first 64 16 bit words of the EEPROM and sums the values read. @@ -2557,7 +3120,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw) DEBUGFUNC("e1000_validate_eeprom_checksum"); for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { - if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2567,7 +3130,7 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw) if(checksum == (uint16_t) EEPROM_SUM) { return 0; } else { - DEBUGOUT("EEPROM Checksum Invalid\n"); + DEBUGOUT("EEPROM Checksum Invalid\n"); return -E1000_ERR_EEPROM; } } @@ -2589,14 +3152,14 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw) DEBUGFUNC("e1000_update_eeprom_checksum"); for(i = 0; i < EEPROM_CHECKSUM_REG; i++) { - if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } checksum += eeprom_data; } checksum = (uint16_t) EEPROM_SUM - checksum; - if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) { + if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) { DEBUGOUT("EEPROM Write Error\n"); return -E1000_ERR_EEPROM; } @@ -2604,118 +3167,201 @@ e1000_update_eeprom_checksum(struct e1000_hw *hw) } /****************************************************************************** - * Writes a 16 bit word to a given offset in the EEPROM. + * Parent function for writing words to the different EEPROM types. * * hw - Struct containing variables accessed by shared code * offset - offset within the EEPROM to be written to - * data - 16 bit word to be writen to the EEPROM + * words - number of words to write + * data - 16 bit word to be written to the EEPROM * - * If e1000_update_eeprom_checksum is not called after this function, the + * If e1000_update_eeprom_checksum is not called after this function, the * EEPROM will most likely contain an invalid checksum. *****************************************************************************/ int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t offset, - uint16_t data) + uint16_t words, + uint16_t *data) { - uint32_t eecd; - uint32_t i = 0; + struct e1000_eeprom_info *eeprom = &hw->eeprom; int32_t status = 0; - boolean_t large_eeprom = FALSE; DEBUGFUNC("e1000_write_eeprom"); - /* Request EEPROM Access */ - if(hw->mac_type > e1000_82544) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE; - eecd |= E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - eecd = E1000_READ_REG(hw, EECD); - while((!(eecd & E1000_EECD_GNT)) && (i < 100)) { - i++; - udelay(5); - eecd = E1000_READ_REG(hw, EECD); - } - if(!(eecd & E1000_EECD_GNT)) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); - DEBUGOUT("Could not acquire EEPROM grant\n"); - return -E1000_ERR_EEPROM; - } + /* A check for invalid values: offset too large, too many words, and not + * enough words. + */ + if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) || + (words == 0)) { + DEBUGOUT("\"words\" parameter out of bounds\n"); + return -E1000_ERR_EEPROM; } /* Prepare the EEPROM for writing */ - e1000_setup_eeprom(hw); + if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; - /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM - * into write/erase mode. - */ - e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5); - if(large_eeprom) - e1000_shift_out_ee_bits(hw, 0, 6); + if(eeprom->type == e1000_eeprom_microwire) + status = e1000_write_eeprom_microwire(hw, offset, words, data); else - e1000_shift_out_ee_bits(hw, 0, 4); + status = e1000_write_eeprom_spi(hw, offset, words, data); - /* Prepare the EEPROM */ - e1000_standby_eeprom(hw); + /* Done with writing */ + e1000_release_eeprom(hw); - /* Send the Write command (3-bit opcode + addr) */ - e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3); - if(large_eeprom) - /* If we have a 256 word EEPROM, there are 8 address bits */ - e1000_shift_out_ee_bits(hw, offset, 8); - else - /* If we have a 64 word EEPROM, there are 6 address bits */ - e1000_shift_out_ee_bits(hw, offset, 6); + return status; +} + +/****************************************************************************** + * Writes a 16 bit word to a given offset in an SPI EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 8 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +e1000_write_eeprom_spi(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct e1000_eeprom_info *eeprom = &hw->eeprom; + uint16_t widx = 0; - /* Send the data */ - e1000_shift_out_ee_bits(hw, data, 16); + DEBUGFUNC("e1000_write_eeprom_spi"); - /* Toggle the CS line. This in effect tells to EEPROM to actually execute - * the command in question. - */ - e1000_standby_eeprom(hw); + while (widx < words) { + uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI; - /* Now read DO repeatedly until is high (equal to '1'). The EEEPROM will - * signal that the command has been completed by raising the DO signal. - * If DO does not go high in 10 milliseconds, then error out. - */ - for(i = 0; i < 200; i++) { - eecd = E1000_READ_REG(hw, EECD); - if(eecd & E1000_EECD_DO) break; - udelay(50); - } - if(i == 200) { - DEBUGOUT("EEPROM Write did not complete\n"); - status = -E1000_ERR_EEPROM; + if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM; + + e1000_standby_eeprom(hw); + + /* Send the WRITE ENABLE command (8 bit opcode ) */ + e1000_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI, + eeprom->opcode_bits); + + e1000_standby_eeprom(hw); + + /* Some SPI eeproms use the 8th address bit embedded in the opcode */ + if((eeprom->address_bits == 8) && (offset >= 128)) + write_opcode |= EEPROM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + e1000_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits); + + e1000_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2), + eeprom->address_bits); + + /* Send the data */ + + /* Loop to allow for up to whole page write (32 bytes) of eeprom */ + while (widx < words) { + uint16_t word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + e1000_shift_out_ee_bits(hw, word_out, 16); + widx++; + + /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE + * operation, while the smaller eeproms are capable of an 8-byte + * PAGE WRITE operation. Break the inner loop to pass new address + */ + if((((offset + widx)*2) % eeprom->page_size) == 0) { + e1000_standby_eeprom(hw); + break; + } + } } - /* Recover from write */ - e1000_standby_eeprom(hw); + return E1000_SUCCESS; +} - /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command - * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM - * out of write/erase mode. +/****************************************************************************** + * Writes a 16 bit word to a given offset in a Microwire EEPROM. + * + * hw - Struct containing variables accessed by shared code + * offset - offset within the EEPROM to be written to + * words - number of words to write + * data - pointer to array of 16 bit words to be written to the EEPROM + * + *****************************************************************************/ +int32_t +e1000_write_eeprom_microwire(struct e1000_hw *hw, + uint16_t offset, + uint16_t words, + uint16_t *data) +{ + struct e1000_eeprom_info *eeprom = &hw->eeprom; + uint32_t eecd; + uint16_t words_written = 0; + uint16_t i = 0; + + DEBUGFUNC("e1000_write_eeprom_microwire"); + + /* Send the write enable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 11). It's less work to include + * the 11 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This puts the + * EEPROM into write/erase mode. */ - e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5); - if(large_eeprom) - e1000_shift_out_ee_bits(hw, 0, 6); - else - e1000_shift_out_ee_bits(hw, 0, 4); + e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); - /* Done with writing */ - e1000_cleanup_eeprom(hw); + e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); - /* Stop requesting EEPROM access */ - if(hw->mac_type > e1000_82544) { - eecd = E1000_READ_REG(hw, EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, EECD, eecd); + /* Prepare the EEPROM */ + e1000_standby_eeprom(hw); + + while (words_written < words) { + /* Send the Write command (3-bit opcode + addr) */ + e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE, + eeprom->opcode_bits); + + e1000_shift_out_ee_bits(hw, (uint16_t)(offset + words_written), + eeprom->address_bits); + + /* Send the data */ + e1000_shift_out_ee_bits(hw, data[words_written], 16); + + /* Toggle the CS line. This in effect tells the EEPROM to execute + * the previous command. + */ + e1000_standby_eeprom(hw); + + /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will + * signal that the command has been completed by raising the DO signal. + * If DO does not go high in 10 milliseconds, then error out. + */ + for(i = 0; i < 200; i++) { + eecd = E1000_READ_REG(hw, EECD); + if(eecd & E1000_EECD_DO) break; + udelay(50); + } + if(i == 200) { + DEBUGOUT("EEPROM Write did not complete\n"); + return -E1000_ERR_EEPROM; + } + + /* Recover from write */ + e1000_standby_eeprom(hw); + + words_written++; } - return status; + /* Send the write disable command to the EEPROM (3-bit opcode plus + * 6/8-bit dummy address beginning with 10). It's less work to include + * the 10 of the dummy address as part of the opcode than it is to shift + * it over the correct number of bits for the address. This takes the + * EEPROM out of write/erase mode. + */ + e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE, + (uint16_t)(eeprom->opcode_bits + 2)); + + e1000_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2)); + + return 0; } /****************************************************************************** @@ -2734,7 +3380,7 @@ e1000_read_part_num(struct e1000_hw *hw, DEBUGFUNC("e1000_read_part_num"); /* Get word 0 from EEPROM */ - if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2742,7 +3388,7 @@ e1000_read_part_num(struct e1000_hw *hw, *part_num = (uint32_t) (eeprom_data << 16); /* Get word 1 from EEPROM */ - if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2768,7 +3414,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) { offset = i >> 1; - if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) { + if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } @@ -2790,7 +3436,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) /****************************************************************************** * Initializes receive address filters. * - * hw - Struct containing variables accessed by shared code + * hw - Struct containing variables accessed by shared code * * Places the MAC address in receive address register 0 and clears the rest * of the receive addresss registers. Clears the multicast table. Assumes @@ -2835,7 +3481,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers - * for the first 15 multicast addresses, and hashes the rest into the + * for the first 15 multicast addresses, and hashes the rest into the * multicast table. *****************************************************************************/ void @@ -2884,7 +3530,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, DEBUGOUT1(" Hash value = 0x%03X\n", hash_value); /* Place this multicast address in the RAR if there is room, * - * else put it in the MTA + * else put it in the MTA */ if(rar_used_count < E1000_RAR_ENTRIES) { e1000_rar_set(hw, @@ -2902,7 +3548,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, * 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 + * mc_addr - the multicast address to hash *****************************************************************************/ uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, @@ -2911,7 +3557,7 @@ e1000_hash_mc_addr(struct e1000_hw *hw, uint32_t hash_value = 0; /* The portion of the address that is used for the hash table is - * determined by the mc_filter_type setting. + * determined by the mc_filter_type setting. */ switch (hw->mc_filter_type) { /* [0] [1] [2] [3] [4] [5] @@ -2954,12 +3600,12 @@ e1000_mta_set(struct e1000_hw *hw, uint32_t mta; uint32_t temp; - /* The MTA is a register array of 128 32-bit registers. - * It is treated like an array of 4096 bits. We want to set + /* The MTA is a register array of 128 32-bit registers. + * It is treated like an array of 4096 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 + * 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 >> 5) & 0x7F; @@ -2997,7 +3643,7 @@ e1000_rar_set(struct e1000_hw *hw, uint32_t rar_low, rar_high; /* HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian + * from network order (big endian) to little endian */ rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) | @@ -3055,24 +3701,24 @@ e1000_id_led_init(struct e1000_hw * hw) const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF; uint16_t eeprom_data, i, temp; const uint16_t led_mask = 0x0F; - + DEBUGFUNC("e1000_id_led_init"); - + if(hw->mac_type < e1000_82540) { /* Nothing to do */ return 0; } - + ledctl = E1000_READ_REG(hw, LEDCTL); hw->ledctl_default = ledctl; hw->ledctl_mode1 = hw->ledctl_default; hw->ledctl_mode2 = hw->ledctl_default; - - if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) { + + if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) { DEBUGOUT("EEPROM Read Error\n"); return -E1000_ERR_EEPROM; } - if((eeprom_data== ID_LED_RESERVED_0000) || + if((eeprom_data== ID_LED_RESERVED_0000) || (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT; for(i = 0; i < 4; i++) { temp = (eeprom_data >> (i << 2)) & led_mask; @@ -3123,9 +3769,9 @@ int32_t e1000_setup_led(struct e1000_hw *hw) { uint32_t ledctl; - + DEBUGFUNC("e1000_setup_led"); - + switch(hw->device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: @@ -3143,7 +3789,7 @@ e1000_setup_led(struct e1000_hw *hw) hw->ledctl_default = ledctl; /* Turn off LED0 */ ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | + E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED0_MODE_MASK); ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT); E1000_WRITE_REG(hw, LEDCTL, ledctl); @@ -3155,6 +3801,9 @@ e1000_setup_led(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); break; default: @@ -3193,6 +3842,9 @@ e1000_cleanup_led(struct e1000_hw *hw) case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: /* Restore LEDCTL settings */ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default); break; @@ -3202,7 +3854,7 @@ e1000_cleanup_led(struct e1000_hw *hw) } return 0; } - + /****************************************************************************** * Turns on the software controllable LED * @@ -3244,6 +3896,9 @@ e1000_led_on(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2); break; default: @@ -3294,6 +3949,9 @@ e1000_led_off(struct e1000_hw *hw) case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82541EI: + case E1000_DEV_ID_82541EP: + case E1000_DEV_ID_82547EI: E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1); break; default: @@ -3304,7 +3962,7 @@ e1000_led_off(struct e1000_hw *hw) } /****************************************************************************** - * Clears all hardware statistics counters. + * Clears all hardware statistics counters. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ @@ -3423,7 +4081,7 @@ e1000_update_adaptive(struct e1000_hw *hw) DEBUGFUNC("e1000_update_adaptive"); if(hw->adaptive_ifs) { - if((hw->collision_delta * hw->ifs_ratio) > + if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) { if(hw->tx_packet_delta > MIN_NUM_XMITS) { hw->in_ifs_mode = TRUE; @@ -3436,7 +4094,7 @@ e1000_update_adaptive(struct e1000_hw *hw) } } } else { - if((hw->in_ifs_mode == TRUE) && + if((hw->in_ifs_mode == TRUE) && (hw->tx_packet_delta <= MIN_NUM_XMITS)) { hw->current_ifs_val = 0; hw->in_ifs_mode = FALSE; @@ -3450,7 +4108,7 @@ e1000_update_adaptive(struct e1000_hw *hw) /****************************************************************************** * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT - * + * * hw - Struct containing variables accessed by shared code * frame_len - The length of the frame in question * mac_addr - The Ethernet destination address of the frame in question @@ -3478,16 +4136,16 @@ e1000_tbi_adjust_stats(struct e1000_hw *hw, carry_bit = 0x80000000 & stats->gorcl; stats->gorcl += frame_len; /* If the high bit of Gorcl (the low 32 bits of the Good Octets - * Received Count) was one before the addition, - * AND it is zero after, then we lost the carry out, + * Received Count) was one before the addition, + * AND it is zero after, then we lost the carry out, * need to add one to Gorch (Good Octets Received Count High). - * This could be simplified if all environments supported + * This could be simplified if all environments supported * 64-bit integers. */ if(carry_bit && ((stats->gorcl & 0x80000000) == 0)) stats->gorch++; /* Is this a broadcast or multicast? Check broadcast first, - * since the test for a multicast frame will test positive on + * since the test for a multicast frame will test positive on * a broadcast frame. */ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff)) @@ -3608,3 +4266,221 @@ e1000_write_reg_io(struct e1000_hw *hw, e1000_io_write(hw, io_data, value); } + +/****************************************************************************** + * Estimates the cable length. + * + * hw - Struct containing variables accessed by shared code + * min_length - The estimated minimum length + * max_length - The estimated maximum length + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * This function always returns a ranged length (minimum & maximum). + * So for M88 phy's, this function interprets the one value returned from the + * register to the minimum and maximum range. + * For IGP phy's, the function calculates the range by the AGC registers. + *****************************************************************************/ +int32_t +e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, + uint16_t *max_length) +{ + uint16_t agc_value = 0; + uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE; + uint16_t i, phy_data; + + DEBUGFUNC("e1000_get_cable_length"); + + *min_length = *max_length = 0; + + /* Use old method for Phy older than IGP */ + if(hw->phy_type == e1000_phy_m88) { + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* Convert the enum value to ranged values */ + switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT) { + case e1000_cable_length_50: + *min_length = 0; + *max_length = e1000_igp_cable_length_50; + break; + case e1000_cable_length_50_80: + *min_length = e1000_igp_cable_length_50; + *max_length = e1000_igp_cable_length_80; + break; + case e1000_cable_length_80_110: + *min_length = e1000_igp_cable_length_80; + *max_length = e1000_igp_cable_length_110; + break; + case e1000_cable_length_110_140: + *min_length = e1000_igp_cable_length_110; + *max_length = e1000_igp_cable_length_140; + break; + case e1000_cable_length_140: + *min_length = e1000_igp_cable_length_140; + *max_length = e1000_igp_cable_length_170; + break; + default: + return -E1000_ERR_PHY; + break; + } + } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */ + uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A, + IGP01E1000_PHY_AGC_B, + IGP01E1000_PHY_AGC_C, + IGP01E1000_PHY_AGC_D}; + /* Read the AGC registers for all channels */ + for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) { + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + agc_reg_array[i]) != E1000_SUCCESS) + return -E1000_ERR_PHY; + if(e1000_read_phy_reg(hw, agc_reg_array[i] & + IGP01E1000_PHY_PAGE_SELECT, &phy_data) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT; + + /* Array bound check. */ + if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || + (cur_agc == 0)) + return -E1000_ERR_PHY; + + agc_value += cur_agc; + + /* Update minimal AGC value. */ + if(min_agc > cur_agc) + min_agc = cur_agc; + } + + /* Return to page 0 */ + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + /* Remove the minimal AGC result for length < 50m */ + if(agc_value < IGP01E1000_PHY_AGC_NUM * e1000_igp_cable_length_50) { + agc_value -= min_agc; + + /* Get the average length of the remaining 3 channels */ + agc_value /= (IGP01E1000_PHY_AGC_NUM - 1); + } else { + /* Get the average length of all the 4 channels. */ + agc_value /= IGP01E1000_PHY_AGC_NUM; + } + + /* Set the range of the calculated length. */ + *min_length = ((e1000_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) > 0) ? + (e1000_igp_cable_length_table[agc_value] - + IGP01E1000_AGC_RANGE) : 0; + *max_length = e1000_igp_cable_length_table[agc_value] + + IGP01E1000_AGC_RANGE; + } + + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check the cable polarity + * + * hw - Struct containing variables accessed by shared code + * polarity - output parameter : 0 - Polarity is not reversed + * 1 - Polarity is reversed. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * For phy's older then IGP, this function simply reads the polarity bit in the + * Phy Status register. For IGP phy's, this bit is valid only if link speed is + * 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will + * return 0. If the link speed is 1000 Mbps the polarity status is in the + * IGP01E1000_PHY_PCS_INIT_REG. + *****************************************************************************/ +int32_t +e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity) +{ + uint16_t phy_data; + + DEBUGFUNC("e1000_check_polarity"); + + if(hw->phy_type == e1000_phy_m88) { + /* return the Polarity bit in the Status register. */ + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >> + M88E1000_PSSR_REV_POLARITY_SHIFT; + } else if(hw->phy_type == e1000_phy_igp) { + /* Read the Status register to check the speed */ + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to + * find the polarity status */ + if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + + /* Read the GIG initialization PCS register (0x00B4) */ + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_PCS_INIT_REG) < 0) + return -E1000_ERR_PHY; + + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG & + IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0) + return -E1000_ERR_PHY; + + /* Return to page 0 */ + if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) != + E1000_SUCCESS) + return -E1000_ERR_PHY; + + /* Check the polarity bits */ + *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0; + } else { + /* For 10 Mbps, read the polarity bit in the status register. (for + * 100 Mbps this bit is always 0) */ + *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED; + } + } + return E1000_SUCCESS; +} + +/****************************************************************************** + * Check if Downshift occured + * + * hw - Struct containing variables accessed by shared code + * downshift - output parameter : 0 - No Downshift ocured. + * 1 - Downshift ocured. + * + * returns: E1000_SUCCESS / -E1000_ERR_XXX + * + * For phy's older then IGP, this function reads the Downshift bit in the Phy + * Specific Status register. For IGP phy's, it reads the Downgrade bit in the + * Link Health register. In IGP this bit is latched high, so the driver must + * read it immediately after link is established. + *****************************************************************************/ +int32_t +e1000_check_downshift(struct e1000_hw *hw) +{ + uint16_t phy_data; + + DEBUGFUNC("e1000_check_downshift"); + + if(hw->phy_type == e1000_phy_igp) { + if(e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; + } + else if(hw->phy_type == e1000_phy_m88) { + if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { + DEBUGOUT("PHY Read Error\n"); + return -E1000_ERR_PHY; + } + hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >> + M88E1000_PSSR_DOWNSHIFT_SHIFT; + } + return E1000_SUCCESS; +} + diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 812dfd140f35..3fe0febaa7e7 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -33,6 +33,7 @@ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ + #include "e1000_osdep.h" /* Forward declarations of structures used by the shared code */ @@ -50,9 +51,18 @@ typedef enum { e1000_82540, e1000_82545, e1000_82546, + e1000_82541, + e1000_82547, e1000_num_macs } e1000_mac_type; +typedef enum { + e1000_eeprom_uninitialized = 0, + e1000_eeprom_spi, + e1000_eeprom_microwire, + e1000_num_eeprom_types +} e1000_eeprom_type; + /* Media Types */ typedef enum { e1000_media_type_copper = 0, @@ -111,6 +121,27 @@ typedef enum { } e1000_cable_length; typedef enum { + e1000_igp_cable_length_10 = 10, + e1000_igp_cable_length_20 = 20, + e1000_igp_cable_length_30 = 30, + e1000_igp_cable_length_40 = 40, + e1000_igp_cable_length_50 = 50, + e1000_igp_cable_length_60 = 60, + e1000_igp_cable_length_70 = 70, + e1000_igp_cable_length_80 = 80, + e1000_igp_cable_length_90 = 90, + e1000_igp_cable_length_100 = 100, + e1000_igp_cable_length_110 = 110, + e1000_igp_cable_length_120 = 120, + e1000_igp_cable_length_130 = 130, + e1000_igp_cable_length_140 = 140, + e1000_igp_cable_length_150 = 150, + e1000_igp_cable_length_160 = 160, + e1000_igp_cable_length_170 = 170, + e1000_igp_cable_length_180 = 180 +} e1000_igp_cable_length; + +typedef enum { e1000_10bt_ext_dist_enable_normal = 0, e1000_10bt_ext_dist_enable_lower, e1000_10bt_ext_dist_enable_undefined = 0xFF @@ -123,6 +154,12 @@ typedef enum { } e1000_rev_polarity; typedef enum { + e1000_downshift_normal = 0, + e1000_downshift_activated, + e1000_downshift_undefined = 0xFF +} e1000_downshift; + +typedef enum { e1000_polarity_reversal_enabled = 0, e1000_polarity_reversal_disabled, e1000_polarity_reversal_undefined = 0xFF @@ -142,10 +179,17 @@ typedef enum { e1000_1000t_rx_status_undefined = 0xFF } e1000_1000t_rx_status; +typedef enum { + e1000_phy_m88 = 0, + e1000_phy_igp, + e1000_phy_undefined = 0xFF +} e1000_phy_type; + struct e1000_phy_info { e1000_cable_length cable_length; e1000_10bt_ext_dist_enable extended_10bt_distance; e1000_rev_polarity cable_polarity; + e1000_downshift downshift; e1000_polarity_reversal polarity_correction; e1000_auto_x_mode mdix_mode; e1000_1000t_rx_status local_rx; @@ -157,6 +201,15 @@ struct e1000_phy_stats { uint32_t receive_errors; }; +struct e1000_eeprom_info { + e1000_eeprom_type type; + uint16_t word_size; + uint16_t opcode_bits; + uint16_t address_bits; + uint16_t delay_usec; + uint16_t page_size; +}; + /* Error Codes */ @@ -166,6 +219,7 @@ struct e1000_phy_stats { #define E1000_ERR_CONFIG 3 #define E1000_ERR_PARAM 4 #define E1000_ERR_MAC_TYPE 5 +#define E1000_ERR_PHY_TYPE 6 /* Function prototypes */ /* Initialization */ @@ -189,13 +243,19 @@ void e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); int32_t e1000_detect_gig_phy(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); +int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); +int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); +int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length); +int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity); +int32_t e1000_check_downshift(struct e1000_hw *hw); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); /* EEPROM Functions */ -int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data); +void e1000_init_eeprom_params(struct e1000_hw *hw); +int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw); int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw); -int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t data); +int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num); int32_t e1000_read_mac_addr(struct e1000_hw * hw); @@ -231,6 +291,7 @@ uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port); uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); + #define E1000_READ_REG_IO(a, reg) \ e1000_read_reg_io((a), E1000_##reg) #define E1000_WRITE_REG_IO(a, reg, val) \ @@ -253,7 +314,10 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define NUM_DEV_IDS 16 +#define E1000_DEV_ID_82541EI 0x1013 +#define E1000_DEV_ID_82541EP 0x1018 +#define E1000_DEV_ID_82547EI 0x1019 +#define NUM_DEV_IDS 19 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -298,7 +362,7 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); /* This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error + * o RXSEQ = Receive Sequence Error */ #define POLL_IMS_ENABLE_MASK ( \ E1000_IMS_RXDMT0 | \ @@ -322,9 +386,9 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); /* The number of high/low register pairs in the RAR. The RAR (Receive Address * Registers) holds the directed and multicast addresses that we monitor. We * reserve one of these spots for our directed address, allowing us room for - * E1000_RAR_ENTRIES - 1 multicast addresses. + * E1000_RAR_ENTRIES - 1 multicast addresses. */ -#define E1000_RAR_ENTRIES 16 +#define E1000_RAR_ENTRIES 15 #define MIN_NUMBER_OF_DESCRIPTORS 8 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8 @@ -523,7 +587,7 @@ struct e1000_ffvt_entry { /* Register Set. (82543, 82544) * * Registers are defined to be 32 bits and should be accessed as 32 bit values. - * These registers are physically located on the NIC, but are mapped into the + * These registers are physically located on the NIC, but are mapped into the * host memory address space. * * RW - register is both readable and writable @@ -537,6 +601,7 @@ struct e1000_ffvt_entry { #define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define E1000_EERD 0x00014 /* EEPROM Read - RW */ #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_FLA 0x0001C /* Flash Access Register - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ @@ -569,6 +634,11 @@ struct e1000_ffvt_entry { #define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */ #define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ +#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ +#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ +#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ +#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */ +#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ #define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ #define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ #define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ @@ -664,6 +734,7 @@ struct e1000_ffvt_entry { #define E1000_82542_EECD E1000_EECD #define E1000_82542_EERD E1000_EERD #define E1000_82542_CTRL_EXT E1000_CTRL_EXT +#define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH @@ -705,6 +776,9 @@ struct e1000_ffvt_entry { #define E1000_82542_RADV E1000_RADV #define E1000_82542_RSRPD E1000_RSRPD #define E1000_82542_TXDMAC E1000_TXDMAC +#define E1000_82542_TDFHS E1000_TDFHS +#define E1000_82542_TDFTS E1000_TDFTS +#define E1000_82542_TDFPC E1000_TDFPC #define E1000_82542_TXDCTL E1000_TXDCTL #define E1000_82542_TADV E1000_TADV #define E1000_82542_TSPMT E1000_TSPMT @@ -777,6 +851,8 @@ struct e1000_ffvt_entry { #define E1000_82542_WUPL E1000_WUPL #define E1000_82542_WUPM E1000_WUPM #define E1000_82542_FFLT E1000_FFLT +#define E1000_82542_TDFH 0x08010 +#define E1000_82542_TDFT 0x08018 #define E1000_82542_FFMT E1000_FFMT #define E1000_82542_FFVT E1000_FFVT @@ -846,12 +922,15 @@ struct e1000_hw_stats { struct e1000_hw { uint8_t *hw_addr; e1000_mac_type mac_type; + e1000_phy_type phy_type; + uint32_t phy_init_script; e1000_media_type media_type; void *back; e1000_fc_type fc; e1000_bus_speed bus_speed; e1000_bus_width bus_width; e1000_bus_type bus_type; + struct e1000_eeprom_info eeprom; uint32_t io_base; uint32_t phy_id; uint32_t phy_revision; @@ -891,6 +970,7 @@ struct e1000_hw { uint8_t mac_addr[NODE_ADDRESS_SIZE]; uint8_t perm_mac_addr[NODE_ADDRESS_SIZE]; boolean_t disable_polarity_correction; + boolean_t speed_downgraded; boolean_t get_link_status; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; @@ -967,14 +1047,20 @@ struct e1000_hw { #define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */ #define E1000_EECD_DI 0x00000004 /* EEPROM Data In */ #define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 +#define E1000_EECD_FWE_MASK 0x00000030 #define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ #define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ #define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ #define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */ #define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */ #define E1000_EECD_PRES 0x00000100 /* EEPROM Present */ +#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */ +#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type + * (0-small, 1-large) */ +#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */ +#ifndef E1000_EEPROM_GRANT_ATTEMPTS +#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */ +#endif /* EEPROM Read */ #define E1000_EERD_START 0x00000001 /* Start Read */ @@ -984,8 +1070,15 @@ struct e1000_hw { #define E1000_EERD_DATA_SHIFT 16 #define E1000_EERD_DATA_MASK 0xFFFF0000 /* Read Data */ +/* SPI EEPROM Status Register */ +#define EEPROM_STATUS_RDY_SPI 0x01 +#define EEPROM_STATUS_WEN_SPI 0x02 +#define EEPROM_STATUS_BP0_SPI 0x04 +#define EEPROM_STATUS_BP1_SPI 0x08 +#define EEPROM_STATUS_WPEN_SPI 0x80 + /* Extended Device Control */ -#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ +#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ #define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ #define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN #define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ @@ -1239,6 +1332,7 @@ struct e1000_hw { #define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ #define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ #define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ +#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -1282,7 +1376,7 @@ struct e1000_hw { #define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ #define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ #define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery +#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery * Filtering */ #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ @@ -1302,18 +1396,40 @@ struct e1000_hw { #define E1000_MDALIGN 4096 -/* EEPROM Commands */ -#define EEPROM_READ_OPCODE 0x6 /* EERPOM read opcode */ -#define EEPROM_WRITE_OPCODE 0x5 /* EERPOM write opcode */ -#define EEPROM_ERASE_OPCODE 0x7 /* EERPOM erase opcode */ -#define EEPROM_EWEN_OPCODE 0x13 /* EERPOM erase/write enable */ -#define EEPROM_EWDS_OPCODE 0x10 /* EERPOM erast/write disable */ +/* EEPROM Commands - Microwire */ +#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ +#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */ +#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */ +#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */ + +/* EEPROM Commands - SPI */ +#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define EEPROM_READ_OPCODE_SPI 0x3 /* EEPROM read opcode */ +#define EEPROM_WRITE_OPCODE_SPI 0x2 /* EEPROM write opcode */ +#define EEPROM_A8_OPCODE_SPI 0x8 /* opcode bit-3 = address bit-8 */ +#define EEPROM_WREN_OPCODE_SPI 0x6 /* EEPROM set Write Enable latch */ +#define EEPROM_WRDI_OPCODE_SPI 0x4 /* EEPROM reset Write Enable latch */ +#define EEPROM_RDSR_OPCODE_SPI 0x5 /* EEPROM read Status register */ +#define EEPROM_WRSR_OPCODE_SPI 0x1 /* EEPROM write Status register */ + +/* EEPROM Size definitions */ +#define EEPROM_SIZE_16KB 0x1800 +#define EEPROM_SIZE_8KB 0x1400 +#define EEPROM_SIZE_4KB 0x1000 +#define EEPROM_SIZE_2KB 0x0C00 +#define EEPROM_SIZE_1KB 0x0800 +#define EEPROM_SIZE_512B 0x0400 +#define EEPROM_SIZE_128B 0x0000 +#define EEPROM_SIZE_MASK 0x1C00 + /* EEPROM Word Offsets */ #define EEPROM_COMPAT 0x0003 #define EEPROM_ID_LED_SETTINGS 0x0004 #define EEPROM_INIT_CONTROL1_REG 0x000A #define EEPROM_INIT_CONTROL2_REG 0x000F +#define EEPROM_CFG 0x0012 #define EEPROM_FLASH_VERSION 0x0032 #define EEPROM_CHECKSUM_REG 0x003F @@ -1334,9 +1450,10 @@ struct e1000_hw { #define ID_LED_OFF1_ON2 0x8 #define ID_LED_OFF1_OFF2 0x9 -/* Mask bits for fields in Word 0x03 of the EEPROM */ -#define EEPROM_COMPAT_SERVER 0x0400 -#define EEPROM_COMPAT_CLIENT 0x0200 +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + /* Mask bits for fields in Word 0x0a of the EEPROM */ #define EEPROM_WORD0A_ILOS 0x0010 @@ -1409,7 +1526,9 @@ struct e1000_hw { /* PBA constants */ #define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_22K 0x0016 #define E1000_PBA_24K 0x0018 +#define E1000_PBA_30K 0x001E #define E1000_PBA_40K 0x0028 #define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */ @@ -1438,26 +1557,26 @@ struct e1000_hw { /* The number of bits that we need to shift right to move the "pause" * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field - * in the TXCW register + * in the TXCW register */ #define PAUSE_SHIFT 5 /* The number of bits that we need to shift left to move the "SWDPIO" * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field - * in the CTRL register + * in the CTRL register */ #define SWDPIO_SHIFT 17 /* The number of bits that we need to shift left to move the "SWDPIO_EXT" * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The * Extended CTRL register. - * in the CTRL register + * in the CTRL register */ #define SWDPIO__EXT_SHIFT 4 /* The number of bits that we need to shift left to move the "ILOS" * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field - * in the CTRL register + * in the CTRL register */ #define ILOS_SHIFT 3 @@ -1475,7 +1594,7 @@ struct e1000_hw { /* TBI_ACCEPT macro definition: * * This macro requires: - * adapter = a pointer to struct e1000_hw + * adapter = a pointer to struct e1000_hw * status = the 8 bit status field of the RX descriptor with EOP set * error = the 8 bit error field of the RX descriptor with EOP set * length = the sum of all the length fields of the RX descriptors that @@ -1484,7 +1603,7 @@ struct e1000_hw { * max_frame_length = the maximum frame length we want to accept. * min_frame_length = the minimum frame length we want to accept. * - * This macro is a conditional that should be used in the interrupt + * This macro is a conditional that should be used in the interrupt * handler's Rx processing routine when RxErrors have been detected. * * Typical use: @@ -1547,6 +1666,29 @@ struct e1000_hw { #define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ #define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */ +#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */ +#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */ + +/* IGP01E1000 AGC Registers - stores the cable length values*/ +#define IGP01E1000_PHY_AGC_A 0x1172 +#define IGP01E1000_PHY_AGC_B 0x1272 +#define IGP01E1000_PHY_AGC_C 0x1472 +#define IGP01E1000_PHY_AGC_D 0x1872 + +/* Number of AGC registers */ +#define IGP01E1000_PHY_AGC_NUM 4 + +/* IGP01E1000 PCS Initialization register - stores the polarity status when + * speed = 1000 Mbps. */ +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 + + #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ /* PHY Control Register */ @@ -1608,7 +1750,7 @@ struct e1000_hw { #define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ #define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ #define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ -#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */ +#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ /* Next Page TX Register */ #define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */ @@ -1619,7 +1761,7 @@ struct e1000_hw { * 0 = cannot comply with msg */ #define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ -#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow +#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow * 0 = sending last NP */ @@ -1628,13 +1770,13 @@ struct e1000_hw { #define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges * of different NP */ -#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg +#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg * 0 = cannot comply with msg */ #define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */ #define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */ #define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow - * 0 = sending last NP + * 0 = sending last NP */ /* 1000BASE-T Control Register */ @@ -1681,20 +1823,20 @@ struct e1000_hw { #define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ #define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ #define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ -#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, +#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, * 0=CLK125 toggling */ #define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ /* Manual MDI configuration */ #define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ #define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, - * 100BASE-TX/10BASE-T: + * 100BASE-TX/10BASE-T: * MDI Mode */ -#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled - * all speeds. +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled + * all speeds. */ -#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 +#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance * (Lower 10BASE-T RX Threshold) * 0=Normal 10BASE-T RX Threshold */ @@ -1712,6 +1854,7 @@ struct e1000_hw { /* M88E1000 PHY Specific Status Register */ #define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ #define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ #define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ #define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M; * 3=110-140M;4=>140M */ @@ -1725,6 +1868,7 @@ struct e1000_hw { #define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ #define M88E1000_PSSR_REV_POLARITY_SHIFT 1 +#define M88E1000_PSSR_DOWNSHIFT_SHIFT 5 #define M88E1000_PSSR_MDIX_SHIFT 6 #define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 @@ -1733,12 +1877,12 @@ struct e1000_hw { #define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled. * Will assert lost lock and bring * link down if idle not seen - * within 1ms in 1000BASE-T + * within 1ms in 1000BASE-T */ /* Number of times we will attempt to autonegotiate before downshifting if we * are the master */ #define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 @@ -1753,10 +1897,93 @@ struct e1000_hw { #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ #define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ + +/* IGP01E1000 Specific Port Config Register - R/W */ +#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010 +#define IGP01E1000_PSCFR_PRE_EN 0x0020 +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 +#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK 0x0100 +#define IGP01E1000_PSCFR_DISABLE_JABBER 0x0400 +#define IGP01E1000_PSCFR_DISABLE_TRANSMIT 0x2000 + +/* IGP01E1000 Specific Port Status Register - R/O */ +#define IGP01E1000_PSSR_AUTONEG_FAILED 0x0001 /* RO LH SC */ +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_CABLE_LENGTH 0x007C +#define IGP01E1000_PSSR_FULL_DUPLEX 0x0200 +#define IGP01E1000_PSSR_LINK_UP 0x0400 +#define IGP01E1000_PSSR_MDIX 0x0800 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 /* speed bits mask */ +#define IGP01E1000_PSSR_SPEED_10MBPS 0x4000 +#define IGP01E1000_PSSR_SPEED_100MBPS 0x8000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 +#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT 0x0002 /* shift right 2 */ +#define IGP01E1000_PSSR_MDIX_SHIFT 0x000B /* shift right 11 */ + +/* IGP01E1000 Specific Port Control Register - R/W */ +#define IGP01E1000_PSCR_TP_LOOPBACK 0x0001 +#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR 0x0200 +#define IGP01E1000_PSCR_TEN_CRS_SELECT 0x0400 +#define IGP01E1000_PSCR_FLIP_CHIP 0x0800 +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0-MDI, 1-MDIX */ + +/* IGP01E1000 Specific Port Link Health Register */ +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 +#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR 0x4000 +#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK 0x0800 /* LH */ +#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW 0x0400 /* LH */ +#define IGP01E1000_PLHR_DATA_ERR_1 0x0200 /* LH */ +#define IGP01E1000_PLHR_DATA_ERR_0 0x0100 +#define IGP01E1000_PLHR_AUTONEG_FAULT 0x0010 +#define IGP01E1000_PLHR_AUTONEG_ACTIVE 0x0008 +#define IGP01E1000_PLHR_VALID_CHANNEL_D 0x0004 +#define IGP01E1000_PLHR_VALID_CHANNEL_C 0x0002 +#define IGP01E1000_PLHR_VALID_CHANNEL_B 0x0001 +#define IGP01E1000_PLHR_VALID_CHANNEL_A 0x0000 + +/* IGP01E1000 Channel Quality Register */ +#define IGP01E1000_MSE_CHANNEL_D 0x000F +#define IGP01E1000_MSE_CHANNEL_C 0x00F0 +#define IGP01E1000_MSE_CHANNEL_B 0x0F00 +#define IGP01E1000_MSE_CHANNEL_A 0xF000 + +/* IGP01E1000 AGC Registers */ + +#define IGP01E1000_AGC_LENGTH_SHIFT 7 /* Coarse - 13:11, Fine - 10:7 */ + +/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */ +#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128 + +/* The precision of the length is +/- 10 meters */ +#define IGP01E1000_AGC_RANGE 10 + +/* IGP cable length table */ +static const +uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = + { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25, + 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120}; + +/* IGP01E1000 PCS Initialization register */ +/* bits 3:6 in the PCS registers stores the channels polarity */ +#define IGP01E1000_PHY_POLARITY_MASK 0x0078 + +/* IGP01E1000 GMII FIFO Register */ +#define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed + * on Link-Up */ +#define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */ + /* Bit definitions for valid PHY IDs. */ #define M88E1000_E_PHY_ID 0x01410C50 #define M88E1000_I_PHY_ID 0x01410C30 #define M88E1011_I_PHY_ID 0x01410C20 +#define IGP01E1000_I_PHY_ID 0x02A80380 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID #define M88E1011_I_REV_4 0x04 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 1b66efa8a2b0..10a831f3bbbd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -30,7 +30,22 @@ /* Change Log * - * 4.4.19 11/27/02 + * 5.0.43 3/5/03 + * o Feature: Added support for 82541 and 82547 hardware. + * o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of + * eeproms. + * o Feature: Added support for TCP Segmentation Offload (TSO). + * o Feature: Added MII ioctl. + * o Feature: Added support for statistics reporting through ethtool. + * o Cleanup: Removed proprietary hooks for ANS. + * o Cleanup: Miscellaneous code changes to improve CPU utilization. + * - Replaced "%" with conditionals and "+-" operators. + * - Implemented dynamic Interrupt Throttle Rate (ITR). + * - Reduced expensive PCI reads of ICR in interrupt. + * o Bug fix: Request IRQ after descriptor ring setup to avoid panic in + * shared interrupt instances. + * + * 4.4.18 11/27/02 * o Feature: Added user-settable knob for interrupt throttle rate (ITR). * o Cleanup: removed large static array allocations. * o Cleanup: C99 struct initializer format. @@ -42,25 +57,12 @@ * o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool. * * 4.4.12 10/15/02 - * o Clean up: use members of pci_device rather than direct calls to - * pci_read_config_word. - * o Bug fix: changed default flow control settings. - * o Clean up: ethtool file now has an inclusive list for adapters in the - * Wake-On-LAN capabilities instead of an exclusive list. - * o Bug fix: miscellaneous WoL bug fixes. - * o Added software interrupt for clearing rx ring - * o Bug fix: easier to undo "forcing" of 1000/fd using ethtool. - * o Now setting netdev->mem_end in e1000_probe. - * o Clean up: Moved tx_timeout from interrupt context to process context - * using schedule_task. - * - * 4.3.15 8/9/02 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "4.4.19-k3"; -char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation."; +char e1000_driver_version[] = "5.0.43-k1"; +char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * @@ -104,6 +106,8 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = { {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* required last entry */ {0,} }; @@ -112,7 +116,7 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); static char *e1000_strings[] = { "Intel(R) PRO/1000 Network Connection", - "Compaq Gigabit Ethernet Server Adapter", + "HP Gigabit Ethernet Server Adapter", "IBM Mobile, Desktop & Server Adapters" }; @@ -121,6 +125,7 @@ static char *e1000_strings[] = { int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); +int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); static int e1000_init_module(void); static void e1000_exit_module(void); @@ -141,6 +146,7 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); +static void e1000_82547_tx_fifo_stall(unsigned long data); static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev); static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); @@ -149,14 +155,18 @@ static void e1000_update_stats(struct e1000_adapter *adapter); static inline void e1000_irq_disable(struct e1000_adapter *adapter); static inline void e1000_irq_enable(struct e1000_adapter *adapter); static void e1000_intr(int irq, void *data, struct pt_regs *regs); -static void e1000_clean_tx_irq(struct e1000_adapter *adapter); #ifdef CONFIG_E1000_NAPI -static int e1000_poll(struct net_device *netdev, int *budget); +static int e1000_clean(struct net_device *netdev, int *budget); +static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, + int *work_done, int work_to_do); #else -static void e1000_clean_rx_irq(struct e1000_adapter *adapter); +static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); #endif +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); +static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, + int cmd); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static inline void e1000_rx_checksum(struct e1000_adapter *adapter, @@ -164,6 +174,9 @@ static inline void e1000_rx_checksum(struct e1000_adapter *adapter, struct sk_buff *skb); static void e1000_tx_timeout(struct net_device *dev); static void e1000_tx_timeout_task(struct net_device *dev); +static void e1000_smartspeed(struct e1000_adapter *adapter); +static inline int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, + struct sk_buff *skb); static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); @@ -182,6 +195,7 @@ struct notifier_block e1000_notifier_reboot = { .priority = 0 }; + /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -249,13 +263,10 @@ e1000_up(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, - netdev->name, netdev)) - return -1; - /* hardware has been reset, we need to reload some things */ e1000_set_multi(netdev); + e1000_restore_vlan(adapter); e1000_configure_tx(adapter); @@ -263,6 +274,14 @@ e1000_up(struct e1000_adapter *adapter) e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); + if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, + netdev->name, netdev)) { + e1000_reset_hw(&adapter->hw); + e1000_free_tx_resources(adapter); + e1000_free_rx_resources(adapter); + return -1; + } + mod_timer(&adapter->watchdog_timer, jiffies); e1000_irq_enable(adapter); @@ -276,6 +295,7 @@ e1000_down(struct e1000_adapter *adapter) e1000_irq_disable(adapter); free_irq(netdev->irq, netdev); + del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); adapter->link_speed = 0; @@ -291,14 +311,28 @@ e1000_down(struct e1000_adapter *adapter) void e1000_reset(struct e1000_adapter *adapter) { + uint32_t pba; /* Repartition Pba for greater than 9k mtu * To take effect CTRL.RST is required. */ - if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) - E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA); - else - E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA); + if(adapter->hw.mac_type < e1000_82547) { + if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) + pba = E1000_PBA_40K; + else + pba = E1000_PBA_48K; + } else { + if(adapter->rx_buffer_len > E1000_RXBUFFER_8192) + pba = E1000_PBA_22K; + else + pba = E1000_PBA_30K; + adapter->tx_fifo_head = 0; + adapter->tx_head_addr = pba << E1000_TX_HEAD_ADDR_SHIFT; + adapter->tx_fifo_size = + (E1000_PBA_40K - pba) << E1000_TX_FIFO_SIZE_SHIFT; + atomic_set(&adapter->tx_fifo_stall, 0); + } + E1000_WRITE_REG(&adapter->hw, PBA, pba); adapter->hw.fc = adapter->hw.original_fc; e1000_reset_hw(&adapter->hw); @@ -389,9 +423,9 @@ e1000_probe(struct pci_dev *pdev, netdev->change_mtu = &e1000_change_mtu; netdev->do_ioctl = &e1000_ioctl; netdev->tx_timeout = &e1000_tx_timeout; - netdev->watchdog_timeo = HZ; + netdev->watchdog_timeo = 5 * HZ; #ifdef CONFIG_E1000_NAPI - netdev->poll = &e1000_poll; + netdev->poll = &e1000_clean; netdev->weight = 64; #endif netdev->vlan_rx_register = e1000_vlan_rx_register; @@ -413,17 +447,18 @@ e1000_probe(struct pci_dev *pdev, if(adapter->hw.mac_type >= e1000_82543) { netdev->features = NETIF_F_SG | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | - NETIF_F_HW_VLAN_RX | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; } else { netdev->features = NETIF_F_SG; } - if(adapter->hw.mac_type >= e1000_82544) + if((adapter->hw.mac_type >= e1000_82544) && + (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; - + if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -446,13 +481,9 @@ e1000_probe(struct pci_dev *pdev, e1000_get_bus_info(&adapter->hw); - if((adapter->hw.mac_type == e1000_82544) && - (adapter->hw.bus_type == e1000_bus_type_pcix)) - - adapter->max_data_per_txd = 4096; - else - adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE; - + init_timer(&adapter->tx_fifo_stall_timer); + adapter->tx_fifo_stall_timer.function = &e1000_82547_tx_fifo_stall; + adapter->tx_fifo_stall_timer.data = (unsigned long) adapter; init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &e1000_watchdog; @@ -482,11 +513,12 @@ e1000_probe(struct pci_dev *pdev, * enable the ACPI Magic Packet filter */ - e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data); + e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG,1, &eeprom_data); if((adapter->hw.mac_type >= e1000_82544) && (eeprom_data & E1000_EEPROM_APME)) adapter->wol |= E1000_WUFC_MAG; + /* reset the hardware with the new settings */ e1000_reset(adapter); @@ -533,6 +565,7 @@ e1000_remove(struct pci_dev *pdev) e1000_phy_hw_reset(&adapter->hw); + iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); @@ -568,7 +601,7 @@ e1000_sw_init(struct e1000_adapter *adapter) adapter->rx_buffer_len = E1000_RXBUFFER_2048; hw->max_frame_size = netdev->mtu + - ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; /* identify the MAC */ @@ -578,6 +611,10 @@ e1000_sw_init(struct e1000_adapter *adapter) return -1; } + /* initialize eeprom parameters */ + + e1000_init_eeprom_params(hw); + /* flow control settings */ hw->fc_high_water = E1000_FC_HIGH_THRESH; @@ -585,6 +622,9 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->fc_pause_time = E1000_FC_PAUSE_TIME; hw->fc_send_xon = 1; + if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) + hw->phy_init_script = 1; + /* Media type - copper or fiber */ if(hw->mac_type >= e1000_82543) { @@ -782,7 +822,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) tctl &= ~E1000_TCTL_CT; tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | - (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); E1000_WRITE_REG(&adapter->hw, TCTL, tctl); @@ -852,8 +892,8 @@ e1000_setup_rctl(struct e1000_adapter *adapter) rctl &= ~(3 << E1000_RCTL_MO_SHIFT); rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | - E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | - (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); if(adapter->hw.tbi_compatibility_on == 1) rctl |= E1000_RCTL_SBP; @@ -907,12 +947,9 @@ e1000_configure_rx(struct e1000_adapter *adapter) if(adapter->hw.mac_type >= e1000_82540) { E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay); - - /* Set the interrupt throttling rate. Value is calculated - * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */ -#define MAX_INTS_PER_SEC 8000 -#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256) - E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR); + if(adapter->itr > 1) + E1000_WRITE_REG(&adapter->hw, ITR, + 1000000000 / (adapter->itr * 256)); } /* Setup the Base and Length of the Rx Descriptor Ring */ @@ -1184,9 +1221,9 @@ e1000_set_multi(struct net_device *netdev) if(hw->mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); - /* load the first 15 multicast address into the exact filters 1-15 + /* load the first 14 multicast address into the exact filters 1-14 * RAR 0 is used for the station MAC adddress - * if there are not 15 addresses, go ahead and clear the filters + * if there are not 14 addresses, go ahead and clear the filters */ mc_ptr = netdev->mc_list; @@ -1216,6 +1253,40 @@ e1000_set_multi(struct net_device *netdev) e1000_leave_82542_rst(adapter); } +static void +e1000_tx_flush(struct e1000_adapter *adapter) +{ + uint32_t ctrl, tctl, txcw, icr; + + e1000_irq_disable(adapter); + + if(adapter->hw.mac_type < e1000_82543) { + /* Transmit Unit Reset */ + tctl = E1000_READ_REG(&adapter->hw, TCTL); + E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST); + E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + e1000_clean_tx_ring(adapter); + e1000_configure_tx(adapter); + } else { + txcw = E1000_READ_REG(&adapter->hw, TXCW); + E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE); + + ctrl = E1000_READ_REG(&adapter->hw, CTRL); + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU | + E1000_CTRL_ILOS); + + mdelay(10); + + e1000_clean_tx_irq(adapter); + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); + E1000_WRITE_REG(&adapter->hw, TXCW, txcw); + + /* clear the link status change interrupts this caused */ + icr = E1000_READ_REG(&adapter->hw, ICR); + } + + e1000_irq_enable(adapter); +} /* need to wait a few seconds after link up to get diagnostic information from the phy */ @@ -1227,6 +1298,48 @@ e1000_update_phy_info(unsigned long data) } /** + * e1000_82547_tx_fifo_stall - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ + +static void +e1000_82547_tx_fifo_stall(unsigned long data) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) data; + struct net_device *netdev = adapter->netdev; + uint32_t tctl; + + if(atomic_read(&adapter->tx_fifo_stall)) { + if((E1000_READ_REG(&adapter->hw, TDT) == + E1000_READ_REG(&adapter->hw, TDH)) && + (E1000_READ_REG(&adapter->hw, TDFT) == + E1000_READ_REG(&adapter->hw, TDFH)) && + (E1000_READ_REG(&adapter->hw, TDFTS) == + E1000_READ_REG(&adapter->hw, TDFHS))) { + tctl = E1000_READ_REG(&adapter->hw, TCTL); + E1000_WRITE_REG(&adapter->hw, TCTL, + tctl & ~E1000_TCTL_EN); + E1000_WRITE_REG(&adapter->hw, TDFT, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, TDFH, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, TDFTS, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, TDFHS, + adapter->tx_head_addr); + E1000_WRITE_REG(&adapter->hw, TCTL, tctl); + E1000_WRITE_FLUSH(&adapter->hw); + + adapter->tx_fifo_head = 0; + atomic_set(&adapter->tx_fifo_stall, 0); + netif_wake_queue(netdev); + } else { + mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1); + } + } +} + +/** * e1000_watchdog - Timer Call-back * @data: pointer to netdev cast into an unsigned long **/ @@ -1256,6 +1369,7 @@ e1000_watchdog(unsigned long data) netif_carrier_on(netdev); netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + adapter->smartspeed = 0; } } else { if(netif_carrier_ok(netdev)) { @@ -1268,11 +1382,34 @@ e1000_watchdog(unsigned long data) netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); } + + e1000_smartspeed(adapter); } e1000_update_stats(adapter); e1000_update_adaptive(&adapter->hw); + if(!netif_carrier_ok(netdev)) { + if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { + unsigned long flags; + spin_lock_irqsave(&netdev->xmit_lock, flags); + e1000_tx_flush(adapter); + spin_unlock_irqrestore(&netdev->xmit_lock, flags); + } + } + + /* Dynamic mode for Interrupt Throttle Rate (ITR) */ + if(adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) { + /* Symmetric Tx/Rx gets a reduced ITR=2000; Total + * asymmetrical Tx or Rx gets ITR=8000; everyone + * else is between 2000-8000. */ + uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000; + uint32_t dif = (adapter->gotcl > adapter->gorcl ? + adapter->gotcl - adapter->gorcl : + adapter->gorcl - adapter->gotcl) / 10000; + uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000; + E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (itr * 256)); + } /* Cause software interrupt to ensure rx ring is cleaned */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); @@ -1301,7 +1438,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) int i; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; uint16_t ipcse, tucse, mss; - + if(skb_shinfo(skb)->tso_size) { hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->tso_size; @@ -1321,7 +1458,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); - + context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); @@ -1335,12 +1472,12 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); - i = (i + 1) % adapter->tx_ring.count; + if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; } - + return FALSE; } @@ -1365,7 +1502,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); - i = (i + 1) % adapter->tx_ring.count; + if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; @@ -1374,24 +1511,24 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) return FALSE; } +#define E1000_MAX_TXD_PWR 12 +#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR) + static inline int e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; - int len, offset, size, count, i; + int len = skb->len, offset = 0, size, count = 0, i; + int tso = skb_shinfo(skb)->tso_size; int nr_frags = skb_shinfo(skb)->nr_frags; - int f; - len = skb->len - skb->data_len; - i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count; - count = 0; + len -= skb->data_len; - offset = 0; + i = tx_ring->next_to_use; while(len) { - i = (i + 1) % tx_ring->count; - size = min(len, adapter->max_data_per_txd); + size = min(len, E1000_MAX_DATA_PER_TXD); /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if(tso && !nr_frags && size == len && size > 4) @@ -1407,6 +1544,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) len -= size; offset += size; count++; + if(++i == tx_ring->count) i = 0; } for(f = 0; f < nr_frags; f++) { @@ -1417,8 +1555,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) offset = 0; while(len) { - i = (i + 1) % tx_ring->count; - size = min(len, adapter->max_data_per_txd); + size = min(len, E1000_MAX_DATA_PER_TXD); /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if(tso && f == (nr_frags-1) && size == len && size > 4) @@ -1435,8 +1572,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb) len -= size; offset += size; count++; + if(++i == tx_ring->count) i = 0; } } + if(--i < 0) i = tx_ring->count - 1; tx_ring->buffer_info[i].skb = skb; return count; @@ -1477,7 +1616,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) tx_desc->lower.data = cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length); tx_desc->upper.data = cpu_to_le32(txd_upper); - i = (i + 1) % tx_ring->count; + if(++i == tx_ring->count) i = 0; } tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); @@ -1492,34 +1631,74 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) E1000_WRITE_REG(&adapter->hw, TDT, i); } -#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0)) +/** + * 82547 workaround to avoid controller hang in half-duplex environment. + * The workaround is to avoid queuing a large packet that would span + * the internal Tx FIFO ring boundary by notifying the stack to resend + * the packet at a later time. This gives the Tx FIFO an opportunity to + * flush all packets. When that occurs, we reset the Tx FIFO pointers + * to the beginning of the Tx FIFO. + **/ + +#define E1000_FIFO_HDR 0x10 +#define E1000_82547_PAD_LEN 0x3E0 + +static inline int +e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb) +{ + uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; + uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; + + E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); + + if(adapter->link_duplex != HALF_DUPLEX) + goto no_fifo_stall_required; + + if(atomic_read(&adapter->tx_fifo_stall)) + return 1; + + if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { + atomic_set(&adapter->tx_fifo_stall, 1); + return 1; + } + +no_fifo_stall_required: + adapter->tx_fifo_head += skb_fifo_len; + if(adapter->tx_fifo_head >= adapter->tx_fifo_size) + adapter->tx_fifo_head -= adapter->tx_fifo_size; + return 0; +} + +/* Tx Descriptors needed, worst case */ +#define TXD_USE_COUNT(S) (((S) >> E1000_MAX_TXD_PWR) + \ + (((S) & (E1000_MAX_DATA_PER_TXD - 1)) ? 1 : 0)) +#define DESC_NEEDED TXD_USE_COUNT(MAX_JUMBO_FRAME_SIZE) + \ + MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; - int tx_flags = 0, count; - int f; - - count = TXD_USE_COUNT(skb->len - skb->data_len, - adapter->max_data_per_txd); + int tx_flags = 0; - if(count == 0) { + if(skb->len <= 0) { dev_kfree_skb_any(skb); return 0; } - for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) - count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size, - adapter->max_data_per_txd); - if((skb_shinfo(skb)->tso_size) || (skb->ip_summed == CHECKSUM_HW)) - count++; - - if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) { + if(E1000_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED) { netif_stop_queue(netdev); return 1; } + if(adapter->hw.mac_type == e1000_82547) { + if(e1000_82547_fifo_workaround(adapter, skb)) { + netif_stop_queue(netdev); + mod_timer(&adapter->tx_fifo_stall_timer, jiffies); + return 1; + } + } + if(adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); @@ -1530,9 +1709,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) else if(e1000_tx_csum(adapter, skb)) tx_flags |= E1000_TX_FLAGS_CSUM; - count = e1000_tx_map(adapter, skb); - - e1000_tx_queue(adapter, count, tx_flags); + e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags); netdev->trans_start = jiffies; @@ -1653,7 +1830,8 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS); adapter->stats.gprc += E1000_READ_REG(hw, GPRC); - adapter->stats.gorcl += E1000_READ_REG(hw, GORCL); + adapter->gorcl = E1000_READ_REG(hw, GORCL); + adapter->stats.gorcl += adapter->gorcl; adapter->stats.gorch += E1000_READ_REG(hw, GORCH); adapter->stats.bprc += E1000_READ_REG(hw, BPRC); adapter->stats.mprc += E1000_READ_REG(hw, MPRC); @@ -1684,7 +1862,8 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC); adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC); adapter->stats.gptc += E1000_READ_REG(hw, GPTC); - adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL); + adapter->gotcl = E1000_READ_REG(hw, GOTCL); + adapter->stats.gotcl += adapter->gotcl; adapter->stats.gotch += E1000_READ_REG(hw, GOTCH); adapter->stats.rnbc += E1000_READ_REG(hw, RNBC); adapter->stats.ruc += E1000_READ_REG(hw, RUC); @@ -1807,60 +1986,57 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; - -#ifdef CONFIG_E1000_NAPI - if (netif_rx_schedule_prep(netdev)) { - /* Disable interrupts and enable polling */ - atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); - E1000_WRITE_FLUSH(&adapter->hw); - __netif_rx_schedule(netdev); - } -#else - uint32_t icr; - int i = E1000_MAX_INTR; + uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); +#ifndef CONFIG_E1000_NAPI + int i; +#endif - while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) { - - if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; - mod_timer(&adapter->watchdog_timer, jiffies); - } - - e1000_clean_rx_irq(adapter); - e1000_clean_tx_irq(adapter); - i--; + if(!icr) + return; /* Not our interrupt */ + if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + adapter->hw.get_link_status = 1; + mod_timer(&adapter->watchdog_timer, jiffies); } + +#ifdef CONFIG_E1000_NAPI + /* Don't disable interrupts - rely on h/w interrupt + * moderation to keep interrupts low. netif_rx_schedule + * is NOP if already polling. */ + netif_rx_schedule(netdev); +#else + for(i = 0; i < E1000_MAX_INTR; i++) + if(!e1000_clean_rx_irq(adapter) && + !e1000_clean_tx_irq(adapter)) + break; #endif } #ifdef CONFIG_E1000_NAPI +/** + * e1000_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ + static int -e1000_process_intr(struct net_device *netdev) +e1000_clean(struct net_device *netdev, int *budget) { struct e1000_adapter *adapter = netdev->priv; - uint32_t icr; - int i = E1000_MAX_INTR; - int hasReceived = 0; - - while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) { - if (icr & E1000_ICR_RXT0) - hasReceived = 1; - - if (!(icr & ~(E1000_ICR_RXT0))) + int work_to_do = min(*budget, netdev->quota); + int work_done = 0; + + while(work_done < work_to_do) + if(!e1000_clean_rx_irq(adapter, &work_done, work_to_do) && + !e1000_clean_tx_irq(adapter)) break; - - if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; - mod_timer(&adapter->watchdog_timer, jiffies); - } - - e1000_clean_tx_irq(adapter); - i--; - } - return hasReceived; + *budget -= work_done; + netdev->quota -= work_done; + + if(work_done < work_to_do) + netif_rx_complete(netdev); + + return (work_done >= work_to_do); } #endif @@ -1869,20 +2045,22 @@ e1000_process_intr(struct net_device *netdev) * @adapter: board private structure **/ -static void +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_tx_desc *tx_desc; - int i; + int i, cleaned = FALSE; i = tx_ring->next_to_clean; tx_desc = E1000_TX_DESC(*tx_ring, i); while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + cleaned = TRUE; + if(tx_ring->buffer_info[i].dma) { pci_unmap_page(pdev, @@ -1900,158 +2078,34 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) tx_ring->buffer_info[i].skb = NULL; } + tx_desc->buffer_addr = 0; + tx_desc->lower.data = 0; tx_desc->upper.data = 0; - i = (i + 1) % tx_ring->count; + if(++i == tx_ring->count) i = 0; tx_desc = E1000_TX_DESC(*tx_ring, i); } tx_ring->next_to_clean = i; - if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) && - (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) { - + if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) netif_wake_queue(netdev); - } -} - -#ifdef CONFIG_E1000_NAPI -static int -e1000_poll(struct net_device *netdev, int *budget) -{ - struct e1000_adapter *adapter = netdev->priv; - struct e1000_desc_ring *rx_ring = &adapter->rx_ring; - struct pci_dev *pdev = adapter->pdev; - struct e1000_rx_desc *rx_desc; - struct sk_buff *skb; - unsigned long flags; - uint32_t length; - uint8_t last_byte; - int i; - int received = 0; - int rx_work_limit = *budget; - - if(rx_work_limit > netdev->quota) - rx_work_limit = netdev->quota; - - e1000_process_intr(netdev); - - i = rx_ring->next_to_clean; - rx_desc = E1000_RX_DESC(*rx_ring, i); - - while(rx_desc->status & E1000_RXD_STAT_DD) { - if(--rx_work_limit < 0) - goto not_done; - - pci_unmap_single(pdev, - rx_ring->buffer_info[i].dma, - rx_ring->buffer_info[i].length, - PCI_DMA_FROMDEVICE); - - skb = rx_ring->buffer_info[i].skb; - length = le16_to_cpu(rx_desc->length); - - if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { - - /* All receives must fit into a single buffer */ - - E1000_DBG("Receive packet consumed multiple buffers\n"); - - dev_kfree_skb_irq(skb); - rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; - - i = (i + 1) % rx_ring->count; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; - } - - if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { - - last_byte = *(skb->data + length - 1); - - if(TBI_ACCEPT(&adapter->hw, rx_desc->status, - rx_desc->errors, length, last_byte)) { - - spin_lock_irqsave(&adapter->stats_lock, flags); - - e1000_tbi_adjust_stats(&adapter->hw, - &adapter->stats, - length, skb->data); - - spin_unlock_irqrestore(&adapter->stats_lock, - flags); - length--; - } else { - - dev_kfree_skb_irq(skb); - rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; - - i = (i + 1) % rx_ring->count; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - continue; - } - } - - /* Good Receive */ - skb_put(skb, length - ETHERNET_FCS_SIZE); - - /* Receive Checksum Offload */ - e1000_rx_checksum(adapter, rx_desc, skb); - - skb->protocol = eth_type_trans(skb, netdev); - if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { - vlan_hwaccel_rx(skb, adapter->vlgrp, - (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); - } else { - netif_receive_skb(skb); - } - netdev->last_rx = jiffies; - - rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; - - i = (i + 1) % rx_ring->count; - - rx_desc = E1000_RX_DESC(*rx_ring, i); - received++; - } - - if(!received) - received = 1; - - e1000_alloc_rx_buffers(adapter); - - rx_ring->next_to_clean = i; - netdev->quota -= received; - *budget -= received; - - netif_rx_complete(netdev); - - e1000_irq_enable(adapter); - return 0; - -not_done: - - e1000_alloc_rx_buffers(adapter); - - rx_ring->next_to_clean = i; - netdev->quota -= received; - *budget -= received; - return 1; + return cleaned; } -#else + /** * e1000_clean_rx_irq - Send received data up the network stack, * @adapter: board private structure **/ -static void +static boolean_t +#ifdef CONFIG_E1000_NAPI +e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done, + int work_to_do) +#else e1000_clean_rx_irq(struct e1000_adapter *adapter) +#endif { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; @@ -2061,13 +2115,22 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) unsigned long flags; uint32_t length; uint8_t last_byte; - int i; + int i, cleaned = FALSE; i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); while(rx_desc->status & E1000_RXD_STAT_DD) { +#ifdef CONFIG_E1000_NAPI + if(*work_done >= work_to_do) + break; + + (*work_done)++; +#endif + + cleaned = TRUE; + pci_unmap_single(pdev, rx_ring->buffer_info[i].dma, rx_ring->buffer_info[i].length, @@ -2086,7 +2149,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; - i = (i + 1) % rx_ring->count; + if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); continue; @@ -2114,7 +2177,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; - i = (i + 1) % rx_ring->count; + if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); continue; @@ -2128,18 +2191,28 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) e1000_rx_checksum(adapter, rx_desc, skb); skb->protocol = eth_type_trans(skb, netdev); +#ifdef CONFIG_E1000_NAPI + if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); + } else { + netif_receive_skb(skb); + } +#else /* CONFIG_E1000_NAPI */ if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { vlan_hwaccel_rx(skb, adapter->vlgrp, (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); } else { netif_rx(skb); } +#endif /* CONFIG_E1000_NAPI */ + netdev->last_rx = jiffies; rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; - i = (i + 1) % rx_ring->count; + if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); } @@ -2147,8 +2220,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) rx_ring->next_to_clean = i; e1000_alloc_rx_buffers(adapter); + + return cleaned; } -#endif /** * e1000_alloc_rx_buffers - Replace used receive buffers @@ -2163,11 +2237,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; struct sk_buff *skb; - int reserve_len; + int reserve_len = 2; int i; - reserve_len = 2; - i = rx_ring->next_to_use; while(!rx_ring->buffer_info[i].skb) { @@ -2198,7 +2270,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); - if(!(i % E1000_RX_BUFFER_WRITE)) { + if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, @@ -2208,13 +2280,68 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) E1000_WRITE_REG(&adapter->hw, RDT, i); } - i = (i + 1) % rx_ring->count; + if(++i == rx_ring->count) i = 0; } rx_ring->next_to_use = i; } /** + * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers. + * @adapter: + **/ + +static void +e1000_smartspeed(struct e1000_adapter *adapter) +{ + uint16_t phy_status; + uint16_t phy_ctrl; + + if((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg || + !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) + return; + + if(adapter->smartspeed == 0) { + /* If Master/Slave config fault is asserted twice, + * we assume back-to-back */ + e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); + if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; + e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); + if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; + e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); + if(phy_ctrl & CR_1000T_MS_ENABLE) { + phy_ctrl &= ~CR_1000T_MS_ENABLE; + e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, + phy_ctrl); + adapter->smartspeed++; + if(!e1000_phy_setup_autoneg(&adapter->hw) && + !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, + &phy_ctrl)) { + phy_ctrl |= (MII_CR_AUTO_NEG_EN | + MII_CR_RESTART_AUTO_NEG); + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, + phy_ctrl); + } + } + return; + } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { + /* If still no link, perhaps using 2/3 pair cable */ + e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); + phy_ctrl |= CR_1000T_MS_ENABLE; + e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); + if(!e1000_phy_setup_autoneg(&adapter->hw) && + !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { + phy_ctrl |= (MII_CR_AUTO_NEG_EN | + MII_CR_RESTART_AUTO_NEG); + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl); + } + } + /* Restart process after E1000_SMARTSPEED_MAX iterations */ + if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX) + adapter->smartspeed = 0; +} + +/** * e1000_ioctl - * @netdev: * @ifreq: @@ -2225,6 +2352,10 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return e1000_mii_ioctl(netdev, ifr, cmd); case SIOCETHTOOL: return e1000_ethtool_ioctl(netdev, ifr); default: @@ -2233,6 +2364,86 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) } /** + * e1000_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ + +static int +e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct e1000_adapter *adapter = netdev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + int retval; + uint16_t mii_reg; + uint16_t spddplx; + + if(adapter->hw.media_type == e1000_media_type_fiber) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = adapter->hw.phy_addr; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, + &data->val_out)) + return -EIO; + break; + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data->reg_num & ~(0x1F)) + return -EFAULT; + mii_reg = data->val_in; + if (e1000_write_phy_reg(&adapter->hw, data->reg_num, + data->val_in)) + return -EIO; + if (adapter->hw.phy_type == e1000_phy_m88) { + switch (data->reg_num) { + case PHY_CTRL: + if(data->val_in & MII_CR_AUTO_NEG_EN) { + adapter->hw.autoneg = 1; + adapter->hw.autoneg_advertised = 0x2F; + } else { + if (data->val_in & 0x40) + spddplx = SPEED_1000; + else if (data->val_in & 0x2000) + spddplx = SPEED_100; + else + spddplx = SPEED_10; + spddplx += (data->val_in & 0x100) + ? FULL_DUPLEX : + HALF_DUPLEX; + retval = e1000_set_spd_dplx(adapter, + spddplx); + if(retval) + return retval; + } + if(netif_running(adapter->netdev)) { + e1000_down(adapter); + e1000_up(adapter); + } else + e1000_reset(adapter); + break; + case M88E1000_PHY_SPEC_CTRL: + case M88E1000_EXT_PHY_SPEC_CTRL: + if (e1000_phy_reset(&adapter->hw)) + return -EIO; + break; + } + } + break; + default: + return -EOPNOTSUPP; + } + return E1000_SUCCESS; +} + +/** * e1000_rx_checksum - Receive Checksum Offload for 82543 * @adapter: board private structure * @rx_desc: receive descriptor @@ -2402,6 +2613,35 @@ e1000_restore_vlan(struct e1000_adapter *adapter) } } +int +e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) +{ + adapter->hw.autoneg = 0; + + switch(spddplx) { + case SPEED_10 + DUPLEX_HALF: + adapter->hw.forced_speed_duplex = e1000_10_half; + break; + case SPEED_10 + DUPLEX_FULL: + adapter->hw.forced_speed_duplex = e1000_10_full; + break; + case SPEED_100 + DUPLEX_HALF: + adapter->hw.forced_speed_duplex = e1000_100_half; + break; + case SPEED_100 + DUPLEX_FULL: + adapter->hw.forced_speed_duplex = e1000_100_full; + break; + case SPEED_1000 + DUPLEX_FULL: + adapter->hw.autoneg = 1; + adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + return -EINVAL; + } + return 0; +} + static int e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) { @@ -2419,6 +2659,7 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) return NOTIFY_DONE; } + static int e1000_suspend(struct pci_dev *pdev, uint32_t state) { @@ -2483,7 +2724,8 @@ e1000_suspend(struct pci_dev *pdev, uint32_t state) if(manc & E1000_MANC_SMBUS_EN) { manc |= E1000_MANC_ARP_EN; E1000_WRITE_REG(&adapter->hw, MANC, manc); - state = 0; + pci_enable_wake(pdev, 3, 1); + pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */ } } diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 0d68940f9b98..fe351959ed47 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -77,24 +77,22 @@ typedef enum { #define E1000_WRITE_REG(a, reg, value) ( \ - ((a)->mac_type >= e1000_82543) ? \ - (writel((value), ((a)->hw_addr + E1000_##reg))) : \ - (writel((value), ((a)->hw_addr + E1000_82542_##reg)))) + writel((value), ((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))) #define E1000_READ_REG(a, reg) ( \ - ((a)->mac_type >= e1000_82543) ? \ - readl((a)->hw_addr + E1000_##reg) : \ - readl((a)->hw_addr + E1000_82542_##reg)) + readl((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))) #define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \ - ((a)->mac_type >= e1000_82543) ? \ - writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \ - writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))) + writel((value), ((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + ((offset) << 2)))) #define E1000_READ_REG_ARRAY(a, reg, offset) ( \ - ((a)->mac_type >= e1000_82543) ? \ - readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \ - readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))) + readl((a)->hw_addr + \ + (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \ + ((offset) << 2))) #define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS) diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index a11941f3f213..75a50ff6f42e 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2003 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 @@ -169,7 +169,7 @@ E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); * * Valid Range: 0-65535 * - * Default Value: 0/128 + * Default Value: 0 */ E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); @@ -183,6 +183,15 @@ E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); +/* Interrupt Throttle Rate (interrupts/sec) + * + * Valid Range: 100-100000 (0=off, 1=dynamic) + * + * Default Value: 1 + */ + +E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); + #define AUTONEG_ADV_DEFAULT 0x2F #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL @@ -213,6 +222,10 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); #define MAX_TXABSDELAY 0xFFFF #define MIN_TXABSDELAY 0 +#define DEFAULT_ITR 1 +#define MAX_ITR 100000 +#define MIN_ITR 100 + struct e1000_option { enum { enable_option, range_option, list_option } type; char *name; @@ -309,7 +322,7 @@ e1000_check_options(struct e1000_adapter *adapter) .name = "Transmit Descriptors", .err = "using default of " __MODULE_STRING(DEFAULT_TXD), .def = DEFAULT_TXD, - .arg = { .r = { .min = MIN_TXD }} + .arg = { .r { .min = MIN_TXD }} }; struct e1000_desc_ring *tx_ring = &adapter->tx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; @@ -362,7 +375,8 @@ e1000_check_options(struct e1000_adapter *adapter) .name = "Flow Control", .err = "reading default settings from EEPROM", .def = e1000_fc_default, - .arg = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }} + .arg = { .l = { .nr = ARRAY_SIZE(fc_list), + .p = fc_list }} }; int fc = FlowControl[bd]; @@ -370,58 +384,78 @@ e1000_check_options(struct e1000_adapter *adapter) adapter->hw.fc = adapter->hw.original_fc = fc; } { /* Transmit Interrupt Delay */ - char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV); struct e1000_option opt = { .type = range_option, .name = "Transmit Interrupt Delay", - .arg = { .r = { .min = MIN_TXDELAY, .max = MAX_TXDELAY }} + .err = "using default of " __MODULE_STRING(DEFAULT_TIDV), + .def = DEFAULT_TIDV, + .arg = { .r = { .min = MIN_TXDELAY, + .max = MAX_TXDELAY }} }; - opt.def = DEFAULT_TIDV; - opt.err = tidv; adapter->tx_int_delay = TxIntDelay[bd]; e1000_validate_option(&adapter->tx_int_delay, &opt); } { /* Transmit Absolute Interrupt Delay */ - char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV); struct e1000_option opt = { .type = range_option, .name = "Transmit Absolute Interrupt Delay", - .arg = { .r = { .min = MIN_TXABSDELAY, .max = MAX_TXABSDELAY }} + .err = "using default of " __MODULE_STRING(DEFAULT_TADV), + .def = DEFAULT_TADV, + .arg = { .r = { .min = MIN_TXABSDELAY, + .max = MAX_TXABSDELAY }} }; - opt.def = DEFAULT_TADV; - opt.err = tadv; adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; e1000_validate_option(&adapter->tx_abs_int_delay, &opt); } { /* Receive Interrupt Delay */ - char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR); struct e1000_option opt = { .type = range_option, .name = "Receive Interrupt Delay", - .arg = { .r = { .min = MIN_RXDELAY, .max = MAX_RXDELAY }} + .err = "using default of " __MODULE_STRING(DEFAULT_RDTR), + .def = DEFAULT_RDTR, + .arg = { .r = { .min = MIN_RXDELAY, + .max = MAX_RXDELAY }} }; - opt.def = DEFAULT_RDTR; - opt.err = rdtr; adapter->rx_int_delay = RxIntDelay[bd]; e1000_validate_option(&adapter->rx_int_delay, &opt); } { /* Receive Absolute Interrupt Delay */ - char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV); struct e1000_option opt = { .type = range_option, .name = "Receive Absolute Interrupt Delay", - .arg = { .r = { .min = MIN_RXABSDELAY, .max = MAX_RXABSDELAY }} + .err = "using default of " __MODULE_STRING(DEFAULT_RADV), + .def = DEFAULT_RADV, + .arg = { .r = { .min = MIN_RXABSDELAY, + .max = MAX_RXABSDELAY }} }; - opt.def = DEFAULT_RADV; - opt.err = radv; adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; e1000_validate_option(&adapter->rx_abs_int_delay, &opt); } - + { /* Interrupt Throttling Rate */ + struct e1000_option opt = { + .type = range_option, + .name = "Interrupt Throttling Rate (ints/sec)", + .err = "using default of " __MODULE_STRING(DEFAULT_ITR), + .def = DEFAULT_ITR, + .arg = { .r = { .min = MIN_ITR, + .max = MAX_ITR }} + }; + + adapter->itr = InterruptThrottleRate[bd]; + if(adapter->itr == 0) { + printk(KERN_INFO "%s turned off\n", opt.name); + } else if(adapter->itr == 1 || adapter->itr == -1) { + /* Dynamic mode */ + adapter->itr = 1; + } else { + e1000_validate_option(&adapter->itr, &opt); + } + } + switch(adapter->hw.media_type) { case e1000_media_type_fiber: e1000_check_fiber_options(adapter); @@ -486,7 +520,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .name = "Speed", .err = "parameter ignored", .def = 0, - .arg = { .l = { .nr = ARRAY_SIZE(speed_list), .p = speed_list }} + .arg = { .l = { .nr = ARRAY_SIZE(speed_list), + .p = speed_list }} }; speed = Speed[bd]; @@ -502,7 +537,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .name = "Duplex", .err = "parameter ignored", .def = 0, - .arg = { .l = { .nr = ARRAY_SIZE(dplx_list), .p = dplx_list }} + .arg = { .l = { .nr = ARRAY_SIZE(dplx_list), + .p = dplx_list }} }; dplx = Duplex[bd]; @@ -554,7 +590,8 @@ e1000_check_copper_options(struct e1000_adapter *adapter) .name = "AutoNeg", .err = "parameter ignored", .def = AUTONEG_ADV_DEFAULT, - .arg = { .l = { .nr = ARRAY_SIZE(an_list), .p = an_list }} + .arg = { .l = { .nr = ARRAY_SIZE(an_list), + .p = an_list }} }; int an = AutoNeg[bd]; diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 4e8a08b78804..a99f7d037d0a 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -331,8 +331,8 @@ static int mace_open(struct net_device *dev) return -ENOMEM; } - mp->rx_ring_phys = (unsigned char *) virt_to_bus(mp->rx_ring); - mp->tx_ring_phys = (unsigned char *) virt_to_bus(mp->tx_ring); + mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring); + mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring); /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ diff --git a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c new file mode 100644 index 000000000000..861e1086934c --- /dev/null +++ b/drivers/net/ne2k_cbus.c @@ -0,0 +1,879 @@ +/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ +/* + Written 1992-94 by Donald Becker. + + Copyright 1993 United States Government as represented by the + Director, National Security Agency. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 + + This driver should work with many programmed-I/O 8390-based ethernet + boards. Currently it supports the NE1000, NE2000, many clones, + and some Cabletron products. + + Changelog: + + Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made + sanity checks and bad clone support optional. + Paul Gortmaker : new reset code, reset card after probe at boot. + Paul Gortmaker : multiple card support for module users. + Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c + Paul Gortmaker : Allow users with bad cards to avoid full probe. + Paul Gortmaker : PCI probe changes, more PCI cards supported. + rjohnson@analogic.com : Changed init order so an interrupt will only + occur after memory is allocated for dev->priv. Deallocated memory + last in cleanup_modue() + Richard Guenther : Added support for ISAPnP cards + Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. + Osamu Tomita : Separate driver for NEC PC-9800. + +*/ + +/* Routines for the NatSemi-based designs (NE[12]000). */ + +static const char version1[] = +"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n"; +static const char version2[] = +"Last modified Nov 1, 2000 by Paul Gortmaker\n"; + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/isapnp.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> + +#include <asm/system.h> +#include <asm/io.h> + +#include "8390.h" + +/* Some defines that people can play with if so inclined. */ + +/* Do we support clones that don't adhere to 14,15 of the SAprom ? */ +#define SUPPORT_NE_BAD_CLONES + +/* Do we perform extra sanity checks on stuff ? */ +/* #define NE_SANITY_CHECK */ + +/* Do we implement the read before write bugfix ? */ +/* #define NE_RW_BUGFIX */ + +/* Do we have a non std. amount of memory? (in units of 256 byte pages) */ +/* #define PACKETBUF_MEMSIZE 0x40 */ + +#ifdef SUPPORT_NE_BAD_CLONES +/* A list of bad clones that we none-the-less recognize. */ +static struct { const char *name8, *name16; unsigned char SAprefix[4];} +bad_clone_list[] __initdata = { + {"LA/T-98?", "LA/T-98", {0x00, 0xa0, 0xb0}}, /* I/O Data */ + {"EGY-98?", "EGY-98", {0x00, 0x40, 0x26}}, /* Melco EGY98 */ + {"ICM?", "ICM-27xx-ET", {0x00, 0x80, 0xc8}}, /* ICM IF-27xx-ET */ + {"CNET-98/EL?", "CNET(98)E/L", {0x00, 0x80, 0x4C}}, /* Contec CNET-98/EL */ + {0,} +}; +#endif + +/* ---- No user-serviceable parts below ---- */ + +#define NE_BASE (dev->base_addr) +#define NE_CMD EI_SHIFT(0x00) +#define NE_DATAPORT EI_SHIFT(0x10) /* NatSemi-defined port window offset. */ +#define NE_RESET EI_SHIFT(0x1f) /* Issue a read to reset, a write to clear. */ +#define NE_IO_EXTENT 0x20 + +#define NE1SM_START_PG 0x20 /* First page of TX buffer */ +#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ +#define NESM_START_PG 0x40 /* First page of TX buffer */ +#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ + +#include "ne2k_cbus.h" + +int ne_probe(struct net_device *dev); +static int ne_probe1(struct net_device *dev, int ioaddr); +static int ne_open(struct net_device *dev); +static int ne_close(struct net_device *dev); + +static void ne_reset_8390(struct net_device *dev); +static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void ne_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void ne_block_output(struct net_device *dev, const int count, + const unsigned char *buf, const int start_page); + + +/* Probe for various non-shared-memory ethercards. + + NEx000-clone boards have a Station Address PROM (SAPROM) in the packet + buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of + the SAPROM, while other supposed NE2000 clones must be detected by their + SA prefix. + + Reading the SAPROM from a word-wide card with the 8390 set in byte-wide + mode results in doubled values, which can be detected and compensated for. + + The probe is also responsible for initializing the card and filling + in the 'dev' and 'ei_status' structures. + + We use the minimum memory size for some ethercard product lines, iff we can't + distinguish models. You can increase the packet buffer size by setting + PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: + E1010 starts at 0x100 and ends at 0x2000. + E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") + E2010 starts at 0x100 and ends at 0x4000. + E2010-x starts at 0x100 and ends at 0xffff. */ + +int __init ne_probe(struct net_device *dev) +{ + unsigned int base_addr = dev->base_addr; + + SET_MODULE_OWNER(dev); + + if (ei_debug > 2) + printk(KERN_DEBUG "ne_probe(): entered.\n"); + + /* If CONFIG_NET_CBUS, + we need dev->priv->reg_offset BEFORE to probe */ + if (ne2k_cbus_init(dev) != 0) + return -ENOMEM; + + /* First check any supplied i/o locations. User knows best. <cough> */ + if (base_addr > 0) { + int result; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + if (ei_debug > 2) + printk(KERN_DEBUG "ne_probe(): call ne_probe_cbus(base_addr=0x%x)\n", base_addr); + + result = ne_probe_cbus(dev, hw, base_addr); + if (result != 0) + ne2k_cbus_destroy(dev); + + return result; + } + + if (ei_debug > 2) + printk(KERN_DEBUG "ne_probe(): base_addr is not specified.\n"); + +#ifndef MODULE + /* Last resort. The semi-risky C-Bus auto-probe. */ + if (ei_debug > 2) + printk(KERN_DEBUG "ne_probe(): auto-probe start.\n"); + + { + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + if (hw && hw->hwtype) { + const unsigned short *plist; + for (plist = hw->portlist; *plist; plist++) + if (ne_probe_cbus(dev, hw, *plist) == 0) + return 0; + } else { + for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { + const unsigned short *plist; + for (plist = hw->portlist; *plist; plist++) + if (ne_probe_cbus(dev, hw, *plist) == 0) + return 0; + } + } + } +#endif + + ne2k_cbus_destroy(dev); + + return -ENODEV; +} + +static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr) +{ + if (ei_debug > 2) + printk(KERN_DEBUG "ne_probe_cbus(): entered. (called from %p)\n", + __builtin_return_address(0)); + + if (hw && hw->hwtype) { + ne2k_cbus_set_hwtype(dev, hw, ioaddr); + return ne_probe1(dev, ioaddr); + } else { + /* auto detect */ + + printk(KERN_DEBUG "ne_probe_cbus(): try to determine hardware types.\n"); + for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { + ne2k_cbus_set_hwtype(dev, hw, ioaddr); + if (ne_probe1(dev, ioaddr) == 0) + return 0; + } + } + return -ENODEV; +} + +static int __init ne_probe1(struct net_device *dev, int ioaddr) +{ + int i; + unsigned char SA_prom[32]; + int wordlength = 2; + const char *name = NULL; + int start_page, stop_page; + int neX000, bad_card; + int reg0, ret; + static unsigned version_printed; + const struct ne2k_cbus_region *rlist; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + +#ifdef CONFIG_NE2K_CBUS_CNET98EL + if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) { + outb_p(0, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE); + /* udelay(5000); */ + outb_p(1, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE); + /* udelay(5000); */ + outb_p((ioaddr & 0xf000) >> 8 | 0x08 | 0x01, CONFIG_NE2K_CBUS_CNET98EL_IO_BASE + 2); + /* udelay(5000); */ + } +#endif + + for (rlist = hw->regionlist; rlist->range; rlist++) + if (!request_region(ioaddr + rlist->start, + rlist->range, dev->name)) { + ret = -EBUSY; + goto err_out; + } + + reg0 = inb_p(ioaddr + EI_SHIFT(0)); + if (reg0 == 0xFF) { + ret = -ENODEV; + goto err_out; + } + + /* Do a preliminary verification that we have a 8390. */ +#ifdef CONFIG_NE2K_CBUS_CNET98EL + if (hw->hwtype != NE2K_CBUS_HARDWARE_TYPE_CNET98EL) +#endif + { + int regd; + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + regd = inb_p(ioaddr + EI_SHIFT(0x0d)); + outb_p(0xff, ioaddr + EI_SHIFT(0x0d)); + outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); + inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ + if (inb_p(ioaddr + EN0_COUNTER0) != 0) { + outb_p(reg0, ioaddr); + outb_p(regd, ioaddr + EI_SHIFT(0x0d)); /* Restore the old values. */ + ret = -ENODEV; + goto err_out; + } + } + + if (ei_debug && version_printed++ == 0) + printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); + + printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr); + + /* A user with a poor card that fails to ack the reset, or that + does not have a valid 0x57,0x57 signature can still use this + without having to recompile. Specifying an i/o address along + with an otherwise unused dev->mem_end value of "0xBAD" will + cause the driver to skip these parts of the probe. */ + + bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); + + /* Reset card. Who knows what dain-bramaged state it was left in. */ + + { + unsigned long reset_start_time = jiffies; + + /* derived from CNET98EL-patch for bad clones */ + outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); + + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); + + while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + if (bad_card) { + printk(" (warning: no reset ack)"); + break; + } else { + printk(" not found (no reset ack).\n"); + ret = -ENODEV; + goto err_out; + } + } + + outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ + } + +#ifdef CONFIG_NE2K_CBUS_CNET98EL + if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) { + static const char pat[32] ="AbcdeFghijKlmnoPqrstUvwxyZ789012"; + char buf[32]; + int maxwait = 200; + + if (ei_debug > 2) + printk(" [CNET98EL-specific initialize..."); + outb_p(E8390_NODMA | E8390_STOP, ioaddr + E8390_CMD); /* 0x20|0x1 */ + i = inb(ioaddr); + if ((i & ~0x2) != (0x20 | 0x01)) + return -ENODEV; + if ((inb(ioaddr + 0x7) & 0x80) != 0x80) + return -ENODEV; + outb_p(E8390_RXOFF, ioaddr + EN0_RXCR); /* out(ioaddr+0xc, 0x20) */ + /* outb_p(ENDCFG_WTS|ENDCFG_FT1|ENDCFG_LS, ioaddr+EN0_DCFG); */ + outb_p(ENDCFG_WTS | 0x48, ioaddr + EN0_DCFG); /* 0x49 */ + outb_p(CNET98EL_START_PG, ioaddr + EN0_STARTPG); + outb_p(CNET98EL_STOP_PG, ioaddr + EN0_STOPPG); + if (ei_debug > 2) + printk("memory check"); + for (i = 0; i < 65536; i += 1024) { + if (ei_debug > 2) + printk(" %04x", i); + ne2k_cbus_writemem(dev, ioaddr, i, pat, 32); + while (((inb(ioaddr + EN0_ISR) & ENISR_RDC) != ENISR_RDC) && --maxwait) + ; + ne2k_cbus_readmem(dev, ioaddr, i, buf, 32); + if (memcmp(pat, buf, 32)) { + if (ei_debug > 2) + printk(" failed."); + break; + } + } + if (i != 16384) { + if (ei_debug > 2) + printk("] "); + printk("memory failure at %x\n", i); + return -ENODEV; + } + if (ei_debug > 2) + printk(" good..."); + if (!dev->irq) { + if (ei_debug > 2) + printk("] "); + printk("IRQ must be specified for C-NET(98)E/L. probe failed.\n"); + return -ENODEV; + } + outb((dev->irq > 5) ? (dev->irq & 4):(dev->irq >> 1), ioaddr + (0x2 | 0x400)); + outb(0x7e, ioaddr + (0x4 | 0x400)); + ne2k_cbus_readmem(dev, ioaddr, 16384, SA_prom, 32); + outb(0xff, ioaddr + EN0_ISR); + if (ei_debug > 2) + printk("done]"); + } else +#endif /* CONFIG_NE2K_CBUS_CNET98EL */ + /* Read the 16 bytes of station address PROM. + We must first initialize registers, similar to NS8390_init(eifdev, 0). + We can't reliably read the SAPROM address without this. + (I learned the hard way!). */ + { + struct {unsigned char value; unsigned short offset;} program_seq[] = + { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + /* NEC PC-9800: some board can only handle word-wide access? */ + {0x48 | ENDCFG_WTS, EN0_DCFG}, /* Set word-wide (0x48) access. */ + {16384 / 256, EN0_STARTPG}, + {32768 / 256, EN0_STOPPG}, + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + insw(ioaddr + NE_DATAPORT, SA_prom, 32 >> 1); + + } + + if (wordlength == 2) + { + for (i = 0; i < 16; i++) + SA_prom[i] = SA_prom[i+i]; + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; +#ifdef CONFIG_NE2K_CBUS_CNET98EL + if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_CNET98EL) { + start_page = CNET98EL_START_PG; + stop_page = CNET98EL_STOP_PG; + } +#endif + } else { + start_page = NE1SM_START_PG; + stop_page = NE1SM_STOP_PG; + } + + neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); + if (neX000) { + name = "C-Bus-NE2K-compat"; + } + else + { +#ifdef SUPPORT_NE_BAD_CLONES + /* Ack! Well, there might be a *bad* NE*000 clone there. + Check for total bogus addresses. */ + for (i = 0; bad_clone_list[i].name8; i++) + { + if (SA_prom[0] == bad_clone_list[i].SAprefix[0] && + SA_prom[1] == bad_clone_list[i].SAprefix[1] && + SA_prom[2] == bad_clone_list[i].SAprefix[2]) + { + if (wordlength == 2) + { + name = bad_clone_list[i].name16; + } else { + name = bad_clone_list[i].name8; + } + break; + } + } + if (bad_clone_list[i].name8 == NULL) + { + printk(" not found (invalid signature %2.2x %2.2x).\n", + SA_prom[14], SA_prom[15]); + ret = -ENXIO; + goto err_out; + } +#else + printk(" not found.\n"); + ret = -ENXIO; + goto err_out; +#endif + } + + if (dev->irq < 2) + { + unsigned long cookie = probe_irq_on(); + outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ + outb_p(0x00, ioaddr + EN0_RCNTLO); + outb_p(0x00, ioaddr + EN0_RCNTHI); + outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ + mdelay(10); /* wait 10ms for interrupt to propagate */ + outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ + dev->irq = probe_irq_off(cookie); + if (ei_debug > 2) + printk(" autoirq is %d\n", dev->irq); + } else if (dev->irq == 7) + /* Fixup for users that don't know that IRQ 7 is really IRQ 11, + or don't know which one to set. */ + dev->irq = 11; + + if (! dev->irq) { + printk(" failed to detect IRQ line.\n"); + ret = -EAGAIN; + goto err_out; + } + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) + { + printk (" unable to get memory for dev->priv.\n"); + ret = -ENOMEM; + goto err_out; + } + + /* Snarf the interrupt now. There's no point in waiting since we cannot + share and the board will usually be enabled. */ + ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); + if (ret) { + printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); + goto err_out_kfree; + } + + dev->base_addr = ioaddr; + + for(i = 0; i < ETHER_ADDR_LEN; i++) { + printk(" %2.2x", SA_prom[i]); + dev->dev_addr[i] = SA_prom[i]; + } + + printk("\n%s: %s found at %#x, hardware type %d(%s), using IRQ %d.\n", + dev->name, name, ioaddr, hw->hwtype, hw->hwident, dev->irq); + + ei_status.name = name; + ei_status.tx_start_page = start_page; + ei_status.stop_page = stop_page; + ei_status.word16 = (wordlength == 2); + + ei_status.rx_start_page = start_page + TX_PAGES; +#ifdef PACKETBUF_MEMSIZE + /* Allow the packet buffer size to be overridden by know-it-alls. */ + ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; +#endif + + ei_status.reset_8390 = &ne_reset_8390; + ei_status.block_input = &ne_block_input; + ei_status.block_output = &ne_block_output; + ei_status.get_8390_hdr = &ne_get_8390_hdr; + ei_status.priv = 0; + dev->open = &ne_open; + dev->stop = &ne_close; + NS8390_init(dev, 0); + return 0; + +err_out_kfree: + ne2k_cbus_destroy(dev); +err_out: + while (rlist > hw->regionlist) { + rlist --; + release_region(ioaddr + rlist->start, rlist->range); + } + return ret; +} + +static int ne_open(struct net_device *dev) +{ + ei_open(dev); + return 0; +} + +static int ne_close(struct net_device *dev) +{ + if (ei_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); + ei_close(dev); + return 0; +} + +/* Hard reset the card. This used to pause for the same period that a + 8390 reset command required, but that shouldn't be necessary. */ + +static void ne_reset_8390(struct net_device *dev) +{ + unsigned long reset_start_time = jiffies; + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + + if (ei_debug > 1) + printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); + + /* derived from CNET98EL-patch for bad clones... */ + outb_p(E8390_NODMA | E8390_STOP, NE_BASE + E8390_CMD); /* 0x20 | 0x1 */ + + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + + ei_status.txing = 0; + ei_status.dmaing = 0; + + /* This check _should_not_ be necessary, omit eventually. */ + while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); + break; + } + outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ +} + +/* Grab the 8390 specific header. Similar to the block_input routine, but + we don't need to be concerned with ring wrap as the header will be at + the start of a page, so we optimize accordingly. */ + +static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + int nic_base = dev->base_addr; + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); + outb_p(0, nic_base + EN0_RCNTHI); + outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + + if (ei_status.word16) + insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); + else + insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + + le16_to_cpus(&hdr->count); +} + +/* Block input and output, similar to the Crynwr packet driver. If you + are porting to a new ethercard, look at the packet driver source for hints. + The NEx000 doesn't share the on-board packet memory -- you have to put + the packet out through the "remote DMA" dataport using outb. */ + +static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) +{ +#ifdef NE_SANITY_CHECK + int xfer_count = count; +#endif + int nic_base = dev->base_addr; + char *buf = skb->data; + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + + /* round up count to a word (derived from ICM-patch) */ + count = (count + 1) & ~1; + + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) + { + insw(NE_BASE + NE_DATAPORT,buf,count>>1); + if (count & 0x01) + { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); +#ifdef NE_SANITY_CHECK + xfer_count++; +#endif + } + } else { + insb(NE_BASE + NE_DATAPORT, buf, count); + } + +#ifdef NE_SANITY_CHECK + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. If you see + this message you either 1) have a slightly incompatible clone + or 2) have noise/speed problems with your bus. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken for Rx on some cards! */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + xfer_count) & 0xff) == low) + break; + } while (--tries > 0); + if (tries <= 0) + printk(KERN_WARNING "%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } +#endif + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; +} + +static void ne_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + int nic_base = NE_BASE; + unsigned long dma_start; +#ifdef NE_SANITY_CHECK + int retries = 0; +#endif + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + + if (ei_status.word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + +#ifdef NE_SANITY_CHECK +retry: +#endif + +#ifdef NE8390_RW_BUGFIX + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. + Actually this doesn't always work either, but if you have + problems with your NEx000 this is better than nothing! */ + + outb_p(0x42, nic_base + EN0_RCNTLO); + outb_p(0x00, nic_base + EN0_RCNTHI); + outb_p(0x42, nic_base + EN0_RSARLO); + outb_p(0x00, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + /* Make certain that the dummy read has occurred. */ + udelay(6); +#endif + + outb_p(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) { + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); + } else { + outsb(NE_BASE + NE_DATAPORT, buf, count); + } + + dma_start = jiffies; + +#ifdef NE_SANITY_CHECK + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + + if (tries <= 0) + { + printk(KERN_WARNING "%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } + } +#endif + + while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); + ne_reset_8390(dev); + NS8390_init(dev,1); + break; + } + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + return; +} + + +#ifdef MODULE +#define MAX_NE_CARDS 4 /* Max number of NE cards per module */ +static struct net_device dev_ne[MAX_NE_CARDS]; +static int io[MAX_NE_CARDS]; +static int irq[MAX_NE_CARDS]; +static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ +static int hwtype[MAX_NE_CARDS] = { 0, }; /* board type */ + +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM(hwtype, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +MODULE_PARM_DESC(io, "I/O base address(es),required"); +MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); +MODULE_PARM_DESC(hwtype, "Board type of PC-9800 C-Bus NIC"); +MODULE_DESCRIPTION("NE1000/NE2000 PC-9800 C-bus Ethernet driver"); +MODULE_LICENSE("GPL"); + +/* This is set up so that no ISA autoprobe takes place. We can't guarantee +that the ne2k probe is the last 8390 based probe to take place (as it +is at boot) and so the probe will get confused by any other 8390 cards. +ISA device autoprobes on a running machine are not recommended anyway. */ + +int init_module(void) +{ + int this_dev, found = 0; + + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + struct net_device *dev = &dev_ne[this_dev]; + dev->irq = irq[this_dev]; + dev->mem_end = bad[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = hwtype[this_dev]; + dev->init = ne_probe; + if (register_netdev(dev) == 0) { + found++; + continue; + } + if (found != 0) { /* Got at least one. */ + return 0; + } + if (io[this_dev] != 0) + printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); + else + printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for C-Bus cards.\n"); + return -ENXIO; + } + return 0; +} + +void cleanup_module(void) +{ + int this_dev; + + for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { + struct net_device *dev = &dev_ne[this_dev]; + if (dev->priv != NULL) { + const struct ne2k_cbus_region *rlist; + const struct ne2k_cbus_hwinfo *hw = ne2k_cbus_get_hwinfo((int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + + free_irq(dev->irq, dev); + for (rlist = hw->regionlist; rlist->range; rlist++) { + release_region(dev->base_addr + rlist->start, + rlist->range); + } + unregister_netdev(dev); + ne2k_cbus_destroy(dev); + } + } +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff --git a/drivers/net/ne2k_cbus.h b/drivers/net/ne2k_cbus.h new file mode 100644 index 000000000000..e561ef7f6111 --- /dev/null +++ b/drivers/net/ne2k_cbus.h @@ -0,0 +1,481 @@ +/* ne2k_cbus.h: + vender-specific information definition for NEC PC-9800 + C-bus Ethernet Cards + Used in ne.c + + (C)1998,1999 KITAGWA Takurou & Linux/98 project +*/ + +#include <linux/config.h> + +#undef NE_RESET +#define NE_RESET EI_SHIFT(0x11) /* Issue a read to reset, a write to clear. */ + +#ifdef CONFIG_NE2K_CBUS_CNET98EL +#ifndef CONFIG_NE2K_CBUS_CNET98EL_IO_BASE +#warning CONFIG_NE2K_CBUS_CNET98EL_IO_BASE is not defined(config error?) +#warning use 0xaaed as default +#define CONFIG_NE2K_CBUS_CNET98EL_IO_BASE 0xaaed /* or 0x55ed */ +#endif +#define CNET98EL_START_PG 0x00 +#define CNET98EL_STOP_PG 0x40 +#endif + +/* Hardware type definition (derived from *BSD) */ +#define NE2K_CBUS_HARDWARE_TYPE_MASK 0xff + +/* 0: reserved for auto-detect */ +/* 1: (not tested) + Allied Telesis CentreCom LA-98-T */ +#define NE2K_CBUS_HARDWARE_TYPE_ATLA98 1 +/* 2: (not tested) + ELECOM Laneed + LD-BDN[123]A + PLANET SMART COM 98 EN-2298-C + MACNICA ME98 */ +#define NE2K_CBUS_HARDWARE_TYPE_BDN 2 +/* 3: + Melco EGY-98 + Contec C-NET(98)E*A/L*A,C-NET(98)P */ +#define NE2K_CBUS_HARDWARE_TYPE_EGY98 3 +/* 4: + Melco LGY-98,IND-SP,IND-SS + MACNICA NE2098 */ +#define NE2K_CBUS_HARDWARE_TYPE_LGY98 4 +/* 5: + ICM DT-ET-25,DT-ET-T5,IF-2766ET,IF-2771ET + PLANET SMART COM 98 EN-2298-T,EN-2298P-T + D-Link DE-298PT,DE-298PCAT + ELECOM Laneed LD-98P */ +#define NE2K_CBUS_HARDWARE_TYPE_ICM 5 +/* 6: (reserved for SIC-98, which is not supported in this driver.) */ +/* 7: (unused in *BSD?) + <Original NE2000 compatible> + <for PCI/PCMCIA cards> +*/ +#define NE2K_CBUS_HARDWARE_TYPE_NE2K 7 +/* 8: + NEC PC-9801-108 */ +#define NE2K_CBUS_HARDWARE_TYPE_NEC108 8 +/* 9: + I-O DATA LA-98,LA/T-98 */ +#define NE2K_CBUS_HARDWARE_TYPE_IOLA98 9 +/* 10: (reserved for C-NET(98), which is not supported in this driver.) */ +/* 11: + Contec C-NET(98)E,L */ +#define NE2K_CBUS_HARDWARE_TYPE_CNET98EL 11 + +#define NE2K_CBUS_HARDWARE_TYPE_MAX 11 + +/* HARDWARE TYPE ID 12-31: reserved */ + +struct ne2k_cbus_offsetinfo { + unsigned short skip; + unsigned short offset8; /* +0x8 - +0xf */ + unsigned short offset10; /* +0x10 */ + unsigned short offset1f; /* +0x1f */ +}; + +struct ne2k_cbus_region { + unsigned short start; + short range; +}; + +struct ne2k_cbus_hwinfo { + const unsigned short hwtype; + const unsigned char *hwident; +#ifndef MODULE + const unsigned short *portlist; +#endif + const struct ne2k_cbus_offsetinfo *offsetinfo; + const struct ne2k_cbus_region *regionlist; +}; + +#ifdef CONFIG_NE2K_CBUS_ATLA98 +#ifndef MODULE +static unsigned short atla98_portlist[] __initdata = { + 0xd0, + 0 +}; +#endif +#define atla98_offsetinfo ne2k_offsetinfo +#define atla98_regionlist ne2k_regionlist +#endif /* CONFIG_NE2K_CBUS_ATLA98 */ + +#ifdef CONFIG_NE2K_CBUS_BDN +#ifndef MODULE +static unsigned short bdn_portlist[] __initdata = { + 0xd0, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo bdn_offsetinfo __initdata = { +#if 0 + /* comes from FreeBSD(98) ed98.h */ + 0x1000, 0x8000, 0x100, 0xc200 /* ??? */ +#else + /* comes from NetBSD/pc98 if_ne_isa.c */ + 0x1000, 0x8000, 0x100, 0x7f00 /* ??? */ +#endif +}; +static struct ne2k_cbus_region bdn_regionlist[] __initdata = { + {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000,1}, + {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1}, + {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1}, + {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1}, + {0x100, 1}, {0x7f00, 1}, + {0x0, 0} +}; +#endif /* CONFIG_NE2K_CBUS_BDN */ + +#ifdef CONFIG_NE2K_CBUS_EGY98 +#ifndef MODULE +static unsigned short egy98_portlist[] __initdata = { + 0xd0, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo egy98_offsetinfo __initdata = { + 0x02, 0x100, 0x200, 0x300 +}; +static struct ne2k_cbus_region egy98_regionlist[] __initdata = { + {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1}, + {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1}, + {0x100, 1}, {0x102, 1}, {0x104, 1}, {0x106, 1}, + {0x108, 1}, {0x10a, 1}, {0x10c, 1}, {0x10e, 1}, + {0x200, 1}, {0x300, 1}, + {0x0, 0} +}; +#endif /* CONFIG_NE2K_CBUS_EGY98 */ + +#ifdef CONFIG_NE2K_CBUS_LGY98 +#ifndef MODULE +static unsigned short lgy98_portlist[] __initdata = { + 0xd0, 0x10d0, 0x20d0, 0x30d0, 0x40d0, 0x50d0, 0x60d0, 0x70d0, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo lgy98_offsetinfo __initdata = { + 0x01, 0x08, 0x200, 0x300 +}; +static struct ne2k_cbus_region lgy98_regionlist[] __initdata = { + {0x0, 16}, {0x200, 1}, {0x300, 1}, + {0x0, 0} +}; +#endif /* CONFIG_NE2K_CBUS_LGY98 */ + +#ifdef CONFIG_NE2K_CBUS_ICM +#ifndef MODULE +static unsigned short icm_portlist[] __initdata = { + /* ICM */ + 0x56d0, + /* LD-98PT */ + 0x46d0, 0x66d0, 0x76d0, 0x86d0, 0x96d0, 0xa6d0, 0xb6d0, 0xc6d0, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo icm_offsetinfo __initdata = { + 0x01, 0x08, 0x100, 0x10f +}; +static struct ne2k_cbus_region icm_regionlist[] __initdata = { + {0x0, 16}, {0x100, 16}, + {0x0, 0} +}; +#endif /* CONFIG_NE2K_CBUS_ICM */ + +#if defined(CONFIG_NE2K_CBUS_NE2K) && !defined(MODULE) +static unsigned short ne2k_portlist[] __initdata = { + 0xd0, 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, + 0 +}; +#endif +#if defined(CONFIG_NE2K_CBUS_NE2K) || defined(CONFIG_NE2K_CBUS_ATLA98) +static struct ne2k_cbus_offsetinfo ne2k_offsetinfo __initdata = { + 0x01, 0x08, 0x10, 0x1f +}; +static struct ne2k_cbus_region ne2k_regionlist[] __initdata = { + {0x0, 32}, + {0x0, 0} +}; +#endif + +#ifdef CONFIG_NE2K_CBUS_NEC108 +#ifndef MODULE +static unsigned short nec108_portlist[] __initdata = { + 0x770, 0x2770, 0x4770, 0x6770, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo nec108_offsetinfo __initdata = { + 0x02, 0x1000, 0x888, 0x88a +}; +static struct ne2k_cbus_region nec108_regionlist[] __initdata = { + {0x0, 1}, {0x2, 1}, {0x4, 1}, {0x6, 1}, + {0x8, 1}, {0xa, 1}, {0xc, 1}, {0xe, 1}, + {0x1000, 1}, {0x1002, 1}, {0x1004, 1}, {0x1006, 1}, + {0x1008, 1}, {0x100a, 1}, {0x100c, 1}, {0x100e, 1}, + {0x888, 1}, {0x88a, 1}, {0x88c, 1}, {0x88e, 1}, + {0x0, 0} +}; +#endif + +#ifdef CONFIG_NE2K_CBUS_IOLA98 +#ifndef MODULE +static unsigned short iola98_portlist[] __initdata = { + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo iola98_offsetinfo __initdata = { + 0x1000, 0x8000, 0x100, 0xf100 +}; +static struct ne2k_cbus_region iola98_regionlist[] __initdata = { + {0x0, 1}, {0x1000, 1}, {0x2000, 1}, {0x3000, 1}, + {0x4000, 1}, {0x5000, 1}, {0x6000, 1}, {0x7000, 1}, + {0x8000, 1}, {0x9000, 1}, {0xa000, 1}, {0xb000, 1}, + {0xc000, 1}, {0xd000, 1}, {0xe000, 1}, {0xf000, 1}, + {0x100, 1}, {0xf100, 1}, + {0x0,0} +}; +#endif /* CONFIG_NE2K_CBUS_IOLA98 */ + +#ifdef CONFIG_NE2K_CBUS_CNET98EL +#ifndef MODULE +static unsigned short cnet98el_portlist[] __initdata = { + 0x3d0, 0x13d0, 0x23d0, 0x33d0, 0x43d0, 0x53d0, 0x60d0, 0x70d0, + 0 +}; +#endif +static struct ne2k_cbus_offsetinfo cnet98el_offsetinfo __initdata = { + 0x01, 0x08, 0x40e, 0x400 +}; +static struct ne2k_cbus_region cnet98el_regionlist[] __initdata = { + {0x0, 16}, {0x400, 16}, + {0x0, 0} +}; +#endif + + +/* port information table (for ne.c initialize/probe process) */ + +static struct ne2k_cbus_hwinfo ne2k_cbus_hwinfo_list[] __initdata = { +#ifdef CONFIG_NE2K_CBUS_ATLA98 +/* NOT TESTED */ + { + NE2K_CBUS_HARDWARE_TYPE_ATLA98, + "LA-98-T", +#ifndef MODULE + atla98_portlist, +#endif + &atla98_offsetinfo, atla98_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_BDN +/* NOT TESTED */ + { + NE2K_CBUS_HARDWARE_TYPE_BDN, + "LD-BDN[123]A", +#ifndef MODULE + bdn_portlist, +#endif + &bdn_offsetinfo, bdn_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_ICM + { + NE2K_CBUS_HARDWARE_TYPE_ICM, + "IF-27xxET", +#ifndef MODULE + icm_portlist, +#endif + &icm_offsetinfo, icm_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_NE2K + { + NE2K_CBUS_HARDWARE_TYPE_NE2K, + "NE2000 compat.", +#ifndef MODULE + ne2k_portlist, +#endif + &ne2k_offsetinfo, ne2k_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_NEC108 + { + NE2K_CBUS_HARDWARE_TYPE_NEC108, + "PC-9801-108", +#ifndef MODULE + nec108_portlist, +#endif + &nec108_offsetinfo, nec108_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_IOLA98 + { + NE2K_CBUS_HARDWARE_TYPE_IOLA98, + "LA-98", +#ifndef MODULE + iola98_portlist, +#endif + &iola98_offsetinfo, iola98_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_CNET98EL + { + NE2K_CBUS_HARDWARE_TYPE_CNET98EL, + "C-NET(98)E/L", +#ifndef MODULE + cnet98el_portlist, +#endif + &cnet98el_offsetinfo, cnet98el_regionlist + }, +#endif +/* NOTE: LGY98 must be probed before EGY98, or system stalled!? */ +#ifdef CONFIG_NE2K_CBUS_LGY98 + { + NE2K_CBUS_HARDWARE_TYPE_LGY98, + "LGY-98", +#ifndef MODULE + lgy98_portlist, +#endif + &lgy98_offsetinfo, lgy98_regionlist + }, +#endif +#ifdef CONFIG_NE2K_CBUS_EGY98 + { + NE2K_CBUS_HARDWARE_TYPE_EGY98, + "EGY-98", +#ifndef MODULE + egy98_portlist, +#endif + &egy98_offsetinfo, egy98_regionlist + }, +#endif + { + 0, + "unsupported hardware", +#ifndef MODULE + NULL, +#endif + NULL, NULL + } +}; + +static int __init ne2k_cbus_init(struct net_device *dev) +{ + struct ei_device *ei_local; + if (dev->priv == NULL) { + ei_local = kmalloc(sizeof(struct ei_device), GFP_KERNEL); + if (ei_local == NULL) + return -ENOMEM; + memset(ei_local, 0, sizeof(struct ei_device)); + ei_local->reg_offset = kmalloc(sizeof(typeof(*ei_local->reg_offset))*18, GFP_KERNEL); + if (ei_local->reg_offset == NULL) { + kfree(ei_local); + return -ENOMEM; + } + spin_lock_init(&ei_local->page_lock); + dev->priv = ei_local; + } + return 0; +} + +static void ne2k_cbus_destroy(struct net_device *dev) +{ + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + if (ei_local != NULL) { + if (ei_local->reg_offset) + kfree(ei_local->reg_offset); + kfree(dev->priv); + dev->priv = NULL; + } +} + +static const struct ne2k_cbus_hwinfo * __init ne2k_cbus_get_hwinfo(int hwtype) +{ + const struct ne2k_cbus_hwinfo *hw; + + for (hw = &ne2k_cbus_hwinfo_list[0]; hw->hwtype; hw++) { + if (hw->hwtype == hwtype) break; + } + return hw; +} + +static void __init ne2k_cbus_set_hwtype(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr) +{ + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + int i; + int hwtype_old = dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK; + + if (!ei_local) + panic("Gieee! ei_local == NULL!! (from %p)", + __builtin_return_address(0)); + + dev->mem_start &= ~NE2K_CBUS_HARDWARE_TYPE_MASK; + dev->mem_start |= hw->hwtype & NE2K_CBUS_HARDWARE_TYPE_MASK; + + if (ei_debug > 2) { + printk(KERN_DEBUG "hwtype changed: %d -> %d\n",hwtype_old,(int)(dev->mem_start & NE2K_CBUS_HARDWARE_TYPE_MASK)); + } + + if (hw->offsetinfo) { + for (i = 0; i < 8; i++) { + ei_local->reg_offset[i] = hw->offsetinfo->skip * i; + } + for (i = 8; i < 16; i++) { + ei_local->reg_offset[i] = + hw->offsetinfo->skip*(i-8) + hw->offsetinfo->offset8; + } +#ifdef CONFIG_NE2K_CBUS_NEC108 + if (hw->hwtype == NE2K_CBUS_HARDWARE_TYPE_NEC108) { + int adj = (ioaddr & 0xf000) /2; + ei_local->reg_offset[16] = + (hw->offsetinfo->offset10 | adj) - ioaddr; + ei_local->reg_offset[17] = + (hw->offsetinfo->offset1f | adj) - ioaddr; + } else { +#endif /* CONFIG_NE2K_CBUS_NEC108 */ + ei_local->reg_offset[16] = hw->offsetinfo->offset10; + ei_local->reg_offset[17] = hw->offsetinfo->offset1f; +#ifdef CONFIG_NE2K_CBUS_NEC108 + } +#endif + } else { + /* make dummmy offset list */ + for (i = 0; i < 16; i++) { + ei_local->reg_offset[i] = i; + } + ei_local->reg_offset[16] = 0x10; + ei_local->reg_offset[17] = 0x1f; + } +} + +#if defined(CONFIG_NE2K_CBUS_ICM) || defined(CONFIG_NE2K_CBUS_CNET98EL) +static void __init ne2k_cbus_readmem(struct net_device *dev, int ioaddr, unsigned short memaddr, char *buf, unsigned short len) +{ + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD); + outb_p(len & 0xff, ioaddr+EN0_RCNTLO); + outb_p(len >> 8, ioaddr+EN0_RCNTHI); + outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO); + outb_p(memaddr >> 8, ioaddr+EN0_RSARHI); + outb_p(E8390_RREAD | E8390_START, ioaddr+E8390_CMD); + insw(ioaddr+NE_DATAPORT, buf, len >> 1); +} +static void __init ne2k_cbus_writemem(struct net_device *dev, int ioaddr, unsigned short memaddr, const char *buf, unsigned short len) +{ + struct ei_device *ei_local = (struct ei_device *)(dev->priv); + outb_p(E8390_NODMA | E8390_START, ioaddr+E8390_CMD); + outb_p(ENISR_RDC, ioaddr+EN0_ISR); + outb_p(len & 0xff, ioaddr+EN0_RCNTLO); + outb_p(len >> 8, ioaddr+EN0_RCNTHI); + outb_p(memaddr & 0xff, ioaddr+EN0_RSARLO); + outb_p(memaddr >> 8, ioaddr+EN0_RSARHI); + outb_p(E8390_RWRITE | E8390_START, ioaddr+E8390_CMD); + outsw(ioaddr+NE_DATAPORT, buf, len >> 1); +} +#endif + +static int ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr); +/* End of ne2k_cbus.h */ diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index e5f5670201e1..e78c6e1006ae 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -2214,6 +2214,11 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) * and for initialization. */ +static void ppp_device_destructor(struct net_device *dev) +{ + kfree(dev); +} + /* * Create a new ppp interface unit. Fails if it can't allocate memory * or if there is already a unit with the requested number. @@ -2262,7 +2267,7 @@ ppp_create_interface(int unit, int *retp) dev->init = ppp_net_init; sprintf(dev->name, "ppp%d", unit); dev->priv = ppp; - dev->features |= NETIF_F_DYNALLOC; + dev->destructor = ppp_device_destructor; rtnl_lock(); ret = register_netdevice(dev); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8f48359a3496..ea4082646fde 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -55,8 +55,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4c" -#define DRV_MODULE_RELDATE "Feb 18, 2003" +#define DRV_MODULE_VERSION "1.5" +#define DRV_MODULE_RELDATE "March 21, 2003" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -6581,11 +6581,11 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl); + ret = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) - return 0; + goto out; - ret = 0; while (1) { u32 *p, i; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 69176c1ef875..2e33b62d2d3f 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -322,7 +322,7 @@ static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node u16 status; if (!pnp_bios_present()) return PNP_FUNCTION_NOT_SUPPORTED; - if ( !boot & pnpbios_dont_use_current_config ) + if ( !boot && pnpbios_dont_use_current_config ) return PNP_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0, nodenum, sizeof(char), data, 65536); @@ -350,7 +350,7 @@ static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node * u16 status; if (!pnp_bios_present()) return PNP_FUNCTION_NOT_SUPPORTED; - if ( !boot & pnpbios_dont_use_current_config ) + if ( !boot && pnpbios_dont_use_current_config ) return PNP_FUNCTION_NOT_SUPPORTED; status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0, data, 65536, 0, 0); diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 2652645219fb..c90651671cae 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2002 3ware Inc. + Copyright (C) 1999-2003 3ware Inc. Kernel compatiblity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> @@ -164,6 +164,11 @@ Add support for mode sense opcode. Add support for cache mode page. Add support for synchronize cache opcode. + 1.02.00.032 - Fix small multicard rollcall bug. + Make driver stay loaded with no units for hot add/swap. + Add support for "twe" character device for ioctls. + Clean up request_id queueing code. + Fix tw_scsi_queue() spinlocks. */ #include <linux/module.h> @@ -203,6 +208,9 @@ MODULE_LICENSE("GPL"); #include "3w-xxxx.h" +static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int tw_chrdev_open(struct inode *inode, struct file *file); +static int tw_chrdev_release(struct inode *inode, struct file *file); static int tw_copy_info(TW_Info *info, char *fmt, ...); static void tw_copy_mem_info(TW_Info *info, char *data, int len); static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs); @@ -216,10 +224,19 @@ static struct notifier_block tw_notifier = { tw_halt, NULL, 0 }; +/* File operations struct for character device */ +static struct file_operations tw_fops = { + owner: THIS_MODULE, + ioctl: tw_chrdev_ioctl, + open: tw_chrdev_open, + release: tw_chrdev_release +}; + /* Globals */ -char *tw_driver_version="1.02.00.031"; +char *tw_driver_version="1.02.00.032"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; +static int twe_major = -1; /* Functions */ @@ -599,6 +616,209 @@ int tw_check_errors(TW_Device_Extension *tw_dev) return 0; } /* End tw_check_errors() */ +/* This function handles ioctl for the character device */ +static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int error, request_id; + dma_addr_t dma_handle; + unsigned short tw_aen_code; + struct timeval before, timeout; + unsigned long flags = 0x0; + unsigned int data_buffer_length = 0; + unsigned long data_buffer_length_adjusted = 0; + unsigned long *cpu_addr; + TW_New_Ioctl *tw_ioctl; + TW_Passthru *passthru; + TW_Device_Extension *tw_dev = tw_device_extension_list[minor(inode->i_rdev)]; + + dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n"); + + /* Only let one of these through at a time */ + if (test_and_set_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags)) { + return -EBUSY; + } + + /* First copy down the buffer length */ + error = copy_from_user(&data_buffer_length, (void *)arg, sizeof(unsigned int)); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying buffer length from userspace.\n"); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + return -EFAULT; + } + + /* Check size */ + if (data_buffer_length > TW_MAX_SECTORS * 512) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Invalid buffer size (%d).\n", data_buffer_length); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + return -EFAULT; + } + + /* Hardware can only do multiple of 512 byte transfers */ + if (data_buffer_length % 512) + data_buffer_length_adjusted = data_buffer_length + 512 - (data_buffer_length % 512); + else + data_buffer_length_adjusted = data_buffer_length; + + /* Now allocate ioctl buf memory */ + cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle); + if (cpu_addr == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error allocating memory.\n"); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + return -ENOMEM; + } + + tw_ioctl = (TW_New_Ioctl *)cpu_addr; + + /* Now copy down the entire ioctl */ + error = copy_from_user(tw_ioctl, (void *)arg, data_buffer_length + sizeof(TW_New_Ioctl) - 1); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data from userspace.\n"); + pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + return -EFAULT; + } + + passthru = (TW_Passthru *)&tw_ioctl->firmware_command; + + /* See which ioctl we are doing */ + switch (cmd) { + case TW_OP_NOP: + dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n"); + break; + case TW_OP_AEN_LISTEN: + dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n"); + memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length); + if (tw_dev->aen_head == tw_dev->aen_tail) { + tw_aen_code = TW_AEN_QUEUE_EMPTY; + } else { + tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head]; + if (tw_dev->aen_head == TW_Q_LENGTH - 1) { + tw_dev->aen_head = TW_Q_START; + } else { + tw_dev->aen_head = tw_dev->aen_head + 1; + } + } + memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code)); + break; + case TW_CMD_PACKET_WITH_DATA: + dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n"); + spin_lock_irqsave(&tw_dev->tw_lock, flags); + + tw_state_request_start(tw_dev, &request_id); + + /* Flag internal command */ + tw_dev->srb[request_id] = 0; + + /* Flag chrdev ioctl */ + tw_dev->chrdev_request_id = request_id; + + tw_ioctl->firmware_command.request_id = request_id; + + /* Load the sg list */ + switch (tw_ioctl->firmware_command.byte0.sgl_offset) { + case 2: + tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; + tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted; + break; + case 3: + tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; + tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted; + break; + case 5: + passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; + passthru->sg_list[0].length = data_buffer_length_adjusted; + break; + } + + memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command)); + + /* Now post the command packet to the controller */ + tw_post_command_packet(tw_dev, request_id); + spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + + /* Now wait for the command to complete */ + do_gettimeofday(&before); + + tw_ioctl_chrdev_retry: + + if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { + interruptible_sleep_on_timeout(&tw_dev->ioctl_wqueue, 1); + do_gettimeofday(&timeout); + if (before.tv_sec + TW_IOCTL_CHRDEV_TIMEOUT < timeout.tv_sec) { + /* Now we need to reset the board */ + printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); + spin_lock_irqsave(&tw_dev->tw_lock, flags); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); + tw_dev->posted_request_count--; + if (tw_reset_device_extension(tw_dev)) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); + } + spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + if (signal_pending(current)) + return -EINTR; + else + return -EIO; + } else { + goto tw_ioctl_chrdev_retry; + } + } + + /* Now copy in the command packet response */ + memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command)); + + /* Now complete the io */ + spin_lock_irqsave(&tw_dev->tw_lock, flags); + tw_dev->posted_request_count--; + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + break; + default: + printk(KERN_WARNING "3w-xxxx: Unknown chrdev ioctl 0x%x.\n", cmd); + } + + /* Now copy the response to userspace */ + error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + tw_ioctl->data_buffer_length - 1); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data to userspace.\n"); + pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + return -EFAULT; + } + + /* Now free ioctl buf memory */ + pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); + + clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags); + + return 0; +} /* End tw_chrdev_ioctl() */ + +/* This function handles open for the character device */ +static int tw_chrdev_open(struct inode *inode, struct file *file) +{ + unsigned int minor_number; + + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); + + minor_number = minor(inode->i_rdev); + if (minor_number >= tw_device_extension_count) + return -ENODEV; + + return 0; +} /* End tw_chrdev_open() */ + +/* This function handles close for the character device */ +static int tw_chrdev_release(struct inode *inode, struct file *file) +{ + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n"); + + return 0; +} /* End tw_chrdev_release() */ + /* This function will clear all interrupts on the controller */ void tw_clear_all_interrupts(TW_Device_Extension *tw_dev) { @@ -867,7 +1087,9 @@ int tw_findcards(Scsi_Host_Template *tw_host) /* Disable interrupts on the card */ tw_disable_interrupts(tw_dev); - + + tries = 0; + while (tries < TW_MAX_RESET_TRIES) { /* Do soft reset */ tw_soft_reset(tw_dev); @@ -897,8 +1119,8 @@ int tw_findcards(Scsi_Host_Template *tw_host) continue; } - /* Make sure that io region isn't already taken */ - if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) { + /* Reserve the io address space */ + if (!request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME)) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", (tw_dev->tw_pci_dev->resource[0].start), (tw_dev->tw_pci_dev->resource[0].start) + @@ -907,16 +1129,10 @@ int tw_findcards(Scsi_Host_Template *tw_host) kfree(tw_dev); continue; } - - /* Reserve the io address space */ - request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); + error = tw_initialize_units(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", j); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); @@ -935,7 +1151,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) if (tw_dev->num_units > 0) { /* Use SHT cmd_per_lun here */ tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_LENGTH - 1; + tw_dev->free_tail = TW_Q_START; tw_dev->free_wrap = TW_Q_LENGTH - 1; } @@ -992,13 +1208,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) /* Tell the firmware we support shutdown notification*/ error = tw_setfeature(tw_dev2, 2, 1, &c); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j); - scsi_unregister(host); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - numcards--; - continue; + printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j); } /* Now setup the interrupt handler */ @@ -1023,10 +1233,14 @@ int tw_findcards(Scsi_Host_Template *tw_host) } } - if (numcards == 0) - printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n"); - else - register_reboot_notifier(&tw_notifier); + if (numcards == 0) { + printk(KERN_WARNING "3w-xxxx: No cards found.\n"); + } else { + register_reboot_notifier(&tw_notifier); + if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) { + printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major); + } + } return numcards; } /* End tw_findcards() */ @@ -1153,6 +1367,8 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev) tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; spin_lock_init(&tw_dev->tw_lock); + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; + init_waitqueue_head(&tw_dev->ioctl_wqueue); return 0; } /* End tw_initialize_device_extension() */ @@ -1395,9 +1611,14 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) /* Check for internal command completion */ if (tw_dev->srb[request_id] == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); - retval = tw_aen_complete(tw_dev, request_id); - if (retval) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); + /* Check for chrdev ioctl completion */ + if (request_id != tw_dev->chrdev_request_id) { + retval = tw_aen_complete(tw_dev, request_id); + if (retval) { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); + } + } else { + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; } } else { switch (tw_dev->srb[request_id]->cmnd[0]) { @@ -1409,6 +1630,10 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) case WRITE_6: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n"); break; + case TEST_UNIT_READY: + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n"); + error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id); + break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); error = tw_scsiop_inquiry_complete(tw_dev, request_id); @@ -2070,12 +2295,13 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev) tw_dev->state[i] = TW_S_INITIAL; } tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_LENGTH - 1; + tw_dev->free_tail = TW_Q_START; tw_dev->posted_request_count = 0; tw_dev->pending_request_count = 0; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; tw_dev->reset_print = 0; + tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; return 0; } /* End tw_reset_device_extension() */ @@ -2357,7 +2583,6 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) unsigned char *command = SCpnt->cmnd; int request_id = 0; int error = 0; - unsigned long flags = 0; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; if (tw_dev == NULL) { @@ -2367,14 +2592,14 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } - spin_lock_irqsave(&tw_dev->tw_lock, flags); + spin_lock(&tw_dev->tw_lock); dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n"); /* Skip scsi command if it isn't for us */ - if ((tw_dev->is_unit_present[SCpnt->device->id] == FALSE) || (SCpnt->device->lun != 0)) { + if ((SCpnt->device->channel != 0) || (SCpnt->device->lun != 0)) { SCpnt->result = (DID_BAD_TARGET << 16); done(SCpnt); - spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + spin_unlock(&tw_dev->tw_lock); return 0; } @@ -2387,6 +2612,9 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; + /* Initialize phase to zero */ + SCpnt->SCp.phase = 0; + switch (*command) { case READ_10: case READ_6: @@ -2436,7 +2664,7 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) SCpnt->result = (DID_ERROR << 16); done(SCpnt); } - spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + spin_unlock(&tw_dev->tw_lock); return 0; } /* End tw_scsi_queue() */ @@ -2460,6 +2688,12 @@ int tw_scsi_release(struct Scsi_Host *tw_host) /* Free up the IRQ */ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); + /* Unregister character device */ + if (twe_major >= 0) { + unregister_chrdev(twe_major, "twe"); + twe_major = -1; + } + /* Free up device extension resources */ tw_free_device_extension(tw_dev); @@ -2533,7 +2767,6 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) { unsigned char *is_unit_present; unsigned char *request_buffer; - int i; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n"); @@ -2545,12 +2778,12 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) } request_buffer = tw_dev->srb[request_id]->request_buffer; memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); - request_buffer[0] = TYPE_DISK; /* Peripheral device type */ - request_buffer[1] = 0; /* Device type modifier */ - request_buffer[2] = 0; /* No ansi/iso compliance */ - request_buffer[4] = 31; /* Additional length */ + request_buffer[0] = TYPE_DISK; /* Peripheral device type */ + request_buffer[1] = 0; /* Device type modifier */ + request_buffer[2] = 0; /* No ansi/iso compliance */ + request_buffer[4] = 31; /* Additional length */ memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */ - memcpy(&request_buffer[16], "3w-xxxx ", 16); /* Product ID */ + sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id); memcpy(&request_buffer[32], tw_driver_version, 3); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; @@ -2560,15 +2793,12 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) } is_unit_present = &(param->data[0]); - for (i=0 ; i<TW_MAX_UNITS; i++) { - if (is_unit_present[i] == 0) { - tw_dev->is_unit_present[i] = FALSE; - } else { - if (is_unit_present[i] & TW_UNIT_ONLINE) { - tw_dev->is_unit_present[i] = TRUE; - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete: Unit %d found.\n", i); - } - } + if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE; + } else { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE; + tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); + return TW_ISR_DONT_RESULT; } return 0; @@ -2946,17 +3176,88 @@ int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id) /* This function will handle test unit ready scsi command */ int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id) { + TW_Param *param; + TW_Command *command_packet; + unsigned long command_que_value; + u32 command_que_addr; + unsigned long param_value; + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n"); - /* Tell the scsi layer were done */ - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->srb[request_id]->result = (DID_OK << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + /* Initialize command packet */ + command_que_addr = tw_dev->registers.command_que_addr; + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + if (command_packet == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n"); + return 1; + } + memset(command_packet, 0, sizeof(TW_Sector)); + command_packet->byte0.opcode = TW_OP_GET_PARAM; + command_packet->byte0.sgl_offset = 2; + command_packet->size = 4; + command_packet->request_id = request_id; + command_packet->byte3.unit = 0; + command_packet->byte3.host_id = 0; + command_packet->status = 0; + command_packet->flags = 0; + command_packet->byte6.parameter_count = 1; + + /* Now setup the param */ + if (tw_dev->alignment_virtual_address[request_id] == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n"); + return 1; + } + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + memset(param, 0, sizeof(TW_Sector)); + param->table_id = 3; /* unit summary table */ + param->parameter_id = 3; /* unitsstatus parameter */ + param->parameter_size_bytes = TW_MAX_UNITS; + param_value = tw_dev->alignment_physical_address[request_id]; + if (param_value == 0) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n"); + return 1; + } + + command_packet->byte8.param.sgl[0].address = param_value; + command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); + command_que_value = tw_dev->command_packet_physical_address[request_id]; + if (command_que_value == 0) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n"); + return 1; + } + + /* Now try to post the command packet */ + tw_post_command_packet(tw_dev, request_id); return 0; } /* End tw_scsiop_test_unit_ready() */ +/* This function is called by the isr to complete a testunitready command */ +int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id) +{ + unsigned char *is_unit_present; + TW_Param *param; + + dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n"); + + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + if (param == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n"); + return 1; + } + is_unit_present = &(param->data[0]); + + if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE; + } else { + tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE; + tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); + return TW_ISR_DONT_RESULT; + } + + return 0; +} /* End tw_scsiop_test_unit_ready_complete() */ + /* Set a value in the features table */ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val) @@ -3091,17 +3392,13 @@ int tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id) { dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n"); - do { - if (tw_dev->free_tail == tw_dev->free_wrap) { - tw_dev->free_tail = TW_Q_START; - } else { - tw_dev->free_tail = tw_dev->free_tail + 1; - } - } while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_tail]] != TW_S_COMPLETED)); - tw_dev->free_queue[tw_dev->free_tail] = request_id; - tw_dev->state[request_id] = TW_S_FINISHED; + if (tw_dev->free_tail == tw_dev->free_wrap) + tw_dev->free_tail = TW_Q_START; + else + tw_dev->free_tail++; + dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing request_id %d\n", request_id); return 0; @@ -3115,20 +3412,16 @@ int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id) dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n"); /* Obtain next free request_id */ - do { - if (tw_dev->free_head == tw_dev->free_wrap) { - tw_dev->free_head = TW_Q_START; - } else { - tw_dev->free_head = tw_dev->free_head + 1; - } - } while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK); - id = tw_dev->free_queue[tw_dev->free_head]; + if (tw_dev->free_head == tw_dev->free_wrap) + tw_dev->free_head = TW_Q_START; + else + tw_dev->free_head++; - dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id); *request_id = id; tw_dev->state[id] = TW_S_STARTED; + dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id); return 0; } /* End tw_state_request_start() */ diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 48a550c4107f..7c1947966d66 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2002 3ware Inc. + Copyright (C) 1999-2003 3ware Inc. Kernel compatiblity By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> @@ -113,11 +113,11 @@ static unsigned char tw_sense_table[][4] = {0x84, 0x0b, 0x47, 0x00}, // Data CRC error SCSI parity error {0xd0, 0x0b, 0x00, 0x00}, // Device busy Aborted command {0xd1, 0x0b, 0x00, 0x00}, // Device busy Aborted command + {0x37, 0x02, 0x04, 0x00}, // Unit offline Not ready /* Codes for older firmware */ // 3ware Error SCSI Error {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error Aborted command - {0x37, 0x0b, 0x04, 0x00}, // Unit offline Logical unit not ready {0x51, 0x0b, 0x00, 0x00} // Unspecified Aborted command }; @@ -219,18 +219,23 @@ static unsigned char tw_sense_table[][4] = #define TW_MAX_PCI_BUSES 255 #define TW_MAX_RESET_TRIES 3 #define TW_UNIT_INFORMATION_TABLE_BASE 0x300 -#define TW_MAX_CMDS_PER_LUN 255 +#define TW_MAX_CMDS_PER_LUN 254 /* 254 for io, 1 for + chrdev ioctl, one for + internal aen post */ #define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */ #define TW_IOCTL 0x80 #define TW_UNIT_ONLINE 1 #define TW_IN_INTR 1 #define TW_IN_IOCTL 2 +#define TW_IN_CHRDEV_IOCTL 3 #define TW_MAX_SECTORS 256 #define TW_AEN_WAIT_TIME 1000 #define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ #define TW_ISR_DONT_COMPLETE 2 #define TW_ISR_DONT_RESULT 3 #define TW_IOCTL_TIMEOUT 25 /* 25 seconds */ +#define TW_IOCTL_CHRDEV_TIMEOUT 25 /* 25 seconds */ +#define TW_IOCTL_CHRDEV_FREE -1 /* Macros */ #define TW_STATUS_ERRORS(x) \ @@ -246,6 +251,8 @@ static unsigned char tw_sense_table[][4] = #define dprintk(msg...) do { } while(0) #endif +#pragma pack(1) + /* Scatter Gather List Entry */ typedef struct TAG_TW_SG_Entry { u32 address; @@ -295,6 +302,8 @@ typedef struct TW_Command { } byte8; } TW_Command; +#pragma pack() + typedef struct TAG_TW_Ioctl { unsigned char opcode; unsigned short table_id; @@ -304,6 +313,16 @@ typedef struct TAG_TW_Ioctl { unsigned char data[1]; } TW_Ioctl; +#pragma pack(1) + +/* Structure for new chardev ioctls */ +typedef struct TAG_TW_New_Ioctl { + unsigned int data_buffer_length; + unsigned char padding [508]; + TW_Command firmware_command; + char data_buffer[1]; +} TW_New_Ioctl; + /* GetParam descriptor */ typedef struct { unsigned short table_id; @@ -414,8 +433,12 @@ typedef struct TAG_TW_Device_Extension { unsigned long *ioctl_data[TW_Q_LENGTH]; int reset_print; char online; + volatile int chrdev_request_id; + wait_queue_head_t ioctl_wqueue; } TW_Device_Extension; +#pragma pack() + /* Function prototypes */ int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id); int tw_aen_drain_queue(TW_Device_Extension *tw_dev); @@ -463,6 +486,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id); int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val); int tw_setup_irq(TW_Device_Extension *tw_dev); @@ -483,9 +507,10 @@ void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev); .eh_abort_handler = tw_scsi_eh_abort, \ .eh_host_reset_handler = tw_scsi_eh_reset, \ .bios_param = tw_scsi_biosparam, \ - .can_queue = TW_Q_LENGTH-1, \ + .can_queue = TW_Q_LENGTH-2, \ .this_id = -1, \ .sg_tablesize = TW_MAX_SGL_LENGTH, \ + .max_sectors = TW_MAX_SECTORS, \ .cmd_per_lun = TW_MAX_CMDS_PER_LUN, \ .present = 0, \ .unchecked_isa_dma = 0, \ diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index 7fd1ccaffd2d..55d7c145d5b3 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -1463,9 +1463,9 @@ NCR53c7x0_init_fixup (struct Scsi_Host *host) { patch_abs_32 (hostdata->script, 0, test_src, virt_to_bus(&hostdata->test_source)); patch_abs_32 (hostdata->script, 0, saved_dsa, - virt_to_bus(&hostdata->saved2_dsa)); + virt_to_bus((void *)&hostdata->saved2_dsa)); patch_abs_32 (hostdata->script, 0, emulfly, - virt_to_bus(&hostdata->emulated_intfly)); + virt_to_bus((void *)&hostdata->emulated_intfly)); patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero)); @@ -1759,7 +1759,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) { Scsi_Cmnd *c = cmd->cmd; - struct Scsi_Host *host = c->host; + struct Scsi_Host *host = c->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; int i; @@ -1784,18 +1784,18 @@ NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) { */ patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32), - dsa_temp_lun, c->lun); + dsa_temp_lun, c->device->lun); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero - Ent_dsa_code_template + A_dsa_next); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), - dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->target].script)); + dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script)); patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), - dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->target].sscf_710)); + dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710)); patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32), - dsa_temp_target, 1 << c->target); + dsa_temp_target, 1 << c->device->id); /* XXX - new pointer stuff */ patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer)); @@ -1856,7 +1856,7 @@ run_process_issue_queue(void) { static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) { Scsi_Cmnd *c = cmd->cmd; - struct Scsi_Host *host = c->host; + struct Scsi_Host *host = c->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; unsigned long flags; @@ -1940,7 +1940,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) { host->host_no, c->pid); else if (linux_search) { *linux_prev = linux_search->next; - --hostdata->busy[c->target][c->lun]; + --hostdata->busy[c->device->id][c->device->lun]; } /* Return the NCR command structure to the free list */ @@ -2287,9 +2287,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct hostdata->dsp_changed = 1; if (cmd && (cmd->flags & CMD_FLAG_SDTR)) { printk ("scsi%d : target %d rejected SDTR\n", host->host_no, - c->target); + c->device->id); cmd->flags &= ~CMD_FLAG_SDTR; - asynchronous (host, c->target); + asynchronous (host, c->device->id); print = 0; } break; @@ -2311,7 +2311,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if (print) { printk ("scsi%d : received message", host->host_no); if (c) - printk (" from target %d lun %d ", c->target, c->lun); + printk (" from target %d lun %d ", c->device->id, c->device->lun); print_msg ((unsigned char *) hostdata->msg_buf); printk("\n"); } @@ -2331,7 +2331,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if (cmd) { char buf[80]; - sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->target, + sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id, (cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting"); print_synchronous (buf, (unsigned char *) hostdata->msg_buf); @@ -2346,10 +2346,10 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if (cmd->flags & CMD_FLAG_SDTR) { cmd->flags &= ~CMD_FLAG_SDTR; if (hostdata->msg_buf[4]) - synchronous (host, c->target, (unsigned char *) + synchronous (host, c->device->id, (unsigned char *) hostdata->msg_buf); else - asynchronous (host, c->target); + asynchronous (host, c->device->id); hostdata->dsp = hostdata->script + hostdata->E_accept_message / sizeof(u32); hostdata->dsp_changed = 1; @@ -2357,11 +2357,11 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct } else { if (hostdata->options & OPTION_SYNCHRONOUS) { cmd->flags |= CMD_FLAG_DID_SDTR; - synchronous (host, c->target, (unsigned char *) + synchronous (host, c->device->id, (unsigned char *) hostdata->msg_buf); } else { hostdata->msg_buf[4] = 0; /* 0 offset = async */ - asynchronous (host, c->target); + asynchronous (host, c->device->id); } patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5); patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) @@ -2545,9 +2545,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct host->host_no, NCR53c7x0_read8(SXFER_REG)); if (c) { print_insn (host, (u32 *) - hostdata->sync[c->target].script, "", 1); + hostdata->sync[c->device->id].script, "", 1); print_insn (host, (u32 *) - hostdata->sync[c->target].script + 2, "", 1); + hostdata->sync[c->device->id].script + 2, "", 1); } } return SPECIFIC_INT_RESTART; @@ -2658,7 +2658,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) { if (c) printk("scsi%d : target %d lun %d disconnecting\n", - host->host_no, c->target, c->lun); + host->host_no, c->device->id, c->device->lun); else printk("scsi%d : unknown target disconnecting\n", host->host_no); @@ -2680,9 +2680,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct #endif if (c) { print_insn (host, (u32 *) - hostdata->sync[c->target].script, "", 1); + hostdata->sync[c->device->id].script, "", 1); print_insn (host, (u32 *) - hostdata->sync[c->target].script + 2, "", 1); + hostdata->sync[c->device->id].script + 2, "", 1); } } return SPECIFIC_INT_RESTART; @@ -2734,8 +2734,8 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if ((hostdata->chip / 100) == 8) { scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800); if (c) { - if (sxfer != hostdata->sync[c->target].sxfer_sanity || - scntl3 != hostdata->sync[c->target].scntl3_sanity) { + if (sxfer != hostdata->sync[c->device->id].sxfer_sanity || + scntl3 != hostdata->sync[c->device->id].scntl3_sanity) { printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x", host->host_no, sxfer, scntl3); NCR53c7x0_write8 (SXFER_REG, sxfer); @@ -2746,12 +2746,12 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct host->host_no, (int) sxfer, (int) scntl3); } else { if (c) { - if (sxfer != hostdata->sync[c->target].sxfer_sanity) { + if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) { printk ("scsi%d : sync sanity check failed sxfer=0x%x", host->host_no, sxfer); NCR53c7x0_write8 (SXFER_REG, sxfer); NCR53c7x0_write8 (SBCL_REG, - hostdata->sync[c->target].sscf_710); + hostdata->sync[c->device->id].sscf_710); } } else printk ("scsi%d : unknown command sxfer=0x%x\n", @@ -2807,9 +2807,9 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct (DCMD_REG)) == hostdata->script + Ent_select_check_dsa / sizeof(u32) ? "selection" : "reselection"; - if (c && sdid != c->target) { + if (c && sdid != c->device->id) { printk ("scsi%d : SDID target %d != DSA target %d at %s\n", - host->host_no, sdid, c->target, where); + host->host_no, sdid, c->device->id, where); print_lots(host); dump_events (host, 20); return SPECIFIC_INT_PANIC; @@ -2855,7 +2855,7 @@ NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct if (event->event == EVENT_RESELECT) event->lun = hostdata->reselected_identify & 0xf; else if (c) - event->lun = c->lun; + event->lun = c->device->lun; else event->lun = 255; do_gettimeofday(&(event->time)); @@ -3049,7 +3049,7 @@ my_free_page (void *addr, int dummy) static struct NCR53c7x0_cmd * allocate_cmd (Scsi_Cmnd *cmd) { - struct Scsi_Host *host = cmd->host; + struct Scsi_Host *host = cmd->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; u32 real; /* Real address */ @@ -3061,8 +3061,8 @@ allocate_cmd (Scsi_Cmnd *cmd) { printk ("scsi%d : num_cmds = %d, can_queue = %d\n" " target = %d, lun = %d, %s\n", host->host_no, hostdata->num_cmds, host->can_queue, - cmd->target, cmd->lun, (hostdata->cmd_allocated[cmd->target] & - (1 << cmd->lun)) ? "already allocated" : "not allocated"); + cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] & + (1 << cmd->device->lun)) ? "already allocated" : "not allocated"); /* * If we have not yet reserved commands for this I_T_L nexus, and @@ -3070,11 +3070,11 @@ allocate_cmd (Scsi_Cmnd *cmd) { * being allocated under 1.3.x, or being outside of scan_scsis in * 1.2.x), do so now. */ - if (!(hostdata->cmd_allocated[cmd->target] & (1 << cmd->lun)) && + if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) && cmd->device && cmd->device->has_cmdblocks) { if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue) hostdata->extra_allocate += host->cmd_per_lun; - hostdata->cmd_allocated[cmd->target] |= (1 << cmd->lun); + hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun); } for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate, @@ -3130,7 +3130,7 @@ allocate_cmd (Scsi_Cmnd *cmd) { local_irq_restore(flags); if (!tmp) printk ("scsi%d : can't allocate command for target %d lun %d\n", - host->host_no, cmd->target, cmd->lun); + host->host_no, cmd->device->id, cmd->device->lun); return tmp; } @@ -3150,7 +3150,7 @@ allocate_cmd (Scsi_Cmnd *cmd) { static struct NCR53c7x0_cmd * create_cmd (Scsi_Cmnd *cmd) { NCR53c7x0_local_declare(); - struct Scsi_Host *host = cmd->host; + struct Scsi_Host *host = cmd->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */ @@ -3166,7 +3166,7 @@ create_cmd (Scsi_Cmnd *cmd) { #endif unsigned long flags; u32 exp_select_indirect; /* Used in sanity check */ - NCR53c7x0_local_setup(cmd->host); + NCR53c7x0_local_setup(cmd->device->host); if (!(tmp = allocate_cmd (cmd))) return NULL; @@ -3322,45 +3322,45 @@ create_cmd (Scsi_Cmnd *cmd) { if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) { - exp_select_indirect = ((1 << cmd->target) << 16) | - (hostdata->sync[cmd->target].sxfer_sanity << 8); + exp_select_indirect = ((1 << cmd->device->id) << 16) | + (hostdata->sync[cmd->device->id].sxfer_sanity << 8); - if (hostdata->sync[cmd->target].select_indirect != + if (hostdata->sync[cmd->device->id].select_indirect != exp_select_indirect) { printk ("scsi%d : sanity check failed select_indirect=0x%x\n", - host->host_no, hostdata->sync[cmd->target].select_indirect); + host->host_no, hostdata->sync[cmd->device->id].select_indirect); FATAL(host); } } patch_dsa_32(tmp->dsa, dsa_select, 0, - hostdata->sync[cmd->target].select_indirect); + hostdata->sync[cmd->device->id].select_indirect); /* * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on * different commands; although it should be trivial to do them * both at the same time. */ - if (hostdata->initiate_wdtr & (1 << cmd->target)) { + if (hostdata->initiate_wdtr & (1 << cmd->device->id)) { memcpy ((void *) (tmp->select + 1), (void *) wdtr_message, sizeof(wdtr_message)); patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message)); local_irq_save(flags); - hostdata->initiate_wdtr &= ~(1 << cmd->target); + hostdata->initiate_wdtr &= ~(1 << cmd->device->id); local_irq_restore(flags); - } else if (hostdata->initiate_sdtr & (1 << cmd->target)) { + } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) { memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, sizeof(sdtr_message)); patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message)); tmp->flags |= CMD_FLAG_SDTR; local_irq_save(flags); - hostdata->initiate_sdtr &= ~(1 << cmd->target); + hostdata->initiate_sdtr &= ~(1 << cmd->device->id); local_irq_restore(flags); } #if 1 - else if (!(hostdata->talked_to & (1 << cmd->target)) && + else if (!(hostdata->talked_to & (1 << cmd->device->id)) && !(hostdata->options & OPTION_NO_ASYNC)) { memcpy ((void *) (tmp->select + 1), (void *) async_message, @@ -3372,9 +3372,9 @@ create_cmd (Scsi_Cmnd *cmd) { else patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1); - hostdata->talked_to |= (1 << cmd->target); + hostdata->talked_to |= (1 << cmd->device->id); tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? - IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun); + IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun); patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select)); patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len); patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd)); @@ -3591,7 +3591,7 @@ create_cmd (Scsi_Cmnd *cmd) { int NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - struct Scsi_Host *host = cmd->host; + struct Scsi_Host *host = cmd->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; unsigned long flags; @@ -3604,9 +3604,9 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { #ifdef VALID_IDS /* Ignore commands on invalid IDs */ - if (!hostdata->valid_ids[cmd->target]) { + if (!hostdata->valid_ids[cmd->device->id]) { printk("scsi%d : ignoring target %d lun %d\n", host->host_no, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); cmd->result = (DID_BAD_TARGET << 16); done(cmd); return 0; @@ -3616,16 +3616,16 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { local_irq_save(flags); if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY)) || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) && - !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun))) + !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun))) #ifdef LINUX_1_2 - || cmd->target > 7 + || cmd->device->id > 7 #else - || cmd->target > host->max_id + || cmd->device->id > host->max_id #endif - || cmd->target == host->this_id + || cmd->device->id == host->this_id || hostdata->state == STATE_DISABLED) { printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); cmd->result = (DID_BAD_TARGET << 16); done(cmd); local_irq_restore(flags); @@ -3738,7 +3738,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, --i, ncrcurrent += 2 /* JUMP instructions are two words */); if (i > 0) { - ++hostdata->busy[tmp->target][tmp->lun]; + ++hostdata->busy[tmp->device->id][tmp->device->lun]; cmd->next = hostdata->running_list; hostdata->running_list = cmd; @@ -3799,7 +3799,7 @@ busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, /* FIXME : in the future, this needs to accommodate SCSI-II tagged queuing, and we may be able to play with fairness here a bit. */ - return hostdata->busy[cmd->target][cmd->lun]; + return hostdata->busy[cmd->device->id][cmd->device->lun]; } /* @@ -3873,7 +3873,7 @@ process_issue_queue (unsigned long flags) { if (tmp->host_scribble) { if (hostdata->options & OPTION_DEBUG_QUEUES) printk ("scsi%d : moving command for target %d lun %d to start list\n", - host->host_no, tmp->target, tmp->lun); + host->host_no, tmp->device->id, tmp->device->lun); to_schedule_list (host, hostdata, @@ -3937,7 +3937,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { printk ("scsi%d : Selection Timeout\n", host->host_no); if (cmd) { printk("scsi%d : target %d, lun %d, command ", - host->host_no, cmd->cmd->target, cmd->cmd->lun); + host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun); print_command (cmd->cmd->cmnd); printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no, NCR53c7x0_read32(DSP_REG), @@ -3975,7 +3975,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { fatal = 1; if (cmd) { printk("scsi%d : target %d lun %d unexpected disconnect\n", - host->host_no, cmd->cmd->target, cmd->cmd->lun); + host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun); print_lots (host); abnormal_finished(cmd, DID_ERROR << 16); } else @@ -3991,7 +3991,7 @@ intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { fatal = 1; if (cmd && cmd->cmd) { printk("scsi%d : target %d lun %d parity error.\n", - host->host_no, cmd->cmd->target, cmd->cmd->lun); + host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun); abnormal_finished (cmd, DID_PARITY << 16); } else printk("scsi%d : parity error\n", host->host_no); @@ -4199,7 +4199,7 @@ restart: if (cmd_prev_ptr) *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next; - --hostdata->busy[tmp->target][tmp->lun]; + --hostdata->busy[tmp->device->id][tmp->device->lun]; cmd->next = hostdata->free; hostdata->free = cmd; @@ -4207,7 +4207,7 @@ restart: if (hostdata->options & OPTION_DEBUG_INTR) { printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", - host->host_no, tmp->pid, tmp->target, tmp->lun, tmp->result); + host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result); print_command (tmp->cmnd); } @@ -4292,8 +4292,8 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) { if (hostdata->options & OPTION_DEBUG_INTR) { if (cmd) { printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", - host->host_no, cmd->cmd->pid, (int) cmd->cmd->target, - (int) cmd->cmd->lun); + host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id, + (int) cmd->cmd->device->lun); print_command (cmd->cmd->cmnd); } else { printk("scsi%d : no active command\n", host->host_no); @@ -4671,7 +4671,7 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { hostdata->dsp = dsp + 2 /* two _words_ */; hostdata->dsp_changed = 1; printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n", - host->host_no, cmd->cmd->target); + host->host_no, cmd->cmd->device->id); cmd->flags &= ~CMD_FLAG_SDTR; action = ACTION_CONTINUE; break; @@ -5136,7 +5136,7 @@ print_insn (struct Scsi_Host *host, const u32 *insn, int NCR53c7xx_abort (Scsi_Cmnd *cmd) { NCR53c7x0_local_declare(); - struct Scsi_Host *host = cmd->host; + struct Scsi_Host *host = cmd->device->host; struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) host->hostdata[0] : NULL; unsigned long flags; @@ -5242,7 +5242,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { return SCSI_ABORT_NOT_RUNNING; } else { printk ("scsi%d : DANGER : command running, can not abort.\n", - cmd->host->host_no); + cmd->device->host->host_no); local_irq_restore(flags); return SCSI_ABORT_BUSY; } @@ -5273,7 +5273,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { * command was ever counted as BUSY, so if we end up here we can * decrement the busy count if and only if it is necessary. */ - --hostdata->busy[cmd->target][cmd->lun]; + --hostdata->busy[cmd->device->id][cmd->device->lun]; } local_irq_restore(flags); cmd->scsi_done(cmd); @@ -5318,7 +5318,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) { * each command. */ Scsi_Cmnd *nuke_list = NULL; - struct Scsi_Host *host = cmd->host; + struct Scsi_Host *host = cmd->device->host; struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; @@ -5388,7 +5388,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) { static int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) { struct NCR53c7x0_hostdata *hostdata = - (struct NCR53c7x0_hostdata *) cmd->host->hostdata[0]; + (struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0]; struct NCR53c7x0_cmd *ncmd = (struct NCR53c7x0_cmd *) cmd->host_scribble; int offset = 0, buffers; @@ -5418,7 +5418,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) { --buffers, offset += segment->length, ++segment) #if 0 printk("scsi%d: comparing 0x%p to 0x%p\n", - cmd->host->host_no, saved, page_address(segment->page+segment->offset); + cmd->device->host->host_no, saved, page_address(segment->page+segment->offset); #else ; #endif @@ -5456,7 +5456,7 @@ print_progress (Scsi_Cmnd *cmd) { int offset, i; char *where; u32 *ptr; - NCR53c7x0_local_setup (cmd->host); + NCR53c7x0_local_setup (cmd->device->host); if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0) { @@ -5484,15 +5484,15 @@ print_progress (Scsi_Cmnd *cmd) { if (offset != -1) printk ("scsi%d : %s data pointer at offset %d\n", - cmd->host->host_no, where, offset); + cmd->device->host->host_no, where, offset); else { int size; printk ("scsi%d : can't determine %s data pointer offset\n", - cmd->host->host_no, where); + cmd->device->host->host_no, where); if (ncmd) { - size = print_insn (cmd->host, + size = print_insn (cmd->device->host, bus_to_virt(ncmd->saved_data_pointer), "", 1); - print_insn (cmd->host, + print_insn (cmd->device->host, bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32), "", 1); } @@ -5549,7 +5549,7 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) { /* XXX Maybe we should access cmd->host_scribble->result here. RGH */ if (cmd) { printk(" result = 0x%x, target = %d, lun = %d, cmd = ", - cmd->result, cmd->target, cmd->lun); + cmd->result, cmd->device->id, cmd->device->lun); print_command(cmd->cmnd); } else printk("\n"); @@ -5558,11 +5558,11 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) { if (cmd) { printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n" " script : ", - host->host_no, cmd->target, - hostdata->sync[cmd->target].sxfer_sanity, - hostdata->sync[cmd->target].scntl3_sanity); - for (i = 0; i < (sizeof(hostdata->sync[cmd->target].script) / 4); ++i) - printk ("0x%x ", hostdata->sync[cmd->target].script[i]); + host->host_no, cmd->device->id, + hostdata->sync[cmd->device->id].sxfer_sanity, + hostdata->sync[cmd->device->id].scntl3_sanity); + for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i) + printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]); printk ("\n"); print_progress (cmd); } @@ -5604,7 +5604,7 @@ print_queues (struct Scsi_Host *host) { -> dsa, ""); } else printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n", - host->host_no, cmd->pid, cmd->target, cmd->lun); + host->host_no, cmd->pid, cmd->device->id, cmd->device->lun); local_irq_restore(flags); } diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index a1f8470c1a5f..340614409b3b 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -1099,7 +1099,7 @@ do_sync_known: * disconnect. */ ESPMISC(("esp: Selecting device for first time. target=%d " - "lun=%d\n", target, SCptr->lun)); + "lun=%d\n", target, SCptr->device->lun)); if(!SDptr->borken && !esp_dev->disconnect) esp_dev->disconnect = 1; @@ -1173,7 +1173,7 @@ do_sync_known: if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) || toshiba_cdrom_hwbug_wkaround || SDptr->borken) { ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d " - "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun)); + "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun)); esp_dev->disconnect = 0; *cmdp++ = IDENTIFY(0, lun); } else { @@ -1255,8 +1255,8 @@ int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) esp->dma_led_on(esp); /* We use the scratch area. */ - ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun)); - ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun)); + ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun)); + ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun)); esp_get_dmabufs(esp, SCpnt); esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */ @@ -2235,7 +2235,7 @@ static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs) * state. */ ESPMISC(("esp: Status <%d> for target %d lun %d\n", - SCptr->SCp.Status, SCptr->target, SCptr->lun)); + SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun)); /* But don't do this when spinning up a disk at * boot time while we poll for completion as it @@ -2246,14 +2246,14 @@ static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs) if(esp_should_clear_sync(SCptr) != 0) esp_dev->sync = 0; } - ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun)); + ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); esp_done(esp, ((SCptr->SCp.Status & 0xff) | ((SCptr->SCp.Message & 0xff)<<8) | (DID_OK << 16))); } else if(esp->prevmsgin == DISCONNECT) { /* Normal disconnect. */ esp_cmd(esp, eregs, ESP_CMD_ESEL); - ESPDISC(("D<%02x,%02x>", SCptr->target, SCptr->lun)); + ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun)); append_SC(&esp->disconnected_SC, SCptr); esp->current_SC = NULL; if(esp->issue_SC) @@ -2811,7 +2811,7 @@ static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs) /* Else, there really isn't anyone there. */ ESPMISC(("esp: selection failure, maybe nobody there?\n")); ESPMISC(("esp: target %d lun %d\n", - SCptr->target, SCptr->lun)); + SCptr->device->id, SCptr->device->lun)); esp_done(esp, (DID_BAD_TARGET << 16)); } return do_intr_end; @@ -3084,7 +3084,7 @@ static int check_multibyte_msg(struct NCR_ESP *esp, ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n", esp_dev->sync_max_offset, esp_dev->sync_min_period, - esp->config3[SCptr->target])); + esp->config3[SCptr->device->id])); esp->snip = 0; } else if(esp_dev->sync_max_offset) { diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index f8b04da74c83..bf82d0b2df1b 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -52,7 +52,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) { unsigned short cntr = CNTR_PDMD | CNTR_INTEN; unsigned long addr = virt_to_bus(cmd->SCp.ptr); - struct Scsi_Host *instance = cmd->host; + struct Scsi_Host *instance = cmd->device->host; /* don't allow DMA if the physical address is bad */ if (addr & A2091_XFER_MASK || @@ -102,12 +102,12 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) cntr |= CNTR_DDIR; /* remember direction */ - HDATA(cmd->host)->dma_dir = dir_in; + HDATA(cmd->device->host)->dma_dir = dir_in; - DMA(cmd->host)->CNTR = cntr; + DMA(cmd->device->host)->CNTR = cntr; /* setup DMA *physical* address */ - DMA(cmd->host)->ACR = addr; + DMA(cmd->device->host)->ACR = addr; if (dir_in){ /* invalidate any cache */ @@ -117,7 +117,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) cache_push (addr, cmd->SCp.this_residual); } /* start DMA */ - DMA(cmd->host)->ST_DMA = 1; + DMA(cmd->device->host)->ST_DMA = 1; /* return success */ return 0; diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 28a393b68c5c..a6a56c9014f2 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -225,7 +225,7 @@ static Scsi_Host_Template driver_template = { #include "scsi_module.c" -int __exit a3000_release(struct Scsi_Host *instance) +int a3000_release(struct Scsi_Host *instance) { wd33c93_release(); DMA(instance)->CNTR = 0; diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 715365d8c02c..89c454b2685f 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -86,7 +86,7 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt) #ifdef CONFIG_WARPENGINE_SCSI case ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx: if (request_mem_region(address+0x40000, 0x1000, "ncr53c710")) { - address = (unsigned long)ioremap(address, size); + address = (unsigned long)z_ioremap(address, size); options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY | OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT; @@ -102,7 +102,7 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt) case ZORRO_PROD_CBM_A4091_1: case ZORRO_PROD_CBM_A4091_2: if (request_mem_region(address+0x800000, 0x1000, "ncr53c710")) { - address = (unsigned long)ioremap(address, size); + address = (unsigned long)z_ioremap(address, size); options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY | OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT; diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index df9da107d11b..387a14db1fa9 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -266,7 +266,7 @@ static Scsi_Host_Template *the_template = NULL; #define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no -#define H_NO(cmd) (cmd)->host->host_no +#define H_NO(cmd) (cmd)->device->host->host_no #ifdef SUPPORT_TAGS @@ -350,17 +350,17 @@ static void __init init_tags( void ) static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); - if (hostdata->busy[cmd->target] & (1 << cmd->lun)) + if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) return( 1 ); if (!should_be_tagged || !setup_use_tagged_queuing || !cmd->device->tagged_supported) return( 0 ); - if (TagAlloc[cmd->target][cmd->lun].nr_allocated >= - TagAlloc[cmd->target][cmd->lun].queue_size ) { + if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= + TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->target, cmd->lun ); + H_NO(cmd), cmd->device->id, cmd->device->lun ); return( 1 ); } return( 0 ); @@ -374,7 +374,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); /* If we or the target don't support tagged queuing, allocate the LUN for * an untagged command. @@ -382,19 +382,19 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) if (!should_be_tagged || !setup_use_tagged_queuing || !cmd->device->tagged_supported) { cmd->tag = TAG_NONE; - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->target, cmd->lun ); + "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); } else { - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS ); set_bit( cmd->tag, ta->allocated ); ta->nr_allocated++; TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->target, cmd->lun, + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, ta->nr_allocated ); } } @@ -406,23 +406,23 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) static void cmd_free_tag( Scsi_Cmnd *cmd ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->target, cmd->lun ); + H_NO(cmd), cmd->device->id, cmd->device->lun ); } else if (cmd->tag >= MAX_TAGS) { printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", H_NO(cmd), cmd->tag ); } else { - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; clear_bit( cmd->tag, ta->allocated ); ta->nr_allocated--; TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->target, cmd->lun ); + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); } } @@ -811,7 +811,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) int i, s; unsigned char *command; SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->target, cmd->lun); + H_NO(cmd), cmd->device->id, cmd->device->lun); SPRINTF(" command = "); command = cmd->cmnd; SPRINTF("%2d (0x%02x)", command[0], command[0]); @@ -834,7 +834,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) * */ -static void __init NCR5380_init (struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); @@ -878,6 +878,8 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags) NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0); + + return 0; } /* @@ -898,13 +900,10 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags) * */ -/* Only make static if a wrapper function is used */ -#ifndef NCR5380_queue_command static -#endif int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); Scsi_Cmnd *tmp; int oldto; unsigned long flags; @@ -938,15 +937,15 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) case WRITE: case WRITE_6: case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->target] += cmd->request_bufflen; + hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; hostdata->pendingw++; break; case READ: case READ_6: case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->target] += cmd->request_bufflen; + hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; hostdata->pendingr++; break; } @@ -1014,7 +1013,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) if (in_interrupt() || ((flags >> 8) & 7) >= 6) queue_main(); else - NCR5380_main(); + NCR5380_main(NULL); return 0; } @@ -1030,7 +1029,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * reenable them. This prevents reentrancy and kernel stack overflow. */ -static void NCR5380_main (void) +static void NCR5380_main (void *bl) { Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance = first_instance; @@ -1087,8 +1086,8 @@ static void NCR5380_main (void) #if (NDEBUG & NDEBUG_LISTS) if (prev != tmp) printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", - tmp, tmp->target, hostdata->busy[tmp->target], - tmp->lun); + tmp, tmp->device->id, hostdata->busy[tmp->device->id], + tmp->device->lun); #endif /* When we find one, remove it from the issue queue. */ /* ++guenther: possible race with Falcon locking */ @@ -1096,7 +1095,7 @@ static void NCR5380_main (void) #ifdef SUPPORT_TAGS !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) #else - !(hostdata->busy[tmp->target] & (1 << tmp->lun)) + !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) #endif ) { /* ++guenther: just to be sure, this must be atomic */ @@ -1122,7 +1121,7 @@ static void NCR5380_main (void) */ MAIN_PRINTK("scsi%d: main(): command for target %d " "lun %d removed from issue_queue\n", - HOSTNO, tmp->target, tmp->lun); + HOSTNO, tmp->device->id, tmp->device->lun); /* * REQUEST SENSE commands are issued without tagged * queueing, even on SCSI-II devices because the @@ -1356,15 +1355,15 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) case WRITE: case WRITE_6: case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/ + hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/ + hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ hostdata->pendingr--; break; } @@ -1525,7 +1524,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * the host and target ID's on the SCSI bus. */ - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); /* * Raise ATN while SEL is true before BSY goes false from arbitration, @@ -1578,7 +1577,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) udelay(1); - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target); + SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1629,7 +1628,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->target)) { + if (hostdata->targets_present & (1 << cmd->device->id)) { printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); if (hostdata->restart_select) printk(KERN_NOTICE "\trestart select\n"); @@ -1651,7 +1650,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) return 0; } - hostdata->targets_present |= (1 << cmd->target); + hostdata->targets_present |= (1 << cmd->device->id); /* * Since we followed the SCSI spec, and raised ATN while SEL @@ -1672,8 +1671,8 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) while (!(NCR5380_read(STATUS_REG) & SR_REQ)); SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->target); - tmp[0] = IDENTIFY(1, cmd->lun); + HOSTNO, cmd->device->id); + tmp[0] = IDENTIFY(1, cmd->device->lun); #ifdef SUPPORT_TAGS if (cmd->tag != TAG_NONE) { @@ -1695,7 +1694,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) /* XXX need to handle errors here */ hostdata->connected = cmd; #ifndef SUPPORT_TAGS - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); #endif initialize_SCp(cmd); @@ -2085,7 +2084,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * polled-IO. */ printk(KERN_NOTICE "scsi%d: switching target %d " "lun %d to slow handshake\n", HOSTNO, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); cmd->device->borken = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); @@ -2137,7 +2136,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->target, cmd->lun); + "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -2150,7 +2149,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) if (!cmd->next_link) { printk(KERN_NOTICE "scsi%d: target %d lun %d " "linked command complete, no next_link\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); sink = 1; do_abort (instance); return; @@ -2163,7 +2162,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); LNK_PRINTK("scsi%d: target %d lun %d linked request " "done, calling scsi_done().\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); #ifdef NCR5380_STATS collect_stats(hostdata, cmd); #endif @@ -2179,7 +2178,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) falcon_dont_release++; hostdata->connected = NULL; QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->target, cmd->lun); + "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { @@ -2191,16 +2190,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) */ /* ++Andreas: the mid level code knows about QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; TAG_PRINTK("scsi%d: target %d lun %d returned " "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->target, cmd->lun, + HOSTNO, cmd->device->id, cmd->device->lun, ta->nr_allocated); if (ta->queue_size > ta->nr_allocated) ta->nr_allocated = ta->queue_size; } #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -2296,12 +2295,12 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * the command is treated as untagged further on. */ cmd->device->tagged_supported = 0; - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); cmd->tag = TAG_NONE; TAG_PRINTK("scsi%d: target %d lun %d rejected " "QUEUE_TAG message; tagged queuing " "disabled\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); break; } break; @@ -2318,7 +2317,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) QU_PRINTK("scsi%d: command for target %d lun %d was " "moved from connected to the " "disconnected_queue\n", HOSTNO, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2417,13 +2416,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) } else if (tmp != EXTENDED_MESSAGE) printk(KERN_DEBUG "scsi%d: rejecting unknown " "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->target, cmd->lun); + HOSTNO, tmp, cmd->device->id, cmd->device->lun); else printk(KERN_DEBUG "scsi%d: rejecting unknown " "extended message " "code %02x, length %d from target %d, lun %d\n", HOSTNO, extended_msg[1], extended_msg[0], - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); msgout = MESSAGE_REJECT; @@ -2441,7 +2440,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif hostdata->connected = NULL; cmd->result = DID_ERROR << 16; @@ -2577,7 +2576,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { - if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) + if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) #ifdef SUPPORT_TAGS && (tag == tmp->tag) #endif @@ -2620,7 +2619,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) hostdata->connected = tmp; RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - HOSTNO, tmp->target, tmp->lun, tmp->tag); + HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); falcon_dont_release--; } @@ -2642,12 +2641,10 @@ static void NCR5380_reselect (struct Scsi_Host *instance) * called where the loop started in NCR5380_main(). */ -#ifndef NCR5380_abort static -#endif int NCR5380_abort (Scsi_Cmnd *cmd) { - struct Scsi_Host *instance = cmd->host; + struct Scsi_Host *instance = cmd->device->host; SETUP_HOSTDATA(instance); Scsi_Cmnd *tmp, **prev; unsigned long flags; @@ -2701,7 +2698,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif local_irq_restore(flags); cmd->scsi_done(cmd); @@ -2808,7 +2805,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif local_irq_restore(flags); tmp->scsi_done(tmp); @@ -2842,7 +2839,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) /* - * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) + * Function : int NCR5380_reset (Scsi_Cmnd *cmd) * * Purpose : reset the SCSI bus. * @@ -2850,9 +2847,9 @@ int NCR5380_abort (Scsi_Cmnd *cmd) * */ -static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +static int NCR5380_bus_reset( Scsi_Cmnd *cmd) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); int i; unsigned long flags; #if 1 @@ -2863,7 +2860,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", H_NO(cmd) ); - NCR5380_print_status (cmd->host); + NCR5380_print_status (cmd->device->host); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 07c40bd87e67..17dfa0835bfb 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -819,11 +819,11 @@ void __init atari_scsi_setup(char *str, int *ints) #endif } -int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +int atari_scsi_bus_reset(Scsi_Cmnd *cmd) { int rv; struct NCR5380_hostdata *hostdata = - (struct NCR5380_hostdata *)cmd->host->hostdata; + (struct NCR5380_hostdata *)cmd->device->host->hostdata; /* For doing the reset, SCSI interrupts must be disabled first, * since the 5380 raises its IRQ line while _RST is active and we @@ -845,7 +845,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #endif /* REAL_DMA */ } - rv = NCR5380_reset(cmd, reset_flags); + rv = NCR5380_bus_reset(cmd); /* Re-enable ints */ if (IS_A_TT()) { @@ -1146,8 +1146,8 @@ static Scsi_Host_Template driver_template = { .release = atari_scsi_release, .info = atari_scsi_info, .queuecommand = atari_scsi_queue_command, - .abort = atari_scsi_abort, - .reset = atari_scsi_reset, + .eh_abort_handler = atari_scsi_abort, + .eh_bus_reset_handler = atari_scsi_bus_reset, .can_queue = 0, /* initialized at run-time */ .this_id = 0, /* initialized at run-time */ .sg_tablesize = 0, /* initialized at run-time */ diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h index a6fd05a74d33..b417d6c6880c 100644 --- a/drivers/scsi/atari_scsi.h +++ b/drivers/scsi/atari_scsi.h @@ -18,10 +18,8 @@ /* (I_HAVE_OVERRUNS stuff removed) */ #ifndef ASM -int atari_scsi_abort (Scsi_Cmnd *); int atari_scsi_detect (Scsi_Host_Template *); const char *atari_scsi_info (struct Scsi_Host *); -int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int atari_scsi_reset (Scsi_Cmnd *, unsigned int); int atari_scsi_proc_info (char *, char **, off_t, int, int, int); #ifdef MODULE diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 57296ffd25af..1fb8cd9890cf 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -167,8 +167,8 @@ int __init blz1230_esp_detect(Scsi_Host_Template *tpnt) esp->eregs = eregs; /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = virt_to_bus(cmd_buffer); + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; esp->slot = board+REAL_BLZ1230_ESP_ADDR; diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c index 07a9220816a3..77f77e9cefdb 100644 --- a/drivers/scsi/blz2060.c +++ b/drivers/scsi/blz2060.c @@ -142,8 +142,8 @@ int __init blz2060_esp_detect(Scsi_Host_Template *tpnt) esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR); /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = virt_to_bus(cmd_buffer); + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c index 83a3a0a9e5da..e795eeb78629 100644 --- a/drivers/scsi/cyberstorm.c +++ b/drivers/scsi/cyberstorm.c @@ -168,8 +168,8 @@ int __init cyber_esp_detect(Scsi_Host_Template *tpnt) esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR); /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = virt_to_bus(cmd_buffer); + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c index 25eb423ce467..4d0bf3ed1456 100644 --- a/drivers/scsi/cyberstormII.c +++ b/drivers/scsi/cyberstormII.c @@ -149,8 +149,8 @@ int __init cyberII_esp_detect(Scsi_Host_Template *tpnt) esp->eregs = eregs; /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = virt_to_bus(cmd_buffer); + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c index b58c0289ea14..62a473c3497e 100644 --- a/drivers/scsi/fastlane.c +++ b/drivers/scsi/fastlane.c @@ -191,8 +191,8 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt) esp->edev = (void *) address; /* Set the command buffer */ - esp->esp_command = (volatile unsigned char*) cmd_buffer; - esp->esp_command_dvma = virt_to_bus(cmd_buffer); + esp->esp_command = cmd_buffer; + esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer); esp->irq = IRQ_AMIGA_PORTS; esp->slot = board+FASTLANE_ESP_ADDR; diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index ad2d6c301d30..f3ec633166a6 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -62,61 +62,62 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) static int scsi_alloc_out_of_range = 0; /* use bounce buffer if the physical address is bad */ - if (addr & HDATA(cmd->host)->dma_xfer_mask || + if (addr & HDATA(cmd->device->host)->dma_xfer_mask || (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) { - HDATA(cmd->host)->dma_bounce_len = (cmd->SCp.this_residual + 511) + HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; if( !scsi_alloc_out_of_range ) { - HDATA(cmd->host)->dma_bounce_buffer = - kmalloc (HDATA(cmd->host)->dma_bounce_len, GFP_KERNEL); - HDATA(cmd->host)->dma_buffer_pool = BUF_SCSI_ALLOCED; + HDATA(cmd->device->host)->dma_bounce_buffer = + kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL); + HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED; } - if ( scsi_alloc_out_of_range || !HDATA(cmd->host)->dma_bounce_buffer) { - HDATA(cmd->host)->dma_bounce_buffer = - amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len, + if (scsi_alloc_out_of_range || + !HDATA(cmd->device->host)->dma_bounce_buffer) { + HDATA(cmd->device->host)->dma_bounce_buffer = + amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len, "GVP II SCSI Bounce Buffer"); - if(!HDATA(cmd->host)->dma_bounce_buffer) + if(!HDATA(cmd->device->host)->dma_bounce_buffer) { - HDATA(cmd->host)->dma_bounce_len = 0; + HDATA(cmd->device->host)->dma_bounce_len = 0; return 1; } - HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; + HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; } /* check if the address of the bounce buffer is OK */ - addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer); + addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer); - if (addr & HDATA(cmd->host)->dma_xfer_mask) { + if (addr & HDATA(cmd->device->host)->dma_xfer_mask) { /* fall back to Chip RAM if address out of range */ - if( HDATA(cmd->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) { - kfree (HDATA(cmd->host)->dma_bounce_buffer); + if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) { + kfree (HDATA(cmd->device->host)->dma_bounce_buffer); scsi_alloc_out_of_range = 1; } else { - amiga_chip_free (HDATA(cmd->host)->dma_bounce_buffer); + amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer); } - HDATA(cmd->host)->dma_bounce_buffer = - amiga_chip_alloc(HDATA(cmd->host)->dma_bounce_len, + HDATA(cmd->device->host)->dma_bounce_buffer = + amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len, "GVP II SCSI Bounce Buffer"); - if(!HDATA(cmd->host)->dma_bounce_buffer) + if(!HDATA(cmd->device->host)->dma_bounce_buffer) { - HDATA(cmd->host)->dma_bounce_len = 0; + HDATA(cmd->device->host)->dma_bounce_len = 0; return 1; } - addr = virt_to_bus(HDATA(cmd->host)->dma_bounce_buffer); - HDATA(cmd->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; + addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer); + HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED; } if (!dir_in) { /* copy to bounce buffer for a write */ - memcpy (HDATA(cmd->host)->dma_bounce_buffer, + memcpy (HDATA(cmd->device->host)->dma_bounce_buffer, cmd->SCp.ptr, cmd->SCp.this_residual); } } @@ -125,11 +126,11 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) if (!dir_in) cntr |= GVP11_DMAC_DIR_WRITE; - HDATA(cmd->host)->dma_dir = dir_in; - DMA(cmd->host)->CNTR = cntr; + HDATA(cmd->device->host)->dma_dir = dir_in; + DMA(cmd->device->host)->CNTR = cntr; /* setup DMA *physical* address */ - DMA(cmd->host)->ACR = addr; + DMA(cmd->device->host)->ACR = addr; if (dir_in) /* invalidate any cache */ @@ -138,11 +139,11 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in) /* push any dirty cache */ cache_push (addr, cmd->SCp.this_residual); - if ((bank_mask = (~HDATA(cmd->host)->dma_xfer_mask >> 18) & 0x01c0)) - DMA(cmd->host)->BANK = bank_mask & (addr >> 18); + if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0)) + DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18); /* start DMA */ - DMA(cmd->host)->ST_DMA = 1; + DMA(cmd->device->host)->ST_DMA = 1; /* return success */ return 0; diff --git a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c index b51eda3f8110..81e94a695e5e 100644 --- a/drivers/scsi/mac_NCR5380.c +++ b/drivers/scsi/mac_NCR5380.c @@ -850,7 +850,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) /* - * Function : void NCR5380_init (struct Scsi_Host *instance) + * Function : void NCR5380_init (struct Scsi_Host *instance, int flags) * * Purpose : initializes *instance and corresponding 5380 chip. * @@ -861,7 +861,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) * */ -static void NCR5380_init (struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); @@ -905,6 +905,8 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags) NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0); + + return 0; } /* @@ -925,17 +927,13 @@ static void NCR5380_init (struct Scsi_Host *instance, int flags) * */ -/* Only make static if a wrapper function is used */ -#ifndef NCR5380_queue_command static -#endif int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { SETUP_HOSTDATA(cmd->host); Scsi_Cmnd *tmp; int oldto; unsigned long flags; - extern int update_timeout(Scsi_Cmnd * SCset, int timeout); #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { @@ -1025,12 +1023,12 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) if (in_interrupt() > 0 || ((flags >> 8) & 7) >= 6) queue_main(); else - NCR5380_main(); + NCR5380_main(NULL); return 0; } /* - * Function : NCR5380_main (void) + * Function : NCR5380_main (void *bl) * * Purpose : NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both @@ -1041,7 +1039,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * reenable them. This prevents reentrancy and kernel stack overflow. */ -static void NCR5380_main (void) +static void NCR5380_main (void *bl) { Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance = first_instance; @@ -2790,9 +2788,6 @@ static void NCR5380_reselect (struct Scsi_Host *instance) * called where the loop started in NCR5380_main(). */ -#ifndef NCR5380_abort -static -#endif int NCR5380_abort (Scsi_Cmnd *cmd) { struct Scsi_Host *instance = cmd->host; @@ -2982,7 +2977,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) /* - * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) + * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd) * * Purpose : reset the SCSI bus. * @@ -2990,7 +2985,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) * */ -static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +static int NCR5380_bus_reset( Scsi_Cmnd *cmd) { SETUP_HOSTDATA(cmd->host); int i; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 7ab4086e6f26..89d3b02c8a05 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -268,7 +268,7 @@ static Scsi_Host_Template *the_template = NULL; #define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) #define HOSTNO instance->host_no -#define H_NO(cmd) (cmd)->host->host_no +#define H_NO(cmd) (cmd)->device->host->host_no #define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \ (buffer)->offset) @@ -360,17 +360,17 @@ static void __init init_tags( void ) static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); - if (hostdata->busy[cmd->target] & (1 << cmd->lun)) + if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) return( 1 ); if (!should_be_tagged || !setup_use_tagged_queuing || !cmd->device->tagged_supported) return( 0 ); - if (TagAlloc[cmd->target][cmd->lun].nr_allocated >= - TagAlloc[cmd->target][cmd->lun].queue_size ) { + if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= + TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->target, cmd->lun ); + H_NO(cmd), cmd->device->id, cmd->device->lun ); return( 1 ); } return( 0 ); @@ -384,7 +384,7 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); /* If we or the target don't support tagged queuing, allocate the LUN for * an untagged command. @@ -392,19 +392,19 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) if (!should_be_tagged || !setup_use_tagged_queuing || !cmd->device->tagged_supported) { cmd->tag = TAG_NONE; - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->target, cmd->lun ); + "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); } else { - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS ); set_bit( cmd->tag, &ta->allocated ); ta->nr_allocated++; TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->target, cmd->lun, + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, ta->nr_allocated ); } } @@ -416,23 +416,23 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) static void cmd_free_tag( Scsi_Cmnd *cmd ) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->target, cmd->lun ); + H_NO(cmd), cmd->device->id, cmd->device->lun ); } else if (cmd->tag >= MAX_TAGS) { printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", H_NO(cmd), cmd->tag ); } else { - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; clear_bit( cmd->tag, &ta->allocated ); ta->nr_allocated--; TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->target, cmd->lun ); + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); } } @@ -616,11 +616,11 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) - printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); else { for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); - printk("scsi%d: phase %s\n", HOSTNO, phases[i].name); + printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); } } @@ -819,7 +819,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) int i, s; unsigned char *command; SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->target, cmd->lun); + H_NO(cmd), cmd->device->id, cmd->device->lun); SPRINTF(" command = "); command = cmd->cmnd; SPRINTF("%2d (0x%02x)", command[0], command[0]); @@ -842,7 +842,7 @@ lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) * */ -static void __init NCR5380_init (struct Scsi_Host *instance, int flags) +static int NCR5380_init (struct Scsi_Host *instance, int flags) { int i; SETUP_HOSTDATA(instance); @@ -886,6 +886,8 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags) NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0); + + return 0; } /* @@ -909,10 +911,9 @@ static void __init NCR5380_init (struct Scsi_Host *instance, int flags) /* Only make static if a wrapper function is used */ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); Scsi_Cmnd *tmp; unsigned long flags; - extern int update_timeout(Scsi_Cmnd * SCset, int timeout); #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { @@ -942,15 +943,15 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) case WRITE: case WRITE_6: case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->target] += cmd->request_bufflen; + hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; hostdata->pendingw++; break; case READ: case READ_6: case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->target] += cmd->request_bufflen; + hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; hostdata->pendingr++; break; } @@ -1014,7 +1015,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) if (in_interrupt() || ((flags >> 8) & 7) >= 6) queue_main(); else - NCR5380_main(); + NCR5380_main(NULL); return 0; } @@ -1030,7 +1031,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * reenable them. This prevents reentrancy and kernel stack overflow. */ -static void NCR5380_main (void) +static void NCR5380_main (void *bl) { Scsi_Cmnd *tmp, *prev; struct Scsi_Host *instance = first_instance; @@ -1065,7 +1066,7 @@ static void NCR5380_main (void) local_save_flags(flags); do { - local_irq_disable(flags); /* Freeze request queues */ + local_irq_disable(); /* Freeze request queues */ done = 1; if (!hostdata->connected) { @@ -1095,7 +1096,7 @@ static void NCR5380_main (void) #ifdef SUPPORT_TAGS !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) #else - !(hostdata->busy[tmp->target] & (1 << tmp->lun)) + !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) #endif ) { /* ++guenther: just to be sure, this must be atomic */ @@ -1217,8 +1218,8 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance ) BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK)) { printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG)); - printk("scsi%d: bus stuck in data phase -- probably a - single byte overrun!\n", HOSTNO); + printk("scsi%d: bus stuck in data phase -- probably a single byte " + "overrun!\n", HOSTNO); printk("not prepared for this error!\n"); printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); @@ -1349,15 +1350,15 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) case WRITE: case WRITE_6: case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/ + hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/ + hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ hostdata->pendingr--; break; } @@ -1518,7 +1519,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * the host and target ID's on the SCSI bus. */ - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); /* * Raise ATN while SEL is true before BSY goes false from arbitration, @@ -1571,7 +1572,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) udelay(1); - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target); + SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1622,7 +1623,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->target)) { + if (hostdata->targets_present & (1 << cmd->device->id)) { printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); if (hostdata->restart_select) printk(KERN_NOTICE "\trestart select\n"); @@ -1644,7 +1645,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) return 0; } - hostdata->targets_present |= (1 << cmd->target); + hostdata->targets_present |= (1 << cmd->device->id); /* * Since we followed the SCSI spec, and raised ATN while SEL @@ -1665,8 +1666,8 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) while (!(NCR5380_read(STATUS_REG) & SR_REQ)); SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->target); - tmp[0] = IDENTIFY(1, cmd->lun); + HOSTNO, cmd->device->id); + tmp[0] = IDENTIFY(1, cmd->device->lun); #ifdef SUPPORT_TAGS if (cmd->tag != TAG_NONE) { @@ -1688,7 +1689,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) /* XXX need to handle errors here */ hostdata->connected = cmd; #ifndef SUPPORT_TAGS - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); #endif #ifdef SUN3_SCSI_VME dregs->csr |= CSR_INTR; @@ -2103,7 +2104,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * polled-IO. */ printk(KERN_NOTICE "scsi%d: switching target %d " "lun %d to slow handshake\n", HOSTNO, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); cmd->device->borken = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); @@ -2161,7 +2162,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->target, cmd->lun); + "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -2174,7 +2175,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) if (!cmd->next_link) { printk(KERN_NOTICE "scsi%d: target %d lun %d " "linked command complete, no next_link\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); sink = 1; do_abort (instance); return; @@ -2187,7 +2188,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); LNK_PRINTK("scsi%d: target %d lun %d linked request " "done, calling scsi_done().\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); #ifdef NCR5380_STATS collect_stats(hostdata, cmd); #endif @@ -2201,7 +2202,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); hostdata->connected = NULL; QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->target, cmd->lun); + "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { @@ -2213,16 +2214,16 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) */ /* ++Andreas: the mid level code knows about QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; TAG_PRINTK("scsi%d: target %d lun %d returned " "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->target, cmd->lun, + HOSTNO, cmd->device->id, cmd->device->lun, ta->nr_allocated); if (ta->queue_size > ta->nr_allocated) ta->nr_allocated = ta->queue_size; } #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -2312,12 +2313,12 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * the command is treated as untagged further on. */ cmd->device->tagged_supported = 0; - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); cmd->tag = TAG_NONE; TAG_PRINTK("scsi%d: target %d lun %d rejected " "QUEUE_TAG message; tagged queuing " "disabled\n", - HOSTNO, cmd->target, cmd->lun); + HOSTNO, cmd->device->id, cmd->device->lun); break; } break; @@ -2334,7 +2335,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) QU_PRINTK("scsi%d: command for target %d lun %d was " "moved from connected to the " "disconnected_queue\n", HOSTNO, - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2436,13 +2437,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) } else if (tmp != EXTENDED_MESSAGE) printk(KERN_DEBUG "scsi%d: rejecting unknown " "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->target, cmd->lun); + HOSTNO, tmp, cmd->device->id, cmd->device->lun); else printk(KERN_DEBUG "scsi%d: rejecting unknown " "extended message " "code %02x, length %d from target %d, lun %d\n", HOSTNO, extended_msg[1], extended_msg[0], - cmd->target, cmd->lun); + cmd->device->id, cmd->device->lun); msgout = MESSAGE_REJECT; @@ -2460,7 +2461,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif hostdata->connected = NULL; cmd->result = DID_ERROR << 16; @@ -2579,7 +2580,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { - if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) + if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) #ifdef SUPPORT_TAGS && (tag == tmp->tag) #endif @@ -2686,7 +2687,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) static int NCR5380_abort (Scsi_Cmnd *cmd) { - struct Scsi_Host *instance = cmd->host; + struct Scsi_Host *instance = cmd->device->host; SETUP_HOSTDATA(instance); Scsi_Cmnd *tmp, **prev; unsigned long flags; @@ -2736,7 +2737,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) #ifdef SUPPORT_TAGS cmd_free_tag( cmd ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif local_irq_restore(flags); cmd->scsi_done(cmd); @@ -2841,7 +2842,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); #else - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif local_irq_restore(flags); tmp->scsi_done(tmp); @@ -2868,7 +2869,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) /* - * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) + * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd) * * Purpose : reset the SCSI bus. * @@ -2876,9 +2877,9 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) * */ -static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +static int NCR5380_bus_reset( Scsi_Cmnd *cmd) { - SETUP_HOSTDATA(cmd->host); + SETUP_HOSTDATA(cmd->device->host); int i; unsigned long flags; #if 1 @@ -2886,7 +2887,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #endif - NCR5380_print_status (cmd->host); + NCR5380_print_status (cmd->device->host); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 978e81e9e602..e3d27cc486dd 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -79,6 +79,8 @@ #include "sun3_scsi.h" #include "NCR5380.h" +static void NCR5380_print(struct Scsi_Host *instance); + /* #define OLDDMA */ #define USE_WRAPPER @@ -312,7 +314,7 @@ int sun3scsi_release (struct Scsi_Host *shpnt) if (shpnt->irq != IRQ_NONE) free_irq (shpnt->irq, NULL); - iounmap(sun3_scsi_regp); + iounmap((void *)sun3_scsi_regp); return 0; } @@ -621,8 +623,8 @@ static Scsi_Host_Template driver_template = { .release = sun3scsi_release, .info = sun3scsi_info, .queuecommand = sun3scsi_queue_command, - .abort = sun3scsi_abort, - .reset = sun3scsi_reset, + .eh_abort_handler = sun3scsi_abort, + .eh_bus_reset_handler = sun3scsi_bus_reset, .can_queue = CAN_QUEUE, .this_id = 7, .sg_tablesize = SG_TABLESIZE, diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h index b7a569b3d2bb..23a897d39c87 100644 --- a/drivers/scsi/sun3_scsi.h +++ b/drivers/scsi/sun3_scsi.h @@ -55,7 +55,7 @@ static int sun3scsi_abort (Scsi_Cmnd *); static int sun3scsi_detect (Scsi_Host_Template *); static const char *sun3scsi_info (struct Scsi_Host *); -static int sun3scsi_reset(Scsi_Cmnd *, unsigned int); +static int sun3scsi_bus_reset(Scsi_Cmnd *); static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int sun3scsi_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -109,7 +109,7 @@ static int sun3scsi_release (struct Scsi_Host *); #define NCR5380_intr sun3scsi_intr #define NCR5380_queue_command sun3scsi_queue_command -#define NCR5380_reset sun3scsi_reset +#define NCR5380_bus_reset sun3scsi_bus_reset #define NCR5380_abort sun3scsi_abort #define NCR5380_proc_info sun3scsi_proc_info #define NCR5380_dma_xfer_len(i, cmd, phase) \ diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index 056a65cd4551..484500e20395 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -1,4 +1,4 @@ -/* + /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) @@ -566,8 +566,8 @@ static Scsi_Host_Template driver_template = { .release = sun3scsi_release, .info = sun3scsi_info, .queuecommand = sun3scsi_queue_command, - .abort = sun3scsi_abort, - .reset = sun3scsi_reset, + .eh_abort_handler = sun3scsi_abort, + .eh_bus_reset_handler = sun3scsi_bus_reset, .can_queue = CAN_QUEUE, .this_id = 7, .sg_tablesize = SG_TABLESIZE, diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index bfbdf74c018b..7c44fc01f784 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -374,11 +374,44 @@ static void dma_advance_sg (Scsi_Cmnd *sp) sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); } + +static int esp_slave_alloc(Scsi_Device *SDptr) +{ + struct esp_device *esp_dev = + kmalloc(sizeof(struct esp_device), GFP_ATOMIC); + + if (!esp_dev) + return -ENOMEM; + memset(esp_dev, 0, sizeof(struct esp_device)); + SDptr->hostdata = esp_dev; + return 0; +} + +static void esp_slave_destroy(Scsi_Device *SDptr) +{ + struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata; + + esp->targets_present &= ~(1 << SDptr->id); + kfree(SDptr->hostdata); + SDptr->hostdata = NULL; +} + + +static int sun3x_esp_release(struct Scsi_Host *instance) +{ + /* this code does not support being compiled as a module */ + return 1; + +} + static Scsi_Host_Template driver_template = { .proc_name = "esp", .proc_info = &esp_proc_info, .name = "Sun ESP 100/100a/200", .detect = sun3x_esp_detect, + .release = sun3x_esp_release, + .slave_alloc = esp_slave_alloc, + .slave_destroy = esp_slave_destroy, .info = esp_info, .command = esp_command, .queuecommand = esp_queue, diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index f9cb9e3c8d1e..520f1d4f318c 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -1471,7 +1471,7 @@ reset_wd33c93(struct Scsi_Host *instance) int busycount = 0; extern void sgiwd93_reset(unsigned long); /* wait 'til the chip gets some time for us */ - while ((READ_AUX_STAT() & ASR_BSY) && busycount++ < 100) + while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100) udelay (10); /* * there are scsi devices out there, which manage to lock up @@ -1481,7 +1481,7 @@ reset_wd33c93(struct Scsi_Host *instance) * does this for the SGI Indy, where this is possible */ /* still busy ? */ - if (READ_AUX_STAT() & ASR_BSY) + if (read_aux_stat(regs) & ASR_BSY) sgiwd93_reset(instance->base); /* yeah, give it the hard one */ } #endif @@ -2086,3 +2086,4 @@ EXPORT_SYMBOL(wd33c93_release); EXPORT_SYMBOL(wd33c93_abort); EXPORT_SYMBOL(wd33c93_queuecommand); EXPORT_SYMBOL(wd33c93_intr); +EXPORT_SYMBOL(wd33c93_proc_info); diff --git a/drivers/serial/uart00.c b/drivers/serial/uart00.c index c5c4bfc1161c..deba4a10e439 100644 --- a/drivers/serial/uart00.c +++ b/drivers/serial/uart00.c @@ -235,8 +235,8 @@ static void uart00_modem_status(struct uart_port *port) status = UART_GET_MSR(port); - if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | - UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)) + if (!(status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | + UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))) return; if (status & UART_MSR_DDCD_MSK) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b8f282d5524a..03696016c495 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1175,7 +1175,7 @@ void usb_hub_cleanup(void) int usb_reset_device(struct usb_device *dev) { struct usb_device *parent = dev->parent; - struct usb_device_descriptor descriptor; + struct usb_device_descriptor *descriptor; int i, ret, port = -1; if (!parent) { @@ -1224,17 +1224,24 @@ int usb_reset_device(struct usb_device *dev) * If nothing changed, we reprogram the configuration and then * the alternate settings. */ - ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor, - sizeof(descriptor)); - if (ret < 0) + descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); + if (!descriptor) { + return -ENOMEM; + } + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, + sizeof(*descriptor)); + if (ret < 0) { + kfree(descriptor); return ret; + } - le16_to_cpus(&descriptor.bcdUSB); - le16_to_cpus(&descriptor.idVendor); - le16_to_cpus(&descriptor.idProduct); - le16_to_cpus(&descriptor.bcdDevice); + le16_to_cpus(&descriptor->bcdUSB); + le16_to_cpus(&descriptor->idVendor); + le16_to_cpus(&descriptor->idProduct); + le16_to_cpus(&descriptor->bcdDevice); - if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) { + if (memcmp(&dev->descriptor, descriptor, sizeof(*descriptor))) { + kfree(descriptor); usb_destroy_configuration(dev); ret = usb_get_device_descriptor(dev); @@ -1268,6 +1275,8 @@ int usb_reset_device(struct usb_device *dev) return 1; } + kfree(descriptor); + ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue); if (ret < 0) { err("failed to set dev %s active configuration (error=%d)", diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 97c986e346d2..793a82b23ac2 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -88,7 +88,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, int retv; int length; - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) return -ENOMEM; @@ -131,7 +131,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout) { - struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); + struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); int ret; if (!dr) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 4e57b88d616d..32478229d4c9 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -117,10 +117,10 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} static void __attribute__((__unused__)) dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) { - dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label, - qh, qh->hw_info1, qh->hw_info2, + dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label, + qh, qh->hw_next, qh->hw_info1, qh->hw_info2, qh->hw_current, qh->hw_qtd_next); - dbg (" alt+errs= %x, token= %x, page0= %x, page1= %x", + dbg (" alt+nak+t= %x, token= %x, page0= %x, page1= %x", qh->hw_alt_next, qh->hw_token, qh->hw_buf [0], qh->hw_buf [1]); if (qh->hw_buf [2]) { diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d0954475b709..072d70416540 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -576,7 +576,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state) int ports; int i; - dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state); + ehci_dbg (ehci, "suspend to %d\n", state); ports = HCS_N_PORTS (ehci->hcs_params); @@ -593,7 +593,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state) if ((temp & PORT_PE) == 0 || (temp & PORT_OWNER) != 0) continue; -dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i); + ehci_dbg (ehci, "suspend port %d", i); temp |= PORT_SUSPEND; writel (temp, &ehci->regs->port_status [i]); } @@ -615,7 +615,7 @@ static int ehci_resume (struct usb_hcd *hcd) int ports; int i; - dbg ("%s: resume", hcd_to_bus (hcd)->bus_name); + ehci_dbg (ehci, "resume\n"); ports = HCS_N_PORTS (ehci->hcs_params); @@ -635,7 +635,7 @@ static int ehci_resume (struct usb_hcd *hcd) if ((temp & PORT_PE) == 0 || (temp & PORT_SUSPEND) != 0) continue; -dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i); + ehci_dbg (ehci, "resume port %d", i); temp |= PORT_RESUME; writel (temp, &ehci->regs->port_status [i]); readl (&ehci->regs->command); /* unblock posted writes */ @@ -880,8 +880,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev) /* ASSERT: no requests/urbs are still linked (so no TDs) */ /* ASSERT: nobody can be submitting urbs for this any more */ - dbg ("%s: free_config devnum %d", - hcd_to_bus (hcd)->bus_name, udev->devnum); + ehci_dbg (ehci, "free_config %s devnum %d\n", + udev->devpath, udev->devnum); spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < 32; i++) { @@ -912,7 +912,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev) dev->ep [i] = 0; if (qh->qh_state == QH_STATE_IDLE) goto idle; - dbg ("free_config, async ep 0x%02x qh %p", i, qh); + ehci_dbg (ehci, "free_config, async ep 0x%02x qh %p", + i, qh); /* scan_async() empties the ring as it does its work, * using IAA, but doesn't (yet?) turn it off. if it diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c index 6fb7c46362d6..284baf47656f 100644 --- a/drivers/usb/image/scanner.c +++ b/drivers/usb/image/scanner.c @@ -347,8 +347,9 @@ * - Don't print errors when the device is busy. * * 0.4.11 2003-02-25 - * - Added vendor/product ids for Artec, Avision, Brother, Medion, Primax, - * Prolink, Fujitsu, Plustek, and SYSCAN scanners. + * - Added vendor/product ids for Artec, Avision, Brother, Canon, Compaq, + * Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek, + * Primax, Prolink, Plustek, SYSCAN, Trust and UMAX scanners. * - Fixed generation of devfs names if dynamic minors are disabled. * - Used kobject reference counting to free the scn struct when the device * is closed and disconnected. Avoids crashes when writing to a diff --git a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h index dc77eb090dec..230f08c307b7 100644 --- a/drivers/usb/image/scanner.h +++ b/drivers/usb/image/scanner.h @@ -105,6 +105,7 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */ /* Benq: see Acer */ /* Brother */ + { USB_DEVICE(0x04f9, 0x010f) }, /* MFC 5100C */ { USB_DEVICE(0x04f9, 0x0111) }, /* MFC 6800 */ /* Canon */ { USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */ @@ -118,9 +119,11 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x04a9, 0x220c) }, /* CanoScan D1250U2 */ { USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */ { USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */ + { USB_DEVICE(0x04a9, 0x2213) }, /* LIDE 50 */ { USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */ /* Colorado -- See Primax/Colorado below */ /* Compaq */ + { USB_DEVICE(0x049f, 0x001a) }, /* S4 100 */ { USB_DEVICE(0x049f, 0x0021) }, /* S200 */ /* Epson -- See Seiko/Epson below */ /* Fujitsu */ @@ -152,6 +155,8 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */ // { USB_DEVICE(0x03f0, 0x0801) }, /* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */ { USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */ + { USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */ + { USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */ { USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */ { USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */ { USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */ @@ -159,12 +164,16 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ /* Lexmark */ { USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */ + { USB_DEVICE(0x043d, 0x003d) }, /* X83 */ + /* LG Electronics */ + { USB_DEVICE(0x0461, 0x0364) }, /* Scanworks 600U (repackaged Primax?) */ /* Medion */ { USB_DEVICE(0x0461, 0x0377) }, /* MD 5345 - repackaged Primax? */ /* Memorex */ { USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */ /* Microtek */ { USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */ + { USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */ /* The following SCSI-over-USB Microtek devices are supported by the microtek driver: Enable SCSI and USB Microtek in kernel config */ // { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */ @@ -259,7 +268,11 @@ static struct usb_device_id scanner_device_ids [] = { { USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */ /* SYSCAN */ { USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */ + /* Trust */ + { USB_DEVICE(0x05cb, 0x1483) }, /* CombiScan 19200 */ + { USB_DEVICE(0x05d8, 0x4006) }, /* Easy Webscan 19200 (repackaged Artec?) */ /* Umax */ + { USB_DEVICE(0x05d8, 0x4009) }, /* Astraslim (actually Artec?) */ { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ { USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */ diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 4da30222593a..9ec19ad566ef 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1334,6 +1334,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_TANGTOP 0x0d3d #define USB_DEVICE_ID_TANGTOP_USBPS2 0x0001 +#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f +#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1377,6 +1380,7 @@ struct hid_blacklist { { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { 0, 0 } }; diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index e333dbe6d07b..c24cebd97cba 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -12,5 +12,3 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o obj-$(CONFIG_USB_TEST) += usbtest.o obj-$(CONFIG_USB_TIGL) += tiglusb.o obj-$(CONFIG_USB_USS720) += uss720.o - -speedtch-objs := speedtouch.o atmsar.o diff --git a/drivers/usb/misc/atmsar.c b/drivers/usb/misc/atmsar.c deleted file mode 100644 index e9afd62768c8..000000000000 --- a/drivers/usb/misc/atmsar.c +++ /dev/null @@ -1,380 +0,0 @@ -/****************************************************************************** - * atmsar.c -- General SAR library for ATM devices. - * - * Copyright (C) 2000, Johan Verrept - * - * 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. - * - ******************************************************************************/ - -/* - * Written by Johan Verrept (Johan.Verrept@advalvas.be) - * - * 0.2.4A: - Version for inclusion in 2.5 series kernel - * - Modifications by Richard Purdie (rpurdie@rpsys.net) - * - replaced "sarlib" with "atmsar" - * - adaptations for inclusion in kernel tree - * - * 0.2.4: - Fixed wrong buffer overrun check in atmsar_decode_rawcell() - * reported by Stephen Robinson <stephen.robinson@zen.co.uk> - * - Fixed bug when input skb did not contain a multple of 52/53 - * bytes (would happen when the speedtouch device resynced) - * also reported by Stephen Robinson <stephen.robinson@zen.co.uk> - * - * 0.2.3: - Fixed wrong allocation size. caused memory corruption in some - * cases. Reported by Vladimir Dergachev <volodya@mindspring.com> - * - Added some comments - * - * 0.2.2: - Fixed CRCASM - * patch from Linus Flannagan <linusf@netservices.eng.net> - * - Fixed problem when user did NOT use the - * ATMSAR_USE_53BYTE_CELL flag. - * reported by Piers Scannell <email@lot105.com> - * - No more in-buffer rewriting for cloned buffers. - * - Removed the PII specific CFLAGS in the Makefile. - * - * 0.2.1: - removed dependency on alloc_tx. tis presented problems when - * using this with the br2684 code. - * - * 0.2: - added AAL0 reassembly - * - added alloc_tx support - * - replaced alloc_skb in decode functions to dev_alloc_skb to - * allow calling from interrupt - * - fixed embarassing AAL5 bug. I was setting the pti bit in the - * wrong byte... - * - fixed another emabrassing bug.. picked up the wrong crc type - * and forgot to invert the crc result... - * - fixed AAL5 length calculations. - * - removed automatic skb freeing from encode functions. - * This caused problems because i did kfree_skb it, while it - * needed to be popped. I cannot determine though whether it - * needs to be popped or not. Figu'e it out ye'self ;-) - * - added mru field. This is the buffersize. atmsar_decode_aal0 - * will use when it allocates a receive buffer. A stop gap for - * real buffer management. - * - * 0.1: - library created. - * - only contains AAL5, AAL0 can be easily added. (actually, only - * AAL0 reassembly is missing) - * - */ - -#include <linux/crc32.h> -#include "atmsar.h" - -/*********************** - ** - ** things to remember - ** - ***********************/ - -/* - 1. the atmsar_vcc_data list pointer MUST be initialized to NULL - 2. atmsar_encode_rawcell will drop incomplete cells. - 3. ownership of the skb goes to the library ! -*/ - -#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK) - -/*********************** - ** - ** LOCAL STRUCTURES - ** - ***********************/ - -/*********************** - ** - ** LOCAL MACROS - ** - ***********************/ -/* -#define DEBUG 1 -*/ -#ifdef DEBUG -#define PDEBUG(arg...) printk(KERN_DEBUG "atmsar: " arg) -#else -#define PDEBUG(arg...) -#endif - -#define ADD_HEADER(dest, header) \ - *dest++ = (unsigned char) (header >> 24); \ - *dest++ = (unsigned char) (header >> 16); \ - *dest++ = (unsigned char) (header >> 8); \ - *dest++ = (unsigned char) (header & 0xff); - - -struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type, - ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags) -{ - struct atmsar_vcc_data *new; - - if (!vcc) - return NULL; - - new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL); - - if (!new) - return NULL; - - memset (new, 0, sizeof (struct atmsar_vcc_data)); - new->vcc = vcc; - new->stats = vcc->stats; - new->type = type; - new->next = NULL; - new->gfc = gfc; - new->vp = vpi; - new->vc = vci; - new->pti = pti; - - switch (type) { - case ATMSAR_TYPE_AAL0: - new->mtu = ATMSAR_DEF_MTU_AAL0; - break; - case ATMSAR_TYPE_AAL1: - new->mtu = ATMSAR_DEF_MTU_AAL1; - break; - case ATMSAR_TYPE_AAL2: - new->mtu = ATMSAR_DEF_MTU_AAL2; - break; - case ATMSAR_TYPE_AAL34: - /* not supported */ - new->mtu = ATMSAR_DEF_MTU_AAL34; - break; - case ATMSAR_TYPE_AAL5: - new->mtu = ATMSAR_DEF_MTU_AAL5; - break; - } - - new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT) - | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT) - | ((unsigned long) vci << ATM_HDR_VCI_SHIFT) - | ((unsigned long) pti << ATM_HDR_PTI_SHIFT); - new->flags = flags; - new->next = NULL; - new->reasBuffer = NULL; - - new->next = *list; - *list = new; - - PDEBUG ("Allocated new SARLib vcc 0x%p with vp %d vc %d\n", new, vpi, vci); - - return new; -} - -void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) -{ - struct atmsar_vcc_data *work; - - if (*list == vcc) { - *list = (*list)->next; - } else { - for (work = *list; work && work->next && (work->next != vcc); work = work->next); - - /* return if not found */ - if (work->next != vcc) - return; - - work->next = work->next->next; - } - - if (vcc->reasBuffer) { - dev_kfree_skb (vcc->reasBuffer); - } - - PDEBUG ("Allocated SARLib vcc 0x%p with vp %d vc %d\n", vcc, vcc->vp, vcc->vc); - - kfree (vcc); -} - - -/*********************** - ** - ** DECODE FUNCTIONS - ** - ***********************/ - -struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, - struct atmsar_vcc_data **ctx) -{ - while (skb->len) { - unsigned char *cell = skb->data; - unsigned char *cell_payload; - struct atmsar_vcc_data *vcc = list; - unsigned long atmHeader = - ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) | - ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff); - - PDEBUG ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called\n", list, skb, ctx); - PDEBUG ("atmsar_decode_rawcell skb->data %p, skb->tail %p\n", skb->data, skb->tail); - - if (!list || !skb || !ctx) - return NULL; - if (!skb->data || !skb->tail) - return NULL; - - /* here should the header CRC check be... */ - - /* look up correct vcc */ - for (; - vcc - && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK)); - vcc = vcc->next); - - PDEBUG ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d\n", vcc, - (int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT), - (int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT)); - - if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) { - cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4); - - switch (vcc->type) { - case ATMSAR_TYPE_AAL0: - /* case ATMSAR_TYPE_AAL1: when we have a decode AAL1 function... */ - { - struct sk_buff *tmp = dev_alloc_skb (vcc->mtu); - - if (tmp) { - memcpy (tmp->tail, cell_payload, 48); - skb_put (tmp, 48); - - if (vcc->stats) - atomic_inc (&vcc->stats->rx); - - skb_pull (skb, - (vcc-> - flags & ATMSAR_USE_53BYTE_CELL ? 53 : - 52)); - PDEBUG - ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL0 pdu 0x%p with length %d\n", - tmp, tmp->len); - return tmp; - }; - } - break; - case ATMSAR_TYPE_AAL1: - case ATMSAR_TYPE_AAL2: - case ATMSAR_TYPE_AAL34: - /* not supported */ - break; - case ATMSAR_TYPE_AAL5: - if (!vcc->reasBuffer) - vcc->reasBuffer = dev_alloc_skb (vcc->mtu); - - /* if alloc fails, we just drop the cell. it is possible that we can still - * receive cells on other vcc's - */ - if (vcc->reasBuffer) { - /* if (buffer overrun) discard received cells until now */ - if ((vcc->reasBuffer->len) > (vcc->mtu - 48)) - skb_trim (vcc->reasBuffer, 0); - - /* copy data */ - memcpy (vcc->reasBuffer->tail, cell_payload, 48); - skb_put (vcc->reasBuffer, 48); - - /* check for end of buffer */ - if (cell[3] & 0x2) { - struct sk_buff *tmp; - - /* the aal5 buffer ends here, cut the buffer. */ - /* buffer will always have at least one whole cell, so */ - /* don't need to check return from skb_pull */ - skb_pull (skb, - (vcc-> - flags & ATMSAR_USE_53BYTE_CELL ? 53 : - 52)); - *ctx = vcc; - tmp = vcc->reasBuffer; - vcc->reasBuffer = NULL; - - PDEBUG - ("atmsar_decode_rawcell returns ATMSAR_TYPE_AAL5 pdu 0x%p with length %d\n", - tmp, tmp->len); - return tmp; - } - } - break; - }; - /* flush the cell */ - /* buffer will always contain at least one whole cell, so don't */ - /* need to check return value from skb_pull */ - skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)); - } else { - /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ - if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) == - NULL) - return NULL; - } - } - - return NULL; -}; - -struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb) -{ - uint crc = 0xffffffff; - uint length, pdu_crc, pdu_length; - - PDEBUG ("atmsar_decode_aal5 (0x%p, 0x%p) called\n", ctx, skb); - - if (skb->len && (skb->len % 48)) - return NULL; - - length = (skb->tail[-6] << 8) + skb->tail[-5]; - pdu_crc = - (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1]; - pdu_length = ((length + 47 + 8) / 48) * 48; - - PDEBUG ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d\n", - skb->len, length, pdu_crc, pdu_length); - - /* is skb long enough ? */ - if (skb->len < pdu_length) { - if (ctx->stats) - atomic_inc (&ctx->stats->rx_err); - return NULL; - } - - /* is skb too long ? */ - if (skb->len > pdu_length) { - PDEBUG ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d\n", - skb->len, pdu_length); - /* buffer is too long. we can try to recover - * if we discard the first part of the skb. - * the crc will decide whether this was ok - */ - skb_pull (skb, skb->len - pdu_length); - } - - crc = ~crc32_be (crc, skb->data, pdu_length - 4); - - /* check crc */ - if (pdu_crc != crc) { - PDEBUG ("atmsar_decode_aal5: crc check failed!\n"); - if (ctx->stats) - atomic_inc (&ctx->stats->rx_err); - return NULL; - } - - /* pdu is ok */ - skb_trim (skb, length); - - /* update stats */ - if (ctx->stats) - atomic_inc (&ctx->stats->rx); - - PDEBUG ("atmsar_decode_aal5 returns pdu 0x%p with length %d\n", skb, skb->len); - return skb; -}; diff --git a/drivers/usb/misc/atmsar.h b/drivers/usb/misc/atmsar.h deleted file mode 100644 index 29727e784b72..000000000000 --- a/drivers/usb/misc/atmsar.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _ATMSAR_H_ -#define _ATMSAR_H_ - -/****************************************************************************** - * atmsar.h -- General SAR library for ATM devices. - * - * Copyright (C) 2000, Johan Verrept - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#include <linux/kernel.h> -#include <linux/proc_fs.h> -#include <linux/slab.h> -#include <linux/atmdev.h> -#include <linux/skbuff.h> -#include <linux/types.h> -#include <linux/atm.h> - -#define ATMSAR_USE_53BYTE_CELL 0x1L -#define ATMSAR_SET_PTI 0x2L - -#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) - -/* types */ -#define ATMSAR_TYPE_AAL0 ATM_AAL0 -#define ATMSAR_TYPE_AAL1 ATM_AAL1 -#define ATMSAR_TYPE_AAL2 ATM_AAL2 -#define ATMSAR_TYPE_AAL34 ATM_AAL34 -#define ATMSAR_TYPE_AAL5 ATM_AAL5 - - -/* default MTU's */ -#define ATMSAR_DEF_MTU_AAL0 48 -#define ATMSAR_DEF_MTU_AAL1 47 -#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */ -#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */ -#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */ - -struct atmsar_vcc_data { - struct atmsar_vcc_data *next; - - /* general atmsar flags, per connection */ - int flags; - int type; - - /* connection specific non-atmsar data */ - struct atm_vcc *vcc; - struct k_atm_aal_stats *stats; - unsigned short mtu; /* max is actually 65k for AAL5... */ - - /* cell data */ - unsigned int vp; - unsigned int vc; - unsigned char gfc; - unsigned char pti; - unsigned int headerFlags; - unsigned long atmHeader; - - /* raw cell reassembly */ - struct sk_buff *reasBuffer; -}; - - -extern struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, - uint type, ushort vpi, ushort vci, unchar pti, - unchar gfc, uint flags); -extern void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc); - -struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, - struct atmsar_vcc_data **ctx); -struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb); - -#endif /* _ATMSAR_H_ */ diff --git a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtch.c index 58bb47c64e6a..d2006a09c36e 100644 --- a/drivers/usb/misc/speedtouch.c +++ b/drivers/usb/misc/speedtch.c @@ -61,7 +61,6 @@ #include <linux/atm.h> #include <linux/atmdev.h> #include <linux/crc32.h> -#include "atmsar.h" /* #define DEBUG 1 @@ -102,6 +101,8 @@ static int udsl_print_packet (const unsigned char *data, int len); #define UDSL_ENDPOINT_DATA_OUT 0x07 #define UDSL_ENDPOINT_DATA_IN 0x87 +#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) + #define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) ) /* usb_device_id struct */ @@ -147,6 +148,30 @@ struct udsl_control { #define UDSL_SKB(x) ((struct udsl_control *)(x)->cb) +struct atmsar_vcc_data { + struct atmsar_vcc_data *next; + + /* general atmsar flags, per connection */ + int flags; + int type; + + /* connection specific non-atmsar data */ + struct atm_vcc *vcc; + struct k_atm_aal_stats *stats; + unsigned short mtu; /* max is actually 65k for AAL5... */ + + /* cell data */ + unsigned int vp; + unsigned int vc; + unsigned char gfc; + unsigned char pti; + unsigned int headerFlags; + unsigned long atmHeader; + + /* raw cell reassembly */ + struct sk_buff *reasBuffer; +}; + /* * UDSL main driver data */ @@ -230,6 +255,188 @@ static struct usb_driver udsl_usb_driver = { /************* +** decode ** +*************/ + +#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK) +#define ATMSAR_USE_53BYTE_CELL 0x1L + +struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, + struct atmsar_vcc_data **ctx) +{ + while (skb->len) { + unsigned char *cell = skb->data; + unsigned char *cell_payload; + struct atmsar_vcc_data *vcc = list; + unsigned long atmHeader = + ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) | + ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff); + + dbg ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx); + dbg ("atmsar_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail); + + if (!list || !skb || !ctx) + return NULL; + if (!skb->data || !skb->tail) + return NULL; + + /* here should the header CRC check be... */ + + /* look up correct vcc */ + for (; + vcc + && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK)); + vcc = vcc->next); + + dbg ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d", vcc, + (int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT), + (int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT)); + + if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) { + cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4); + + switch (vcc->type) { + case ATM_AAL0: + /* case ATM_AAL1: when we have a decode AAL1 function... */ + { + struct sk_buff *tmp = dev_alloc_skb (vcc->mtu); + + if (tmp) { + memcpy (tmp->tail, cell_payload, 48); + skb_put (tmp, 48); + + if (vcc->stats) + atomic_inc (&vcc->stats->rx); + + skb_pull (skb, + (vcc-> + flags & ATMSAR_USE_53BYTE_CELL ? 53 : + 52)); + dbg + ("atmsar_decode_rawcell returns ATM_AAL0 pdu 0x%p with length %d", + tmp, tmp->len); + return tmp; + }; + } + break; + case ATM_AAL1: + case ATM_AAL2: + case ATM_AAL34: + /* not supported */ + break; + case ATM_AAL5: + if (!vcc->reasBuffer) + vcc->reasBuffer = dev_alloc_skb (vcc->mtu); + + /* if alloc fails, we just drop the cell. it is possible that we can still + * receive cells on other vcc's + */ + if (vcc->reasBuffer) { + /* if (buffer overrun) discard received cells until now */ + if ((vcc->reasBuffer->len) > (vcc->mtu - 48)) + skb_trim (vcc->reasBuffer, 0); + + /* copy data */ + memcpy (vcc->reasBuffer->tail, cell_payload, 48); + skb_put (vcc->reasBuffer, 48); + + /* check for end of buffer */ + if (cell[3] & 0x2) { + struct sk_buff *tmp; + + /* the aal5 buffer ends here, cut the buffer. */ + /* buffer will always have at least one whole cell, so */ + /* don't need to check return from skb_pull */ + skb_pull (skb, + (vcc-> + flags & ATMSAR_USE_53BYTE_CELL ? 53 : + 52)); + *ctx = vcc; + tmp = vcc->reasBuffer; + vcc->reasBuffer = NULL; + + dbg + ("atmsar_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", + tmp, tmp->len); + return tmp; + } + } + break; + }; + /* flush the cell */ + /* buffer will always contain at least one whole cell, so don't */ + /* need to check return value from skb_pull */ + skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)); + } else { + /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ + if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) == + NULL) + return NULL; + } + } + + return NULL; +}; + +struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb) +{ + uint crc = 0xffffffff; + uint length, pdu_crc, pdu_length; + + dbg ("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb); + + if (skb->len && (skb->len % 48)) + return NULL; + + length = (skb->tail[-6] << 8) + skb->tail[-5]; + pdu_crc = + (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1]; + pdu_length = ((length + 47 + 8) / 48) * 48; + + dbg ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", + skb->len, length, pdu_crc, pdu_length); + + /* is skb long enough ? */ + if (skb->len < pdu_length) { + if (ctx->stats) + atomic_inc (&ctx->stats->rx_err); + return NULL; + } + + /* is skb too long ? */ + if (skb->len > pdu_length) { + dbg ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d", + skb->len, pdu_length); + /* buffer is too long. we can try to recover + * if we discard the first part of the skb. + * the crc will decide whether this was ok + */ + skb_pull (skb, skb->len - pdu_length); + } + + crc = ~crc32_be (crc, skb->data, pdu_length - 4); + + /* check crc */ + if (pdu_crc != crc) { + dbg ("atmsar_decode_aal5: crc check failed!"); + if (ctx->stats) + atomic_inc (&ctx->stats->rx_err); + return NULL; + } + + /* pdu is ok */ + skb_trim (skb, length); + + /* update stats */ + if (ctx->stats) + atomic_inc (&ctx->stats->rx); + + dbg ("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len); + return skb; +}; + + +/************* ** encode ** *************/ @@ -396,7 +603,7 @@ static void udsl_process_receive (unsigned long data) dbg ("(after cell processing)skb->len = %d", new->len); switch (atmsar_vcc->type) { - case ATMSAR_TYPE_AAL5: + case ATM_AAL5: tmp = new; new = atmsar_decode_aal5 (atmsar_vcc, new); @@ -690,15 +897,98 @@ static int udsl_atm_send (struct atm_vcc *vcc, struct sk_buff *skb) } -/************ -** ATM ** -************/ +/********** +** ATM ** +**********/ + +#define ATMSAR_DEF_MTU_AAL0 48 +#define ATMSAR_DEF_MTU_AAL1 47 +#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */ +#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */ +#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */ + +struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type, + ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags) +{ + struct atmsar_vcc_data *new; + + if (!vcc) + return NULL; + + new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL); + + if (!new) + return NULL; + + memset (new, 0, sizeof (struct atmsar_vcc_data)); + new->vcc = vcc; + new->stats = vcc->stats; + new->type = type; + new->next = NULL; + new->gfc = gfc; + new->vp = vpi; + new->vc = vci; + new->pti = pti; + + switch (type) { + case ATM_AAL0: + new->mtu = ATMSAR_DEF_MTU_AAL0; + break; + case ATM_AAL1: + new->mtu = ATMSAR_DEF_MTU_AAL1; + break; + case ATM_AAL2: + new->mtu = ATMSAR_DEF_MTU_AAL2; + break; + case ATM_AAL34: + /* not supported */ + new->mtu = ATMSAR_DEF_MTU_AAL34; + break; + case ATM_AAL5: + new->mtu = ATMSAR_DEF_MTU_AAL5; + break; + } + + new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT) + | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT) + | ((unsigned long) vci << ATM_HDR_VCI_SHIFT) + | ((unsigned long) pti << ATM_HDR_PTI_SHIFT); + new->flags = flags; + new->next = NULL; + new->reasBuffer = NULL; + + new->next = *list; + *list = new; + + dbg ("Allocated new SARLib vcc 0x%p with vp %d vc %d", new, vpi, vci); + + return new; +} + +void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) +{ + struct atmsar_vcc_data *work; + + if (*list == vcc) { + *list = (*list)->next; + } else { + for (work = *list; work && work->next && (work->next != vcc); work = work->next); + + /* return if not found */ + if (work->next != vcc) + return; -/*************************************************************************** -* -* init functions -* -****************************************************************************/ + work->next = work->next->next; + } + + if (vcc->reasBuffer) { + dev_kfree_skb (vcc->reasBuffer); + } + + dbg ("Allocated SARLib vcc 0x%p with vp %d vc %d", vcc, vcc->vp, vcc->vc); + + kfree (vcc); +} static void udsl_atm_dev_close (struct atm_dev *dev) { @@ -718,13 +1008,6 @@ static void udsl_atm_dev_close (struct atm_dev *dev) dev->dev_data = NULL; } - -/*************************************************************************** -* -* ATM helper functions -* -****************************************************************************/ - static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page) { struct udsl_instance_data *instance = atm_dev->dev_data; @@ -778,12 +1061,7 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page) return 0; } - -/*************************************************************************** -* -* SAR driver entries -* -****************************************************************************/ +#define ATMSAR_SET_PTI 0x2L static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) { @@ -803,7 +1081,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) MOD_INC_USE_COUNT; vcc->dev_data = - atmsar_open (&(instance->atmsar_vcc_list), vcc, ATMSAR_TYPE_AAL5, vpi, vci, 0, 0, + atmsar_open (&(instance->atmsar_vcc_list), vcc, ATM_AAL5, vpi, vci, 0, 0, ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI); if (!vcc->dev_data) { MOD_DEC_USE_COUNT; @@ -866,9 +1144,9 @@ static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) } -/************ -** USB ** -************/ +/********** +** USB ** +**********/ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *user_data) { @@ -1180,11 +1458,9 @@ static void udsl_usb_disconnect (struct usb_interface *intf) } -/*************************************************************************** -* -* Driver Init -* -****************************************************************************/ +/*********** +** init ** +***********/ static int __init udsl_usb_init (void) { @@ -1215,13 +1491,11 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); -#ifdef DEBUG_PACKET -/******************************************************************************* -* -* Debug -* -*******************************************************************************/ +/************ +** debug ** +************/ +#ifdef DEBUG_PACKET static int udsl_print_packet (const unsigned char *data, int len) { unsigned char buffer [256]; @@ -1237,5 +1511,4 @@ static int udsl_print_packet (const unsigned char *data, int len) } return i; } - -#endif /* PACKETDEBUG */ +#endif diff --git a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c index 2dc8dfe0ba99..e6b530720209 100644 --- a/drivers/usb/net/cdc-ether.c +++ b/drivers/usb/net/cdc-ether.c @@ -1064,15 +1064,23 @@ static void set_ethernet_addr( ether_dev_t *ether_dev ) // Used by driver's probe routine //////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -void log_device_info(ether_dev_t *ether_dev) +static void log_device_info(ether_dev_t *ether_dev) { int len; int string_num; - unsigned char manu[256]; - unsigned char prod[256]; - unsigned char sern[256]; + unsigned char *manu = NULL; + unsigned char *prod = NULL; + unsigned char *sern = NULL; unsigned char *mac_addr; + manu = kmalloc(256, GFP_KERNEL); + prod = kmalloc(256, GFP_KERNEL); + sern = kmalloc(256, GFP_KERNEL); + if (!manu || !prod || !sern) { + dbg("no mem for log_device_info"); + goto fini; + } + // Default empty strings in case we don't find a real one manu[0] = 0x00; prod[0] = 0x00; @@ -1113,6 +1121,10 @@ void log_device_info(ether_dev_t *ether_dev) ether_dev->net->name, manu, prod, sern, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5] ); +fini: + kfree(manu); + kfree(prod); + kfree(sern); } /* Forward declaration */ diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 138ca704f779..a72a4ce7456e 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -121,7 +121,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, char *buffer; DECLARE_WAITQUEUE(wait, current); - buffer = kmalloc(size, GFP_DMA); + buffer = kmalloc(size, GFP_KERNEL); if (!buffer) { warn("%s: looks like we're out of memory", __FUNCTION__); return -ENOMEM; @@ -170,7 +170,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, char *buffer; DECLARE_WAITQUEUE(wait, current); - buffer = kmalloc(size, GFP_DMA); + buffer = kmalloc(size, GFP_KERNEL); if (!buffer) { warn("%s: looks like we're out of memory", __FUNCTION__); return -ENOMEM; @@ -218,7 +218,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) char *tmp; DECLARE_WAITQUEUE(wait, current); - tmp = kmalloc(1, GFP_DMA); + tmp = kmalloc(1, GFP_KERNEL); if (!tmp) { warn("%s: looks like we're out of memory", __FUNCTION__); return -ENOMEM; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 7738a16f5b40..7acdf0580a3f 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -783,7 +783,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un if (info->mcr & UART_MCR_RTS) modem_signals |= TIOCM_RTS; - if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int))); + if (copy_to_user((unsigned int *)arg, &modem_signals, sizeof(unsigned int))) return -EFAULT; break; diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index b89ca760a959..643d71fc64ea 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -1,5 +1,5 @@ /* - * USB Skeleton driver - 0.9 + * USB Skeleton driver - 1.0 * * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) * @@ -12,14 +12,17 @@ * USB driver quickly. The design of it is based on the usb-serial and * dc2xx drivers. * - * Thanks to Oliver Neukum and David Brownell for their help in debugging - * this driver. + * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help + * in debugging this driver. * - * TODO: - * - fix urb->status race condition in write sequence * * History: * + * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and + * disconnect. Fix transfer amount in read(). Use + * macros instead of magic numbers in probe(). Change + * size variables to size_t. Show how to eliminate + * DMA bounce buffer. * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array. * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device * driver. @@ -33,7 +36,7 @@ * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people * 2001_05_01 - 0.1 - first version - * + * */ #include <linux/config.h> @@ -42,8 +45,8 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/spinlock.h> #include <linux/smp_lock.h> +#include <linux/completion.h> #include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <linux/usb.h> @@ -60,7 +63,7 @@ /* Version Information */ -#define DRIVER_VERSION "v0.4" +#define DRIVER_VERSION "v1.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" #define DRIVER_DESC "USB Skeleton Driver" @@ -101,15 +104,16 @@ struct usb_skel { char num_bulk_out; /* number of bulk out endpoints we have */ unsigned char * bulk_in_buffer; /* the buffer to receive data */ - int bulk_in_size; /* the size of the receive buffer */ + size_t bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ unsigned char * bulk_out_buffer; /* the buffer to send data */ - int bulk_out_size; /* the size of the send buffer */ + size_t bulk_out_size; /* the size of the send buffer */ struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + atomic_t write_busy; /* true iff write urb is busy */ + struct completion write_finished; /* wait for the write to finish */ - struct work_struct work; /* work queue entry for line discipline waking up */ int open; /* if the port is open or not */ struct semaphore sem; /* locks this structure */ }; @@ -118,6 +122,8 @@ struct usb_skel { /* the global usb devfs handle */ extern devfs_handle_t usb_devfs_handle; +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX (disconnect_sem); /* local function prototypes */ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos); @@ -125,7 +131,7 @@ static ssize_t skel_write (struct file *file, const char *buffer, size_t count, static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static int skel_open (struct inode *inode, struct file *file); static int skel_release (struct inode *inode, struct file *file); - + static int skel_probe (struct usb_interface *intf, const struct usb_device_id *id); static void skel_disconnect (struct usb_interface *intf); @@ -138,7 +144,7 @@ static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs); * to have a node in the /dev directory. If the USB * device were for a network interface then the driver * would use "struct net_driver" instead, and a serial - * device would use "struct tty_driver". + * device would use "struct tty_driver". */ static struct file_operations skel_fops = { /* @@ -167,7 +173,7 @@ static struct file_operations skel_fops = { .ioctl = skel_ioctl, .open = skel_open, .release = skel_release, -}; +}; /* usb specific object needed to register this driver with the usb subsystem */ @@ -188,8 +194,8 @@ static inline void usb_skel_debug_data (const char *function, int size, const un if (!debug) return; - - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", + + printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size); for (i = 0; i < size; ++i) { printk ("%.2x ", data[i]); @@ -206,7 +212,9 @@ static inline void skel_delete (struct usb_skel *dev) if (dev->bulk_in_buffer != NULL) kfree (dev->bulk_in_buffer); if (dev->bulk_out_buffer != NULL) - kfree (dev->bulk_out_buffer); + usb_buffer_free (dev->udev, dev->bulk_out_size, + dev->bulk_out_buffer, + dev->write_urb->transfer_dma); if (dev->write_urb != NULL) usb_free_urb (dev->write_urb); kfree (dev); @@ -222,22 +230,28 @@ static int skel_open (struct inode *inode, struct file *file) struct usb_interface *interface; int subminor; int retval = 0; - + dbg("%s", __FUNCTION__); subminor = minor (inode->i_rdev); + /* prevent disconnects */ + down (&disconnect_sem); + interface = usb_find_interface (&skel_driver, mk_kdev(USB_MAJOR, subminor)); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); - return -ENODEV; + retval = -ENODEV; + goto exit_no_device; } - + dev = usb_get_intfdata(interface); - if (!dev) - return -ENODEV; + if (!dev) { + retval = -ENODEV; + goto exit_no_device; + } /* lock this device */ down (&dev->sem); @@ -251,6 +265,8 @@ static int skel_open (struct inode *inode, struct file *file) /* unlock this device */ up (&dev->sem); +exit_no_device: + up (&disconnect_sem); return retval; } @@ -280,6 +296,12 @@ static int skel_release (struct inode *inode, struct file *file) goto exit_not_opened; } + /* wait for any bulk writes that might be going on to finish up */ + if (atomic_read (&dev->write_busy)) + wait_for_completion (&dev->write_finished); + + dev->open = 0; + if (dev->udev == NULL) { /* the device was unplugged before the file was released */ up (&dev->sem); @@ -287,11 +309,6 @@ static int skel_release (struct inode *inode, struct file *file) return 0; } - /* shutdown any bulk writes that might be going on */ - usb_unlink_urb (dev->write_urb); - - dev->open = 0; - exit_not_opened: up (&dev->sem); @@ -308,7 +325,7 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t int retval = 0; dev = (struct usb_skel *)file->private_data; - + dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); /* lock this object */ @@ -319,12 +336,13 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t up (&dev->sem); return -ENODEV; } - - /* do an immediate bulk read to get data from the device */ + + /* do a blocking bulk read to get data from the device */ retval = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, + usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, dev->bulk_in_size, + dev->bulk_in_buffer, + min (dev->bulk_in_size, count), &count, HZ*10); /* if the read was successful, copy the data to userspace */ @@ -334,7 +352,7 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t else retval = count; } - + /* unlock the device */ up (&dev->sem); return retval; @@ -343,6 +361,18 @@ static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t /** * skel_write + * + * A device driver has to decide how to report I/O errors back to the + * user. The safest course is to wait for the transfer to finish before + * returning so that any errors will be reported reliably. skel_read() + * works like this. But waiting for I/O is slow, so many drivers only + * check for errors during I/O initiation and do not report problems + * that occur during the actual transfer. That's what we will do here. + * + * A driver concerned with maximum I/O throughput would use double- + * buffering: Two urbs would be devoted to write transfers, so that + * one urb could always be active while the other was waiting for the + * user to send more data. */ static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos) { @@ -369,37 +399,38 @@ static ssize_t skel_write (struct file *file, const char *buffer, size_t count, goto exit; } - /* see if we are already in the middle of a write */ - if (dev->write_urb->status == -EINPROGRESS) { - dbg ("%s - already writing", __FUNCTION__); - goto exit; - } + /* wait for a previous write to finish up; we don't use a timeout + * and so a nonresponsive device can delay us indefinitely. + */ + if (atomic_read (&dev->write_busy)) + wait_for_completion (&dev->write_finished); - /* we can only write as much as 1 urb will hold */ - bytes_written = (count > dev->bulk_out_size) ? - dev->bulk_out_size : count; + /* we can only write as much as our buffer will hold */ + bytes_written = min (dev->bulk_out_size, count); - /* copy the data from userspace into our urb */ - if (copy_from_user(dev->write_urb->transfer_buffer, buffer, + /* copy the data from userspace into our transfer buffer; + * this is the only copy required. + */ + if (copy_from_user(dev->write_urb->transfer_buffer, buffer, bytes_written)) { retval = -EFAULT; goto exit; } - usb_skel_debug_data (__FUNCTION__, bytes_written, + usb_skel_debug_data (__FUNCTION__, bytes_written, dev->write_urb->transfer_buffer); - /* set up our urb */ - usb_fill_bulk_urb(dev->write_urb, dev->udev, - usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), - dev->write_urb->transfer_buffer, bytes_written, - skel_write_bulk_callback, dev); + /* this urb was already set up, except for this write size */ + dev->write_urb->transfer_buffer_length = bytes_written; /* send the data out the bulk port */ /* a character device write uses GFP_KERNEL, unless a spinlock is held */ + init_completion (&dev->write_finished); + atomic_set (&dev->write_busy, 1); retval = usb_submit_urb(dev->write_urb, GFP_KERNEL); if (retval) { + atomic_set (&dev->write_busy, 0); err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); } else { @@ -435,12 +466,11 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__, dev->minor, cmd, arg); - /* fill in your device specific stuff here */ - + /* unlock the device */ up (&dev->sem); - + /* return that we did not understand this ioctl call */ return -ENOTTY; } @@ -455,14 +485,16 @@ static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs) dbg("%s - minor %d", __FUNCTION__, dev->minor); - if ((urb->status != -ENOENT) && - (urb->status != -ECONNRESET)) { + /* sync/async unlink faults aren't errors */ + if (urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET)) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); - return; } - return; + /* notify anyone waiting that the write has finished */ + atomic_set (&dev->write_busy, 0); + complete (&dev->write_finished); } @@ -479,12 +511,12 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int minor; - int buffer_size; + size_t buffer_size; int i; int retval; char name[10]; - + /* See if the device offered us matches what we can accept */ if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { @@ -513,12 +545,15 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i /* set up the endpoint information */ /* check out the endpoints */ + /* use only the first bulk-in and bulk-out endpoints */ iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { + if (!dev->bulk_in_endpointAddr && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk in endpoint */ buffer_size = endpoint->wMaxPacketSize; dev->bulk_in_size = buffer_size; @@ -529,9 +564,11 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i goto error; } } - - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { + + if (!dev->bulk_out_endpointAddr && + !(endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk out endpoint */ /* a probe() may sleep and has no restrictions on memory allocations */ dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -539,40 +576,56 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i err("No free urbs available"); goto error; } + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + + /* on some platforms using this kind of buffer alloc + * call eliminates a dma "bounce buffer". + * + * NOTE: you'd normally want i/o buffers that hold + * more than one packet, so that i/o delays between + * packets don't hurt throughput. + */ buffer_size = endpoint->wMaxPacketSize; dev->bulk_out_size = buffer_size; - dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); + dev->write_urb->transfer_flags = (URB_NO_DMA_MAP | + URB_ASYNC_UNLINK); + dev->bulk_out_buffer = usb_buffer_alloc (udev, + buffer_size, GFP_KERNEL, + &dev->write_urb->transfer_dma); if (!dev->bulk_out_buffer) { err("Couldn't allocate bulk_out_buffer"); goto error; } - usb_fill_bulk_urb(dev->write_urb, udev, - usb_sndbulkpipe(udev, + usb_fill_bulk_urb(dev->write_urb, udev, + usb_sndbulkpipe(udev, endpoint->bEndpointAddress), dev->bulk_out_buffer, buffer_size, skel_write_bulk_callback, dev); } } + if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { + err("Couldn't find both bulk-in and bulk-out endpoints"); + goto error; + } /* initialize the devfs node for this device and register it */ sprintf(name, "skel%d", dev->minor); - + dev->devfs = devfs_register (usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, dev->minor, - S_IFCHR | S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | S_IROTH, + S_IFCHR | S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH, &skel_fops, NULL); /* let the user know what node this device is now attached to */ - info ("USB Skeleton device now attached to USBSkel%d", dev->minor); + info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); /* add device id so the device works when advertised */ interface->kdev = mk_kdev(USB_MAJOR, dev->minor); goto exit; - + error: skel_delete (dev); dev = NULL; @@ -593,12 +646,21 @@ exit: * skel_disconnect * * Called by the usb core when the device is removed from the system. + * + * This routine guarantees that the driver will not submit any more urbs + * by clearing dev->udev. It is also supposed to terminate any currently + * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does + * not provide any way to do this. But at least we can cancel an active + * write. */ static void skel_disconnect(struct usb_interface *interface) { struct usb_skel *dev; int minor; + /* prevent races with open() */ + down (&disconnect_sem); + dev = usb_get_intfdata (interface); usb_set_intfdata (interface, NULL); @@ -606,7 +668,7 @@ static void skel_disconnect(struct usb_interface *interface) return; down (&dev->sem); - + /* remove device id to disable open() */ interface->kdev = NODEV; @@ -617,15 +679,21 @@ static void skel_disconnect(struct usb_interface *interface) /* give back our dynamic minor */ usb_deregister_dev (1, minor); - + + /* terminate an ongoing write */ + if (atomic_read (&dev->write_busy)) { + usb_unlink_urb (dev->write_urb); + wait_for_completion (&dev->write_finished); + } + + dev->udev = NULL; + up (&dev->sem); + /* if the device is not opened, then we clean up right now */ - if (!dev->open) { - up (&dev->sem); + if (!dev->open) skel_delete (dev); - } else { - dev->udev = NULL; - up (&dev->sem); - } + + up (&disconnect_sem); info("USB Skeleton #%d now disconnected", minor); } @@ -668,4 +736,3 @@ module_exit (usb_skel_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 227bd6af7e85..03f5dcef1d0a 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_PPC) += macmodes.o endif obj-$(CONFIG_FB_ACORN) += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_AMIGA) += amifb.o +obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o @@ -58,7 +58,7 @@ obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbi obj-$(CONFIG_FB_MATROX) += matrox/ obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o obj-$(CONFIG_FB_SIS) += sis/ -obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o cfbfillrect.o cfbimgblt.o +obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \ cfbimgblt.o vgastate.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 1a5410518e0b..5470149c077f 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -1,7 +1,7 @@ /* * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device * - * Copyright (C) 1995 Geert Uytterhoeven + * Copyright (C) 1995-2003 Geert Uytterhoeven * * with work by Roman Zippel * @@ -62,10 +62,7 @@ #include <asm/amigaints.h> #include <asm/setup.h> -#include <video/fbcon.h> -#include <video/fbcon-afb.h> -#include <video/fbcon-ilbm.h> -#include <video/fbcon-mfb.h> +#include "c2p.h" #define DEBUG @@ -613,12 +610,11 @@ static u_short maxfmode, chipset; #define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ #define DUMMYSPRITEMEMSIZE (8) +static u_long spritememory; #define CHIPRAM_SAFETY_LIMIT (16384) -static u_long videomemory, spritememory; -static u_long videomemorysize; -static u_long videomemory_phys; +static u_long videomemory; /* * This is the earliest allowed start of fetching display data. @@ -660,6 +656,47 @@ static struct copdisplay { static u_short currentcop = 0; /* + * Hardware Cursor API Definitions + * These used to be in linux/fb.h, but were preliminary and used by + * amifb only anyway + */ + +#define FBIOGET_FCURSORINFO 0x4607 +#define FBIOGET_VCURSORINFO 0x4608 +#define FBIOPUT_VCURSORINFO 0x4609 +#define FBIOGET_CURSORSTATE 0x460A +#define FBIOPUT_CURSORSTATE 0x460B + + +struct fb_fix_cursorinfo { + __u16 crsr_width; /* width and height of the cursor in */ + __u16 crsr_height; /* pixels (zero if no cursor) */ + __u16 crsr_xsize; /* cursor size in display pixels */ + __u16 crsr_ysize; + __u16 crsr_color1; /* colormap entry for cursor color1 */ + __u16 crsr_color2; /* colormap entry for cursor color2 */ +}; + +struct fb_var_cursorinfo { + __u16 width; + __u16 height; + __u16 xspot; + __u16 yspot; + __u8 data[1]; /* field with [height][width] */ +}; + +struct fb_cursorstate { + __s16 xoffset; + __s16 yoffset; + __u16 mode; +}; + +#define FB_CURSOR_OFF 0 +#define FB_CURSOR_ON 1 +#define FB_CURSOR_FLASH 2 + + + /* * Hardware Cursor */ @@ -738,28 +775,28 @@ static struct amifb_par { u_short fmode; /* vmode */ } currentpar; -static struct display disp; -static struct fb_info fb_info; +static struct fb_info fb_info = { + .fix = { + .id = "Amiga ", + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_AMIGABLITT + } +}; /* - * Since we can't read the palette on OCS/ECS, and since reading one - * single color palette entry requires 5 expensive custom chip bus accesses - * on AGA, we keep a copy of the current palette. - * Note that the entries are always 24 bit! + * Saved color entry 0 so we can restore it when unblanking */ -#if defined(CONFIG_FB_AMIGA_AGA) -static struct { u_char red, green, blue, pad; } palette[256]; -#else -static struct { u_char red, green, blue, pad; } palette[32]; -#endif +static u_char red0, green0, blue0; + #if defined(CONFIG_FB_AMIGA_ECS) static u_short ecs_palette[32]; #endif + /* * Latches for Display Changes during VBlank */ @@ -778,15 +815,6 @@ static u_short is_blanked = 0; /* Screen is Blanked */ static u_short is_lace = 0; /* Screen is laced */ /* - * Frame Buffer Name - * - * The rest of the name is filled in during initialization - */ - -static char amifb_name[16] = "Amiga "; - - - /* * Predefined Video Modes * */ @@ -1087,29 +1115,22 @@ static u_short sprfetchmode[3] = { int amifb_setup(char*); -static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -static int amifb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int amifb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); +static int amifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int amifb_set_par(struct fb_info *info); +static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info); static int amifb_blank(int blank, struct fb_info *info); -static int amifb_pan_display(struct fb_var_screeninfo *var, int con, +static int amifb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); -static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); +static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect); +static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *region); +static void amifb_imageblit(struct fb_info *info, struct fb_image *image); +static int amifb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info); -static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); -static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, - u_char *data, int con); -static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, - u_char *data, int con); -static int amifb_get_cursorstate(struct fb_cursorstate *state, int con); -static int amifb_set_cursorstate(struct fb_cursorstate *state, int con); /* * Interface to the low level console driver @@ -1117,8 +1138,6 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con); int amifb_init(void); static void amifb_deinit(void); -static int amifbcon_switch(int con, struct fb_info *info); -static int amifbcon_updatevar(int con, struct fb_info *info); /* * Internal routines @@ -1133,29 +1152,20 @@ static void chipfree(void); * Hardware routines */ -static int ami_encode_fix(struct fb_fix_screeninfo *fix, - struct amifb_par *par); static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par); static int ami_encode_var(struct fb_var_screeninfo *var, struct amifb_par *par); -static void ami_get_par(struct amifb_par *par); -static void ami_set_var(struct fb_var_screeninfo *var); -#ifdef DEBUG -static void ami_set_par(struct amifb_par *par); -#endif static void ami_pan_var(struct fb_var_screeninfo *var); static int ami_update_par(void); -static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); static void ami_update_display(void); static void ami_init_display(void); static void ami_do_blank(void); -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con); -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con); -static int ami_get_cursorstate(struct fb_cursorstate *state, int con); -static int ami_set_cursorstate(struct fb_cursorstate *state, int con); +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix); +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data); +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data); +static int ami_get_cursorstate(struct fb_cursorstate *state); +static int ami_set_cursorstate(struct fb_cursorstate *state); static void ami_set_sprite(void); static void ami_init_copper(void); static void ami_reinit_copper(void); @@ -1165,14 +1175,15 @@ static void ami_rebuild_copper(void); static struct fb_ops amifb_ops = { .owner = THIS_MODULE, - .fb_get_fix = amifb_get_fix, - .fb_get_var = amifb_get_var, - .fb_set_var = amifb_set_var, - .fb_get_cmap = amifb_get_cmap, - .fb_set_cmap = gen_set_cmap, + .fb_check_var = amifb_check_var, + .fb_set_par = amifb_set_par, .fb_setcolreg = amifb_setcolreg, - .fb_pan_display = amifb_pan_display, .fb_blank = amifb_blank, + .fb_pan_display = amifb_pan_display, + .fb_fillrect = amifb_fillrect, + .fb_copyarea = amifb_copyarea, + .fb_imageblit = amifb_imageblit, + .fb_cursor = soft_cursor, .fb_ioctl = amifb_ioctl, }; @@ -1217,8 +1228,6 @@ int __init amifb_setup(char *options) { char *this_opt; - fb_info.fontname[0] = '\0'; - if (!options || !*options) return 0; @@ -1234,8 +1243,6 @@ int __init amifb_setup(char *options) amifb_ilbm = 1; else if (!strncmp(this_opt, "monitorcap:", 11)) amifb_setup_mcap(this_opt+11); - else if (!strncmp(this_opt, "font:", 5)) - strcpy(fb_info.fontname, this_opt+5); else if (!strncmp(this_opt, "fstart:", 7)) min_fstrt = simple_strtoul(this_opt+7, NULL, 0); else @@ -1248,293 +1255,975 @@ int __init amifb_setup(char *options) return 0; } - /* - * Get the Fixed Part of the Display - */ -static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) +static int amifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { + int err; struct amifb_par par; - if (con == -1) - ami_get_par(&par); - else { - int err; + /* Validate wanted screen parameters */ + if ((err = ami_decode_var(var, &par))) + return err; - if ((err = ami_decode_var(&fb_display[con].var, &par))) - return err; - } - return ami_encode_fix(fix, &par); + /* Encode (possibly rounded) screen parameters */ + ami_encode_var(var, &par); + return 0; } - /* - * Get the User Defined Part of the Display - */ -static int amifb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +static int amifb_set_par(struct fb_info *info) { - int err = 0; - - if (con == -1) { - struct amifb_par par; - - ami_get_par(&par); - err = ami_encode_var(var, &par); - } else - *var = fb_display[con].var; - return err; -} + struct amifb_par *par = (struct amifb_par *)info->par; - /* - * Set the User Defined Part of the Display - */ + do_vmode_pan = 0; + do_vmode_full = 0; -static int amifb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - int err, activate = var->activate; - int oldxres, oldyres, oldvxres, oldvyres, oldbpp; - struct amifb_par par; + /* Decode wanted screen parameters */ + ami_decode_var(&info->var, par); - struct display *display; - if (con >= 0) - display = &fb_display[con]; - else - display = &disp; /* used during initialization */ + /* Set new videomode */ + ami_build_copper(); - /* - * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! - * as FB_VMODE_SMOOTH_XPAN is only used internally - */ + /* Set VBlank trigger */ + do_vmode_full = 1; - if (var->vmode & FB_VMODE_CONUPDATE) { - var->vmode |= FB_VMODE_YWRAP; - var->xoffset = display->var.xoffset; - var->yoffset = display->var.yoffset; + /* Update fix for new screen parameters */ + if (par->bpp == 1) { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + } else if (amifb_ilbm) { + info->fix.type = FB_TYPE_INTERLEAVED_PLANES; + info->fix.type_aux = par->next_line; + } else { + info->fix.type = FB_TYPE_PLANES; + info->fix.type_aux = 0; } - if ((err = ami_decode_var(var, &par))) - return err; - ami_encode_var(var, &par); - if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres = display->var.xres; - oldyres = display->var.yres; - oldvxres = display->var.xres_virtual; - oldvyres = display->var.yres_virtual; - oldbpp = display->var.bits_per_pixel; - display->var = *var; - if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel) { - struct fb_fix_screeninfo fix; - - ami_encode_fix(&fix, &par); - display->visual = fix.visual; - display->type = fix.type; - display->type_aux = fix.type_aux; - display->ypanstep = fix.ypanstep; - display->ywrapstep = fix.ywrapstep; - display->line_length = fix.line_length; - display->can_soft_blank = 1; - display->inverse = amifb_inverse; - switch (fix.type) { -#ifdef FBCON_HAS_ILBM - case FB_TYPE_INTERLEAVED_PLANES: - display->dispsw = &fbcon_ilbm; - break; -#endif -#ifdef FBCON_HAS_AFB - case FB_TYPE_PLANES: - display->dispsw = &fbcon_afb; - break; -#endif -#ifdef FBCON_HAS_MFB - case FB_TYPE_PACKED_PIXELS: /* depth == 1 */ - display->dispsw = &fbcon_mfb; - break; -#endif - default: - display->dispsw = &fbcon_dummy; - } - if (fb_info.changevar) - (*fb_info.changevar)(con); - } - if (oldbpp != var->bits_per_pixel) { - if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) - return err; - do_install_cmap(con, info); - } - if (con == info->currcon) - ami_set_var(&display->var); + info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); + + if (par->vmode & FB_VMODE_YWRAP) { + info->fix.ywrapstep = 1; + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + } else { + info->fix.ywrapstep = 0; + if (par->vmode &= FB_VMODE_SMOOTH_XPAN) + info->fix.xpanstep = 1; + else + info->fix.xpanstep = 16<<maxfmode; + info->fix.ypanstep = 1; } return 0; } + /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag */ -static int amifb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +static int amifb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) + if (var->yoffset < 0 || + var->yoffset >= info->var.yres_virtual || var->xoffset) return -EINVAL; } else { /* * TODO: There will be problems when xpan!=1, so some columns * on the right side will never be seen */ - if (var->xoffset+fb_display[con].var.xres > upx(16<<maxfmode, fb_display[con].var.xres_virtual) || - var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) + if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || + var->yoffset+info->var.yres > info->var.yres_virtual) return -EINVAL; } - if (con == info->currcon) - ami_pan_var(var); - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; + ami_pan_var(var); + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) - fb_display[con].var.vmode |= FB_VMODE_YWRAP; + info->var.vmode |= FB_VMODE_YWRAP; else - fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + info->var.vmode &= ~FB_VMODE_YWRAP; return 0; } - /* - * Get the Colormap - */ -static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) +#if BITS_PER_LONG == 32 +#define BYTES_PER_LONG 4 +#define SHIFT_PER_LONG 5 +#elif BITS_PER_LONG == 64 +#define BYTES_PER_LONG 8 +#define SHIFT_PER_LONG 6 +#else +#define Please update me +#endif + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long comp(unsigned long a, unsigned long b, + unsigned long mask) { - if (con == info->currcon) /* current console? */ - return fb_get_cmap(cmap, kspc, ami_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), - cmap, kspc ? 0 : 2); - return 0; + return ((a ^ b) & mask) ^ b; } - - /* - * Amiga Frame Buffer Specific ioctls - */ -static int amifb_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg, int con, struct fb_info *info) + +static inline unsigned long xor(unsigned long a, unsigned long b, + unsigned long mask) { - int i; + return (a & mask) ^ b; +} - switch (cmd) { - case FBIOGET_FCURSORINFO : { - struct fb_fix_cursorinfo crsrfix; - - i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix)); - if (!i) { - i = amifb_get_fix_cursorinfo(&crsrfix, con); - copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix)); + + /* + * Unaligned forward bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, + int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + shift = dst_idx-src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG-dst_idx; } - return i; - } - case FBIOGET_VCURSORINFO : { - struct fb_var_cursorinfo crsrvar; - - i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar)); - if (!i) { - i = amifb_get_var_cursorinfo(&crsrvar, - ((struct fb_var_cursorinfo *)arg)->data, con); - copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar)); + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + n -= 8; } - return i; + while (n--) + *dst++ = *src++; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); } - case FBIOPUT_VCURSORINFO : { - struct fb_var_cursorinfo crsrvar; - - i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar)); - if (!i) { - copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar)); - i = amifb_set_var_cursorinfo(&crsrvar, - ((struct fb_var_cursorinfo *)arg)->data, con); + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else if (src_idx+n <= BITS_PER_LONG) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else { + // 2 source words + d0 = *src++; + d1 = *src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } else { + // 2 source words + d1 = *src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } } - return i; } - case FBIOGET_CURSORSTATE : { - struct fb_cursorstate crsrstate; + } +} + + + /* + * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses + */ + +static void bitcpy_rev(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; + + if (!n) + return; + + dst += (n-1)/BITS_PER_LONG; + src += (n-1)/BITS_PER_LONG; + if ((n-1) % BITS_PER_LONG) { + dst_idx += (n-1) % BITS_PER_LONG; + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= BITS_PER_LONG-1; + src_idx += (n-1) % BITS_PER_LONG; + src += src_idx >> SHIFT_PER_LONG; + src_idx &= BITS_PER_LONG-1; + } + + shift = dst_idx-src_idx; + first = ~0UL << (BITS_PER_LONG-1-dst_idx); + last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); + + if (!shift) { + // Same alignment for source and dest - i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate)); - if (!i) { - i = amifb_get_cursorstate(&crsrstate, con); - copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate)); + if ((unsigned long)dst_idx+1 >= n) { + // Single word + if (last) + first &= last; + *dst = comp(*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(*src, *dst, first); + dst--; + src--; + n -= dst_idx+1; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + *dst-- = *src--; + n -= 8; } - return i; + while (n--) + *dst-- = *src--; + + // Trailing bits + if (last) + *dst = comp(*src, *dst, last); } - case FBIOPUT_CURSORSTATE : { - struct fb_cursorstate crsrstate; + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if ((unsigned long)dst_idx+1 >= n) { + // Single destination word + if (last) + first &= last; + if (shift < 0) { + // Single source word + *dst = comp(*src << left, *dst, first); + } else if (1+(unsigned long)src_idx >= n) { + // Single source word + *dst = comp(*src >> right, *dst, first); + } else { + // 2 source words + d0 = *src--; + d1 = *src; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + } + } else { + // Multiple destination words + d0 = *src--; + // Leading bits + if (shift < 0) { + // Single source word + *dst = comp(d0 << left, *dst, first); + dst--; + n -= dst_idx+1; + } else { + // 2 source words + d1 = *src--; + *dst = comp(d0 >> right | d1 << left, *dst, + first); + d0 = d1; + dst--; + n -= dst_idx+1; + } - i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate)); - if (!i) { - copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate)); - i = amifb_set_cursorstate(&crsrstate, con); + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = *src--; + *dst-- = d0 >> right | d1 << left; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= left) { + // Single source word + *dst = comp(d0 >> right, *dst, last); + } else { + // 2 source words + d1 = *src; + *dst = comp(d0 >> right | d1 << left, + *dst, last); + } } - return i; } -#ifdef DEBUG - case FBCMD_GET_CURRENTPAR : { - struct amifb_par par; + } +} + + + /* + * Unaligned forward inverting bit copy using 32-bit or 64-bit memory + * accesses + */ + +static void bitcpy_not(unsigned long *dst, int dst_idx, + const unsigned long *src, int src_idx, u32 n) +{ + unsigned long first, last; + int shift = dst_idx-src_idx, left, right; + unsigned long d0, d1; + int m; - i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par)); - if (!i) { - ami_get_par(&par); - copy_to_user((void *)arg, &par, sizeof(struct amifb_par)); + if (!n) + return; + + shift = dst_idx-src_idx; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(~*src, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(~*src, *dst, first); + dst++; + src++; + n -= BITS_PER_LONG-dst_idx; } - return i; + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + *dst++ = ~*src++; + n -= 8; + } + while (n--) + *dst++ = ~*src++; + + // Trailing bits + if (last) + *dst = comp(~*src, *dst, last); } - case FBCMD_SET_CURRENTPAR : { - struct amifb_par par; + } else { + // Different alignment for source and dest + + right = shift & (BITS_PER_LONG-1); + left = -shift & (BITS_PER_LONG-1); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single destination word + if (last) + first &= last; + if (shift > 0) { + // Single source word + *dst = comp(~*src >> right, *dst, first); + } else if (src_idx+n <= BITS_PER_LONG) { + // Single source word + *dst = comp(~*src << left, *dst, first); + } else { + // 2 source words + d0 = ~*src++; + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + } + } else { + // Multiple destination words + d0 = ~*src++; + // Leading bits + if (shift > 0) { + // Single source word + *dst = comp(d0 >> right, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } else { + // 2 source words + d1 = ~*src++; + *dst = comp(d0 << left | d1 >> right, *dst, + first); + d0 = d1; + dst++; + n -= BITS_PER_LONG-dst_idx; + } - i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par)); - if (!i) { - copy_from_user(&par, (void *)arg, sizeof(struct amifb_par)); - ami_set_par(&par); + // Main chunk + m = n % BITS_PER_LONG; + n /= BITS_PER_LONG; + while (n >= 4) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + n -= 4; + } + while (n--) { + d1 = ~*src++; + *dst++ = d0 << left | d1 >> right; + d0 = d1; + } + + // Trailing bits + if (last) { + if (m <= right) { + // Single source word + *dst = comp(d0 << left, *dst, last); + } else { + // 2 source words + d1 = ~*src; + *dst = comp(d0 << left | d1 >> right, + *dst, last); + } } - return i; } -#endif /* DEBUG */ } - return -EINVAL; } + + /* + * Unaligned 32-bit pattern fill using 32/64-bit memory accesses + */ + +static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = comp(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = comp(val, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 8) { + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = val; + n -= 8; + } + while (n--) + *dst++ = val; + + // Trailing bits + if (last) + *dst = comp(val, *dst, last); + } +} + + + /* + * Unaligned 32-bit pattern xor using 32/64-bit memory accesses + */ + +static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) +{ + unsigned long val = pat; + unsigned long first, last; + + if (!n) + return; + +#if BITS_PER_LONG == 64 + val |= val << 32; +#endif + + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + + if (dst_idx+n <= BITS_PER_LONG) { + // Single word + if (last) + first &= last; + *dst = xor(val, *dst, first); + } else { + // Multiple destination words + // Leading bits + if (first) { + *dst = xor(val, *dst, first); + dst++; + n -= BITS_PER_LONG-dst_idx; + } + + // Main chunk + n /= BITS_PER_LONG; + while (n >= 4) { + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + *dst++ ^= val; + n -= 4; + } + while (n--) + *dst++ ^= val; + + // Trailing bits + if (last) + *dst = xor(val, *dst, last); + } +} + +static inline void fill_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane*8; + } +} + +static inline void xor_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + u32 color) +{ + while (color) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); + if (!--bpp) + break; + color >>= 1; + dst_idx += next_plane*8; + } +} + + +static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect) +{ + struct amifb_par *par = (struct amifb_par *)info->par; + int dst_idx, x2, y2; + unsigned long *dst; + + if (!rect->width || !rect->height) + return; + /* - * Hardware Cursor - */ + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + * */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + rect->width = x2 - rect->dx; + rect->height = y2 - rect->dy; + + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx += rect->dy*par->next_line*8+rect->dx; + while (rect->height--) { + switch (rect->rop) { + case ROP_COPY: + fill_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, + rect->width, rect->color); + break; -static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) + case ROP_XOR: + xor_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, + rect->width, rect->color); + break; + } + dst_idx += par->next_line*8; + } +} + +static inline void copy_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) { - return ami_get_fix_cursorinfo(fix, con); + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG-1); + bitcpy(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane*8; + src_idx += next_plane*8; + } } -static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +static inline void copy_one_line_rev(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, + unsigned long *src, int src_idx, u32 n) { - return ami_get_var_cursorinfo(var, data, con); + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + src += src_idx >> SHIFT_PER_LONG; + src_idx &= (BITS_PER_LONG-1); + bitcpy_rev(dst, dst_idx, src, src_idx, n); + if (!--bpp) + break; + dst_idx += next_plane*8; + src_idx += next_plane*8; + } } -static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) + +static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *area) { - return ami_set_var_cursorinfo(var, data, con); + struct amifb_par *par = (struct amifb_par *)info->par; + int x2, y2, old_dx, old_dy; + unsigned long *dst, *src; + int dst_idx, src_idx, height; + int rev_copy = 0; + + /* clip the destination */ + old_dx = area->dx; + old_dy = area->dy; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + area->dx = area->dx > 0 ? area->dx : 0; + area->dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + area->width = x2 - area->dx; + area->height = y2 - area->dy; + + /* update sx1,sy1 */ + area->sx += (area->dx - old_dx); + area->sy += (area->dy - old_dy); + + height = area->height; + + /* the source must be completely inside the virtual screen */ + if (area->sx < 0 || area->sy < 0 || + (area->sx + area->width) > info->var.xres_virtual || + (area->sy + area->height) > info->var.yres_virtual) + return; + + if (area->dy > area->sy || + (area->dy == area->sy && area->dx > area->sx)) { + area->dy += area->height; + area->sy += area->height; + rev_copy = 1; + } + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + src = dst; + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + src_idx = dst_idx; + dst_idx += area->dy*par->next_line*8+area->dx; + src_idx += area->sy*par->next_line*8+area->sx; + if (rev_copy) { + while (height--) { + dst_idx -= par->next_line*8; + src_idx -= par->next_line*8; + copy_one_line_rev(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, area->width); + } + } else { + while (height--) { + copy_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, src, + src_idx, area->width); + dst_idx += par->next_line*8; + src_idx += par->next_line*8; + } + } } -static int amifb_get_cursorstate(struct fb_cursorstate *state, int con) + +static inline void expand_one_line(int bpp, unsigned long next_plane, + unsigned long *dst, int dst_idx, u32 n, + const u8 *data, u32 bgcolor, u32 fgcolor) { - return ami_get_cursorstate(state, con); + const unsigned long *src; + int src_idx; + + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG-1); + if ((bgcolor ^ fgcolor) & 1) { + src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1)); + src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8; + if (fgcolor & 1) + bitcpy(dst, dst_idx, src, src_idx, n); + else + bitcpy_not(dst, dst_idx, src, src_idx, n); + /* set or clear */ + } else + bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); + if (!--bpp) + break; + bgcolor >>= 1; + fgcolor >>= 1; + dst_idx += next_plane*8; + } } -static int amifb_set_cursorstate(struct fb_cursorstate *state, int con) + +static void amifb_imageblit(struct fb_info *info, struct fb_image *image) { - return ami_set_cursorstate(state, con); + struct amifb_par *par = (struct amifb_par *)info->par; + int x2, y2; + unsigned long *dst; + int dst_idx; + const char *src; + u32 dx, dy, width, height, pitch; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly like we are + * doing here. + */ + x2 = image->dx + image->width; + y2 = image->dy + image->height; + dx = image->dx; + dy = image->dy; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + if (image->depth == 1) { + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx += dy*par->next_line*8+dx; + src = image->data; + pitch = (image->width+7)/8; + while (height--) { + expand_one_line(info->var.bits_per_pixel, + par->next_plane, dst, dst_idx, width, + src, image->bg_color, + image->fg_color); + dst_idx += par->next_line*8; + src += pitch; + } + } else { + c2p(info->screen_base, image->data, dx, dy, width, height, + par->next_line, par->next_plane, image->width, + info->var.bits_per_pixel); + } +} + + + /* + * Amiga Frame Buffer Specific ioctls + */ + +static int amifb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info) +{ + union { + struct fb_fix_cursorinfo fix; + struct fb_var_cursorinfo var; + struct fb_cursorstate state; + } crsr; + int i; + + switch (cmd) { + case FBIOGET_FCURSORINFO: + i = ami_get_fix_cursorinfo(&crsr.fix); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.fix, + sizeof(crsr.fix)) ? -EFAULT : 0; + + case FBIOGET_VCURSORINFO: + i = ami_get_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo *)arg)->data); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.var, + sizeof(crsr.var)) ? -EFAULT : 0; + + case FBIOPUT_VCURSORINFO: + if (copy_from_user(&crsr.var, (void *)arg, + sizeof(crsr.var))) + return -EFAULT; + return ami_set_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo *)arg)->data); + + case FBIOGET_CURSORSTATE: + i = ami_get_cursorstate(&crsr.state); + if (i) + return i; + return copy_to_user((void *)arg, &crsr.state, + sizeof(crsr.state)) ? -EFAULT : 0; + + case FBIOPUT_CURSORSTATE: + if (copy_from_user(&crsr.state, (void *)arg, + sizeof(crsr.state))) + return -EFAULT; + return ami_set_cursorstate(&crsr.state); + } + return -EINVAL; } @@ -1570,7 +2259,6 @@ int __init amifb_init(void) int tag, i, err = 0; u_long chipptr; u_int defmode; - struct fb_var_screeninfo var; if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) return -ENXIO; @@ -1600,7 +2288,7 @@ int __init amifb_init(void) switch (amiga_chipset) { #ifdef CONFIG_FB_AMIGA_OCS case CS_OCS: - strcat(amifb_name, "OCS"); + strcat(fb_info.fix.id, "OCS"); default_chipset: chipset = TAG_OCS; maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ @@ -1609,13 +2297,13 @@ default_chipset: maxfmode = TAG_FMODE_1; defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; - videomemorysize = VIDEOMEMSIZE_OCS; + fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; break; #endif /* CONFIG_FB_AMIGA_OCS */ #ifdef CONFIG_FB_AMIGA_ECS case CS_ECS: - strcat(amifb_name, "ECS"); + strcat(fb_info.fix.id, "ECS"); chipset = TAG_ECS; maxdepth[TAG_SHRES] = 2; maxdepth[TAG_HIRES] = 4; @@ -1629,15 +2317,15 @@ default_chipset: : DEFMODE_NTSC; if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > VIDEOMEMSIZE_ECS_1M) - videomemorysize = VIDEOMEMSIZE_ECS_2M; + fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; else - videomemorysize = VIDEOMEMSIZE_ECS_1M; + fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; break; #endif /* CONFIG_FB_AMIGA_ECS */ #ifdef CONFIG_FB_AMIGA_AGA case CS_AGA: - strcat(amifb_name, "AGA"); + strcat(fb_info.fix.id, "AGA"); chipset = TAG_AGA; maxdepth[TAG_SHRES] = 8; maxdepth[TAG_HIRES] = 8; @@ -1646,16 +2334,16 @@ default_chipset: defmode = DEFMODE_AGA; if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > VIDEOMEMSIZE_AGA_1M) - videomemorysize = VIDEOMEMSIZE_AGA_2M; + fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; else - videomemorysize = VIDEOMEMSIZE_AGA_1M; + fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; break; #endif /* CONFIG_FB_AMIGA_AGA */ default: #ifdef CONFIG_FB_AMIGA_OCS printk("Unknown graphics chipset, defaulting to OCS\n"); - strcat(amifb_name, "Unknown"); + strcat(fb_info.fix.id, "Unknown"); goto default_chipset; #else /* CONFIG_FB_AMIGA_OCS */ err = -ENXIO; @@ -1698,31 +2386,25 @@ default_chipset: fb_info.monspecs.vfmax = 90; } - strcpy(fb_info.modename, amifb_name); - fb_info.changevar = NULL; fb_info.node = NODEV; fb_info.fbops = &amifb_ops; - fb_info.disp = &disp; - fb_info.currcon = 1; - fb_info.switch_con = &amifbcon_switch; - fb_info.updatevar = &amifbcon_updatevar; + fb_info.par = ¤tpar; fb_info.flags = FBINFO_FLAG_DEFAULT; - memset(&var, 0, sizeof(var)); - if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb, + if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { err = -EINVAL; goto amifb_error; } round_down_bpp = 0; - chipptr = chipalloc(videomemorysize+ + chipptr = chipalloc(fb_info.fix.smem_len+ SPRITEMEMSIZE+ DUMMYSPRITEMEMSIZE+ COPINITSIZE+ 4*COPLISTSIZE); - assignchunk(videomemory, u_long, chipptr, videomemorysize); + assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); @@ -1734,11 +2416,12 @@ default_chipset: /* * access the videomem with writethrough cache */ - videomemory_phys = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize); + fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, + fb_info.fix.smem_len); if (!videomemory) { printk("amifb: WARNING! unable to map videomem cached writethrough\n"); - videomemory = ZTWO_VADDR(videomemory_phys); + videomemory = ZTWO_VADDR(fb_info.fix.smem_start); } fb_info.screen_base = (char *)videomemory; @@ -1757,25 +2440,24 @@ default_chipset: ami_init_copper(); - if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0, + if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, "fb vertb handler", ¤tpar)) { err = -EBUSY; goto amifb_error; } - amifb_set_var(&var, -1, &fb_info); + fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); if (register_framebuffer(&fb_info) < 0) { err = -EINVAL; goto amifb_error; } - printk("fb%d: %s frame buffer device, using %ldK of video memory\n", - minor(fb_info.node), fb_info.modename, - videomemorysize>>10); + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + minor(fb_info.node), fb_info.fix.id, fb_info.fix.smem_len>>10); return 0; - + amifb_error: amifb_deinit(); return err; @@ -1783,33 +2465,12 @@ amifb_error: static void amifb_deinit(void) { - chipfree(); + fb_dealloc_cmap(&fb_info.cmap); + chipfree(); release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120); custom.dmacon = DMAF_ALL | DMAF_MASTER; } -static int amifbcon_switch(int con, struct fb_info *info) -{ - /* Do we have to save the colormap? */ - if (fb_display[info->currcon].cmap.len) - fb_get_cmap(&fb_display[info->currcon].cmap, 1, ami_getcolreg, info); - - info->currcon = con; - ami_set_var(&fb_display[con].var); - /* Install new colormap */ - do_install_cmap(con, info); - return 0; -} - - /* - * Update the `var' structure (called by fbcon.c) - */ - -static int amifbcon_updatevar(int con, struct fb_info *info) -{ - ami_pan_var(&fb_display[con].var); - return 0; -} /* * Blank the display. @@ -1821,6 +2482,10 @@ static int amifb_blank(int blank, struct fb_info *info) return 0; } + /* + * Flash the cursor (called by VBlank interrupt) + */ + static int flash_cursor(void) { static int cursorcount = 1; @@ -1875,50 +2540,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) /* --------------------------- Hardware routines --------------------------- */ /* - * This function should fill in the `fix' structure based on the - * values in the `par' structure. - */ - -static int ami_encode_fix(struct fb_fix_screeninfo *fix, - struct amifb_par *par) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, amifb_name); - fix->smem_start = videomemory_phys; - fix->smem_len = videomemorysize; - -#ifdef FBCON_HAS_MFB - if (par->bpp == 1) { - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - } else -#endif - if (amifb_ilbm) { - fix->type = FB_TYPE_INTERLEAVED_PLANES; - fix->type_aux = par->next_line; - } else { - fix->type = FB_TYPE_PLANES; - fix->type_aux = 0; - } - fix->line_length = div8(upx(16<<maxfmode, par->vxres)); - fix->visual = FB_VISUAL_PSEUDOCOLOR; - - if (par->vmode & FB_VMODE_YWRAP) { - fix->ywrapstep = 1; - fix->xpanstep = fix->ypanstep = 0; - } else { - fix->ywrapstep = 0; - if (par->vmode &= FB_VMODE_SMOOTH_XPAN) - fix->xpanstep = 1; - else - fix->xpanstep = 16<<maxfmode; - fix->ypanstep = 1; - } - fix->accel = FB_ACCEL_AMIGABLITT; - return 0; -} - - /* * Get the video params out of `var'. If a value doesn't fit, round * it up, if it's too big, return -EINVAL. */ @@ -2074,7 +2695,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var, if (!IS_OCS) { par->beamcon0 = BMC0_PAL; par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { par->beamcon0 = BMC0_PAL; par->hsstop = 1; @@ -2104,7 +2725,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var, if (!IS_OCS) { par->beamcon0 = 0; par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { par->beamcon0 = 0; par->hsstop = 1; @@ -2235,14 +2856,14 @@ static int ami_decode_var(struct fb_var_screeninfo *var, if (amifb_ilbm) { par->next_plane = div8(upx(16<<maxfmode, par->vxres)); par->next_line = par->bpp*par->next_plane; - if (par->next_line * par->vyres > videomemorysize) { + if (par->next_line * par->vyres > fb_info.fix.smem_len) { DPRINTK("too few video mem\n"); return -EINVAL; } } else { par->next_line = div8(upx(16<<maxfmode, par->vxres)); par->next_plane = par->vyres*par->next_line; - if (par->next_plane * par->bpp > videomemorysize) { + if (par->next_plane * par->bpp > fb_info.fix.smem_len) { DPRINTK("too few video mem\n"); return -EINVAL; } @@ -2402,38 +3023,6 @@ static int ami_encode_var(struct fb_var_screeninfo *var, return 0; } - /* - * Get current hardware setting - */ - -static void ami_get_par(struct amifb_par *par) -{ - *par = currentpar; -} - - /* - * Set new videomode - */ - -static void ami_set_var(struct fb_var_screeninfo *var) -{ - do_vmode_pan = 0; - do_vmode_full = 0; - ami_decode_var(var, ¤tpar); - ami_build_copper(); - do_vmode_full = 1; -} - -#ifdef DEBUG -static void ami_set_par(struct amifb_par *par) -{ - do_vmode_pan = 0; - do_vmode_full = 0; - currentpar = *par; - ami_build_copper(); - do_vmode_full = 1; -} -#endif /* * Pan or Wrap the Display @@ -2506,16 +3095,16 @@ static int ami_update_par(void) par->bpl1mod = par->bpl2mod; if (par->yoffset) { - par->bplpt0 = videomemory_phys + par->next_line*par->yoffset + move; + par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move; if (par->vmode & FB_VMODE_YWRAP) { if (par->yoffset > par->vyres-par->yres) { - par->bplpt0wrap = videomemory_phys + move; + par->bplpt0wrap = fb_info.fix.smem_start + move; if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) par->bplpt0wrap += par->next_line; } } } else - par->bplpt0 = videomemory_phys + move; + par->bplpt0 = fb_info.fix.smem_start + move; if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) par->bplpt0 += par->next_line; @@ -2523,45 +3112,6 @@ static int ami_update_par(void) return 0; } - /* - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. - */ - -static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ - int len, tr, tg, tb; - - if (IS_AGA) { - if (regno > 255) - return 1; - len = 8; - } else if (currentpar.bplcon0 & BPC0_SHRES) { - if (regno > 3) - return 1; - len = 2; - } else { - if (regno > 31) - return 1; - len = 4; - } - tr = palette[regno].red>>(8-len); - tg = palette[regno].green>>(8-len); - tb = palette[regno].blue>>(8-len); - while (len < 16) { - tr |= tr<<len; - tg |= tg<<len; - tb |= tb<<len; - len <<= 1; - } - *red = tr; - *green = tg; - *blue = tb; - *transp = 0; - return 0; -} - /* * Set a single color register. The values supplied are already @@ -2585,9 +3135,11 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, red >>= 8; green >>= 8; blue >>= 8; - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; + if (!regno) { + red0 = red; + green0 = green; + blue0 = blue; + } /* * Update the corresponding Hardware Color Register, unless it's Color @@ -2650,6 +3202,7 @@ static void ami_update_display(void) static void ami_init_display(void) { struct amifb_par *par = ¤tpar; + int i; custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; @@ -2685,18 +3238,16 @@ static void ami_init_display(void) is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; #if 1 if (is_lace) { - if (custom.vposr & 0x8000) - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); - else - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]); + i = custom.vposr >> 15; } else { custom.vposw = custom.vposr | 0x8000; - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); + i = 1; } #else + i = 1; custom.vposw = custom.vposr | 0x8000; - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]); #endif + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); } /* @@ -2744,9 +3295,9 @@ static void ami_do_blank(void) } } else { custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; - red = palette[0].red; - green = palette[0].green; - blue = palette[0].blue; + red = red0; + green = green0; + blue = blue0; if (!IS_OCS) { custom.hsstrt = hsstrt2hw(par->hsstrt); custom.hsstop = hsstop2hw(par->hsstop); @@ -2782,11 +3333,7 @@ static void ami_do_blank(void) is_blanked = do_blank > 0 ? do_blank : 0; } - /* - * Flash the cursor (called by VBlank interrupt) - */ - -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) { struct amifb_par *par = ¤tpar; @@ -2797,7 +3344,7 @@ static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con) return 0; } -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data) { struct amifb_par *par = ¤tpar; register u_short *lspr, *sspr; @@ -2846,7 +3393,7 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i "swap %1 ; lslw #1,%1 ; roxlb #1,%0" : "=d" (color), "=d" (datawords) : "1" (datawords)); #else - color = (((datawords >> 30) & 2) + color = (((datawords >> 30) & 2) | ((datawords >> 15) & 1)); datawords <<= 1; #endif @@ -2872,7 +3419,7 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i return 0; } -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con) +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data) { struct amifb_par *par = ¤tpar; register u_short *lspr, *sspr; @@ -2991,7 +3538,7 @@ static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, i return 0; } -static int ami_get_cursorstate(struct fb_cursorstate *state, int con) +static int ami_get_cursorstate(struct fb_cursorstate *state) { struct amifb_par *par = ¤tpar; @@ -3001,7 +3548,7 @@ static int ami_get_cursorstate(struct fb_cursorstate *state, int con) return 0; } -static int ami_set_cursorstate(struct fb_cursorstate *state, int con) +static int ami_set_cursorstate(struct fb_cursorstate *state) { struct amifb_par *par = ¤tpar; @@ -3062,6 +3609,7 @@ static void ami_set_sprite(void) } } + /* * Initialise the Copper Initialisation List */ diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c new file mode 100644 index 000000000000..5c30bbd33054 --- /dev/null +++ b/drivers/video/c2p.c @@ -0,0 +1,229 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003 Geert Uytterhoeven + * + * NOTES: + * - This code was inspired by Scout's C2P tutorial + * - It assumes to run on a big endian system + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/string.h> +#include "c2p.h" + + + /* + * Basic transpose step + */ + +#define _transp(d, i1, i2, shift, mask) \ + do { \ + u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; \ + d[i1] ^= t; \ + d[i2] ^= t << shift; \ + } while (0) + +static inline u32 get_mask(int n) +{ + switch (n) { + case 1: + return 0x55555555; + break; + + case 2: + return 0x33333333; + break; + + case 4: + return 0x0f0f0f0f; + break; + + case 8: + return 0x00ff00ff; + break; + + case 16: + return 0x0000ffff; + break; + } + return 0; +} + +#define transp_nx1(d, n) \ + do { \ + u32 mask = get_mask(n); \ + /* First block */ \ + _transp(d, 0, 1, n, mask); \ + /* Second block */ \ + _transp(d, 2, 3, n, mask); \ + /* Third block */ \ + _transp(d, 4, 5, n, mask); \ + /* Fourth block */ \ + _transp(d, 6, 7, n, mask); \ + } while (0) + +#define transp_nx2(d, n) \ + do { \ + u32 mask = get_mask(n); \ + /* First block */ \ + _transp(d, 0, 2, n, mask); \ + _transp(d, 1, 3, n, mask); \ + /* Second block */ \ + _transp(d, 4, 6, n, mask); \ + _transp(d, 5, 7, n, mask); \ + } while (0) + +#define transp_nx4(d, n) \ + do { \ + u32 mask = get_mask(n); \ + _transp(d, 0, 4, n, mask); \ + _transp(d, 1, 5, n, mask); \ + _transp(d, 2, 6, n, mask); \ + _transp(d, 3, 7, n, mask); \ + } while (0) + +#define transp(d, n, m) transp_nx ## m(d, n) + + + /* + * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words + * containing + * - 32 8-bit chunky pixels on input + * - permuted planar data on output + */ + +static void c2p_8bpp(u32 d[8]) +{ + transp(d, 16, 4); + transp(d, 8, 2); + transp(d, 4, 1); + transp(d, 2, 4); + transp(d, 1, 2); +} + + + /* + * Array containing the permution indices of the planar data after c2p + */ + +static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 }; + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long comp(unsigned long a, unsigned long b, + unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + + /* + * Store a full block of planar data after c2p conversion + */ + +static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8]) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + *(u32 *)dst = d[perm_c2p_8bpp[i]]; +} + + + /* + * Store a partial block of planar data after c2p conversion + */ + +static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp, + u32 d[8], u32 mask) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + *(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask); +} + + + /* + * c2p - Copy 8-bit chunky image data to a planar frame buffer + * @dst: Starting address of the planar frame buffer + * @dx: Horizontal destination offset (in pixels) + * @dy: Vertical destination offset (in pixels) + * @width: Image width (in pixels) + * @height: Image height (in pixels) + * @dst_nextline: Frame buffer offset to the next line (in bytes) + * @dst_nextplane: Frame buffer offset to the next plane (in bytes) + * @src_nextline: Image offset to the next line (in bytes) + * @bpp: Bits per pixel of the planar frame buffer (1-8) + */ + +void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, + u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp) +{ + int dst_idx; + u32 d[8], first, last, w; + const u8 *c; + u8 *p; + + dst += dy*dst_nextline+(dx & ~31); + dst_idx = dx % 32; + first = ~0UL >> dst_idx; + last = ~(~0UL >> ((dst_idx+width) % 32)); + while (height--) { + c = src; + p = dst; + w = width; + if (dst_idx+width <= 32) { + /* Single destination word */ + first &= last; + memset(d, 0, sizeof(d)); + memcpy((u8 *)d+dst_idx, c, width); + c += width; + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, first); + p += 4; + } else { + /* Multiple destination words */ + w = width; + /* Leading bits */ + if (dst_idx) { + w = 32 - dst_idx; + memset(d, 0, dst_idx); + memcpy((u8 *)d+dst_idx, c, w); + c += w; + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, first); + p += 4; + w = width-w; + } + /* Main chunk */ + while (w >= 32) { + memcpy(d, c, 32); + c += 32; + c2p_8bpp(d); + store_planar(p, dst_nextplane, bpp, d); + p += 4; + w -= 32; + } + /* Trailing bits */ + w %= 32; + if (w > 0) { + memcpy(d, c, w); + memset((u8 *)d+w, 0, 32-w); + c2p_8bpp(d); + store_planar_masked(p, dst_nextplane, bpp, d, last); + } + } + src += src_nextline; + dst += dst_nextline; + } +} + diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h new file mode 100644 index 000000000000..c77cbf17e043 --- /dev/null +++ b/drivers/video/c2p.h @@ -0,0 +1,16 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/types.h> + +extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, + u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, + u32 bpp); + diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 4b9cfc5e38b9..3fc167670230 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -456,7 +456,7 @@ void accel_clear_margins(struct vc_data *vc, struct display *p, region.color = attr_bgcol_ec(p, vc); region.rop = ROP_COPY; - if (rw & !bottom_only) { + if (rw && !bottom_only) { region.dx = info->var.xoffset + rs; region.dy = 0; region.width = rw; diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 1809827e3af9..9d0a3e908771 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -103,11 +103,6 @@ #define SWAP(A) ((A>>8) | ((A&0xff) <<8)) -#if 0 -#define outb(a,d) *(char *)(a)=(d) -#define outw(a,d) *(unsigned short *)a=d -#endif - static struct fb_info fb_info; /* frame buffer operations */ @@ -147,9 +142,9 @@ static struct fb_fix_screeninfo dnfb_fix __initdata = { static int dnfb_blank(int blank, struct fb_info *info) { if (blank) - outb(0x0, AP_CONTROL_3A); + out_8(AP_CONTROL_3A, 0x0); else - outb(0x1, AP_CONTROL_3A); + out_8(AP_CONTROL_3A, 0x1); return 0; } @@ -175,8 +170,8 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area) x_word_count = (x_end >> 4) - (area->dx >> 4) + 1; start_mask = 0xffff0000 >> (area->dx & 0xf); end_mask = 0x7ffff >> (x_end & 0xf); - outb((((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5), - AP_CONTROL_0); + out_8(AP_CONTROL_0, + (((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5)); if ((area->dx & 0xf) < (area->sx & 0xf)) pre_read = 1; } else { @@ -185,15 +180,16 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area) x_word_count = (area->dx >> 4) - (x_end >> 4) + 1; start_mask = 0x7ffff >> (area->dx & 0xf); end_mask = 0xffff0000 >> (x_end & 0xf); - outb(((-((area->sx & 0xf) - (area->dx & 0xf))) % - 16) | (0x4 << 5), AP_CONTROL_0); + out_8(AP_CONTROL_0, + ((-((area->sx & 0xf) - (area->dx & 0xf))) % 16) | + (0x4 << 5)); if ((area->dx & 0xf) > (area->sx & 0xf)) pre_read = 1; } for (i = 0; i < area->height; i++) { - outb(0xc | (dest >> 16), AP_CONTROL_3A); + out_8(AP_CONTROL_3A, 0xc | (dest >> 16)); if (pre_read) { dummy = *src; @@ -201,11 +197,11 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area) } if (x_word_count) { - outb(start_mask, AP_WRITE_ENABLE); + out_8(AP_WRITE_ENABLE, start_mask); *src = dest; src += incr; dest += incr; - outb(0, AP_WRITE_ENABLE); + out_8(AP_WRITE_ENABLE, 0); for (j = 1; j < (x_word_count - 1); j++) { *src = dest; @@ -213,12 +209,12 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area) dest += incr; } - outb(start_mask, AP_WRITE_ENABLE); + out_8(AP_WRITE_ENABLE, start_mask); *src = dest; dest += incr; src += incr; } else { - outb(start_mask | end_mask, AP_WRITE_ENABLE); + out_8(AP_WRITE_ENABLE, start_mask | end_mask); *src = dest; dest += incr; src += incr; @@ -226,7 +222,7 @@ void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area) src += (y_delta / 16); dest += (y_delta / 16); } - outb(NORMAL_MODE, AP_CONTROL_0); + out_8(AP_CONTROL_0, NORMAL_MODE); } @@ -247,12 +243,12 @@ unsigned long __init dnfb_init(unsigned long mem_start) panic("unable to register apollo frame buffer\n"); /* now we have registered we can safely setup the hardware */ - outb(RESET_CREG, AP_CONTROL_3A); - outw(0x0, AP_WRITE_ENABLE); - outb(NORMAL_MODE, AP_CONTROL_0); - outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1); - outb(S_DATA_PLN, AP_CONTROL_2); - outw(SWAP(0x3), AP_ROP_1); + out_8(AP_CONTROL_3A, RESET_CREG); + out_be16(AP_WRITE_ENABLE, 0x0); + out_8(AP_CONTROL_0, NORMAL_MODE); + out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1)); + out_8(AP_CONTROL_2, S_DATA_PLN); + out_be16(AP_ROP_1, SWAP(0x3)); printk("apollo frame buffer alive and kicking !\n"); return mem_start; |
