diff options
Diffstat (limited to 'drivers')
93 files changed, 3036 insertions, 703 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a4fddb24476..f6e54bf8dd9 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -285,7 +285,7 @@ static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file); static ssize_t acpi_video_device_write_brightness(struct file *file, const char __user *buffer, size_t count, loff_t *data); -static struct file_operations acpi_video_device_brightness_fops = { +static const struct file_operations acpi_video_device_brightness_fops = { .owner = THIS_MODULE, .open = acpi_video_device_brightness_open_fs, .read = seq_read, diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 703364b5217..66e181345b3 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1306,14 +1306,6 @@ static void amb_close (struct atm_vcc * atm_vcc) { return; } -/********** Set socket options for a VC **********/ - -// int amb_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen); - -/********** Set socket options for a VC **********/ - -// int amb_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, void * optval, int optlen); - /********** Send **********/ static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 5503bfc8e13..0c302614544 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2031,7 +2031,7 @@ static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, static int eni_setsockopt(struct atm_vcc *vcc,int level,int optname, - void __user *optval,int optlen) + void __user *optval,unsigned int optlen) { return -EINVAL; } diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index b119640e1ee..cd5049af47a 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1244,7 +1244,7 @@ static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname, static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname, - void __user *optval,int optlen) + void __user *optval,unsigned int optlen) { func_enter (); func_exit (); diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 10f000dbe44..f766cc46b4c 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1795,7 +1795,7 @@ fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void __user *op static int -fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, int optlen) +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void __user *optval, unsigned int optlen) { /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */ diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 01ce241dbea..4e49021e67e 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2590,7 +2590,7 @@ static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, } static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, - void *optval, int optlen) { + void *optval, unsigned int optlen) { hrz_dev * dev = HRZ_DEV(atm_vcc->dev); PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt"); switch (level) { diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 78c9736c357..b2c1b37ab2e 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2862,7 +2862,7 @@ static int ia_getsockopt(struct atm_vcc *vcc, int level, int optname, } static int ia_setsockopt(struct atm_vcc *vcc, int level, int optname, - void __user *optval, int optlen) + void __user *optval, unsigned int optlen) { IF_EVENT(printk(">ia_setsockopt\n");) return -EINVAL; diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 752b1ba81f7..2e9635be048 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1517,7 +1517,7 @@ static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname, static int zatm_setsockopt(struct atm_vcc *vcc,int level,int optname, - void __user *optval,int optlen) + void __user *optval,unsigned int optlen) { return -EINVAL; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 24c3e21ab26..1ece0b47b58 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -426,7 +426,7 @@ out: return err; } -static struct file_operations cciss_proc_fops = { +static const struct file_operations cciss_proc_fops = { .owner = THIS_MODULE, .open = cciss_seq_open, .read = seq_read, diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index aaca40283be..4f568cb9af3 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -393,7 +393,7 @@ static int apm_open(struct inode * inode, struct file * filp) return as ? 0 : -ENOMEM; } -static struct file_operations apm_bios_fops = { +static const struct file_operations apm_bios_fops = { .owner = THIS_MODULE, .read = apm_read, .poll = apm_poll, diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c index e3dd24bff51..836d4f0a876 100644 --- a/drivers/char/bfin-otp.c +++ b/drivers/char/bfin-otp.c @@ -217,7 +217,7 @@ static long bfin_otp_ioctl(struct file *filp, unsigned cmd, unsigned long arg) # define bfin_otp_ioctl NULL #endif -static struct file_operations bfin_otp_fops = { +static const struct file_operations bfin_otp_fops = { .owner = THIS_MODULE, .unlocked_ioctl = bfin_otp_ioctl, .read = bfin_otp_read, diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index df5038bbcbc..4254457d391 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -3354,7 +3354,7 @@ static int __init cy_detect_isa(void) continue; } #ifdef MODULE - if (isparam && irq[i]) + if (isparam && i < NR_CARDS && irq[i]) cy_isa_irq = irq[i]; else #endif diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 5942a9d674c..452370af95d 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -220,8 +220,7 @@ static inline int serial_paranoia_check(struct cyclades_port *info, char *name, return 1; } - if ((long)info < (long)(&cy_port[0]) - || (long)(&cy_port[NR_PORTS]) < (long)info) { + if (info < &cy_port[0] || info >= &cy_port[NR_PORTS]) { printk("Warning: cyclades_port out of range for (%s) in %s\n", name, routine); return 1; @@ -520,15 +519,13 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id) panic("TxInt on debug port!!!"); } #endif - - info = &cy_port[channel]; - /* validate the port number (as configured and open) */ if ((channel < 0) || (NR_PORTS <= channel)) { base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); base_addr[CyTEOIR] = CyNOTRANS; return IRQ_HANDLED; } + info = &cy_port[channel]; info->last_active = jiffies; if (info->tty == 0) { base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index aafdbaebc16..feb55075819 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -518,7 +518,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) static int tty_ldisc_halt(struct tty_struct *tty) { clear_bit(TTY_LDISC, &tty->flags); - return cancel_delayed_work(&tty->buf.work); + return cancel_delayed_work_sync(&tty->buf.work); } /** @@ -756,12 +756,9 @@ void tty_ldisc_hangup(struct tty_struct *tty) * N_TTY. */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - /* Make sure the old ldisc is quiescent */ - tty_ldisc_halt(tty); - flush_scheduled_work(); - /* Avoid racing set_ldisc or tty_ldisc_release */ mutex_lock(&tty->ldisc_mutex); + tty_ldisc_halt(tty); if (tty->ldisc) { /* Not yet closed */ /* Switch back to N_TTY */ tty_ldisc_reinit(tty); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 29c651ab0d7..6b36ee56e6f 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -981,8 +981,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, goto eperm; if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, - sizeof(struct vt_setactivate))) - return -EFAULT; + sizeof(struct vt_setactivate))) { + ret = -EFAULT; + goto out; + } if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) ret = -ENXIO; else { diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index f40ab699860..4846d50199f 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -559,7 +559,7 @@ static int hwicap_release(struct inode *inode, struct file *file) return status; } -static struct file_operations hwicap_fops = { +static const struct file_operations hwicap_fops = { .owner = THIS_MODULE, .write = hwicap_write, .read = hwicap_read, diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 4a1dfe1f4ba..210338ea222 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -78,18 +78,20 @@ void cn_queue_wrapper(struct work_struct *work) struct cn_callback_entry *cbq = container_of(work, struct cn_callback_entry, work); struct cn_callback_data *d = &cbq->data; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb)); + struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb); - d->callback(d->callback_priv); + d->callback(msg, nsp); - d->destruct_data(d->ddata); - d->ddata = NULL; + kfree_skb(d->skb); + d->skb = NULL; kfree(d->free); } static struct cn_callback_entry * cn_queue_alloc_callback_entry(char *name, struct cb_id *id, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq; @@ -123,7 +125,7 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2) } int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq, *__cbq; int found = 0; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 74f52af7956..f06024668f9 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -129,21 +129,19 @@ EXPORT_SYMBOL_GPL(cn_netlink_send); /* * Callback helper - queues work and setup destructor for given data. */ -static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data) +static int cn_call_callback(struct sk_buff *skb) { struct cn_callback_entry *__cbq, *__new_cbq; struct cn_dev *dev = &cdev; + struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb)); int err = -ENODEV; spin_lock_bh(&dev->cbdev->queue_lock); list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, &msg->id)) { if (likely(!work_pending(&__cbq->work) && - __cbq->data.ddata == NULL)) { - __cbq->data.callback_priv = msg; - - __cbq->data.ddata = data; - __cbq->data.destruct_data = destruct_data; + __cbq->data.skb == NULL)) { + __cbq->data.skb = skb; if (queue_cn_work(__cbq, &__cbq->work)) err = 0; @@ -156,10 +154,8 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC); if (__new_cbq) { d = &__new_cbq->data; - d->callback_priv = msg; + d->skb = skb; d->callback = __cbq->data.callback; - d->ddata = data; - d->destruct_data = destruct_data; d->free = __new_cbq; __new_cbq->pdev = __cbq->pdev; @@ -191,7 +187,6 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v */ static void cn_rx_skb(struct sk_buff *__skb) { - struct cn_msg *msg; struct nlmsghdr *nlh; int err; struct sk_buff *skb; @@ -208,8 +203,7 @@ static void cn_rx_skb(struct sk_buff *__skb) return; } - msg = NLMSG_DATA(nlh); - err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb); + err = cn_call_callback(skb); if (err < 0) kfree_skb(skb); } @@ -270,7 +264,7 @@ static void cn_notify(struct cb_id *id, u32 notify_event) * May sleep. */ int cn_add_callback(struct cb_id *id, char *name, - void (*callback)(struct cn_msg *)) + void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { int err; struct cn_dev *dev = &cdev; @@ -352,7 +346,7 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) * * Used for notification of a request's processing. */ -static void cn_callback(struct cn_msg *msg) +static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct cn_ctl_msg *ctl; struct cn_ctl_entry *ent; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bb11a429394..662ed923d9e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1487,7 +1487,7 @@ static int gpiolib_open(struct inode *inode, struct file *file) return single_open(file, gpiolib_show, NULL); } -static struct file_operations gpiolib_operations = { +static const struct file_operations gpiolib_operations = { .open = gpiolib_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index ea955edde87..2a7a85a6dc3 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -915,7 +915,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *filp, return ret; } -static struct file_operations watchdog_fops = { +static const struct file_operations watchdog_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = watchdog_open, diff --git a/drivers/input/input.c b/drivers/input/input.c index e828aab7dac..16ec33f27c5 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1273,6 +1273,7 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) } \ } while (0) +#ifdef CONFIG_PM static void input_dev_reset(struct input_dev *dev, bool activate) { if (!dev->event) @@ -1287,7 +1288,6 @@ static void input_dev_reset(struct input_dev *dev, bool activate) } } -#ifdef CONFIG_PM static int input_dev_suspend(struct device *dev) { struct input_dev *input_dev = to_input_dev(dev); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index c36f5213745..feb0fa45b66 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -415,7 +415,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } static int data_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int len) + char __user *optval, unsigned int len) { struct sock *sk = sock->sk; int err = 0, opt = 0; diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index b4d3f7ca554..bd1632388e4 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -508,7 +508,7 @@ static int close(struct inode *inode, struct file *file) * uses: reading and writing a character device called /dev/lguest. All the * work happens in the read(), write() and close() routines: */ -static struct file_operations lguest_fops = { +static const struct file_operations lguest_fops = { .owner = THIS_MODULE, .release = close, .write = write, diff --git a/drivers/md/dm-log-userspace-transfer.c b/drivers/md/dm-log-userspace-transfer.c index ba0edad2d04..54abf9e303b 100644 --- a/drivers/md/dm-log-userspace-transfer.c +++ b/drivers/md/dm-log-userspace-transfer.c @@ -129,11 +129,13 @@ static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) * This is the connector callback that delivers data * that was sent from userspace. */ -static void cn_ulog_callback(void *data) +static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { - struct cn_msg *msg = (struct cn_msg *)data; struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + spin_lock(&receiving_list_lock); if (msg->len == 0) fill_pkg(msg, NULL); diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 3750ff48cba..51641498359 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -1203,7 +1203,7 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) return mask; } -static struct file_operations dvb_dvr_fops = { +static const struct file_operations dvb_dvr_fops = { .owner = THIS_MODULE, .read = dvb_dvr_read, .write = dvb_dvr_write, diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c index eeb80d0ea3f..853e04b7cb3 100644 --- a/drivers/media/dvb/firewire/firedtv-ci.c +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -215,7 +215,7 @@ static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait) return POLLIN; } -static struct file_operations fdtv_ca_fops = { +static const struct file_operations fdtv_ca_fops = { .owner = THIS_MODULE, .ioctl = dvb_generic_ioctl, .open = dvb_generic_open, diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index fa57b67593a..90a95ce8dc3 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -271,7 +271,7 @@ static unsigned int phantom_poll(struct file *file, poll_table *wait) return mask; } -static struct file_operations phantom_file_ops = { +static const struct file_operations phantom_file_ops = { .open = phantom_open, .release = phantom_release, .unlocked_ioctl = phantom_ioctl, diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 300e7ba391a..41c8fe2a928 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -53,7 +53,6 @@ struct gru_stats_s gru_stats; /* Guaranteed user available resources on each node */ static int max_user_cbrs, max_user_dsr_bytes; -static struct file_operations gru_fops; static struct miscdevice gru_miscdev; @@ -426,7 +425,7 @@ static void __exit gru_exit(void) gru_proc_exit(); } -static struct file_operations gru_fops = { +static const struct file_operations gru_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gru_file_unlocked_ioctl, .mmap = gru_file_mmap, diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 610dbd1fcc8..96d10f40fb2 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -240,7 +240,7 @@ static int mmc_ext_csd_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations mmc_dbg_ext_csd_fops = { +static const struct file_operations mmc_dbg_ext_csd_fops = { .open = mmc_ext_csd_open, .read = mmc_ext_csd_read, .release = mmc_ext_csd_release, diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 6636354b48c..e1035c89580 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -98,6 +98,22 @@ static const unsigned char speed_val[16] = static const unsigned int speed_unit[8] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; +/* FUNCE tuples with these types get passed to SDIO drivers */ +static const unsigned char funce_type_whitelist[] = { + 4 /* CISTPL_FUNCE_LAN_NODE_ID used in Broadcom cards */ +}; + +static int cistpl_funce_whitelisted(unsigned char type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(funce_type_whitelist); i++) { + if (funce_type_whitelist[i] == type) + return 1; + } + return 0; +} + static int cistpl_funce_common(struct mmc_card *card, const unsigned char *buf, unsigned size) { @@ -120,6 +136,10 @@ static int cistpl_funce_func(struct sdio_func *func, unsigned vsn; unsigned min_size; + /* let SDIO drivers take care of whitelisted FUNCE tuples */ + if (cistpl_funce_whitelisted(buf[0])) + return -EILSEQ; + vsn = func->card->cccr.sdio_vsn; min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; @@ -154,13 +174,12 @@ static int cistpl_funce(struct mmc_card *card, struct sdio_func *func, else ret = cistpl_funce_common(card, buf, size); - if (ret) { + if (ret && ret != -EILSEQ) { printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u " "type %u\n", mmc_hostname(card->host), size, buf[0]); - return ret; } - return 0; + return ret; } typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *, @@ -253,21 +272,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) if (cis_tpl_list[i].code == tpl_code) break; - if (i >= ARRAY_SIZE(cis_tpl_list)) { - /* this tuple is unknown to the core */ - this->next = NULL; - this->code = tpl_code; - this->size = tpl_link; - *prev = this; - prev = &this->next; - printk(KERN_DEBUG - "%s: queuing CIS tuple 0x%02x length %u\n", - mmc_hostname(card->host), tpl_code, tpl_link); - } else { + if (i < ARRAY_SIZE(cis_tpl_list)) { const struct cis_tpl *tpl = cis_tpl_list + i; if (tpl_link < tpl->min_size) { printk(KERN_ERR - "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n", + "%s: bad CIS tuple 0x%02x" + " (length = %u, expected >= %u)\n", mmc_hostname(card->host), tpl_code, tpl_link, tpl->min_size); ret = -EINVAL; @@ -275,7 +285,30 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) ret = tpl->parse(card, func, this->data, tpl_link); } - kfree(this); + /* + * We don't need the tuple anymore if it was + * successfully parsed by the SDIO core or if it is + * not going to be parsed by SDIO drivers. + */ + if (!ret || ret != -EILSEQ) + kfree(this); + } else { + /* unknown tuple */ + ret = -EILSEQ; + } + + if (ret == -EILSEQ) { + /* this tuple is unknown to the core or whitelisted */ + this->next = NULL; + this->code = tpl_code; + this->size = tpl_link; + *prev = this; + prev = &this->next; + printk(KERN_DEBUG + "%s: queuing CIS tuple 0x%02x length %u\n", + mmc_hostname(card->host), tpl_code, tpl_link); + /* keep on analyzing tuples */ + ret = 0; } ptr += tpl_link; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7cb057f3f88..432ae8358c8 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -276,6 +276,47 @@ config MMC_S3C If unsure, say N. +config MMC_S3C_HW_SDIO_IRQ + bool "Hardware support for SDIO IRQ" + depends on MMC_S3C + help + Enable the hardware support for SDIO interrupts instead of using + the generic polling code. + +choice + prompt "Samsung S3C SD/MMC transfer code" + depends on MMC_S3C + +config MMC_S3C_PIO + bool "Use PIO transfers only" + help + Use PIO to transfer data between memory and the hardware. + + PIO is slower than DMA as it requires CPU instructions to + move the data. This has been the traditional default for + the S3C MCI driver. + +config MMC_S3C_DMA + bool "Use DMA transfers only (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Use DMA to transfer data between memory and the hardare. + + Currently, the DMA support in this driver seems to not be + working properly and needs to be debugged before this + option is useful. + +config MMC_S3C_PIODMA + bool "Support for both PIO and DMA (EXPERIMENTAL)" + help + Compile both the PIO and DMA transfer routines into the + driver and let the platform select at run-time which one + is best. + + See notes for the DMA option. + +endchoice + config MMC_SDRICOH_CS tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)" depends on EXPERIMENTAL && PCI && PCMCIA diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 3d1e5329da1..705a5894a6b 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -678,7 +678,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); -#ifdef CONFIG_GPIOLIB if (gpio_is_valid(plat->gpio_cd)) { ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); if (ret == 0) @@ -697,7 +696,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) else if (ret != -ENOSYS) goto err_gpio_wp; } -#endif ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 8c08cd7efa7..99b74a35102 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -17,6 +17,8 @@ #include <linux/mmc/host.h> #include <linux/platform_device.h> #include <linux/cpufreq.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> #include <linux/gpio.h> #include <linux/irq.h> #include <linux/io.h> @@ -58,8 +60,6 @@ static const int dbgmap_debug = dbg_err | dbg_debug; dev_dbg(&host->pdev->dev, args); \ } while (0) -#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1) - static struct s3c2410_dma_client s3cmci_dma_client = { .name = "s3c-mci", }; @@ -164,6 +164,40 @@ static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { } #endif /* CONFIG_MMC_DEBUG */ +/** + * s3cmci_host_usedma - return whether the host is using dma or pio + * @host: The host state + * + * Return true if the host is using DMA to transfer data, else false + * to use PIO mode. Will return static data depending on the driver + * configuration. + */ +static inline bool s3cmci_host_usedma(struct s3cmci_host *host) +{ +#ifdef CONFIG_MMC_S3C_PIO + return false; +#elif defined(CONFIG_MMC_S3C_DMA) + return true; +#else + return host->dodma; +#endif +} + +/** + * s3cmci_host_canpio - return true if host has pio code available + * + * Return true if the driver has been compiled with the PIO support code + * available. + */ +static inline bool s3cmci_host_canpio(void) +{ +#ifdef CONFIG_MMC_S3C_PIO + return true; +#else + return false; +#endif +} + static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) { u32 newmask; @@ -190,7 +224,33 @@ static inline u32 disable_imask(struct s3cmci_host *host, u32 imask) static inline void clear_imask(struct s3cmci_host *host) { - writel(0, host->base + host->sdiimsk); + u32 mask = readl(host->base + host->sdiimsk); + + /* preserve the SDIO IRQ mask state */ + mask &= S3C2410_SDIIMSK_SDIOIRQ; + writel(mask, host->base + host->sdiimsk); +} + +/** + * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled + * @host: The host to check. + * + * Test to see if the SDIO interrupt is being signalled in case the + * controller has failed to re-detect a card interrupt. Read GPE8 and + * see if it is low and if so, signal a SDIO interrupt. + * + * This is currently called if a request is finished (we assume that the + * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is + * already being indicated. +*/ +static void s3cmci_check_sdio_irq(struct s3cmci_host *host) +{ + if (host->sdio_irqen) { + if (gpio_get_value(S3C2410_GPE(8)) == 0) { + printk(KERN_DEBUG "%s: signalling irq\n", __func__); + mmc_signal_sdio_irq(host->mmc); + } + } } static inline int get_data_buffer(struct s3cmci_host *host, @@ -238,6 +298,64 @@ static inline u32 fifo_free(struct s3cmci_host *host) return 63 - fifostat; } +/** + * s3cmci_enable_irq - enable IRQ, after having disabled it. + * @host: The device state. + * @more: True if more IRQs are expected from transfer. + * + * Enable the main IRQ if needed after it has been disabled. + * + * The IRQ can be one of the following states: + * - disabled during IDLE + * - disabled whilst processing data + * - enabled during transfer + * - enabled whilst awaiting SDIO interrupt detection + */ +static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) +{ + unsigned long flags; + bool enable = false; + + local_irq_save(flags); + + host->irq_enabled = more; + host->irq_disabled = false; + + enable = more | host->sdio_irqen; + + if (host->irq_state != enable) { + host->irq_state = enable; + + if (enable) + enable_irq(host->irq); + else + disable_irq(host->irq); + } + + local_irq_restore(flags); +} + +/** + * + */ +static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) +{ + unsigned long flags; + + local_irq_save(flags); + + //printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer); + + host->irq_disabled = transfer; + + if (transfer && host->irq_state) { + host->irq_state = false; + disable_irq(host->irq); + } + + local_irq_restore(flags); +} + static void do_pio_read(struct s3cmci_host *host) { int res; @@ -374,8 +492,7 @@ static void pio_tasklet(unsigned long data) { struct s3cmci_host *host = (struct s3cmci_host *) data; - - disable_irq(host->irq); + s3cmci_disable_irq(host, true); if (host->pio_active == XFER_WRITE) do_pio_write(host); @@ -395,9 +512,10 @@ static void pio_tasklet(unsigned long data) host->mrq->data->error = -EINVAL; } + s3cmci_enable_irq(host, false); finalize_request(host); } else - enable_irq(host->irq); + s3cmci_enable_irq(host, true); } /* @@ -432,17 +550,27 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) struct s3cmci_host *host = dev_id; struct mmc_command *cmd; u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; - u32 mci_cclear, mci_dclear; + u32 mci_cclear = 0, mci_dclear; unsigned long iflags; + mci_dsta = readl(host->base + S3C2410_SDIDSTA); + mci_imsk = readl(host->base + host->sdiimsk); + + if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { + if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) { + mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT; + writel(mci_dclear, host->base + S3C2410_SDIDSTA); + + mmc_signal_sdio_irq(host->mmc); + return IRQ_HANDLED; + } + } + spin_lock_irqsave(&host->complete_lock, iflags); mci_csta = readl(host->base + S3C2410_SDICMDSTAT); - mci_dsta = readl(host->base + S3C2410_SDIDSTA); mci_dcnt = readl(host->base + S3C2410_SDIDCNT); mci_fsta = readl(host->base + S3C2410_SDIFSTA); - mci_imsk = readl(host->base + host->sdiimsk); - mci_cclear = 0; mci_dclear = 0; if ((host->complete_what == COMPLETION_NONE) || @@ -466,7 +594,7 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) goto irq_out; } - if (!host->dodma) { + if (!s3cmci_host_usedma(host)) { if ((host->pio_active == XFER_WRITE) && (mci_fsta & S3C2410_SDIFSTA_TFDET)) { @@ -673,6 +801,7 @@ static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", size, mci_dsta, mci_dcnt); + host->dma_complete = 1; host->complete_what = COMPLETION_FINALIZE; out: @@ -683,9 +812,9 @@ out: fail_request: host->mrq->data->error = -EINVAL; host->complete_what = COMPLETION_FINALIZE; - writel(0, host->base + host->sdiimsk); - goto out; + clear_imask(host); + goto out; } static void finalize_request(struct s3cmci_host *host) @@ -702,8 +831,9 @@ static void finalize_request(struct s3cmci_host *host) if (cmd->data && (cmd->error == 0) && (cmd->data->error == 0)) { - if (host->dodma && (!host->dma_complete)) { - dbg(host, dbg_dma, "DMA Missing!\n"); + if (s3cmci_host_usedma(host) && (!host->dma_complete)) { + dbg(host, dbg_dma, "DMA Missing (%d)!\n", + host->dma_complete); return; } } @@ -728,7 +858,7 @@ static void finalize_request(struct s3cmci_host *host) writel(0, host->base + S3C2410_SDICMDARG); writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); - writel(0, host->base + host->sdiimsk); + clear_imask(host); if (cmd->data && cmd->error) cmd->data->error = cmd->error; @@ -754,7 +884,7 @@ static void finalize_request(struct s3cmci_host *host) /* If we had an error while transfering data we flush the * DMA channel and the fifo to clear out any garbage. */ if (mrq->data->error != 0) { - if (host->dodma) + if (s3cmci_host_usedma(host)) s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); if (host->is2440) { @@ -776,6 +906,8 @@ static void finalize_request(struct s3cmci_host *host) request_done: host->complete_what = COMPLETION_NONE; host->mrq = NULL; + + s3cmci_check_sdio_irq(host); mmc_request_done(host->mmc, mrq); } @@ -872,7 +1004,7 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK; - if (host->dodma) + if (s3cmci_host_usedma(host)) dcon |= S3C2410_SDIDCON_DMAEN; if (host->bus_width == MMC_BUS_WIDTH_4) @@ -950,7 +1082,7 @@ static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data) static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) { int dma_len, i; - int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; + int rw = data->flags & MMC_DATA_WRITE; BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); @@ -958,7 +1090,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - (rw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (dma_len == 0) return -ENOMEM; @@ -969,11 +1101,11 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) for (i = 0; i < dma_len; i++) { int res; - dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i, - sg_dma_address(&data->sg[i]), - sg_dma_len(&data->sg[i])); + dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i, + sg_dma_address(&data->sg[i]), + sg_dma_len(&data->sg[i])); - res = s3c2410_dma_enqueue(host->dma, (void *) host, + res = s3c2410_dma_enqueue(host->dma, host, sg_dma_address(&data->sg[i]), sg_dma_len(&data->sg[i])); @@ -1018,7 +1150,7 @@ static void s3cmci_send_request(struct mmc_host *mmc) return; } - if (host->dodma) + if (s3cmci_host_usedma(host)) res = s3cmci_prepare_dma(host, cmd->data); else res = s3cmci_prepare_pio(host, cmd->data); @@ -1037,7 +1169,7 @@ static void s3cmci_send_request(struct mmc_host *mmc) s3cmci_send_command(host, cmd); /* Enable Interrupt */ - enable_irq(host->irq); + s3cmci_enable_irq(host, true); } static int s3cmci_card_present(struct mmc_host *mmc) @@ -1049,7 +1181,7 @@ static int s3cmci_card_present(struct mmc_host *mmc) if (pdata->gpio_detect == 0) return -ENOSYS; - ret = s3c2410_gpio_getpin(pdata->gpio_detect) ? 0 : 1; + ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1; return ret ^ pdata->detect_invert; } @@ -1104,12 +1236,12 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD); - s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0); - s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1); - s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2); - s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3); + s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); + s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); + s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); + s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); + s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); + s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); if (host->pdata->set_power) host->pdata->set_power(ios->power_mode, ios->vdd); @@ -1121,8 +1253,7 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: default: - s3c2410_gpio_setpin(S3C2410_GPE5, 0); - s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPIO_OUTPUT); + gpio_direction_output(S3C2410_GPE(5), 0); if (host->is2440) mci_con |= S3C2440_SDICON_SDRESET; @@ -1168,7 +1299,7 @@ static int s3cmci_get_ro(struct mmc_host *mmc) struct s3c24xx_mci_pdata *pdata = host->pdata; int ret; - if (pdata->gpio_wprotect == 0) + if (pdata->no_wprotect) return 0; ret = s3c2410_gpio_getpin(pdata->gpio_wprotect); @@ -1179,11 +1310,52 @@ static int s3cmci_get_ro(struct mmc_host *mmc) return ret; } +static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct s3cmci_host *host = mmc_priv(mmc); + unsigned long flags; + u32 con; + + local_irq_save(flags); + + con = readl(host->base + S3C2410_SDICON); + host->sdio_irqen = enable; + + if (enable == host->sdio_irqen) + goto same_state; + + if (enable) { + con |= S3C2410_SDICON_SDIOIRQ; + enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); + + if (!host->irq_state && !host->irq_disabled) { + host->irq_state = true; + enable_irq(host->irq); + } + } else { + disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); + con &= ~S3C2410_SDICON_SDIOIRQ; + + if (!host->irq_enabled && host->irq_state) { + disable_irq_nosync(host->irq); + host->irq_state = false; + } + } + + writel(con, host->base + S3C2410_SDICON); + + same_state: + local_irq_restore(flags); + + s3cmci_check_sdio_irq(host); +} + static struct mmc_host_ops s3cmci_ops = { .request = s3cmci_request, .set_ios = s3cmci_set_ios, .get_ro = s3cmci_get_ro, .get_cd = s3cmci_card_present, + .enable_sdio_irq = s3cmci_enable_sdio_irq, }; static struct s3c24xx_mci_pdata s3cmci_def_pdata = { @@ -1246,11 +1418,140 @@ static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) } #endif -static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) + +#ifdef CONFIG_DEBUG_FS + +static int s3cmci_state_show(struct seq_file *seq, void *v) +{ + struct s3cmci_host *host = seq->private; + + seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); + seq_printf(seq, "Clock rate = %ld\n", host->clk_rate); + seq_printf(seq, "Prescale = %d\n", host->prescaler); + seq_printf(seq, "is2440 = %d\n", host->is2440); + seq_printf(seq, "IRQ = %d\n", host->irq); + seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled); + seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled); + seq_printf(seq, "IRQ state = %d\n", host->irq_state); + seq_printf(seq, "CD IRQ = %d\n", host->irq_cd); + seq_printf(seq, "Do DMA = %d\n", s3cmci_host_usedma(host)); + seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk); + seq_printf(seq, "SDIDATA at %d\n", host->sdidata); + + return 0; +} + +static int s3cmci_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, s3cmci_state_show, inode->i_private); +} + +static const struct file_operations s3cmci_fops_state = { + .owner = THIS_MODULE, + .open = s3cmci_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r } + +struct s3cmci_reg { + unsigned short addr; + unsigned char *name; +} debug_regs[] = { + DBG_REG(CON), + DBG_REG(PRE), + DBG_REG(CMDARG), + DBG_REG(CMDCON), + DBG_REG(CMDSTAT), + DBG_REG(RSP0), + DBG_REG(RSP1), + DBG_REG(RSP2), + DBG_REG(RSP3), + DBG_REG(TIMER), + DBG_REG(BSIZE), + DBG_REG(DCON), + DBG_REG(DCNT), + DBG_REG(DSTA), + DBG_REG(FSTA), + {} +}; + +static int s3cmci_regs_show(struct seq_file *seq, void *v) +{ + struct s3cmci_host *host = seq->private; + struct s3cmci_reg *rptr = debug_regs; + + for (; rptr->name; rptr++) + seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, + readl(host->base + rptr->addr)); + + seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk)); + + return 0; +} + +static int s3cmci_regs_open(struct inode *inode, struct file *file) +{ + return single_open(file, s3cmci_regs_show, inode->i_private); +} + +static const struct file_operations s3cmci_fops_regs = { + .owner = THIS_MODULE, + .open = s3cmci_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void s3cmci_debugfs_attach(struct s3cmci_host *host) +{ + struct device *dev = &host->pdev->dev; + + host->debug_root = debugfs_create_dir(dev_name(dev), NULL); + if (IS_ERR(host->debug_root)) { + dev_err(dev, "failed to create debugfs root\n"); + return; + } + + host->debug_state = debugfs_create_file("state", 0444, + host->debug_root, host, + &s3cmci_fops_state); + + if (IS_ERR(host->debug_state)) + dev_err(dev, "failed to create debug state file\n"); + + host->debug_regs = debugfs_create_file("regs", 0444, + host->debug_root, host, + &s3cmci_fops_regs); + + if (IS_ERR(host->debug_regs)) + dev_err(dev, "failed to create debug regs file\n"); +} + +static void s3cmci_debugfs_remove(struct s3cmci_host *host) +{ + debugfs_remove(host->debug_regs); + debugfs_remove(host->debug_state); + debugfs_remove(host->debug_root); +} + +#else +static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { } +static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } + +#endif /* CONFIG_DEBUG_FS */ + +static int __devinit s3cmci_probe(struct platform_device *pdev) { struct s3cmci_host *host; struct mmc_host *mmc; int ret; + int is2440; + int i; + + is2440 = platform_get_device_id(pdev)->driver_data; mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); if (!mmc) { @@ -1258,6 +1559,18 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) goto probe_out; } + for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { + ret = gpio_request(i, dev_name(&pdev->dev)); + if (ret) { + dev_err(&pdev->dev, "failed to get gpio %d\n", i); + + for (i--; i >= S3C2410_GPE(5); i--) + gpio_free(i); + + goto probe_free_host; + } + } + host = mmc_priv(mmc); host->mmc = mmc; host->pdev = pdev; @@ -1282,11 +1595,12 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) host->clk_div = 2; } - host->dodma = 0; host->complete_what = COMPLETION_NONE; host->pio_active = XFER_NONE; - host->dma = S3CMCI_DMA; +#ifdef CONFIG_MMC_S3C_PIODMA + host->dodma = host->pdata->dma; +#endif host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!host->mem) { @@ -1294,19 +1608,19 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) "failed to get io memory region resouce.\n"); ret = -ENOENT; - goto probe_free_host; + goto probe_free_gpio; } host->mem = request_mem_region(host->mem->start, - RESSIZE(host->mem), pdev->name); + resource_size(host->mem), pdev->name); if (!host->mem) { dev_err(&pdev->dev, "failed to request io memory region.\n"); ret = -ENOENT; - goto probe_free_host; + goto probe_free_gpio; } - host->base = ioremap(host->mem->start, RESSIZE(host->mem)); + host->base = ioremap(host->mem->start, resource_size(host->mem)); if (!host->base) { dev_err(&pdev->dev, "failed to ioremap() io memory region.\n"); ret = -EINVAL; @@ -1331,31 +1645,60 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) * ensure we don't lock the system with un-serviceable requests. */ disable_irq(host->irq); + host->irq_state = false; - host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect); - - if (host->irq_cd >= 0) { - if (request_irq(host->irq_cd, s3cmci_irq_cd, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRIVER_NAME, host)) { - dev_err(&pdev->dev, "can't get card detect irq.\n"); - ret = -ENOENT; + if (!host->pdata->no_detect) { + ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect"); + if (ret) { + dev_err(&pdev->dev, "failed to get detect gpio\n"); goto probe_free_irq; } - } else { - dev_warn(&pdev->dev, "host detect has no irq available\n"); - s3c2410_gpio_cfgpin(host->pdata->gpio_detect, - S3C2410_GPIO_INPUT); + + host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect); + + if (host->irq_cd >= 0) { + if (request_irq(host->irq_cd, s3cmci_irq_cd, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, + DRIVER_NAME, host)) { + dev_err(&pdev->dev, + "can't get card detect irq.\n"); + ret = -ENOENT; + goto probe_free_gpio_cd; + } + } else { + dev_warn(&pdev->dev, + "host detect has no irq available\n"); + gpio_direction_input(host->pdata->gpio_detect); + } + } else + host->irq_cd = -1; + + if (!host->pdata->no_wprotect) { + ret = gpio_request(host->pdata->gpio_wprotect, "s3cmci wp"); + if (ret) { + dev_err(&pdev->dev, "failed to get writeprotect\n"); + goto probe_free_irq_cd; + } + + gpio_direction_input(host->pdata->gpio_wprotect); } - if (host->pdata->gpio_wprotect) - s3c2410_gpio_cfgpin(host->pdata->gpio_wprotect, - S3C2410_GPIO_INPUT); + /* depending on the dma state, get a dma channel to use. */ - if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL) < 0) { - dev_err(&pdev->dev, "unable to get DMA channel.\n"); - ret = -EBUSY; - goto probe_free_irq_cd; + if (s3cmci_host_usedma(host)) { + host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client, + host); + if (host->dma < 0) { + dev_err(&pdev->dev, "cannot get DMA channel.\n"); + if (!s3cmci_host_canpio()) { + ret = -EBUSY; + goto probe_free_gpio_wp; + } else { + dev_warn(&pdev->dev, "falling back to PIO.\n"); + host->dodma = 0; + } + } } host->clk = clk_get(&pdev->dev, "sdi"); @@ -1363,7 +1706,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) dev_err(&pdev->dev, "failed to find clock source.\n"); ret = PTR_ERR(host->clk); host->clk = NULL; - goto probe_free_host; + goto probe_free_dma; } ret = clk_enable(host->clk); @@ -1376,7 +1719,11 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) mmc->ops = &s3cmci_ops; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; +#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; +#else mmc->caps = MMC_CAP_4_BIT_DATA; +#endif mmc->f_min = host->clk_rate / (host->clk_div * 256); mmc->f_max = host->clk_rate / host->clk_div; @@ -1408,8 +1755,12 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) goto free_cpufreq; } + s3cmci_debugfs_attach(host); + platform_set_drvdata(pdev, mmc); - dev_info(&pdev->dev, "initialisation done.\n"); + dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc), + s3cmci_host_usedma(host) ? "dma" : "pio", + mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); return 0; @@ -1422,6 +1773,18 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) clk_free: clk_put(host->clk); + probe_free_dma: + if (s3cmci_host_usedma(host)) + s3c2410_dma_free(host->dma, &s3cmci_dma_client); + + probe_free_gpio_wp: + if (!host->pdata->no_wprotect) + gpio_free(host->pdata->gpio_wprotect); + + probe_free_gpio_cd: + if (!host->pdata->no_detect) + gpio_free(host->pdata->gpio_detect); + probe_free_irq_cd: if (host->irq_cd >= 0) free_irq(host->irq_cd, host); @@ -1433,10 +1796,15 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440) iounmap(host->base); probe_free_mem_region: - release_mem_region(host->mem->start, RESSIZE(host->mem)); + release_mem_region(host->mem->start, resource_size(host->mem)); + + probe_free_gpio: + for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) + gpio_free(i); probe_free_host: mmc_free_host(mmc); + probe_out: return ret; } @@ -1449,6 +1817,7 @@ static void s3cmci_shutdown(struct platform_device *pdev) if (host->irq_cd >= 0) free_irq(host->irq_cd, host); + s3cmci_debugfs_remove(host); s3cmci_cpufreq_deregister(host); mmc_remove_host(mmc); clk_disable(host->clk); @@ -1458,104 +1827,102 @@ static int __devexit s3cmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct s3cmci_host *host = mmc_priv(mmc); + struct s3c24xx_mci_pdata *pd = host->pdata; + int i; s3cmci_shutdown(pdev); clk_put(host->clk); tasklet_disable(&host->pio_tasklet); - s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client); + + if (s3cmci_host_usedma(host)) + s3c2410_dma_free(host->dma, &s3cmci_dma_client); free_irq(host->irq, host); + if (!pd->no_wprotect) + gpio_free(pd->gpio_wprotect); + + if (!pd->no_detect) + gpio_free(pd->gpio_detect); + + for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) + gpio_free(i); + + iounmap(host->base); - release_mem_region(host->mem->start, RESSIZE(host->mem)); + release_mem_region(host->mem->start, resource_size(host->mem)); mmc_free_host(mmc); return 0; } -static int __devinit s3cmci_2410_probe(struct platform_device *dev) -{ - return s3cmci_probe(dev, 0); -} +static struct platform_device_id s3cmci_driver_ids[] = { + { + .name = "s3c2410-sdi", + .driver_data = 0, + }, { + .name = "s3c2412-sdi", + .driver_data = 1, + }, { + .name = "s3c2440-sdi", + .driver_data = 1, + }, + { } +}; -static int __devinit s3cmci_2412_probe(struct platform_device *dev) -{ - return s3cmci_probe(dev, 1); -} +MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); -static int __devinit s3cmci_2440_probe(struct platform_device *dev) -{ - return s3cmci_probe(dev, 1); -} #ifdef CONFIG_PM -static int s3cmci_suspend(struct platform_device *dev, pm_message_t state) +static int s3cmci_suspend(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); + struct pm_message event = { PM_EVENT_SUSPEND }; - return mmc_suspend_host(mmc, state); + return mmc_suspend_host(mmc, event); } -static int s3cmci_resume(struct platform_device *dev) +static int s3cmci_resume(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); return mmc_resume_host(mmc); } -#else /* CONFIG_PM */ -#define s3cmci_suspend NULL -#define s3cmci_resume NULL -#endif /* CONFIG_PM */ - - -static struct platform_driver s3cmci_2410_driver = { - .driver.name = "s3c2410-sdi", - .driver.owner = THIS_MODULE, - .probe = s3cmci_2410_probe, - .remove = __devexit_p(s3cmci_remove), - .shutdown = s3cmci_shutdown, +static struct dev_pm_ops s3cmci_pm = { .suspend = s3cmci_suspend, .resume = s3cmci_resume, }; -static struct platform_driver s3cmci_2412_driver = { - .driver.name = "s3c2412-sdi", - .driver.owner = THIS_MODULE, - .probe = s3cmci_2412_probe, - .remove = __devexit_p(s3cmci_remove), - .shutdown = s3cmci_shutdown, - .suspend = s3cmci_suspend, - .resume = s3cmci_resume, -}; +#define s3cmci_pm_ops &s3cmci_pm +#else /* CONFIG_PM */ +#define s3cmci_pm_ops NULL +#endif /* CONFIG_PM */ -static struct platform_driver s3cmci_2440_driver = { - .driver.name = "s3c2440-sdi", - .driver.owner = THIS_MODULE, - .probe = s3cmci_2440_probe, + +static struct platform_driver s3cmci_driver = { + .driver = { + .name = "s3c-sdi", + .owner = THIS_MODULE, + .pm = s3cmci_pm_ops, + }, + .id_table = s3cmci_driver_ids, + .probe = s3cmci_probe, .remove = __devexit_p(s3cmci_remove), .shutdown = s3cmci_shutdown, - .suspend = s3cmci_suspend, - .resume = s3cmci_resume, }; - static int __init s3cmci_init(void) { - platform_driver_register(&s3cmci_2410_driver); - platform_driver_register(&s3cmci_2412_driver); - platform_driver_register(&s3cmci_2440_driver); - return 0; + return platform_driver_register(&s3cmci_driver); } static void __exit s3cmci_exit(void) { - platform_driver_unregister(&s3cmci_2410_driver); - platform_driver_unregister(&s3cmci_2412_driver); - platform_driver_unregister(&s3cmci_2440_driver); + platform_driver_unregister(&s3cmci_driver); } module_init(s3cmci_init); @@ -1564,6 +1931,3 @@ module_exit(s3cmci_exit); MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); -MODULE_ALIAS("platform:s3c2410-sdi"); -MODULE_ALIAS("platform:s3c2412-sdi"); -MODULE_ALIAS("platform:s3c2440-sdi"); diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h index ca1ba3d58cf..c76b53dbeb6 100644 --- a/drivers/mmc/host/s3cmci.h +++ b/drivers/mmc/host/s3cmci.h @@ -8,9 +8,6 @@ * published by the Free Software Foundation. */ -/* FIXME: DMA Resource management ?! */ -#define S3CMCI_DMA 0 - enum s3cmci_waitfor { COMPLETION_NONE, COMPLETION_FINALIZE, @@ -42,6 +39,11 @@ struct s3cmci_host { int dodma; int dmatogo; + bool irq_disabled; + bool irq_enabled; + bool irq_state; + int sdio_irqen; + struct mmc_request *mrq; int cmd_is_stop; @@ -68,6 +70,12 @@ struct s3cmci_host { unsigned int ccnt, dcnt; struct tasklet_struct pio_tasklet; +#ifdef CONFIG_DEBUG_FS + struct dentry *debug_root; + struct dentry *debug_state; + struct dentry *debug_regs; +#endif + #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index b9eeadf01b7..975e25b19eb 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -805,52 +805,54 @@ static void poll_vortex(struct net_device *dev) #ifdef CONFIG_PM -static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) +static int vortex_suspend(struct device *dev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct pci_dev *pdev = to_pci_dev(dev); + struct net_device *ndev = pci_get_drvdata(pdev); + + if (!ndev || !netif_running(ndev)) + return 0; + + netif_device_detach(ndev); + vortex_down(ndev, 1); - if (dev && netdev_priv(dev)) { - if (netif_running(dev)) { - netif_device_detach(dev); - vortex_down(dev, 1); - disable_irq(dev->irq); - } - pci_save_state(pdev); - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - } return 0; } -static int vortex_resume(struct pci_dev *pdev) +static int vortex_resume(struct device *dev) { - struct net_device *dev = pci_get_drvdata(pdev); - struct vortex_private *vp = netdev_priv(dev); + struct pci_dev *pdev = to_pci_dev(dev); + struct net_device *ndev = pci_get_drvdata(pdev); int err; - if (dev && vp) { - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); - if (err) { - pr_warning("%s: Could not enable device\n", - dev->name); - return err; - } - pci_set_master(pdev); - if (netif_running(dev)) { - err = vortex_up(dev); - if (err) - return err; - enable_irq(dev->irq); - netif_device_attach(dev); - } - } + if (!ndev || !netif_running(ndev)) + return 0; + + err = vortex_up(ndev); + if (err) + return err; + + netif_device_attach(ndev); + return 0; } -#endif /* CONFIG_PM */ +static struct dev_pm_ops vortex_pm_ops = { + .suspend = vortex_suspend, + .resume = vortex_resume, + .freeze = vortex_suspend, + .thaw = vortex_resume, + .poweroff = vortex_suspend, + .restore = vortex_resume, +}; + +#define VORTEX_PM_OPS (&vortex_pm_ops) + +#else /* !CONFIG_PM */ + +#define VORTEX_PM_OPS NULL + +#endif /* !CONFIG_PM */ #ifdef CONFIG_EISA static struct eisa_device_id vortex_eisa_ids[] = { @@ -3199,10 +3201,7 @@ static struct pci_driver vortex_driver = { .probe = vortex_init_one, .remove = __devexit_p(vortex_remove_one), .id_table = vortex_pci_tbl, -#ifdef CONFIG_PM - .suspend = vortex_suspend, - .resume = vortex_resume, -#endif + .driver.pm = VORTEX_PM_OPS, }; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2bea67c134f..712776089b4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1738,6 +1738,13 @@ config KS8851 help SPI driver for Micrel KS8851 SPI attached network chip. +config KS8851_MLL + tristate "Micrel KS8851 MLL" + depends on HAS_IOMEM + help + This platform driver is for Micrel KS8851 Address/data bus + multiplexed network chip. + config VIA_RHINE tristate "VIA Rhine support" depends on NET_PCI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ae8cd30f13d..d866b8cf65d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_SKY2) += sky2.o obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_KS8842) += ks8842.o obj-$(CONFIG_KS8851) += ks8851.o +obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index 09d270913c5..ba29dc319b3 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -90,7 +90,7 @@ static int do_mdio_op(struct bcm_enet_priv *priv, unsigned int data) if (enet_readl(priv, ENET_IR_REG) & ENET_IR_MII) break; udelay(1); - } while (limit-- >= 0); + } while (limit-- > 0); return (limit < 0) ? 1 : 0; } diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 684c6fe24c8..a80da0e14a5 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -258,6 +258,7 @@ struct be_adapter { bool link_up; u32 port_num; bool promiscuous; + u32 cap; }; extern const struct ethtool_ops be_ethtool_ops; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 3dd76c4170b..79d35d122c0 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1068,7 +1068,7 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) } /* Uses mbox */ -int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) +int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap) { struct be_mcc_wrb *wrb; struct be_cmd_req_query_fw_cfg *req; @@ -1088,6 +1088,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num) if (!status) { struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb); *port_num = le32_to_cpu(resp->phys_port); + *cap = le32_to_cpu(resp->function_cap); } spin_unlock(&adapter->mbox_lock); diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 93e432f3d92..8b4c2cb9ad6 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -760,7 +760,8 @@ extern int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc); extern int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc); -extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num); +extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, + u32 *port_num, u32 *cap); extern int be_cmd_reset_function(struct be_adapter *adapter); extern int be_process_mcc(struct be_adapter *adapter); extern int be_cmd_write_flashrom(struct be_adapter *adapter, diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 409cf059590..2f9b50156e0 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -747,9 +747,16 @@ static void be_rx_compl_process(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { struct sk_buff *skb; - u32 vtp, vid; + u32 vlanf, vid; + u8 vtm; - vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); + vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); + vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp); + + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->cap == 0x400) && !vtm) + vlanf = 0; skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN); if (!skb) { @@ -772,7 +779,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, skb->protocol = eth_type_trans(skb, adapter->netdev); skb->dev = adapter->netdev; - if (vtp) { + if (vlanf) { if (!adapter->vlan_grp || adapter->num_vlans == 0) { kfree_skb(skb); return; @@ -797,11 +804,18 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, struct be_eq_obj *eq_obj = &adapter->rx_eq; u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; u16 i, rxq_idx = 0, vid, j; + u8 vtm; num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); + vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp); + + /* vlanf could be wrongly set in some cards. + * ignore if vtm is not set */ + if ((adapter->cap == 0x400) && !vtm) + vlanf = 0; skb = napi_get_frags(&eq_obj->napi); if (!skb) { @@ -2045,7 +2059,8 @@ static int be_hw_up(struct be_adapter *adapter) if (status) return status; - status = be_cmd_query_fw_cfg(adapter, &adapter->port_num); + status = be_cmd_query_fw_cfg(adapter, + &adapter->port_num, &adapter->cap); return status; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 6044e12ff9f..ff449de6f3c 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1182,6 +1182,7 @@ static ssize_t bonding_store_primary(struct device *d, ": %s: Setting %s as primary slave.\n", bond->dev->name, slave->dev->name); bond->primary_slave = slave; + strcpy(bond->params.primary, slave->dev->name); bond_select_active_slave(bond); goto out; } diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 211c8e9182f..46c87ec7960 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -2733,7 +2733,8 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, cnic_ulp_init(dev); else if (event == NETDEV_UNREGISTER) cnic_ulp_exit(dev); - else if (event == NETDEV_UP) { + + if (event == NETDEV_UP) { if (cnic_register_netdev(dev) != 0) { cnic_put(dev); goto done; diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h index a49235739ee..d8b09efdcb5 100644 --- a/drivers/net/cnic_if.h +++ b/drivers/net/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.0.0" -#define CNIC_MODULE_RELDATE "May 21, 2009" +#define CNIC_MODULE_VERSION "2.0.1" +#define CNIC_MODULE_RELDATE "Oct 01, 2009" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 16c193a6c95..0687c6aa4e4 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4982,12 +4982,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, goto err_pci_reg; /* AER (Advanced Error Reporting) hooks */ - err = pci_enable_pcie_error_reporting(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " - "0x%x\n", err); - /* non-fatal, continue */ - } + pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); /* PCI config space info */ @@ -5263,7 +5258,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - int err; /* * flush_scheduled work may reschedule our watchdog task, so @@ -5299,10 +5293,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev) free_netdev(netdev); /* AER disable */ - err = pci_disable_pcie_error_reporting(pdev); - if (err) - dev_err(&pdev->dev, - "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 33b55f72974..db4b7f1603f 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -258,7 +258,7 @@ static void ax_bump(struct mkiss *ax) } if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) { printk(KERN_INFO - "mkiss: %s: Switchting to crc-smack\n", + "mkiss: %s: Switching to crc-smack\n", ax->dev->name); ax->crcmode = CRC_MODE_SMACK; } @@ -272,7 +272,7 @@ static void ax_bump(struct mkiss *ax) } if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { printk(KERN_INFO - "mkiss: %s: Switchting to crc-flexnet\n", + "mkiss: %s: Switching to crc-flexnet\n", ax->dev->name); ax->crcmode = CRC_MODE_FLEX; } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 5d6c1530a8c..714c3a4a44e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1246,12 +1246,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (err) goto err_pci_reg; - err = pci_enable_pcie_error_reporting(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " - "0x%x\n", err); - /* non-fatal, continue */ - } + pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); pci_save_state(pdev); @@ -1628,7 +1623,6 @@ static void __devexit igb_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - int err; /* flush_scheduled work may reschedule our watchdog task, so * explicitly disable watchdog tasks from being rescheduled */ @@ -1682,10 +1676,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) free_netdev(netdev); - err = pci_disable_pcie_error_reporting(pdev); - if (err) - dev_err(&pdev->dev, - "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index e36e951cbc6..aa7286bc436 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -495,7 +495,7 @@ static void veth_take_cap_ack(struct veth_lpar_connection *cnx, cnx->remote_lp); } else { memcpy(&cnx->cap_ack_event, event, - sizeof(&cnx->cap_ack_event)); + sizeof(cnx->cap_ack_event)); cnx->state |= VETH_STATE_GOTCAPACK; veth_kick_statemachine(cnx); } diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 56b12f3192f..e2d5343f127 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -425,7 +425,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num) #endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; + ret_val = IXGBE_ERR_CONFIG; goto out; break; } diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 6621e172df3..40ff120a9ad 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1355,9 +1355,7 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq) /** * ixgbe_update_uc_addr_list_generic - Updates MAC list of secondary addresses * @hw: pointer to hardware structure - * @addr_list: the list of new addresses - * @addr_count: number of addresses - * @next: iterator function to walk the address list + * @uc_list: the list of new addresses * * The given list replaces any existing list. Clears the secondary addrs from * receive address registers. Uses unused receive address registers for the @@ -1663,7 +1661,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) #endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; + ret_val = IXGBE_ERR_CONFIG; goto out; break; } @@ -1734,75 +1732,140 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) s32 ret_val = 0; ixgbe_link_speed speed; u32 pcs_anadv_reg, pcs_lpab_reg, linkstat; + u32 links2, anlp1_reg, autoc_reg, links; bool link_up; /* * AN should have completed when the cable was plugged in. * Look for reasons to bail out. Bail out if: * - FC autoneg is disabled, or if - * - we don't have multispeed fiber, or if - * - we're not running at 1G, or if - * - link is not up, or if - * - link is up but AN did not complete, or if - * - link is up and AN completed but timed out + * - link is not up. * - * Since we're being called from an LSC, link is already know to be up. + * Since we're being called from an LSC, link is already known to be up. * So use link_up_wait_to_complete=false. */ hw->mac.ops.check_link(hw, &speed, &link_up, false); - linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); - - if (hw->fc.disable_fc_autoneg || - !hw->phy.multispeed_fiber || - (speed != IXGBE_LINK_SPEED_1GB_FULL) || - !link_up || - ((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || - ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + + if (hw->fc.disable_fc_autoneg || (!link_up)) { hw->fc.fc_was_autonegged = false; hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg(hw, "Autoneg FC was skipped.\n"); goto out; } /* + * On backplane, bail out if + * - backplane autoneg was not completed, or if + * - link partner is not AN enabled + */ + if (hw->phy.media_type == ixgbe_media_type_backplane) { + links = IXGBE_READ_REG(hw, IXGBE_LINKS); + links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); + if (((links & IXGBE_LINKS_KX_AN_COMP) == 0) || + ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0)) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + goto out; + } + } + + /* + * On multispeed fiber at 1g, bail out if + * - link is up but AN did not complete, or if + * - link is up and AN completed but timed out + */ + if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL)) { + linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); + if (((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || + ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + goto out; + } + } + + /* * Read the AN advertisement and LP ability registers and resolve * local flow control settings accordingly */ - pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); - if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && - (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE)) { + if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && + (hw->phy.media_type != ixgbe_media_type_backplane)) { + pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); + pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); + if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == ixgbe_fc_full) { + hw->fc.current_mode = ixgbe_fc_full; + hw_dbg(hw, "Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_rx_pause; + hw_dbg(hw, "Flow Control=RX PAUSE only\n"); + } + } else if (!(pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { + hw->fc.current_mode = ixgbe_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); + } else if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && + !(pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && + (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { + hw->fc.current_mode = ixgbe_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_none; + hw_dbg(hw, "Flow Control = NONE.\n"); + } + } + + if (hw->phy.media_type == ixgbe_media_type_backplane) { /* - * Now we need to check if the user selected Rx ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. + * Read the 10g AN autoc and LP ability registers and resolve + * local flow control settings accordingly */ - if (hw->fc.requested_mode == ixgbe_fc_full) { - hw->fc.current_mode = ixgbe_fc_full; - hw_dbg(hw, "Flow Control = FULL.\n"); - } else { + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + anlp1_reg = IXGBE_READ_REG(hw, IXGBE_ANLP1); + + if ((autoc_reg & IXGBE_AUTOC_SYM_PAUSE) && + (anlp1_reg & IXGBE_ANLP1_SYM_PAUSE)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == ixgbe_fc_full) { + hw->fc.current_mode = ixgbe_fc_full; + hw_dbg(hw, "Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_rx_pause; + hw_dbg(hw, "Flow Control=RX PAUSE only\n"); + } + } else if (!(autoc_reg & IXGBE_AUTOC_SYM_PAUSE) && + (autoc_reg & IXGBE_AUTOC_ASM_PAUSE) && + (anlp1_reg & IXGBE_ANLP1_SYM_PAUSE) && + (anlp1_reg & IXGBE_ANLP1_ASM_PAUSE)) { + hw->fc.current_mode = ixgbe_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); + } else if ((autoc_reg & IXGBE_AUTOC_SYM_PAUSE) && + (autoc_reg & IXGBE_AUTOC_ASM_PAUSE) && + !(anlp1_reg & IXGBE_ANLP1_SYM_PAUSE) && + (anlp1_reg & IXGBE_ANLP1_ASM_PAUSE)) { hw->fc.current_mode = ixgbe_fc_rx_pause; hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.current_mode = ixgbe_fc_none; + hw_dbg(hw, "Flow Control = NONE.\n"); } - } else if (!(pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && - (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && - (pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && - (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { - hw->fc.current_mode = ixgbe_fc_tx_pause; - hw_dbg(hw, "Flow Control = TX PAUSE frames only.\n"); - } else if ((pcs_anadv_reg & IXGBE_PCS1GANA_SYM_PAUSE) && - (pcs_anadv_reg & IXGBE_PCS1GANA_ASM_PAUSE) && - !(pcs_lpab_reg & IXGBE_PCS1GANA_SYM_PAUSE) && - (pcs_lpab_reg & IXGBE_PCS1GANA_ASM_PAUSE)) { - hw->fc.current_mode = ixgbe_fc_rx_pause; - hw_dbg(hw, "Flow Control = RX PAUSE frames only.\n"); - } else { - hw->fc.current_mode = ixgbe_fc_none; - hw_dbg(hw, "Flow Control = NONE.\n"); } - /* Record that current_mode is the result of a successful autoneg */ hw->fc.fc_was_autonegged = true; @@ -1919,7 +1982,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) #endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); - ret_val = -IXGBE_ERR_CONFIG; + ret_val = IXGBE_ERR_CONFIG; goto out; break; } @@ -1927,9 +1990,6 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg); reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL); - /* Enable and restart autoneg to inform the link partner */ - reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART; - /* Disable AN timeout */ if (hw->fc.strict_ieee) reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN; @@ -1937,6 +1997,70 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg); hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg); + /* + * Set up the 10G flow control advertisement registers so the HW + * can do fc autoneg once the cable is plugged in. If we end up + * using 1g instead, this is harmless. + */ + reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + /* + * The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 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). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case ixgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(IXGBE_AUTOC_SYM_PAUSE | IXGBE_AUTOC_ASM_PAUSE); + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. 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. + */ + reg |= (IXGBE_AUTOC_SYM_PAUSE | IXGBE_AUTOC_ASM_PAUSE); + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= (IXGBE_AUTOC_ASM_PAUSE); + reg &= ~(IXGBE_AUTOC_SYM_PAUSE); + break; + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= (IXGBE_AUTOC_SYM_PAUSE | IXGBE_AUTOC_ASM_PAUSE); + break; +#ifdef CONFIG_DCB + case ixgbe_fc_pfc: + goto out; + break; +#endif /* CONFIG_DCB */ + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = IXGBE_ERR_CONFIG; + goto out; + break; + } + /* + * AUTOC restart handles negotiation of 1G and 10G. There is + * no need to set the PCS1GCTL register. + */ + reg |= IXGBE_AUTOC_AN_RESTART; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg); + hw_dbg(hw, "Set up FC; IXGBE_AUTOC = 0x%08X\n", reg); + out: return ret_val; } @@ -2000,7 +2124,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) while (timeout) { if (ixgbe_get_eeprom_semaphore(hw)) - return -IXGBE_ERR_SWFW_SYNC; + return IXGBE_ERR_SWFW_SYNC; gssr = IXGBE_READ_REG(hw, IXGBE_GSSR); if (!(gssr & (fwmask | swmask))) @@ -2017,7 +2141,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) if (!timeout) { hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n"); - return -IXGBE_ERR_SWFW_SYNC; + return IXGBE_ERR_SWFW_SYNC; } gssr |= swmask; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 53b0a668025..fa314cb005a 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -53,6 +53,10 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"tx_packets", IXGBE_STAT(net_stats.tx_packets)}, {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)}, {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)}, + {"rx_pkts_nic", IXGBE_STAT(stats.gprc)}, + {"tx_pkts_nic", IXGBE_STAT(stats.gptc)}, + {"rx_bytes_nic", IXGBE_STAT(stats.gorc)}, + {"tx_bytes_nic", IXGBE_STAT(stats.gotc)}, {"lsc_int", IXGBE_STAT(lsc_int)}, {"tx_busy", IXGBE_STAT(tx_busy)}, {"non_eop_descs", IXGBE_STAT(non_eop_descs)}, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index c407bd9de0d..28fbb9d281f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -49,7 +49,7 @@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; -#define DRV_VERSION "2.0.37-k2" +#define DRV_VERSION "2.0.44-k2" const char ixgbe_driver_version[] = DRV_VERSION; static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation."; @@ -1885,12 +1885,29 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); adapter->tx_ring[i].head = IXGBE_TDH(j); adapter->tx_ring[i].tail = IXGBE_TDT(j); - /* Disable Tx Head Writeback RO bit, since this hoses + /* + * Disable Tx Head Writeback RO bit, since this hoses * bookkeeping if things aren't delivered in order. */ - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); + break; + case ixgbe_mac_82599EB: + default: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); + break; + } txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); + break; + case ixgbe_mac_82599EB: + default: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); + break; + } } if (hw->mac.type == ixgbe_mac_82599EB) { /* We enable 8 traffic classes, DCB only */ @@ -4432,10 +4449,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) /* 82598 hardware only has a 32 bit counter in the high register */ if (hw->mac.type == ixgbe_mac_82599EB) { + u64 tmp; adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); - IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */ + tmp = IXGBE_READ_REG(hw, IXGBE_GORCH) & 0xF; /* 4 high bits of GORC */ + adapter->stats.gorc += (tmp << 32); adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); - IXGBE_READ_REG(hw, IXGBE_GOTCH); /* to clear */ + tmp = IXGBE_READ_REG(hw, IXGBE_GOTCH) & 0xF; /* 4 high bits of GOTC */ + adapter->stats.gotc += (tmp << 32); adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL); IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); @@ -5071,7 +5091,6 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, /* Right now, we support IPv4 only */ struct ixgbe_atr_input atr_input; struct tcphdr *th; - struct udphdr *uh; struct iphdr *iph = ip_hdr(skb); struct ethhdr *eth = (struct ethhdr *)skb->data; u16 vlan_id, src_port, dst_port, flex_bytes; @@ -5085,12 +5104,6 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, dst_port = th->dest; l4type |= IXGBE_ATR_L4TYPE_TCP; /* l4type IPv4 type is 0, no need to assign */ - } else if(iph->protocol == IPPROTO_UDP) { - uh = udp_hdr(skb); - src_port = uh->source; - dst_port = uh->dest; - l4type |= IXGBE_ATR_L4TYPE_UDP; - /* l4type IPv4 type is 0, no need to assign */ } else { /* Unsupported L4 header, just bail here */ return; @@ -5494,12 +5507,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_pci_reg; } - err = pci_enable_pcie_error_reporting(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " - "0x%x\n", err); - /* non-fatal, continue */ - } + pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); pci_save_state(pdev); @@ -5808,7 +5816,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbe_adapter *adapter = netdev_priv(netdev); - int err; set_bit(__IXGBE_DOWN, &adapter->state); /* clear the module not found bit to make sure the worker won't @@ -5859,10 +5866,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) free_netdev(netdev); - err = pci_disable_pcie_error_reporting(pdev); - if (err) - dev_err(&pdev->dev, - "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 8761d7899f7..7c93e923bf2 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1336,6 +1336,8 @@ #define IXGBE_AUTOC_KX4_SUPP 0x80000000 #define IXGBE_AUTOC_KX_SUPP 0x40000000 #define IXGBE_AUTOC_PAUSE 0x30000000 +#define IXGBE_AUTOC_ASM_PAUSE 0x20000000 +#define IXGBE_AUTOC_SYM_PAUSE 0x10000000 #define IXGBE_AUTOC_RF 0x08000000 #define IXGBE_AUTOC_PD_TMR 0x06000000 #define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000 @@ -1404,6 +1406,8 @@ #define IXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ #define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define IXGBE_LINKS2_AN_SUPPORTED 0x00000040 + /* PCS1GLSTA Bit Masks */ #define IXGBE_PCS1GLSTA_LINK_OK 1 #define IXGBE_PCS1GLSTA_SYNK_OK 0x10 @@ -1424,6 +1428,11 @@ #define IXGBE_PCS1GLCTL_AN_ENABLE 0x10000 #define IXGBE_PCS1GLCTL_AN_RESTART 0x20000 +/* ANLP1 Bit Masks */ +#define IXGBE_ANLP1_PAUSE 0x0C00 +#define IXGBE_ANLP1_SYM_PAUSE 0x0400 +#define IXGBE_ANLP1_ASM_PAUSE 0x0800 + /* SW Semaphore Register bitmasks */ #define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ #define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c new file mode 100644 index 00000000000..0be14d702be --- /dev/null +++ b/drivers/net/ks8851_mll.c @@ -0,0 +1,1697 @@ +/** + * drivers/net/ks8851_mll.c + * Copyright (c) 2009 Micrel Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +/** + * Supports: + * KS8851 16bit MLL chip from Micrel Inc. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/cache.h> +#include <linux/crc32.h> +#include <linux/mii.h> +#include <linux/platform_device.h> +#include <linux/delay.h> + +#define DRV_NAME "ks8851_mll" + +static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x86, 0x95, 0x11 }; +#define MAX_RECV_FRAMES 32 +#define MAX_BUF_SIZE 2048 +#define TX_BUF_SIZE 2000 +#define RX_BUF_SIZE 2000 + +#define KS_CCR 0x08 +#define CCR_EEPROM (1 << 9) +#define CCR_SPI (1 << 8) +#define CCR_8BIT (1 << 7) +#define CCR_16BIT (1 << 6) +#define CCR_32BIT (1 << 5) +#define CCR_SHARED (1 << 4) +#define CCR_32PIN (1 << 0) + +/* MAC address registers */ +#define KS_MARL 0x10 +#define KS_MARM 0x12 +#define KS_MARH 0x14 + +#define KS_OBCR 0x20 +#define OBCR_ODS_16MA (1 << 6) + +#define KS_EEPCR 0x22 +#define EEPCR_EESA (1 << 4) +#define EEPCR_EESB (1 << 3) +#define EEPCR_EEDO (1 << 2) +#define EEPCR_EESCK (1 << 1) +#define EEPCR_EECS (1 << 0) + +#define KS_MBIR 0x24 +#define MBIR_TXMBF (1 << 12) +#define MBIR_TXMBFA (1 << 11) +#define MBIR_RXMBF (1 << 4) +#define MBIR_RXMBFA (1 << 3) + +#define KS_GRR 0x26 +#define GRR_QMU (1 << 1) +#define GRR_GSR (1 << 0) + +#define KS_WFCR 0x2A +#define WFCR_MPRXE (1 << 7) +#define WFCR_WF3E (1 << 3) +#define WFCR_WF2E (1 << 2) +#define WFCR_WF1E (1 << 1) +#define WFCR_WF0E (1 << 0) + +#define KS_WF0CRC0 0x30 +#define KS_WF0CRC1 0x32 +#define KS_WF0BM0 0x34 +#define KS_WF0BM1 0x36 +#define KS_WF0BM2 0x38 +#define KS_WF0BM3 0x3A + +#define KS_WF1CRC0 0x40 +#define KS_WF1CRC1 0x42 +#define KS_WF1BM0 0x44 +#define KS_WF1BM1 0x46 +#define KS_WF1BM2 0x48 +#define KS_WF1BM3 0x4A + +#define KS_WF2CRC0 0x50 +#define KS_WF2CRC1 0x52 +#define KS_WF2BM0 0x54 +#define KS_WF2BM1 0x56 +#define KS_WF2BM2 0x58 +#define KS_WF2BM3 0x5A + +#define KS_WF3CRC0 0x60 +#define KS_WF3CRC1 0x62 +#define KS_WF3BM0 0x64 +#define KS_WF3BM1 0x66 +#define KS_WF3BM2 0x68 +#define KS_WF3BM3 0x6A + +#define KS_TXCR 0x70 +#define TXCR_TCGICMP (1 << 8) +#define TXCR_TCGUDP (1 << 7) +#define TXCR_TCGTCP (1 << 6) +#define TXCR_TCGIP (1 << 5) +#define TXCR_FTXQ (1 << 4) +#define TXCR_TXFCE (1 << 3) +#define TXCR_TXPE (1 << 2) +#define TXCR_TXCRC (1 << 1) +#define TXCR_TXE (1 << 0) + +#define KS_TXSR 0x72 +#define TXSR_TXLC (1 << 13) +#define TXSR_TXMC (1 << 12) +#define TXSR_TXFID_MASK (0x3f << 0) +#define TXSR_TXFID_SHIFT (0) +#define TXSR_TXFID_GET(_v) (((_v) >> 0) & 0x3f) + + +#define KS_RXCR1 0x74 +#define RXCR1_FRXQ (1 << 15) +#define RXCR1_RXUDPFCC (1 << 14) +#define RXCR1_RXTCPFCC (1 << 13) +#define RXCR1_RXIPFCC (1 << 12) +#define RXCR1_RXPAFMA (1 << 11) +#define RXCR1_RXFCE (1 << 10) +#define RXCR1_RXEFE (1 << 9) +#define RXCR1_RXMAFMA (1 << 8) +#define RXCR1_RXBE (1 << 7) +#define RXCR1_RXME (1 << 6) +#define RXCR1_RXUE (1 << 5) +#define RXCR1_RXAE (1 << 4) +#define RXCR1_RXINVF (1 << 1) +#define RXCR1_RXE (1 << 0) +#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \ + RXCR1_RXMAFMA | RXCR1_RXPAFMA) + +#define KS_RXCR2 0x76 +#define RXCR2_SRDBL_MASK (0x7 << 5) +#define RXCR2_SRDBL_SHIFT (5) +#define RXCR2_SRDBL_4B (0x0 << 5) +#define RXCR2_SRDBL_8B (0x1 << 5) +#define RXCR2_SRDBL_16B (0x2 << 5) +#define RXCR2_SRDBL_32B (0x3 << 5) +/* #define RXCR2_SRDBL_FRAME (0x4 << 5) */ +#define RXCR2_IUFFP (1 << 4) +#define RXCR2_RXIUFCEZ (1 << 3) +#define RXCR2_UDPLFE (1 << 2) +#define RXCR2_RXICMPFCC (1 << 1) +#define RXCR2_RXSAF (1 << 0) + +#define KS_TXMIR 0x78 + +#define KS_RXFHSR 0x7C +#define RXFSHR_RXFV (1 << 15) +#define RXFSHR_RXICMPFCS (1 << 13) +#define RXFSHR_RXIPFCS (1 << 12) +#define RXFSHR_RXTCPFCS (1 << 11) +#define RXFSHR_RXUDPFCS (1 << 10) +#define RXFSHR_RXBF (1 << 7) +#define RXFSHR_RXMF (1 << 6) +#define RXFSHR_RXUF (1 << 5) +#define RXFSHR_RXMR (1 << 4) +#define RXFSHR_RXFT (1 << 3) +#define RXFSHR_RXFTL (1 << 2) +#define RXFSHR_RXRF (1 << 1) +#define RXFSHR_RXCE (1 << 0) +#define RXFSHR_ERR (RXFSHR_RXCE | RXFSHR_RXRF |\ + RXFSHR_RXFTL | RXFSHR_RXMR |\ + RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\ + RXFSHR_RXTCPFCS) +#define KS_RXFHBCR 0x7E +#define RXFHBCR_CNT_MASK 0x0FFF + +#define KS_TXQCR 0x80 +#define TXQCR_AETFE (1 << 2) +#define TXQCR_TXQMAM (1 << 1) +#define TXQCR_METFE (1 << 0) + +#define KS_RXQCR 0x82 +#define RXQCR_RXDTTS (1 << 12) +#define RXQCR_RXDBCTS (1 << 11) +#define RXQCR_RXFCTS (1 << 10) +#define RXQCR_RXIPHTOE (1 << 9) +#define RXQCR_RXDTTE (1 << 7) +#define RXQCR_RXDBCTE (1 << 6) +#define RXQCR_RXFCTE (1 << 5) +#define RXQCR_ADRFE (1 << 4) +#define RXQCR_SDA (1 << 3) +#define RXQCR_RRXEF (1 << 0) +#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE) + +#define KS_TXFDPR 0x84 +#define TXFDPR_TXFPAI (1 << 14) +#define TXFDPR_TXFP_MASK (0x7ff << 0) +#define TXFDPR_TXFP_SHIFT (0) + +#define KS_RXFDPR 0x86 +#define RXFDPR_RXFPAI (1 << 14) + +#define KS_RXDTTR 0x8C +#define KS_RXDBCTR 0x8E + +#define KS_IER 0x90 +#define KS_ISR 0x92 +#define IRQ_LCI (1 << 15) +#define IRQ_TXI (1 << 14) +#define IRQ_RXI (1 << 13) +#define IRQ_RXOI (1 << 11) +#define IRQ_TXPSI (1 << 9) +#define IRQ_RXPSI (1 << 8) +#define IRQ_TXSAI (1 << 6) +#define IRQ_RXWFDI (1 << 5) +#define IRQ_RXMPDI (1 << 4) +#define IRQ_LDI (1 << 3) +#define IRQ_EDI (1 << 2) +#define IRQ_SPIBEI (1 << 1) +#define IRQ_DEDI (1 << 0) + +#define KS_RXFCTR 0x9C +#define RXFCTR_THRESHOLD_MASK 0x00FF + +#define KS_RXFC 0x9D +#define RXFCTR_RXFC_MASK (0xff << 8) +#define RXFCTR_RXFC_SHIFT (8) +#define RXFCTR_RXFC_GET(_v) (((_v) >> 8) & 0xff) +#define RXFCTR_RXFCT_MASK (0xff << 0) +#define RXFCTR_RXFCT_SHIFT (0) + +#define KS_TXNTFSR 0x9E + +#define KS_MAHTR0 0xA0 +#define KS_MAHTR1 0xA2 +#define KS_MAHTR2 0xA4 +#define KS_MAHTR3 0xA6 + +#define KS_FCLWR 0xB0 +#define KS_FCHWR 0xB2 +#define KS_FCOWR 0xB4 + +#define KS_CIDER 0xC0 +#define CIDER_ID 0x8870 +#define CIDER_REV_MASK (0x7 << 1) +#define CIDER_REV_SHIFT (1) +#define CIDER_REV_GET(_v) (((_v) >> 1) & 0x7) + +#define KS_CGCR 0xC6 +#define KS_IACR 0xC8 +#define IACR_RDEN (1 << 12) +#define IACR_TSEL_MASK (0x3 << 10) +#define IACR_TSEL_SHIFT (10) +#define IACR_TSEL_MIB (0x3 << 10) +#define IACR_ADDR_MASK (0x1f << 0) +#define IACR_ADDR_SHIFT (0) + +#define KS_IADLR 0xD0 +#define KS_IAHDR 0xD2 + +#define KS_PMECR 0xD4 +#define PMECR_PME_DELAY (1 << 14) +#define PMECR_PME_POL (1 << 12) +#define PMECR_WOL_WAKEUP (1 << 11) +#define PMECR_WOL_MAGICPKT (1 << 10) +#define PMECR_WOL_LINKUP (1 << 9) +#define PMECR_WOL_ENERGY (1 << 8) +#define PMECR_AUTO_WAKE_EN (1 << 7) +#define PMECR_WAKEUP_NORMAL (1 << 6) +#define PMECR_WKEVT_MASK (0xf << 2) +#define PMECR_WKEVT_SHIFT (2) +#define PMECR_WKEVT_GET(_v) (((_v) >> 2) & 0xf) +#define PMECR_WKEVT_ENERGY (0x1 << 2) +#define PMECR_WKEVT_LINK (0x2 << 2) +#define PMECR_WKEVT_MAGICPKT (0x4 << 2) +#define PMECR_WKEVT_FRAME (0x8 << 2) +#define PMECR_PM_MASK (0x3 << 0) +#define PMECR_PM_SHIFT (0) +#define PMECR_PM_NORMAL (0x0 << 0) +#define PMECR_PM_ENERGY (0x1 << 0) +#define PMECR_PM_SOFTDOWN (0x2 << 0) +#define PMECR_PM_POWERSAVE (0x3 << 0) + +/* Standard MII PHY data */ +#define KS_P1MBCR 0xE4 +#define P1MBCR_FORCE_FDX (1 << 8) + +#define KS_P1MBSR 0xE6 +#define P1MBSR_AN_COMPLETE (1 << 5) +#define P1MBSR_AN_CAPABLE (1 << 3) +#define P1MBSR_LINK_UP (1 << 2) + +#define KS_PHY1ILR 0xE8 +#define KS_PHY1IHR 0xEA +#define KS_P1ANAR 0xEC +#define KS_P1ANLPR 0xEE + +#define KS_P1SCLMD 0xF4 +#define P1SCLMD_LEDOFF (1 << 15) +#define P1SCLMD_TXIDS (1 << 14) +#define P1SCLMD_RESTARTAN (1 << 13) +#define P1SCLMD_DISAUTOMDIX (1 << 10) +#define P1SCLMD_FORCEMDIX (1 << 9) +#define P1SCLMD_AUTONEGEN (1 << 7) +#define P1SCLMD_FORCE100 (1 << 6) +#define P1SCLMD_FORCEFDX (1 << 5) +#define P1SCLMD_ADV_FLOW (1 << 4) +#define P1SCLMD_ADV_100BT_FDX (1 << 3) +#define P1SCLMD_ADV_100BT_HDX (1 << 2) +#define P1SCLMD_ADV_10BT_FDX (1 << 1) +#define P1SCLMD_ADV_10BT_HDX (1 << 0) + +#define KS_P1CR 0xF6 +#define P1CR_HP_MDIX (1 << 15) +#define P1CR_REV_POL (1 << 13) +#define P1CR_OP_100M (1 << 10) +#define P1CR_OP_FDX (1 << 9) +#define P1CR_OP_MDI (1 << 7) +#define P1CR_AN_DONE (1 << 6) +#define P1CR_LINK_GOOD (1 << 5) +#define P1CR_PNTR_FLOW (1 << 4) +#define P1CR_PNTR_100BT_FDX (1 << 3) +#define P1CR_PNTR_100BT_HDX (1 << 2) +#define P1CR_PNTR_10BT_FDX (1 << 1) +#define P1CR_PNTR_10BT_HDX (1 << 0) + +/* TX Frame control */ + +#define TXFR_TXIC (1 << 15) +#define TXFR_TXFID_MASK (0x3f << 0) +#define TXFR_TXFID_SHIFT (0) + +#define KS_P1SR 0xF8 +#define P1SR_HP_MDIX (1 << 15) +#define P1SR_REV_POL (1 << 13) +#define P1SR_OP_100M (1 << 10) +#define P1SR_OP_FDX (1 << 9) +#define P1SR_OP_MDI (1 << 7) +#define P1SR_AN_DONE (1 << 6) +#define P1SR_LINK_GOOD (1 << 5) +#define P1SR_PNTR_FLOW (1 << 4) +#define P1SR_PNTR_100BT_FDX (1 << 3) +#define P1SR_PNTR_100BT_HDX (1 << 2) +#define P1SR_PNTR_10BT_FDX (1 << 1) +#define P1SR_PNTR_10BT_HDX (1 << 0) + +#define ENUM_BUS_NONE 0 +#define ENUM_BUS_8BIT 1 +#define ENUM_BUS_16BIT 2 +#define ENUM_BUS_32BIT 3 + +#define MAX_MCAST_LST 32 +#define HW_MCAST_SIZE 8 +#define MAC_ADDR_LEN 6 + +/** + * union ks_tx_hdr - tx header data + * @txb: The header as bytes + * @txw: The header as 16bit, little-endian words + * + * A dual representation of the tx header data to allow + * access to individual bytes, and to allow 16bit accesses + * with 16bit alignment. + */ +union ks_tx_hdr { + u8 txb[4]; + __le16 txw[2]; +}; + +/** + * struct ks_net - KS8851 driver private data + * @net_device : The network device we're bound to + * @hw_addr : start address of data register. + * @hw_addr_cmd : start address of command register. + * @txh : temporaly buffer to save status/length. + * @lock : Lock to ensure that the device is not accessed when busy. + * @pdev : Pointer to platform device. + * @mii : The MII state information for the mii calls. + * @frame_head_info : frame header information for multi-pkt rx. + * @statelock : Lock on this structure for tx list. + * @msg_enable : The message flags controlling driver output (see ethtool). + * @frame_cnt : number of frames received. + * @bus_width : i/o bus width. + * @irq : irq number assigned to this device. + * @rc_rxqcr : Cached copy of KS_RXQCR. + * @rc_txcr : Cached copy of KS_TXCR. + * @rc_ier : Cached copy of KS_IER. + * @sharedbus : Multipex(addr and data bus) mode indicator. + * @cmd_reg_cache : command register cached. + * @cmd_reg_cache_int : command register cached. Used in the irq handler. + * @promiscuous : promiscuous mode indicator. + * @all_mcast : mutlicast indicator. + * @mcast_lst_size : size of multicast list. + * @mcast_lst : multicast list. + * @mcast_bits : multicast enabed. + * @mac_addr : MAC address assigned to this device. + * @fid : frame id. + * @extra_byte : number of extra byte prepended rx pkt. + * @enabled : indicator this device works. + * + * The @lock ensures that the chip is protected when certain operations are + * in progress. When the read or write packet transfer is in progress, most + * of the chip registers are not accessible until the transfer is finished and + * the DMA has been de-asserted. + * + * The @statelock is used to protect information in the structure which may + * need to be accessed via several sources, such as the network driver layer + * or one of the work queues. + * + */ + +/* Receive multiplex framer header info */ +struct type_frame_head { + u16 sts; /* Frame status */ + u16 len; /* Byte count */ +}; + +struct ks_net { + struct net_device *netdev; + void __iomem *hw_addr; + void __iomem *hw_addr_cmd; + union ks_tx_hdr txh ____cacheline_aligned; + struct mutex lock; /* spinlock to be interrupt safe */ + struct platform_device *pdev; + struct mii_if_info mii; + struct type_frame_head *frame_head_info; + spinlock_t statelock; + u32 msg_enable; + u32 frame_cnt; + int bus_width; + int irq; + + u16 rc_rxqcr; + u16 rc_txcr; + u16 rc_ier; + u16 sharedbus; + u16 cmd_reg_cache; + u16 cmd_reg_cache_int; + u16 promiscuous; + u16 all_mcast; + u16 mcast_lst_size; + u8 mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN]; + u8 mcast_bits[HW_MCAST_SIZE]; + u8 mac_addr[6]; + u8 fid; + u8 extra_byte; + u8 enabled; +}; + +static int msg_enable; + +#define ks_info(_ks, _msg...) dev_info(&(_ks)->pdev->dev, _msg) +#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->pdev->dev, _msg) +#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg) +#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg) + +#define BE3 0x8000 /* Byte Enable 3 */ +#define BE2 0x4000 /* Byte Enable 2 */ +#define BE1 0x2000 /* Byte Enable 1 */ +#define BE0 0x1000 /* Byte Enable 0 */ + +/** + * register read/write calls. + * + * All these calls issue transactions to access the chip's registers. They + * all require that the necessary lock is held to prevent accesses when the + * chip is busy transfering packet data (RX/TX FIFO accesses). + */ + +/** + * ks_rdreg8 - read 8 bit register from device + * @ks : The chip information + * @offset: The register address + * + * Read a 8bit register from the chip, returning the result + */ +static u8 ks_rdreg8(struct ks_net *ks, int offset) +{ + u16 data; + u8 shift_bit = offset & 0x03; + u8 shift_data = (offset & 1) << 3; + ks->cmd_reg_cache = (u16) offset | (u16)(BE0 << shift_bit); + iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); + data = ioread16(ks->hw_addr); + return (u8)(data >> shift_data); +} + +/** + * ks_rdreg16 - read 16 bit register from device + * @ks : The chip information + * @offset: The register address + * + * Read a 16bit register from the chip, returning the result + */ + +static u16 ks_rdreg16(struct ks_net *ks, int offset) +{ + ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02)); + iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); + return ioread16(ks->hw_addr); +} + +/** + * ks_wrreg8 - write 8bit register value to chip + * @ks: The chip information + * @offset: The register address + * @value: The value to write + * + */ +static void ks_wrreg8(struct ks_net *ks, int offset, u8 value) +{ + u8 shift_bit = (offset & 0x03); + u16 value_write = (u16)(value << ((offset & 1) << 3)); + ks->cmd_reg_cache = (u16)offset | (BE0 << shift_bit); + iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); + iowrite16(value_write, ks->hw_addr); +} + +/** + * ks_wrreg16 - write 16bit register value to chip + * @ks: The chip information + * @offset: The register address + * @value: The value to write + * + */ + +static void ks_wrreg16(struct ks_net *ks, int offset, u16 value) +{ + ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02)); + iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); + iowrite16(value, ks->hw_addr); +} + +/** + * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode enabled. + * @ks: The chip state + * @wptr: buffer address to save data + * @len: length in byte to read + * + */ +static inline void ks_inblk(struct ks_net *ks, u16 *wptr, u32 len) +{ + len >>= 1; + while (len--) + *wptr++ = (u16)ioread16(ks->hw_addr); +} + +/** + * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled. + * @ks: The chip information + * @wptr: buffer address + * @len: length in byte to write + * + */ +static inline void ks_outblk(struct ks_net *ks, u16 *wptr, u32 len) +{ + len >>= 1; + while (len--) + iowrite16(*wptr++, ks->hw_addr); +} + +/** + * ks_tx_fifo_space - return the available hardware buffer size. + * @ks: The chip information + * + */ +static inline u16 ks_tx_fifo_space(struct ks_net *ks) +{ + return ks_rdreg16(ks, KS_TXMIR) & 0x1fff; +} + +/** + * ks_save_cmd_reg - save the command register from the cache. + * @ks: The chip information + * + */ +static inline void ks_save_cmd_reg(struct ks_net *ks) +{ + /*ks8851 MLL has a bug to read back the command register. + * So rely on software to save the content of command register. + */ + ks->cmd_reg_cache_int = ks->cmd_reg_cache; +} + +/** + * ks_restore_cmd_reg - restore the command register from the cache and + * write to hardware register. + * @ks: The chip information + * + */ +static inline void ks_restore_cmd_reg(struct ks_net *ks) +{ + ks->cmd_reg_cache = ks->cmd_reg_cache_int; + iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd); +} + +/** + * ks_set_powermode - set power mode of the device + * @ks: The chip information + * @pwrmode: The power mode value to write to KS_PMECR. + * + * Change the power mode of the chip. + */ +static void ks_set_powermode(struct ks_net *ks, unsigned pwrmode) +{ + unsigned pmecr; + + if (netif_msg_hw(ks)) + ks_dbg(ks, "setting power mode %d\n", pwrmode); + + ks_rdreg16(ks, KS_GRR); + pmecr = ks_rdreg16(ks, KS_PMECR); + pmecr &= ~PMECR_PM_MASK; + pmecr |= pwrmode; + + ks_wrreg16(ks, KS_PMECR, pmecr); +} + +/** + * ks_read_config - read chip configuration of bus width. + * @ks: The chip information + * + */ +static void ks_read_config(struct ks_net *ks) +{ + u16 reg_data = 0; + + /* Regardless of bus width, 8 bit read should always work.*/ + reg_data = ks_rdreg8(ks, KS_CCR) & 0x00FF; + reg_data |= ks_rdreg8(ks, KS_CCR+1) << 8; + + /* addr/data bus are multiplexed */ + ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED; + + /* There are garbage data when reading data from QMU, + depending on bus-width. + */ + + if (reg_data & CCR_8BIT) { + ks->bus_width = ENUM_BUS_8BIT; + ks->extra_byte = 1; + } else if (reg_data & CCR_16BIT) { + ks->bus_width = ENUM_BUS_16BIT; + ks->extra_byte = 2; + } else { + ks->bus_width = ENUM_BUS_32BIT; + ks->extra_byte = 4; + } +} + +/** + * ks_soft_reset - issue one of the soft reset to the device + * @ks: The device state. + * @op: The bit(s) to set in the GRR + * + * Issue the relevant soft-reset command to the device's GRR register + * specified by @op. + * + * Note, the delays are in there as a caution to ensure that the reset + * has time to take effect and then complete. Since the datasheet does + * not currently specify the exact sequence, we have chosen something + * that seems to work with our device. + */ +static void ks_soft_reset(struct ks_net *ks, unsigned op) +{ + /* Disable interrupt first */ + ks_wrreg16(ks, KS_IER, 0x0000); + ks_wrreg16(ks, KS_GRR, op); + mdelay(10); /* wait a short time to effect reset */ + ks_wrreg16(ks, KS_GRR, 0); + mdelay(1); /* wait for condition to clear */ +} + + +/** + * ks_read_qmu - read 1 pkt data from the QMU. + * @ks: The chip information + * @buf: buffer address to save 1 pkt + * @len: Pkt length + * Here is the sequence to read 1 pkt: + * 1. set sudo DMA mode + * 2. read prepend data + * 3. read pkt data + * 4. reset sudo DMA Mode + */ +static inline void ks_read_qmu(struct ks_net *ks, u16 *buf, u32 len) +{ + u32 r = ks->extra_byte & 0x1 ; + u32 w = ks->extra_byte - r; + + /* 1. set sudo DMA mode */ + ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI); + ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + + /* 2. read prepend data */ + /** + * read 4 + extra bytes and discard them. + * extra bytes for dummy, 2 for status, 2 for len + */ + + /* use likely(r) for 8 bit access for performance */ + if (unlikely(r)) + ioread8(ks->hw_addr); + ks_inblk(ks, buf, w + 2 + 2); + + /* 3. read pkt data */ + ks_inblk(ks, buf, ALIGN(len, 4)); + + /* 4. reset sudo DMA Mode */ + ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr); +} + +/** + * ks_rcv - read multiple pkts data from the QMU. + * @ks: The chip information + * @netdev: The network device being opened. + * + * Read all of header information before reading pkt content. + * It is not allowed only port of pkts in QMU after issuing + * interrupt ack. + */ +static void ks_rcv(struct ks_net *ks, struct net_device *netdev) +{ + u32 i; + struct type_frame_head *frame_hdr = ks->frame_head_info; + struct sk_buff *skb; + + ks->frame_cnt = ks_rdreg16(ks, KS_RXFCTR) >> 8; + + /* read all header information */ + for (i = 0; i < ks->frame_cnt; i++) { + /* Checking Received packet status */ + frame_hdr->sts = ks_rdreg16(ks, KS_RXFHSR); + /* Get packet len from hardware */ + frame_hdr->len = ks_rdreg16(ks, KS_RXFHBCR); + frame_hdr++; + } + + frame_hdr = ks->frame_head_info; + while (ks->frame_cnt--) { + skb = dev_alloc_skb(frame_hdr->len + 16); + if (likely(skb && (frame_hdr->sts & RXFSHR_RXFV) && + (frame_hdr->len < RX_BUF_SIZE) && frame_hdr->len)) { + skb_reserve(skb, 2); + /* read data block including CRC 4 bytes */ + ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len + 4); + skb_put(skb, frame_hdr->len); + skb->dev = netdev; + skb->protocol = eth_type_trans(skb, netdev); + netif_rx(skb); + } else { + printk(KERN_ERR "%s: err:skb alloc\n", __func__); + ks_wrreg16(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF)); + if (skb) + dev_kfree_skb_irq(skb); + } + frame_hdr++; + } +} + +/** + * ks_update_link_status - link status update. + * @netdev: The network device being opened. + * @ks: The chip information + * + */ + +static void ks_update_link_status(struct net_device *netdev, struct ks_net *ks) +{ + /* check the status of the link */ + u32 link_up_status; + if (ks_rdreg16(ks, KS_P1SR) & P1SR_LINK_GOOD) { + netif_carrier_on(netdev); + link_up_status = true; + } else { + netif_carrier_off(netdev); + link_up_status = false; + } + if (netif_msg_link(ks)) + ks_dbg(ks, "%s: %s\n", + __func__, link_up_status ? "UP" : "DOWN"); +} + +/** + * ks_irq - device interrupt handler + * @irq: Interrupt number passed from the IRQ hnalder. + * @pw: The private word passed to register_irq(), our struct ks_net. + * + * This is the handler invoked to find out what happened + * + * Read the interrupt status, work out what needs to be done and then clear + * any of the interrupts that are not needed. + */ + +static irqreturn_t ks_irq(int irq, void *pw) +{ + struct ks_net *ks = pw; + struct net_device *netdev = ks->netdev; + u16 status; + + /*this should be the first in IRQ handler */ + ks_save_cmd_reg(ks); + + status = ks_rdreg16(ks, KS_ISR); + if (unlikely(!status)) { + ks_restore_cmd_reg(ks); + return IRQ_NONE; + } + + ks_wrreg16(ks, KS_ISR, status); + + if (likely(status & IRQ_RXI)) + ks_rcv(ks, netdev); + + if (unlikely(status & IRQ_LCI)) + ks_update_link_status(netdev, ks); + + if (unlikely(status & IRQ_TXI)) + netif_wake_queue(netdev); + + if (unlikely(status & IRQ_LDI)) { + + u16 pmecr = ks_rdreg16(ks, KS_PMECR); + pmecr &= ~PMECR_WKEVT_MASK; + ks_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK); + } + + /* this should be the last in IRQ handler*/ + ks_restore_cmd_reg(ks); + return IRQ_HANDLED; +} + + +/** + * ks_net_open - open network device + * @netdev: The network device being opened. + * + * Called when the network device is marked active, such as a user executing + * 'ifconfig up' on the device. + */ +static int ks_net_open(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + int err; + +#define KS_INT_FLAGS (IRQF_DISABLED|IRQF_TRIGGER_LOW) + /* lock the card, even if we may not actually do anything + * else at the moment. + */ + + if (netif_msg_ifup(ks)) + ks_dbg(ks, "%s - entry\n", __func__); + + /* reset the HW */ + err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, ks); + + if (err) { + printk(KERN_ERR "Failed to request IRQ: %d: %d\n", + ks->irq, err); + return err; + } + + if (netif_msg_ifup(ks)) + ks_dbg(ks, "network device %s up\n", netdev->name); + + return 0; +} + +/** + * ks_net_stop - close network device + * @netdev: The device being closed. + * + * Called to close down a network device which has been active. Cancell any + * work, shutdown the RX and TX process and then place the chip into a low + * power state whilst it is not being used. + */ +static int ks_net_stop(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + + if (netif_msg_ifdown(ks)) + ks_info(ks, "%s: shutting down\n", netdev->name); + + netif_stop_queue(netdev); + + kfree(ks->frame_head_info); + + mutex_lock(&ks->lock); + + /* turn off the IRQs and ack any outstanding */ + ks_wrreg16(ks, KS_IER, 0x0000); + ks_wrreg16(ks, KS_ISR, 0xffff); + + /* shutdown RX process */ + ks_wrreg16(ks, KS_RXCR1, 0x0000); + + /* shutdown TX process */ + ks_wrreg16(ks, KS_TXCR, 0x0000); + + /* set powermode to soft power down to save power */ + ks_set_powermode(ks, PMECR_PM_SOFTDOWN); + free_irq(ks->irq, netdev); + mutex_unlock(&ks->lock); + return 0; +} + + +/** + * ks_write_qmu - write 1 pkt data to the QMU. + * @ks: The chip information + * @pdata: buffer address to save 1 pkt + * @len: Pkt length in byte + * Here is the sequence to write 1 pkt: + * 1. set sudo DMA mode + * 2. write status/length + * 3. write pkt data + * 4. reset sudo DMA Mode + * 5. reset sudo DMA mode + * 6. Wait until pkt is out + */ +static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) +{ + unsigned fid = ks->fid; + + fid = ks->fid; + ks->fid = (ks->fid + 1) & TXFR_TXFID_MASK; + + /* reduce the tx interrupt occurrances. */ + if (!fid) + fid |= TXFR_TXIC; /* irq on completion */ + + /* start header at txb[0] to align txw entries */ + ks->txh.txw[0] = cpu_to_le16(fid); + ks->txh.txw[1] = cpu_to_le16(len); + + /* 1. set sudo-DMA mode */ + ks_wrreg8(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + /* 2. write status/lenth info */ + ks_outblk(ks, ks->txh.txw, 4); + /* 3. write pkt data */ + ks_outblk(ks, (u16 *)pdata, ALIGN(len, 4)); + /* 4. reset sudo-DMA mode */ + ks_wrreg8(ks, KS_RXQCR, ks->rc_rxqcr); + /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ + ks_wrreg16(ks, KS_TXQCR, TXQCR_METFE); + /* 6. wait until TXQCR_METFE is auto-cleared */ + while (ks_rdreg16(ks, KS_TXQCR) & TXQCR_METFE) + ; +} + +static void ks_disable_int(struct ks_net *ks) +{ + ks_wrreg16(ks, KS_IER, 0x0000); +} /* ks_disable_int */ + +static void ks_enable_int(struct ks_net *ks) +{ + ks_wrreg16(ks, KS_IER, ks->rc_ier); +} /* ks_enable_int */ + +/** + * ks_start_xmit - transmit packet + * @skb : The buffer to transmit + * @netdev : The device used to transmit the packet. + * + * Called by the network layer to transmit the @skb. + * spin_lock_irqsave is required because tx and rx should be mutual exclusive. + * So while tx is in-progress, prevent IRQ interrupt from happenning. + */ +static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + int retv = NETDEV_TX_OK; + struct ks_net *ks = netdev_priv(netdev); + + disable_irq(netdev->irq); + ks_disable_int(ks); + spin_lock(&ks->statelock); + + /* Extra space are required: + * 4 byte for alignment, 4 for status/length, 4 for CRC + */ + + if (likely(ks_tx_fifo_space(ks) >= skb->len + 12)) { + ks_write_qmu(ks, skb->data, skb->len); + dev_kfree_skb(skb); + } else + retv = NETDEV_TX_BUSY; + spin_unlock(&ks->statelock); + ks_enable_int(ks); + enable_irq(netdev->irq); + return retv; +} + +/** + * ks_start_rx - ready to serve pkts + * @ks : The chip information + * + */ +static void ks_start_rx(struct ks_net *ks) +{ + u16 cntl; + + /* Enables QMU Receive (RXCR1). */ + cntl = ks_rdreg16(ks, KS_RXCR1); + cntl |= RXCR1_RXE ; + ks_wrreg16(ks, KS_RXCR1, cntl); +} /* ks_start_rx */ + +/** + * ks_stop_rx - stop to serve pkts + * @ks : The chip information + * + */ +static void ks_stop_rx(struct ks_net *ks) +{ + u16 cntl; + + /* Disables QMU Receive (RXCR1). */ + cntl = ks_rdreg16(ks, KS_RXCR1); + cntl &= ~RXCR1_RXE ; + ks_wrreg16(ks, KS_RXCR1, cntl); + +} /* ks_stop_rx */ + +static unsigned long const ethernet_polynomial = 0x04c11db7U; + +static unsigned long ether_gen_crc(int length, u8 *data) +{ + long crc = -1; + while (--length >= 0) { + u8 current_octet = *data++; + int bit; + + for (bit = 0; bit < 8; bit++, current_octet >>= 1) { + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? + ethernet_polynomial : 0); + } + } + return (unsigned long)crc; +} /* ether_gen_crc */ + +/** +* ks_set_grpaddr - set multicast information +* @ks : The chip information +*/ + +static void ks_set_grpaddr(struct ks_net *ks) +{ + u8 i; + u32 index, position, value; + + memset(ks->mcast_bits, 0, sizeof(u8) * HW_MCAST_SIZE); + + for (i = 0; i < ks->mcast_lst_size; i++) { + position = (ether_gen_crc(6, ks->mcast_lst[i]) >> 26) & 0x3f; + index = position >> 3; + value = 1 << (position & 7); + ks->mcast_bits[index] |= (u8)value; + } + + for (i = 0; i < HW_MCAST_SIZE; i++) { + if (i & 1) { + ks_wrreg16(ks, (u16)((KS_MAHTR0 + i) & ~1), + (ks->mcast_bits[i] << 8) | + ks->mcast_bits[i - 1]); + } + } +} /* ks_set_grpaddr */ + +/* +* ks_clear_mcast - clear multicast information +* +* @ks : The chip information +* This routine removes all mcast addresses set in the hardware. +*/ + +static void ks_clear_mcast(struct ks_net *ks) +{ + u16 i, mcast_size; + for (i = 0; i < HW_MCAST_SIZE; i++) + ks->mcast_bits[i] = 0; + + mcast_size = HW_MCAST_SIZE >> 2; + for (i = 0; i < mcast_size; i++) + ks_wrreg16(ks, KS_MAHTR0 + (2*i), 0); +} + +static void ks_set_promis(struct ks_net *ks, u16 promiscuous_mode) +{ + u16 cntl; + ks->promiscuous = promiscuous_mode; + ks_stop_rx(ks); /* Stop receiving for reconfiguration */ + cntl = ks_rdreg16(ks, KS_RXCR1); + + cntl &= ~RXCR1_FILTER_MASK; + if (promiscuous_mode) + /* Enable Promiscuous mode */ + cntl |= RXCR1_RXAE | RXCR1_RXINVF; + else + /* Disable Promiscuous mode (default normal mode) */ + cntl |= RXCR1_RXPAFMA; + + ks_wrreg16(ks, KS_RXCR1, cntl); + + if (ks->enabled) + ks_start_rx(ks); + +} /* ks_set_promis */ + +static void ks_set_mcast(struct ks_net *ks, u16 mcast) +{ + u16 cntl; + + ks->all_mcast = mcast; + ks_stop_rx(ks); /* Stop receiving for reconfiguration */ + cntl = ks_rdreg16(ks, KS_RXCR1); + cntl &= ~RXCR1_FILTER_MASK; + if (mcast) + /* Enable "Perfect with Multicast address passed mode" */ + cntl |= (RXCR1_RXAE | RXCR1_RXMAFMA | RXCR1_RXPAFMA); + else + /** + * Disable "Perfect with Multicast address passed + * mode" (normal mode). + */ + cntl |= RXCR1_RXPAFMA; + + ks_wrreg16(ks, KS_RXCR1, cntl); + + if (ks->enabled) + ks_start_rx(ks); +} /* ks_set_mcast */ + +static void ks_set_rx_mode(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + struct dev_mc_list *ptr; + + /* Turn on/off promiscuous mode. */ + if ((netdev->flags & IFF_PROMISC) == IFF_PROMISC) + ks_set_promis(ks, + (u16)((netdev->flags & IFF_PROMISC) == IFF_PROMISC)); + /* Turn on/off all mcast mode. */ + else if ((netdev->flags & IFF_ALLMULTI) == IFF_ALLMULTI) + ks_set_mcast(ks, + (u16)((netdev->flags & IFF_ALLMULTI) == IFF_ALLMULTI)); + else + ks_set_promis(ks, false); + + if ((netdev->flags & IFF_MULTICAST) && netdev->mc_count) { + if (netdev->mc_count <= MAX_MCAST_LST) { + int i = 0; + for (ptr = netdev->mc_list; ptr; ptr = ptr->next) { + if (!(*ptr->dmi_addr & 1)) + continue; + if (i >= MAX_MCAST_LST) + break; + memcpy(ks->mcast_lst[i++], ptr->dmi_addr, + MAC_ADDR_LEN); + } + ks->mcast_lst_size = (u8)i; + ks_set_grpaddr(ks); + } else { + /** + * List too big to support so + * turn on all mcast mode. + */ + ks->mcast_lst_size = MAX_MCAST_LST; + ks_set_mcast(ks, true); + } + } else { + ks->mcast_lst_size = 0; + ks_clear_mcast(ks); + } +} /* ks_set_rx_mode */ + +static void ks_set_mac(struct ks_net *ks, u8 *data) +{ + u16 *pw = (u16 *)data; + u16 w, u; + + ks_stop_rx(ks); /* Stop receiving for reconfiguration */ + + u = *pw++; + w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF); + ks_wrreg16(ks, KS_MARH, w); + + u = *pw++; + w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF); + ks_wrreg16(ks, KS_MARM, w); + + u = *pw; + w = ((u & 0xFF) << 8) | ((u >> 8) & 0xFF); + ks_wrreg16(ks, KS_MARL, w); + + memcpy(ks->mac_addr, data, 6); + + if (ks->enabled) + ks_start_rx(ks); +} + +static int ks_set_mac_address(struct net_device *netdev, void *paddr) +{ + struct ks_net *ks = netdev_priv(netdev); + struct sockaddr *addr = paddr; + u8 *da; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + + da = (u8 *)netdev->dev_addr; + + ks_set_mac(ks, da); + return 0; +} + +static int ks_net_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) +{ + struct ks_net *ks = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -EINVAL; + + return generic_mii_ioctl(&ks->mii, if_mii(req), cmd, NULL); +} + +static const struct net_device_ops ks_netdev_ops = { + .ndo_open = ks_net_open, + .ndo_stop = ks_net_stop, + .ndo_do_ioctl = ks_net_ioctl, + .ndo_start_xmit = ks_start_xmit, + .ndo_set_mac_address = ks_set_mac_address, + .ndo_set_rx_mode = ks_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + +/* ethtool support */ + +static void ks_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *di) +{ + strlcpy(di->driver, DRV_NAME, sizeof(di->driver)); + strlcpy(di->version, "1.00", sizeof(di->version)); + strlcpy(di->bus_info, dev_name(netdev->dev.parent), + sizeof(di->bus_info)); +} + +static u32 ks_get_msglevel(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + return ks->msg_enable; +} + +static void ks_set_msglevel(struct net_device *netdev, u32 to) +{ + struct ks_net *ks = netdev_priv(netdev); + ks->msg_enable = to; +} + +static int ks_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct ks_net *ks = netdev_priv(netdev); + return mii_ethtool_gset(&ks->mii, cmd); +} + +static int ks_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +{ + struct ks_net *ks = netdev_priv(netdev); + return mii_ethtool_sset(&ks->mii, cmd); +} + +static u32 ks_get_link(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + return mii_link_ok(&ks->mii); +} + +static int ks_nway_reset(struct net_device *netdev) +{ + struct ks_net *ks = netdev_priv(netdev); + return mii_nway_restart(&ks->mii); +} + +static const struct ethtool_ops ks_ethtool_ops = { + .get_drvinfo = ks_get_drvinfo, + .get_msglevel = ks_get_msglevel, + .set_msglevel = ks_set_msglevel, + .get_settings = ks_get_settings, + .set_settings = ks_set_settings, + .get_link = ks_get_link, + .nway_reset = ks_nway_reset, +}; + +/* MII interface controls */ + +/** + * ks_phy_reg - convert MII register into a KS8851 register + * @reg: MII register number. + * + * Return the KS8851 register number for the corresponding MII PHY register + * if possible. Return zero if the MII register has no direct mapping to the + * KS8851 register set. + */ +static int ks_phy_reg(int reg) +{ + switch (reg) { + case MII_BMCR: + return KS_P1MBCR; + case MII_BMSR: + return KS_P1MBSR; + case MII_PHYSID1: + return KS_PHY1ILR; + case MII_PHYSID2: + return KS_PHY1IHR; + case MII_ADVERTISE: + return KS_P1ANAR; + case MII_LPA: + return KS_P1ANLPR; + } + + return 0x0; +} + +/** + * ks_phy_read - MII interface PHY register read. + * @netdev: The network device the PHY is on. + * @phy_addr: Address of PHY (ignored as we only have one) + * @reg: The register to read. + * + * This call reads data from the PHY register specified in @reg. Since the + * device does not support all the MII registers, the non-existant values + * are always returned as zero. + * + * We return zero for unsupported registers as the MII code does not check + * the value returned for any error status, and simply returns it to the + * caller. The mii-tool that the driver was tested with takes any -ve error + * as real PHY capabilities, thus displaying incorrect data to the user. + */ +static int ks_phy_read(struct net_device *netdev, int phy_addr, int reg) +{ + struct ks_net *ks = netdev_priv(netdev); + int ksreg; + int result; + + ksreg = ks_phy_reg(reg); + if (!ksreg) + return 0x0; /* no error return allowed, so use zero */ + + mutex_lock(&ks->lock); + result = ks_rdreg16(ks, ksreg); + mutex_unlock(&ks->lock); + + return result; +} + +static void ks_phy_write(struct net_device *netdev, + int phy, int reg, int value) +{ + struct ks_net *ks = netdev_priv(netdev); + int ksreg; + + ksreg = ks_phy_reg(reg); + if (ksreg) { + mutex_lock(&ks->lock); + ks_wrreg16(ks, ksreg, value); + mutex_unlock(&ks->lock); + } +} + +/** + * ks_read_selftest - read the selftest memory info. + * @ks: The device state + * + * Read and check the TX/RX memory selftest information. + */ +static int ks_read_selftest(struct ks_net *ks) +{ + unsigned both_done = MBIR_TXMBF | MBIR_RXMBF; + int ret = 0; + unsigned rd; + + rd = ks_rdreg16(ks, KS_MBIR); + + if ((rd & both_done) != both_done) { + ks_warn(ks, "Memory selftest not finished\n"); + return 0; + } + + if (rd & MBIR_TXMBFA) { + ks_err(ks, "TX memory selftest fails\n"); + ret |= 1; + } + + if (rd & MBIR_RXMBFA) { + ks_err(ks, "RX memory selftest fails\n"); + ret |= 2; + } + + ks_info(ks, "the selftest passes\n"); + return ret; +} + +static void ks_disable(struct ks_net *ks) +{ + u16 w; + + w = ks_rdreg16(ks, KS_TXCR); + + /* Disables QMU Transmit (TXCR). */ + w &= ~TXCR_TXE; + ks_wrreg16(ks, KS_TXCR, w); + + /* Disables QMU Receive (RXCR1). */ + w = ks_rdreg16(ks, KS_RXCR1); + w &= ~RXCR1_RXE ; + ks_wrreg16(ks, KS_RXCR1, w); + + ks->enabled = false; + +} /* ks_disable */ + +static void ks_setup(struct ks_net *ks) +{ + u16 w; + + /** + * Configure QMU Transmit + */ + + /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */ + ks_wrreg16(ks, KS_TXFDPR, TXFDPR_TXFPAI); + + /* Setup Receive Frame Data Pointer Auto-Increment */ + ks_wrreg16(ks, KS_RXFDPR, RXFDPR_RXFPAI); + + /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */ + ks_wrreg16(ks, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); + + /* Setup RxQ Command Control (RXQCR) */ + ks->rc_rxqcr = RXQCR_CMD_CNTL; + ks_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); + + /** + * set the force mode to half duplex, default is full duplex + * because if the auto-negotiation fails, most switch uses + * half-duplex. + */ + + w = ks_rdreg16(ks, KS_P1MBCR); + w &= ~P1MBCR_FORCE_FDX; + ks_wrreg16(ks, KS_P1MBCR, w); + + w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP; + ks_wrreg16(ks, KS_TXCR, w); + + w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE; + + if (ks->promiscuous) /* bPromiscuous */ + w |= (RXCR1_RXAE | RXCR1_RXINVF); + else if (ks->all_mcast) /* Multicast address passed mode */ + w |= (RXCR1_RXAE | RXCR1_RXMAFMA | RXCR1_RXPAFMA); + else /* Normal mode */ + w |= RXCR1_RXPAFMA; + + ks_wrreg16(ks, KS_RXCR1, w); +} /*ks_setup */ + + +static void ks_setup_int(struct ks_net *ks) +{ + ks->rc_ier = 0x00; + /* Clear the interrupts status of the hardware. */ + ks_wrreg16(ks, KS_ISR, 0xffff); + + /* Enables the interrupts of the hardware. */ + ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI); +} /* ks_setup_int */ + +void ks_enable(struct ks_net *ks) +{ + u16 w; + + w = ks_rdreg16(ks, KS_TXCR); + /* Enables QMU Transmit (TXCR). */ + ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE); + + /* + * RX Frame Count Threshold Enable and Auto-Dequeue RXQ Frame + * Enable + */ + + w = ks_rdreg16(ks, KS_RXQCR); + ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE); + + /* Enables QMU Receive (RXCR1). */ + w = ks_rdreg16(ks, KS_RXCR1); + ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE); + ks->enabled = true; +} /* ks_enable */ + +static int ks_hw_init(struct ks_net *ks) +{ +#define MHEADER_SIZE (sizeof(struct type_frame_head) * MAX_RECV_FRAMES) + ks->promiscuous = 0; + ks->all_mcast = 0; + ks->mcast_lst_size = 0; + + ks->frame_head_info = (struct type_frame_head *) \ + kmalloc(MHEADER_SIZE, GFP_KERNEL); + if (!ks->frame_head_info) { + printk(KERN_ERR "Error: Fail to allocate frame memory\n"); + return false; + } + + ks_set_mac(ks, KS_DEFAULT_MAC_ADDRESS); + return true; +} + + +static int __devinit ks8851_probe(struct platform_device *pdev) +{ + int err = -ENOMEM; + struct resource *io_d, *io_c; + struct net_device *netdev; + struct ks_net *ks; + u16 id, data; + + io_d = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_c = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + if (!request_mem_region(io_d->start, resource_size(io_d), DRV_NAME)) + goto err_mem_region; + + if (!request_mem_region(io_c->start, resource_size(io_c), DRV_NAME)) + goto err_mem_region1; + + netdev = alloc_etherdev(sizeof(struct ks_net)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + ks = netdev_priv(netdev); + ks->netdev = netdev; + ks->hw_addr = ioremap(io_d->start, resource_size(io_d)); + + if (!ks->hw_addr) + goto err_ioremap; + + ks->hw_addr_cmd = ioremap(io_c->start, resource_size(io_c)); + if (!ks->hw_addr_cmd) + goto err_ioremap1; + + ks->irq = platform_get_irq(pdev, 0); + + if (ks->irq < 0) { + err = ks->irq; + goto err_get_irq; + } + + ks->pdev = pdev; + + mutex_init(&ks->lock); + spin_lock_init(&ks->statelock); + + netdev->netdev_ops = &ks_netdev_ops; + netdev->ethtool_ops = &ks_ethtool_ops; + + /* setup mii state */ + ks->mii.dev = netdev; + ks->mii.phy_id = 1, + ks->mii.phy_id_mask = 1; + ks->mii.reg_num_mask = 0xf; + ks->mii.mdio_read = ks_phy_read; + ks->mii.mdio_write = ks_phy_write; + + ks_info(ks, "message enable is %d\n", msg_enable); + /* set the default message enable */ + ks->msg_enable = netif_msg_init(msg_enable, (NETIF_MSG_DRV | + NETIF_MSG_PROBE | + NETIF_MSG_LINK)); + ks_read_config(ks); + + /* simple check for a valid chip being connected to the bus */ + if ((ks_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) { + ks_err(ks, "failed to read device ID\n"); + err = -ENODEV; + goto err_register; + } + + if (ks_read_selftest(ks)) { + ks_err(ks, "failed to read device ID\n"); + err = -ENODEV; + goto err_register; + } + + err = register_netdev(netdev); + if (err) + goto err_register; + + platform_set_drvdata(pdev, netdev); + + ks_soft_reset(ks, GRR_GSR); + ks_hw_init(ks); + ks_disable(ks); + ks_setup(ks); + ks_setup_int(ks); + ks_enable_int(ks); + ks_enable(ks); + memcpy(netdev->dev_addr, ks->mac_addr, 6); + + data = ks_rdreg16(ks, KS_OBCR); + ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16MA); + + /** + * If you want to use the default MAC addr, + * comment out the 2 functions below. + */ + + random_ether_addr(netdev->dev_addr); + ks_set_mac(ks, netdev->dev_addr); + + id = ks_rdreg16(ks, KS_CIDER); + + printk(KERN_INFO DRV_NAME + " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n", + (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7); + return 0; + +err_register: +err_get_irq: + iounmap(ks->hw_addr_cmd); +err_ioremap1: + iounmap(ks->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + release_mem_region(io_c->start, resource_size(io_c)); +err_mem_region1: + release_mem_region(io_d->start, resource_size(io_d)); +err_mem_region: + return err; +} + +static int __devexit ks8851_remove(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct ks_net *ks = netdev_priv(netdev); + struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + unregister_netdev(netdev); + iounmap(ks->hw_addr); + free_netdev(netdev); + release_mem_region(iomem->start, resource_size(iomem)); + platform_set_drvdata(pdev, NULL); + return 0; + +} + +static struct platform_driver ks8851_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ks8851_probe, + .remove = __devexit_p(ks8851_remove), +}; + +static int __init ks8851_init(void) +{ + return platform_driver_register(&ks8851_platform_driver); +} + +static void __exit ks8851_exit(void) +{ + platform_driver_unregister(&ks8851_platform_driver); +} + +module_init(ks8851_init); +module_exit(ks8851_exit); + +MODULE_DESCRIPTION("KS8851 MLL Network driver"); +MODULE_AUTHOR("David Choi <david.choi@micrel.com>"); +MODULE_LICENSE("GPL"); +module_param_named(message, msg_enable, int, 0); +MODULE_PARM_DESC(message, "Message verbosity level (0=none, 31=all)"); + diff --git a/drivers/net/meth.c b/drivers/net/meth.c index 92ceb689b4d..2af81735386 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -828,7 +828,7 @@ static int __exit meth_remove(struct platform_device *pdev) static struct platform_driver meth_driver = { .probe = meth_probe, - .remove = __devexit_p(meth_remove), + .remove = __exit_p(meth_remove), .driver = { .name = "meth", .owner = THIS_MODULE, diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index cc394d07375..5910df60c93 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2179,7 +2179,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk, * session or the special tunnel type. */ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct pppol2tp_session *session = sk->sk_user_data; diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index a9845a2f243..30d5585beee 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1381,15 +1381,15 @@ struct intr_context { /* adapter flags definitions. */ enum { - QL_ADAPTER_UP = (1 << 0), /* Adapter has been brought up. */ - QL_LEGACY_ENABLED = (1 << 3), - QL_MSI_ENABLED = (1 << 3), - QL_MSIX_ENABLED = (1 << 4), - QL_DMA64 = (1 << 5), - QL_PROMISCUOUS = (1 << 6), - QL_ALLMULTI = (1 << 7), - QL_PORT_CFG = (1 << 8), - QL_CAM_RT_SET = (1 << 9), + QL_ADAPTER_UP = 0, /* Adapter has been brought up. */ + QL_LEGACY_ENABLED = 1, + QL_MSI_ENABLED = 2, + QL_MSIX_ENABLED = 3, + QL_DMA64 = 4, + QL_PROMISCUOUS = 5, + QL_ALLMULTI = 6, + QL_PORT_CFG = 7, + QL_CAM_RT_SET = 8, }; /* link_status bit definitions */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 7783c5db81d..3d0efea3211 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3142,14 +3142,14 @@ static int ql_route_initialize(struct ql_adapter *qdev) { int status = 0; - status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + /* Clear all the entries in the routing table. */ + status = ql_clear_routing_entries(qdev); if (status) return status; - /* Clear all the entries in the routing table. */ - status = ql_clear_routing_entries(qdev); + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); if (status) - goto exit; + return status; status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1); if (status) { @@ -3380,12 +3380,10 @@ static int ql_adapter_down(struct ql_adapter *qdev) ql_free_rx_buffers(qdev); - spin_lock(&qdev->hw_lock); status = ql_adapter_reset(qdev); if (status) QPRINTK(qdev, IFDOWN, ERR, "reset(func #%d) FAILED!\n", qdev->func); - spin_unlock(&qdev->hw_lock); return status; } @@ -3705,7 +3703,7 @@ static void ql_asic_reset_work(struct work_struct *work) struct ql_adapter *qdev = container_of(work, struct ql_adapter, asic_reset_work.work); int status; - + rtnl_lock(); status = ql_adapter_down(qdev); if (status) goto error; @@ -3713,12 +3711,12 @@ static void ql_asic_reset_work(struct work_struct *work) status = ql_adapter_up(qdev); if (status) goto error; - + rtnl_unlock(); return; error: QPRINTK(qdev, IFUP, ALERT, "Driver up/down cycle failed, closing device\n"); - rtnl_lock(); + set_bit(QL_ADAPTER_UP, &qdev->flags); dev_close(qdev->ndev); rtnl_unlock(); @@ -3834,11 +3832,14 @@ static int __devinit ql_init_device(struct pci_dev *pdev, return err; } + qdev->ndev = ndev; + qdev->pdev = pdev; + pci_set_drvdata(pdev, ndev); pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (pos <= 0) { dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " "aborting.\n"); - goto err_out; + return pos; } else { pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16); val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; @@ -3851,7 +3852,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, err = pci_request_regions(pdev, DRV_NAME); if (err) { dev_err(&pdev->dev, "PCI region request failed.\n"); - goto err_out; + return err; } pci_set_master(pdev); @@ -3869,7 +3870,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, goto err_out; } - pci_set_drvdata(pdev, ndev); qdev->reg_base = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); @@ -3889,8 +3889,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev, goto err_out; } - qdev->ndev = ndev; - qdev->pdev = pdev; err = ql_get_board_info(qdev); if (err) { dev_err(&pdev->dev, "Register access failed.\n"); diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index ecf3279fbef..f4dfd1f679a 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -826,7 +826,7 @@ static int __exit sgiseeq_remove(struct platform_device *pdev) static struct platform_driver sgiseeq_driver = { .probe = sgiseeq_probe, - .remove = __devexit_p(sgiseeq_remove), + .remove = __exit_p(sgiseeq_remove), .driver = { .name = "sgiseeq", .owner = THIS_MODULE, diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 55bad408196..01f6811f132 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3935,11 +3935,14 @@ static int __devinit skge_probe(struct pci_dev *pdev, #endif err = -ENOMEM; - hw = kzalloc(sizeof(*hw), GFP_KERNEL); + /* space for skge@pci:0000:04:00.0 */ + hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:" ) + + strlen(pci_name(pdev)) + 1, GFP_KERNEL); if (!hw) { dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } + sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev)); hw->pdev = pdev; spin_lock_init(&hw->hw_lock); @@ -3974,7 +3977,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_netdev; } - err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw); + err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, hw->irq_name, hw); if (err) { dev_err(&pdev->dev, "%s: cannot assign irq %d\n", dev->name, pdev->irq); @@ -3982,14 +3985,17 @@ static int __devinit skge_probe(struct pci_dev *pdev, } skge_show_addr(dev); - if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { - if (register_netdev(dev1) == 0) + if (hw->ports > 1) { + dev1 = skge_devinit(hw, 1, using_dac); + if (dev1 && register_netdev(dev1) == 0) skge_show_addr(dev1); else { /* Failure to register second port need not be fatal */ dev_warn(&pdev->dev, "register of second port failed\n"); hw->dev[1] = NULL; - free_netdev(dev1); + hw->ports = 1; + if (dev1) + free_netdev(dev1); } } pci_set_drvdata(pdev, hw); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 17caccbb768..831de1b6e96 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2423,6 +2423,8 @@ struct skge_hw { u16 phy_addr; spinlock_t phy_lock; struct tasklet_struct phy_task; + + char irq_name[0]; /* skge@pci:000:04:00.0 */ }; enum pause_control { diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ef1165718dd..2ab5c39f33c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4487,13 +4487,16 @@ static int __devinit sky2_probe(struct pci_dev *pdev, wol_default = device_may_wakeup(&pdev->dev) ? WAKE_MAGIC : 0; err = -ENOMEM; - hw = kzalloc(sizeof(*hw), GFP_KERNEL); + + hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:") + + strlen(pci_name(pdev)) + 1, GFP_KERNEL); if (!hw) { dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } hw->pdev = pdev; + sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev)); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { @@ -4539,7 +4542,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, err = request_irq(pdev->irq, sky2_intr, (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED, - dev->name, hw); + hw->irq_name, hw); if (err) { dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); goto err_out_unregister; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index e0f23a10104..ed54129698b 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -2085,6 +2085,8 @@ struct sky2_hw { struct timer_list watchdog_timer; struct work_struct restart_work; wait_queue_head_t msi_wait; + + char irq_name[0]; }; static inline int sky2_is_copper(const struct sky2_hw *hw) diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 82b45d8797b..524691cd989 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2412,7 +2412,6 @@ struct ring_info { struct tx_ring_info { struct sk_buff *skb; - u32 prev_vlan_tag; }; struct tg3_config_info { diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d445845f277..8d009760277 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -948,7 +948,7 @@ free: return err; } -static void virtnet_remove(struct virtio_device *vdev) +static void __devexit virtnet_remove(struct virtio_device *vdev) { struct virtnet_info *vi = vdev->priv; struct sk_buff *skb; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 49ea9c92b7e..d7a764a2fc1 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -31,13 +31,12 @@ config STRIP ---help--- Say Y if you have a Metricom radio and intend to use Starmode Radio IP. STRIP is a radio protocol developed for the MosquitoNet project - (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet - traffic using Metricom radios. Metricom radios are small, battery - powered, 100kbit/sec packet radio transceivers, about the size and - weight of a cellular telephone. (You may also have heard them called - "Metricom modems" but we avoid the term "modem" because it misleads - many people into thinking that you can plug a Metricom modem into a - phone line and use it as a modem.) + to send Internet traffic using Metricom radios. Metricom radios are + small, battery powered, 100kbit/sec packet radio transceivers, about + the size and weight of a cellular telephone. (You may also have heard + them called "Metricom modems" but we avoid the term "modem" because + it misleads many people into thinking that you can plug a Metricom + modem into a phone line and use it as a modem.) You can use STRIP on any Linux machine with a serial port, although it is obviously most useful for people with laptop computers. If you diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index b3e5cf3735b..dbd488da18b 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -1141,7 +1141,8 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar, u8 vpds[2][AR5416_PD_GAIN_ICEPTS]; u8 pwrs[2][AR5416_PD_GAIN_ICEPTS]; int chain, idx, i; - u8 f; + u32 phy_data = 0; + u8 f, tmp; switch (channel->band) { case IEEE80211_BAND_2GHZ: @@ -1208,9 +1209,6 @@ static int ar9170_set_freq_cal_data(struct ar9170 *ar, } for (i = 0; i < 76; i++) { - u32 phy_data; - u8 tmp; - if (i < 25) { tmp = ar9170_interpolate_val(i, &pwrs[0][0], &vpds[0][0]); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index e96091b3149..9c1397996e0 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -340,10 +340,15 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q, q->mmio_base + B43_PIO_TXDATA, sizeof(u16)); if (data_len & 1) { + u8 tail[2] = { 0, }; + /* Write the last byte. */ ctl &= ~B43_PIO_TXCTL_WRITEHI; b43_piotx_write16(q, B43_PIO_TXCTL, ctl); - b43_piotx_write16(q, B43_PIO_TXDATA, data[data_len - 1]); + tail[0] = data[data_len - 1]; + ssb_block_write(dev->dev, tail, 2, + q->mmio_base + B43_PIO_TXDATA, + sizeof(u16)); } return ctl; @@ -386,26 +391,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q, q->mmio_base + B43_PIO8_TXDATA, sizeof(u32)); if (data_len & 3) { - u32 value = 0; + u8 tail[4] = { 0, }; /* Write the last few bytes. */ ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31); - data = &(data[data_len - 1]); switch (data_len & 3) { case 3: - ctl |= B43_PIO8_TXCTL_16_23; - value |= (u32)(*data) << 16; - data--; + ctl |= B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_8_15; + tail[0] = data[data_len - 3]; + tail[1] = data[data_len - 2]; + tail[2] = data[data_len - 1]; + break; case 2: ctl |= B43_PIO8_TXCTL_8_15; - value |= (u32)(*data) << 8; - data--; + tail[0] = data[data_len - 2]; + tail[1] = data[data_len - 1]; + break; case 1: - value |= (u32)(*data); + tail[0] = data[data_len - 1]; + break; } b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); - b43_piotx_write32(q, B43_PIO8_TXDATA, value); + ssb_block_write(dev->dev, tail, 4, + q->mmio_base + B43_PIO8_TXDATA, + sizeof(u32)); } return ctl; @@ -693,21 +703,25 @@ data_ready: q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); if (len & 3) { - u32 value; - char *data; + u8 tail[4] = { 0, }; /* Read the last few bytes. */ - value = b43_piorx_read32(q, B43_PIO8_RXDATA); - data = &(skb->data[len + padding - 1]); + ssb_block_read(dev->dev, tail, 4, + q->mmio_base + B43_PIO8_RXDATA, + sizeof(u32)); switch (len & 3) { case 3: - *data = (value >> 16); - data--; + skb->data[len + padding - 3] = tail[0]; + skb->data[len + padding - 2] = tail[1]; + skb->data[len + padding - 1] = tail[2]; + break; case 2: - *data = (value >> 8); - data--; + skb->data[len + padding - 2] = tail[0]; + skb->data[len + padding - 1] = tail[1]; + break; case 1: - *data = value; + skb->data[len + padding - 1] = tail[0]; + break; } } } else { @@ -715,11 +729,13 @@ data_ready: q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); if (len & 1) { - u16 value; + u8 tail[2] = { 0, }; /* Read the last byte. */ - value = b43_piorx_read16(q, B43_PIO_RXDATA); - skb->data[len + padding - 1] = value; + ssb_block_read(dev->dev, tail, 2, + q->mmio_base + B43_PIO_RXDATA, + sizeof(u16)); + skb->data[len + padding - 1] = tail[0]; } } diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 896f532182f..38cfd79e059 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -631,6 +631,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, data->beacon_int = 1024 * info->beacon_int / 1000 * HZ / 1000; if (WARN_ON(!data->beacon_int)) data->beacon_int = 1; + if (data->started) + mod_timer(&data->beacon_timer, + jiffies + data->beacon_int); } if (changed & BSS_CHANGED_ERP_CTS_PROT) { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 1cbd9b4a3ef..b8f5ee33445 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2381,6 +2381,7 @@ static struct usb_device_id rt73usb_device_table[] = { /* Huawei-3Com */ { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) }, /* Hercules */ + { USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) }, /* Linksys */ diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index f424146a2bc..ac8aa09ba0d 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -130,7 +130,7 @@ static struct pcmcia_low_level assabet_pcmcia_ops = { .socket_suspend = assabet_pcmcia_socket_suspend, }; -int __init pcmcia_assabet_init(struct device *dev) +int pcmcia_assabet_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 4c41e86ccff..0c76d337815 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -123,7 +123,7 @@ static struct pcmcia_low_level neponset_pcmcia_ops = { .socket_suspend = sa1111_pcmcia_socket_suspend, }; -int __init pcmcia_neponset_init(struct sa1111_dev *sadev) +int pcmcia_neponset_init(struct sa1111_dev *sadev) { int ret = -ENODEV; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 1b78f639ead..76769978285 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -125,7 +125,7 @@ static int qstat_seq_open(struct inode *inode, struct file *filp) filp->f_path.dentry->d_inode->i_private); } -static struct file_operations debugfs_fops = { +static const struct file_operations debugfs_fops = { .owner = THIS_MODULE, .open = qstat_seq_open, .read = seq_read, diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index eff943923c6..968e3c7c263 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c @@ -84,7 +84,7 @@ static int qdio_perf_seq_open(struct inode *inode, struct file *filp) return single_open(filp, qdio_perf_proc_show, NULL); } -static struct file_operations qdio_perf_proc_fops = { +static const struct file_operations qdio_perf_proc_fops = { .owner = THIS_MODULE, .open = qdio_perf_seq_open, .read = seq_read, diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0cb049f5cc5..747a5e5c127 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1317,7 +1317,7 @@ static void sg_rq_end_io(struct request *rq, int uptodate) } } -static struct file_operations sg_fops = { +static const struct file_operations sg_fops = { .owner = THIS_MODULE, .read = sg_read, .write = sg_write, @@ -2194,9 +2194,11 @@ static int sg_proc_seq_show_int(struct seq_file *s, void *v); static int sg_proc_single_open_adio(struct inode *inode, struct file *file); static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off); -static struct file_operations adio_fops = { - /* .owner, .read and .llseek added in sg_proc_init() */ +static const struct file_operations adio_fops = { + .owner = THIS_MODULE, .open = sg_proc_single_open_adio, + .read = seq_read, + .llseek = seq_lseek, .write = sg_proc_write_adio, .release = single_release, }; @@ -2204,23 +2206,32 @@ static struct file_operations adio_fops = { static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off); -static struct file_operations dressz_fops = { +static const struct file_operations dressz_fops = { + .owner = THIS_MODULE, .open = sg_proc_single_open_dressz, + .read = seq_read, + .llseek = seq_lseek, .write = sg_proc_write_dressz, .release = single_release, }; static int sg_proc_seq_show_version(struct seq_file *s, void *v); static int sg_proc_single_open_version(struct inode *inode, struct file *file); -static struct file_operations version_fops = { +static const struct file_operations version_fops = { + .owner = THIS_MODULE, .open = sg_proc_single_open_version, + .read = seq_read, + .llseek = seq_lseek, .release = single_release, }; static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v); static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file); -static struct file_operations devhdr_fops = { +static const struct file_operations devhdr_fops = { + .owner = THIS_MODULE, .open = sg_proc_single_open_devhdr, + .read = seq_read, + .llseek = seq_lseek, .release = single_release, }; @@ -2229,8 +2240,11 @@ static int sg_proc_open_dev(struct inode *inode, struct file *file); static void * dev_seq_start(struct seq_file *s, loff_t *pos); static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos); static void dev_seq_stop(struct seq_file *s, void *v); -static struct file_operations dev_fops = { +static const struct file_operations dev_fops = { + .owner = THIS_MODULE, .open = sg_proc_open_dev, + .read = seq_read, + .llseek = seq_lseek, .release = seq_release, }; static const struct seq_operations dev_seq_ops = { @@ -2242,8 +2256,11 @@ static const struct seq_operations dev_seq_ops = { static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v); static int sg_proc_open_devstrs(struct inode *inode, struct file *file); -static struct file_operations devstrs_fops = { +static const struct file_operations devstrs_fops = { + .owner = THIS_MODULE, .open = sg_proc_open_devstrs, + .read = seq_read, + .llseek = seq_lseek, .release = seq_release, }; static const struct seq_operations devstrs_seq_ops = { @@ -2255,8 +2272,11 @@ static const struct seq_operations devstrs_seq_ops = { static int sg_proc_seq_show_debug(struct seq_file *s, void *v); static int sg_proc_open_debug(struct inode *inode, struct file *file); -static struct file_operations debug_fops = { +static const struct file_operations debug_fops = { + .owner = THIS_MODULE, .open = sg_proc_open_debug, + .read = seq_read, + .llseek = seq_lseek, .release = seq_release, }; static const struct seq_operations debug_seq_ops = { @@ -2269,7 +2289,7 @@ static const struct seq_operations debug_seq_ops = { struct sg_proc_leaf { const char * name; - struct file_operations * fops; + const struct file_operations * fops; }; static struct sg_proc_leaf sg_proc_leaf_arr[] = { @@ -2295,9 +2315,6 @@ sg_proc_init(void) for (k = 0; k < num_leaves; ++k) { leaf = &sg_proc_leaf_arr[k]; mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - leaf->fops->owner = THIS_MODULE; - leaf->fops->read = seq_read; - leaf->fops->llseek = seq_lseek; proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } return 0; diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 2209620d234..b1ae774016f 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -64,6 +64,8 @@ static int serial_index(struct uart_port *port) return (serial8250_reg.minor - 64) + port->line; } +static unsigned int skip_txen_test; /* force skip of txen test at init time */ + /* * Debugging. */ @@ -2108,7 +2110,7 @@ static int serial8250_startup(struct uart_port *port) is variable. So, let's just don't test if we receive TX irq. This way, we'll never enable UART_BUG_TXEN. */ - if (up->port.flags & UPF_NO_TXEN_TEST) + if (skip_txen_test || up->port.flags & UPF_NO_TXEN_TEST) goto dont_test_tx_en; /* @@ -3248,6 +3250,9 @@ MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" module_param(nr_uarts, uint, 0644); MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")"); +module_param(skip_txen_test, uint, 0644); +MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time"); + #ifdef CONFIG_SERIAL_8250_RSA module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444); MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e70712044a7..e5225725727 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -862,7 +862,7 @@ config SERIAL_IMX_CONSOLE config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" - depends on PPC32 || MICROBLAZE + depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE select SERIAL_CORE help Say Y here if you want to use the Xilinx uartlite serial controller. diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 2d7feecaf49..0028b6f89ce 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -307,7 +307,7 @@ static void stop_processor(struct icom_port *icom_port) if (port < 4) { temp = readl(stop_proc[port].global_control_reg); temp = - (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; + (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; writel(temp, stop_proc[port].global_control_reg); /* write flush */ @@ -336,7 +336,7 @@ static void start_processor(struct icom_port *icom_port) if (port < 4) { temp = readl(start_proc[port].global_control_reg); temp = - (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; + (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; writel(temp, start_proc[port].global_control_reg); /* write flush */ @@ -509,8 +509,8 @@ static void load_code(struct icom_port *icom_port) dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n"); } - if (new_page != NULL) - pci_free_consistent(dev, 4096, new_page, temp_pci); + if (new_page != NULL) + pci_free_consistent(dev, 4096, new_page, temp_pci); } static int startup(struct icom_port *icom_port) @@ -1493,15 +1493,15 @@ static int __devinit icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { int index; - unsigned int command_reg; - int retval; - struct icom_adapter *icom_adapter; - struct icom_port *icom_port; + unsigned int command_reg; + int retval; + struct icom_adapter *icom_adapter; + struct icom_port *icom_port; - retval = pci_enable_device(dev); - if (retval) { + retval = pci_enable_device(dev); + if (retval) { dev_err(&dev->dev, "Device enable FAILED\n"); - return retval; + return retval; } if ( (retval = pci_request_regions(dev, "icom"))) { @@ -1510,23 +1510,23 @@ static int __devinit icom_probe(struct pci_dev *dev, return retval; } - pci_set_master(dev); + pci_set_master(dev); - if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { dev_err(&dev->dev, "PCI Config read FAILED\n"); - return retval; - } + return retval; + } pci_write_config_dword(dev, PCI_COMMAND, command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - if (ent->driver_data == ADAPTER_V1) { + if (ent->driver_data == ADAPTER_V1) { pci_write_config_dword(dev, 0x44, 0x8300830A); - } else { + } else { pci_write_config_dword(dev, 0x44, 0x42004200); pci_write_config_dword(dev, 0x48, 0x42004200); - } + } retval = icom_alloc_adapter(&icom_adapter); @@ -1536,10 +1536,10 @@ static int __devinit icom_probe(struct pci_dev *dev, goto probe_exit0; } - icom_adapter->base_addr_pci = pci_resource_start(dev, 0); - icom_adapter->pci_dev = dev; - icom_adapter->version = ent->driver_data; - icom_adapter->subsystem_id = ent->subdevice; + icom_adapter->base_addr_pci = pci_resource_start(dev, 0); + icom_adapter->pci_dev = dev; + icom_adapter->version = ent->driver_data; + icom_adapter->subsystem_id = ent->subdevice; retval = icom_init_ports(icom_adapter); @@ -1548,7 +1548,7 @@ static int __devinit icom_probe(struct pci_dev *dev, goto probe_exit1; } - icom_adapter->base_addr = pci_ioremap_bar(dev, 0); + icom_adapter->base_addr = pci_ioremap_bar(dev, 0); if (!icom_adapter->base_addr) goto probe_exit1; @@ -1562,7 +1562,7 @@ static int __devinit icom_probe(struct pci_dev *dev, retval = icom_load_ports(icom_adapter); - for (index = 0; index < icom_adapter->numb_ports; index++) { + for (index = 0; index < icom_adapter->numb_ports; index++) { icom_port = &icom_adapter->port_info[index]; if (icom_port->status == ICOM_PORT_ACTIVE) { @@ -1579,7 +1579,7 @@ static int __devinit icom_probe(struct pci_dev *dev, icom_port->status = ICOM_PORT_OFF; dev_err(&dev->dev, "Device add failed\n"); } else - dev_info(&dev->dev, "Device added\n"); + dev_info(&dev->dev, "Device added\n"); } } @@ -1595,9 +1595,7 @@ probe_exit0: pci_release_regions(dev); pci_disable_device(dev); - return retval; - - + return retval; } static void __devexit icom_remove(struct pci_dev *dev) diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 7f5e2687322..2199d819a98 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -638,7 +638,7 @@ static void __init sa1100_init_ports(void) PPSR |= PPC_TXD1 | PPC_TXD3; } -void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns) +void __devinit sa1100_register_uart_fns(struct sa1100_port_fns *fns) { if (fns->get_mctrl) sa1100_pops.get_mctrl = fns->get_mctrl; diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 0f7cf4c453e..c50e9fbbf74 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -221,21 +221,26 @@ sio_quot_set(struct uart_txx9_port *up, int quot) sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6); } +static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port) +{ + return container_of(port, struct uart_txx9_port, port); +} + static void serial_txx9_stop_tx(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE); } static void serial_txx9_start_tx(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE); } static void serial_txx9_stop_rx(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); up->port.read_status_mask &= ~TXX9_SIDISR_RDIS; } @@ -246,7 +251,7 @@ static void serial_txx9_enable_ms(struct uart_port *port) static void serial_txx9_initialize(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int tmout = 10000; sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); @@ -414,7 +419,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id) static unsigned int serial_txx9_tx_empty(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; unsigned int ret; @@ -427,7 +432,7 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port) static unsigned int serial_txx9_get_mctrl(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int ret; /* no modem control lines */ @@ -440,7 +445,7 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port) static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); if (mctrl & TIOCM_RTS) sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC); @@ -450,7 +455,7 @@ static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial_txx9_break_ctl(struct uart_port *port, int break_state) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; spin_lock_irqsave(&up->port.lock, flags); @@ -494,7 +499,7 @@ static int serial_txx9_get_poll_char(struct uart_port *port) { unsigned int ier; unsigned char c; - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); /* * First save the IER then disable the interrupts @@ -520,7 +525,7 @@ static int serial_txx9_get_poll_char(struct uart_port *port) static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) { unsigned int ier; - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); /* * First save the IER then disable the interrupts @@ -551,7 +556,7 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) static int serial_txx9_startup(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; int retval; @@ -596,7 +601,7 @@ static int serial_txx9_startup(struct uart_port *port) static void serial_txx9_shutdown(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned long flags; /* @@ -636,7 +641,7 @@ static void serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); unsigned int cval, fcr = 0; unsigned long flags; unsigned int baud, quot; @@ -814,19 +819,19 @@ static void serial_txx9_release_resource(struct uart_txx9_port *up) static void serial_txx9_release_port(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); serial_txx9_release_resource(up); } static int serial_txx9_request_port(struct uart_port *port) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); return serial_txx9_request_resource(up); } static void serial_txx9_config_port(struct uart_port *port, int uflags) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); int ret; /* @@ -897,7 +902,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv, static void serial_txx9_console_putchar(struct uart_port *port, int ch) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; + struct uart_txx9_port *up = to_uart_txx9_port(port); wait_for_xmitr(up); sio_out(up, TXX9_SITFIFO, ch); diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 6d7a3f82c54..21a118269ca 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o -obj-$(CONFIG_SPI_IMX) += mxc_spi.o +obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/spi_imx.c index b1447236ae8..89c22efedfb 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/spi_imx.c @@ -48,14 +48,14 @@ #define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */ #define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */ -struct mxc_spi_config { +struct spi_imx_config { unsigned int speed_hz; unsigned int bpw; unsigned int mode; int cs; }; -struct mxc_spi_data { +struct spi_imx_data { struct spi_bitbang bitbang; struct completion xfer_done; @@ -66,43 +66,43 @@ struct mxc_spi_data { int *chipselect; unsigned int count; - void (*tx)(struct mxc_spi_data *); - void (*rx)(struct mxc_spi_data *); + void (*tx)(struct spi_imx_data *); + void (*rx)(struct spi_imx_data *); void *rx_buf; const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ /* SoC specific functions */ - void (*intctrl)(struct mxc_spi_data *, int); - int (*config)(struct mxc_spi_data *, struct mxc_spi_config *); - void (*trigger)(struct mxc_spi_data *); - int (*rx_available)(struct mxc_spi_data *); + void (*intctrl)(struct spi_imx_data *, int); + int (*config)(struct spi_imx_data *, struct spi_imx_config *); + void (*trigger)(struct spi_imx_data *); + int (*rx_available)(struct spi_imx_data *); }; #define MXC_SPI_BUF_RX(type) \ -static void mxc_spi_buf_rx_##type(struct mxc_spi_data *mxc_spi) \ +static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ { \ - unsigned int val = readl(mxc_spi->base + MXC_CSPIRXDATA); \ + unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); \ \ - if (mxc_spi->rx_buf) { \ - *(type *)mxc_spi->rx_buf = val; \ - mxc_spi->rx_buf += sizeof(type); \ + if (spi_imx->rx_buf) { \ + *(type *)spi_imx->rx_buf = val; \ + spi_imx->rx_buf += sizeof(type); \ } \ } #define MXC_SPI_BUF_TX(type) \ -static void mxc_spi_buf_tx_##type(struct mxc_spi_data *mxc_spi) \ +static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \ { \ type val = 0; \ \ - if (mxc_spi->tx_buf) { \ - val = *(type *)mxc_spi->tx_buf; \ - mxc_spi->tx_buf += sizeof(type); \ + if (spi_imx->tx_buf) { \ + val = *(type *)spi_imx->tx_buf; \ + spi_imx->tx_buf += sizeof(type); \ } \ \ - mxc_spi->count -= sizeof(type); \ + spi_imx->count -= sizeof(type); \ \ - writel(val, mxc_spi->base + MXC_CSPITXDATA); \ + writel(val, spi_imx->base + MXC_CSPITXDATA); \ } MXC_SPI_BUF_RX(u8) @@ -119,7 +119,7 @@ static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024}; /* MX21, MX27 */ -static unsigned int mxc_spi_clkdiv_1(unsigned int fin, +static unsigned int spi_imx_clkdiv_1(unsigned int fin, unsigned int fspi) { int i, max; @@ -137,7 +137,7 @@ static unsigned int mxc_spi_clkdiv_1(unsigned int fin, } /* MX1, MX31, MX35 */ -static unsigned int mxc_spi_clkdiv_2(unsigned int fin, +static unsigned int spi_imx_clkdiv_2(unsigned int fin, unsigned int fspi) { int i, div = 4; @@ -174,7 +174,7 @@ static unsigned int mxc_spi_clkdiv_2(unsigned int fin, * the i.MX35 has a slightly different register layout for bits * we do not use here. */ -static void mx31_intctrl(struct mxc_spi_data *mxc_spi, int enable) +static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -183,24 +183,24 @@ static void mx31_intctrl(struct mxc_spi_data *mxc_spi, int enable) if (enable & MXC_INT_RR) val |= MX31_INTREG_RREN; - writel(val, mxc_spi->base + MXC_CSPIINT); + writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx31_trigger(struct mxc_spi_data *mxc_spi) +static void mx31_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; - reg = readl(mxc_spi->base + MXC_CSPICTRL); + reg = readl(spi_imx->base + MXC_CSPICTRL); reg |= MX31_CSPICTRL_XCH; - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx31_config(struct mxc_spi_data *mxc_spi, - struct mxc_spi_config *config) +static int mx31_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; - reg |= mxc_spi_clkdiv_2(mxc_spi->spi_clk, config->speed_hz) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << MX31_CSPICTRL_DR_SHIFT; if (cpu_is_mx31()) @@ -223,14 +223,14 @@ static int mx31_config(struct mxc_spi_data *mxc_spi, reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT; } - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } -static int mx31_rx_available(struct mxc_spi_data *mxc_spi) +static int mx31_rx_available(struct spi_imx_data *spi_imx) { - return readl(mxc_spi->base + MX31_CSPISTATUS) & MX31_STATUS_RR; + return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR; } #define MX27_INTREG_RR (1 << 4) @@ -246,7 +246,7 @@ static int mx31_rx_available(struct mxc_spi_data *mxc_spi) #define MX27_CSPICTRL_DR_SHIFT 14 #define MX27_CSPICTRL_CS_SHIFT 19 -static void mx27_intctrl(struct mxc_spi_data *mxc_spi, int enable) +static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -255,24 +255,24 @@ static void mx27_intctrl(struct mxc_spi_data *mxc_spi, int enable) if (enable & MXC_INT_RR) val |= MX27_INTREG_RREN; - writel(val, mxc_spi->base + MXC_CSPIINT); + writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx27_trigger(struct mxc_spi_data *mxc_spi) +static void mx27_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; - reg = readl(mxc_spi->base + MXC_CSPICTRL); + reg = readl(spi_imx->base + MXC_CSPICTRL); reg |= MX27_CSPICTRL_XCH; - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx27_config(struct mxc_spi_data *mxc_spi, - struct mxc_spi_config *config) +static int mx27_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) { unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER; - reg |= mxc_spi_clkdiv_1(mxc_spi->spi_clk, config->speed_hz) << + reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) << MX27_CSPICTRL_DR_SHIFT; reg |= config->bpw - 1; @@ -285,14 +285,14 @@ static int mx27_config(struct mxc_spi_data *mxc_spi, if (config->cs < 0) reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT; - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } -static int mx27_rx_available(struct mxc_spi_data *mxc_spi) +static int mx27_rx_available(struct spi_imx_data *spi_imx) { - return readl(mxc_spi->base + MXC_CSPIINT) & MX27_INTREG_RR; + return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR; } #define MX1_INTREG_RR (1 << 3) @@ -306,7 +306,7 @@ static int mx27_rx_available(struct mxc_spi_data *mxc_spi) #define MX1_CSPICTRL_MASTER (1 << 10) #define MX1_CSPICTRL_DR_SHIFT 13 -static void mx1_intctrl(struct mxc_spi_data *mxc_spi, int enable) +static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable) { unsigned int val = 0; @@ -315,24 +315,24 @@ static void mx1_intctrl(struct mxc_spi_data *mxc_spi, int enable) if (enable & MXC_INT_RR) val |= MX1_INTREG_RREN; - writel(val, mxc_spi->base + MXC_CSPIINT); + writel(val, spi_imx->base + MXC_CSPIINT); } -static void mx1_trigger(struct mxc_spi_data *mxc_spi) +static void mx1_trigger(struct spi_imx_data *spi_imx) { unsigned int reg; - reg = readl(mxc_spi->base + MXC_CSPICTRL); + reg = readl(spi_imx->base + MXC_CSPICTRL); reg |= MX1_CSPICTRL_XCH; - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); } -static int mx1_config(struct mxc_spi_data *mxc_spi, - struct mxc_spi_config *config) +static int mx1_config(struct spi_imx_data *spi_imx, + struct spi_imx_config *config) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; - reg |= mxc_spi_clkdiv_2(mxc_spi->spi_clk, config->speed_hz) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << MX1_CSPICTRL_DR_SHIFT; reg |= config->bpw - 1; @@ -341,156 +341,151 @@ static int mx1_config(struct mxc_spi_data *mxc_spi, if (config->mode & SPI_CPOL) reg |= MX1_CSPICTRL_POL; - writel(reg, mxc_spi->base + MXC_CSPICTRL); + writel(reg, spi_imx->base + MXC_CSPICTRL); return 0; } -static int mx1_rx_available(struct mxc_spi_data *mxc_spi) +static int mx1_rx_available(struct spi_imx_data *spi_imx) { - return readl(mxc_spi->base + MXC_CSPIINT) & MX1_INTREG_RR; + return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR; } -static void mxc_spi_chipselect(struct spi_device *spi, int is_active) +static void spi_imx_chipselect(struct spi_device *spi, int is_active) { - struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); - unsigned int cs = 0; - int gpio = mxc_spi->chipselect[spi->chip_select]; - struct mxc_spi_config config; + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + int gpio = spi_imx->chipselect[spi->chip_select]; + int active = is_active != BITBANG_CS_INACTIVE; + int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); - if (spi->mode & SPI_CS_HIGH) - cs = 1; - - if (is_active == BITBANG_CS_INACTIVE) { - if (gpio >= 0) - gpio_set_value(gpio, !cs); + if (gpio < 0) return; - } - - config.bpw = spi->bits_per_word; - config.speed_hz = spi->max_speed_hz; - config.mode = spi->mode; - config.cs = mxc_spi->chipselect[spi->chip_select]; - - mxc_spi->config(mxc_spi, &config); - - /* Initialize the functions for transfer */ - if (config.bpw <= 8) { - mxc_spi->rx = mxc_spi_buf_rx_u8; - mxc_spi->tx = mxc_spi_buf_tx_u8; - } else if (config.bpw <= 16) { - mxc_spi->rx = mxc_spi_buf_rx_u16; - mxc_spi->tx = mxc_spi_buf_tx_u16; - } else if (config.bpw <= 32) { - mxc_spi->rx = mxc_spi_buf_rx_u32; - mxc_spi->tx = mxc_spi_buf_tx_u32; - } else - BUG(); - if (gpio >= 0) - gpio_set_value(gpio, cs); - - return; + gpio_set_value(gpio, dev_is_lowactive ^ active); } -static void mxc_spi_push(struct mxc_spi_data *mxc_spi) +static void spi_imx_push(struct spi_imx_data *spi_imx) { - while (mxc_spi->txfifo < 8) { - if (!mxc_spi->count) + while (spi_imx->txfifo < 8) { + if (!spi_imx->count) break; - mxc_spi->tx(mxc_spi); - mxc_spi->txfifo++; + spi_imx->tx(spi_imx); + spi_imx->txfifo++; } - mxc_spi->trigger(mxc_spi); + spi_imx->trigger(spi_imx); } -static irqreturn_t mxc_spi_isr(int irq, void *dev_id) +static irqreturn_t spi_imx_isr(int irq, void *dev_id) { - struct mxc_spi_data *mxc_spi = dev_id; + struct spi_imx_data *spi_imx = dev_id; - while (mxc_spi->rx_available(mxc_spi)) { - mxc_spi->rx(mxc_spi); - mxc_spi->txfifo--; + while (spi_imx->rx_available(spi_imx)) { + spi_imx->rx(spi_imx); + spi_imx->txfifo--; } - if (mxc_spi->count) { - mxc_spi_push(mxc_spi); + if (spi_imx->count) { + spi_imx_push(spi_imx); return IRQ_HANDLED; } - if (mxc_spi->txfifo) { + if (spi_imx->txfifo) { /* No data left to push, but still waiting for rx data, * enable receive data available interrupt. */ - mxc_spi->intctrl(mxc_spi, MXC_INT_RR); + spi_imx->intctrl(spi_imx, MXC_INT_RR); return IRQ_HANDLED; } - mxc_spi->intctrl(mxc_spi, 0); - complete(&mxc_spi->xfer_done); + spi_imx->intctrl(spi_imx, 0); + complete(&spi_imx->xfer_done); return IRQ_HANDLED; } -static int mxc_spi_setupxfer(struct spi_device *spi, +static int spi_imx_setupxfer(struct spi_device *spi, struct spi_transfer *t) { - struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); - struct mxc_spi_config config; + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + struct spi_imx_config config; config.bpw = t ? t->bits_per_word : spi->bits_per_word; config.speed_hz = t ? t->speed_hz : spi->max_speed_hz; config.mode = spi->mode; + config.cs = spi_imx->chipselect[spi->chip_select]; + + if (!config.speed_hz) + config.speed_hz = spi->max_speed_hz; + if (!config.bpw) + config.bpw = spi->bits_per_word; + if (!config.speed_hz) + config.speed_hz = spi->max_speed_hz; + + /* Initialize the functions for transfer */ + if (config.bpw <= 8) { + spi_imx->rx = spi_imx_buf_rx_u8; + spi_imx->tx = spi_imx_buf_tx_u8; + } else if (config.bpw <= 16) { + spi_imx->rx = spi_imx_buf_rx_u16; + spi_imx->tx = spi_imx_buf_tx_u16; + } else if (config.bpw <= 32) { + spi_imx->rx = spi_imx_buf_rx_u32; + spi_imx->tx = spi_imx_buf_tx_u32; + } else + BUG(); - mxc_spi->config(mxc_spi, &config); + spi_imx->config(spi_imx, &config); return 0; } -static int mxc_spi_transfer(struct spi_device *spi, +static int spi_imx_transfer(struct spi_device *spi, struct spi_transfer *transfer) { - struct mxc_spi_data *mxc_spi = spi_master_get_devdata(spi->master); + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); - mxc_spi->tx_buf = transfer->tx_buf; - mxc_spi->rx_buf = transfer->rx_buf; - mxc_spi->count = transfer->len; - mxc_spi->txfifo = 0; + spi_imx->tx_buf = transfer->tx_buf; + spi_imx->rx_buf = transfer->rx_buf; + spi_imx->count = transfer->len; + spi_imx->txfifo = 0; - init_completion(&mxc_spi->xfer_done); + init_completion(&spi_imx->xfer_done); - mxc_spi_push(mxc_spi); + spi_imx_push(spi_imx); - mxc_spi->intctrl(mxc_spi, MXC_INT_TE); + spi_imx->intctrl(spi_imx, MXC_INT_TE); - wait_for_completion(&mxc_spi->xfer_done); + wait_for_completion(&spi_imx->xfer_done); return transfer->len; } -static int mxc_spi_setup(struct spi_device *spi) +static int spi_imx_setup(struct spi_device *spi) { - if (!spi->bits_per_word) - spi->bits_per_word = 8; + struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); + int gpio = spi_imx->chipselect[spi->chip_select]; pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); - mxc_spi_chipselect(spi, BITBANG_CS_INACTIVE); + if (gpio >= 0) + gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); + + spi_imx_chipselect(spi, BITBANG_CS_INACTIVE); return 0; } -static void mxc_spi_cleanup(struct spi_device *spi) +static void spi_imx_cleanup(struct spi_device *spi) { } -static int __init mxc_spi_probe(struct platform_device *pdev) +static int __init spi_imx_probe(struct platform_device *pdev) { struct spi_imx_master *mxc_platform_info; struct spi_master *master; - struct mxc_spi_data *mxc_spi; + struct spi_imx_data *spi_imx; struct resource *res; int i, ret; @@ -500,7 +495,7 @@ static int __init mxc_spi_probe(struct platform_device *pdev) return -EINVAL; } - master = spi_alloc_master(&pdev->dev, sizeof(struct mxc_spi_data)); + master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data)); if (!master) return -ENOMEM; @@ -509,32 +504,32 @@ static int __init mxc_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = mxc_platform_info->num_chipselect; - mxc_spi = spi_master_get_devdata(master); - mxc_spi->bitbang.master = spi_master_get(master); - mxc_spi->chipselect = mxc_platform_info->chipselect; + spi_imx = spi_master_get_devdata(master); + spi_imx->bitbang.master = spi_master_get(master); + spi_imx->chipselect = mxc_platform_info->chipselect; for (i = 0; i < master->num_chipselect; i++) { - if (mxc_spi->chipselect[i] < 0) + if (spi_imx->chipselect[i] < 0) continue; - ret = gpio_request(mxc_spi->chipselect[i], DRIVER_NAME); + ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); if (ret) { i--; while (i > 0) - if (mxc_spi->chipselect[i] >= 0) - gpio_free(mxc_spi->chipselect[i--]); + if (spi_imx->chipselect[i] >= 0) + gpio_free(spi_imx->chipselect[i--]); dev_err(&pdev->dev, "can't get cs gpios"); goto out_master_put; } - gpio_direction_output(mxc_spi->chipselect[i], 1); } - mxc_spi->bitbang.chipselect = mxc_spi_chipselect; - mxc_spi->bitbang.setup_transfer = mxc_spi_setupxfer; - mxc_spi->bitbang.txrx_bufs = mxc_spi_transfer; - mxc_spi->bitbang.master->setup = mxc_spi_setup; - mxc_spi->bitbang.master->cleanup = mxc_spi_cleanup; + spi_imx->bitbang.chipselect = spi_imx_chipselect; + spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; + spi_imx->bitbang.txrx_bufs = spi_imx_transfer; + spi_imx->bitbang.master->setup = spi_imx_setup; + spi_imx->bitbang.master->cleanup = spi_imx_cleanup; + spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - init_completion(&mxc_spi->xfer_done); + init_completion(&spi_imx->xfer_done); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -549,58 +544,58 @@ static int __init mxc_spi_probe(struct platform_device *pdev) goto out_gpio_free; } - mxc_spi->base = ioremap(res->start, resource_size(res)); - if (!mxc_spi->base) { + spi_imx->base = ioremap(res->start, resource_size(res)); + if (!spi_imx->base) { ret = -EINVAL; goto out_release_mem; } - mxc_spi->irq = platform_get_irq(pdev, 0); - if (!mxc_spi->irq) { + spi_imx->irq = platform_get_irq(pdev, 0); + if (!spi_imx->irq) { ret = -EINVAL; goto out_iounmap; } - ret = request_irq(mxc_spi->irq, mxc_spi_isr, 0, DRIVER_NAME, mxc_spi); + ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx); if (ret) { - dev_err(&pdev->dev, "can't get irq%d: %d\n", mxc_spi->irq, ret); + dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); goto out_iounmap; } if (cpu_is_mx31() || cpu_is_mx35()) { - mxc_spi->intctrl = mx31_intctrl; - mxc_spi->config = mx31_config; - mxc_spi->trigger = mx31_trigger; - mxc_spi->rx_available = mx31_rx_available; + spi_imx->intctrl = mx31_intctrl; + spi_imx->config = mx31_config; + spi_imx->trigger = mx31_trigger; + spi_imx->rx_available = mx31_rx_available; } else if (cpu_is_mx27() || cpu_is_mx21()) { - mxc_spi->intctrl = mx27_intctrl; - mxc_spi->config = mx27_config; - mxc_spi->trigger = mx27_trigger; - mxc_spi->rx_available = mx27_rx_available; + spi_imx->intctrl = mx27_intctrl; + spi_imx->config = mx27_config; + spi_imx->trigger = mx27_trigger; + spi_imx->rx_available = mx27_rx_available; } else if (cpu_is_mx1()) { - mxc_spi->intctrl = mx1_intctrl; - mxc_spi->config = mx1_config; - mxc_spi->trigger = mx1_trigger; - mxc_spi->rx_available = mx1_rx_available; + spi_imx->intctrl = mx1_intctrl; + spi_imx->config = mx1_config; + spi_imx->trigger = mx1_trigger; + spi_imx->rx_available = mx1_rx_available; } else BUG(); - mxc_spi->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(mxc_spi->clk)) { + spi_imx->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(spi_imx->clk)) { dev_err(&pdev->dev, "unable to get clock\n"); - ret = PTR_ERR(mxc_spi->clk); + ret = PTR_ERR(spi_imx->clk); goto out_free_irq; } - clk_enable(mxc_spi->clk); - mxc_spi->spi_clk = clk_get_rate(mxc_spi->clk); + clk_enable(spi_imx->clk); + spi_imx->spi_clk = clk_get_rate(spi_imx->clk); if (!cpu_is_mx31() || !cpu_is_mx35()) - writel(1, mxc_spi->base + MXC_RESET); + writel(1, spi_imx->base + MXC_RESET); - mxc_spi->intctrl(mxc_spi, 0); + spi_imx->intctrl(spi_imx, 0); - ret = spi_bitbang_start(&mxc_spi->bitbang); + ret = spi_bitbang_start(&spi_imx->bitbang); if (ret) { dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); goto out_clk_put; @@ -611,18 +606,18 @@ static int __init mxc_spi_probe(struct platform_device *pdev) return ret; out_clk_put: - clk_disable(mxc_spi->clk); - clk_put(mxc_spi->clk); + clk_disable(spi_imx->clk); + clk_put(spi_imx->clk); out_free_irq: - free_irq(mxc_spi->irq, mxc_spi); + free_irq(spi_imx->irq, spi_imx); out_iounmap: - iounmap(mxc_spi->base); + iounmap(spi_imx->base); out_release_mem: release_mem_region(res->start, resource_size(res)); out_gpio_free: for (i = 0; i < master->num_chipselect; i++) - if (mxc_spi->chipselect[i] >= 0) - gpio_free(mxc_spi->chipselect[i]); + if (spi_imx->chipselect[i] >= 0) + gpio_free(spi_imx->chipselect[i]); out_master_put: spi_master_put(master); kfree(master); @@ -630,24 +625,24 @@ out_master_put: return ret; } -static int __exit mxc_spi_remove(struct platform_device *pdev) +static int __exit spi_imx_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct mxc_spi_data *mxc_spi = spi_master_get_devdata(master); + struct spi_imx_data *spi_imx = spi_master_get_devdata(master); int i; - spi_bitbang_stop(&mxc_spi->bitbang); + spi_bitbang_stop(&spi_imx->bitbang); - writel(0, mxc_spi->base + MXC_CSPICTRL); - clk_disable(mxc_spi->clk); - clk_put(mxc_spi->clk); - free_irq(mxc_spi->irq, mxc_spi); - iounmap(mxc_spi->base); + writel(0, spi_imx->base + MXC_CSPICTRL); + clk_disable(spi_imx->clk); + clk_put(spi_imx->clk); + free_irq(spi_imx->irq, spi_imx); + iounmap(spi_imx->base); for (i = 0; i < master->num_chipselect; i++) - if (mxc_spi->chipselect[i] >= 0) - gpio_free(mxc_spi->chipselect[i]); + if (spi_imx->chipselect[i] >= 0) + gpio_free(spi_imx->chipselect[i]); spi_master_put(master); @@ -658,27 +653,27 @@ static int __exit mxc_spi_remove(struct platform_device *pdev) return 0; } -static struct platform_driver mxc_spi_driver = { +static struct platform_driver spi_imx_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, - .probe = mxc_spi_probe, - .remove = __exit_p(mxc_spi_remove), + .probe = spi_imx_probe, + .remove = __exit_p(spi_imx_remove), }; -static int __init mxc_spi_init(void) +static int __init spi_imx_init(void) { - return platform_driver_register(&mxc_spi_driver); + return platform_driver_register(&spi_imx_driver); } -static void __exit mxc_spi_exit(void) +static void __exit spi_imx_exit(void) { - platform_driver_unregister(&mxc_spi_driver); + platform_driver_unregister(&spi_imx_driver); } -module_init(mxc_spi_init); -module_exit(mxc_spi_exit); +module_init(spi_imx_init); +module_exit(spi_imx_exit); MODULE_DESCRIPTION("SPI Master Controller driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index f921bd1109e..5d23983f02f 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -537,7 +537,7 @@ static int spidev_release(struct inode *inode, struct file *filp) return status; } -static struct file_operations spidev_fops = { +static const struct file_operations spidev_fops = { .owner = THIS_MODULE, /* REVISIT switch to aio primitives, so that userspace * gets more complete API coverage. It'll simplify things diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index ac8577358ba..ee1601026fb 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -847,7 +847,7 @@ static dst_command_func dst_commands[] = { /* * Configuration parser. */ -static void cn_dst_callback(struct cn_msg *msg) +static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct dst_ctl *ctl; int err; @@ -855,6 +855,11 @@ static void cn_dst_callback(struct cn_msg *msg) struct dst_node *n = NULL, *tmp; unsigned int hash; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + if (msg->len < sizeof(struct dst_ctl)) { err = -EBADMSG; goto out; diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c index 90f962ee5fd..5d04bf5b021 100644 --- a/drivers/staging/pohmelfs/config.c +++ b/drivers/staging/pohmelfs/config.c @@ -527,10 +527,13 @@ out_unlock: return err; } -static void pohmelfs_cn_callback(struct cn_msg *msg) +static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { int err; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + switch (msg->flags) { case POHMELFS_FLAGS_ADD: case POHMELFS_FLAGS_DEL: diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 333ee02e7b2..864f0ba6a34 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -993,7 +993,7 @@ skip_io_on_zombie: return retval; } -static struct file_operations fops = { +static const struct file_operations fops = { .owner = THIS_MODULE, .read = usbtmc_read, .write = usbtmc_write, diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 29500154d00..2d867fd2241 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -875,7 +875,7 @@ printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) } /* used after endpoint configuration */ -static struct file_operations printer_io_operations = { +static const struct file_operations printer_io_operations = { .owner = THIS_MODULE, .open = printer_open, .read = printer_read, diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index cf2d45946c5..2273c815941 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -134,7 +134,7 @@ static int pzl_open(struct inode *inode, struct file *file) return single_open(file, pzl_print, inode->i_private); } -static struct file_operations di_fops = { +static const struct file_operations di_fops = { .open = di_open, .read = seq_read, .llseek = seq_lseek, @@ -142,7 +142,7 @@ static struct file_operations di_fops = { .owner = THIS_MODULE, }; -static struct file_operations asl_fops = { +static const struct file_operations asl_fops = { .open = asl_open, .read = seq_read, .llseek = seq_lseek, @@ -150,7 +150,7 @@ static struct file_operations asl_fops = { .owner = THIS_MODULE, }; -static struct file_operations pzl_fops = { +static const struct file_operations pzl_fops = { .open = pzl_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index d645f3899fe..32d0199d0c3 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -429,8 +429,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) return read_count; } -static struct -file_operations usb_rio_fops = { +static const struct file_operations usb_rio_fops = { .owner = THIS_MODULE, .read = read_rio, .write = write_rio, diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c index 4a42993700c..2eecec0c13c 100644 --- a/drivers/uwb/uwb-debug.c +++ b/drivers/uwb/uwb-debug.c @@ -205,7 +205,7 @@ static ssize_t command_write(struct file *file, const char __user *buf, return ret < 0 ? ret : len; } -static struct file_operations command_fops = { +static const struct file_operations command_fops = { .open = command_open, .write = command_write, .read = NULL, @@ -255,7 +255,7 @@ static int reservations_open(struct inode *inode, struct file *file) return single_open(file, reservations_print, inode->i_private); } -static struct file_operations reservations_fops = { +static const struct file_operations reservations_fops = { .open = reservations_open, .read = seq_read, .llseek = seq_lseek, @@ -283,7 +283,7 @@ static int drp_avail_open(struct inode *inode, struct file *file) return single_open(file, drp_avail_print, inode->i_private); } -static struct file_operations drp_avail_fops = { +static const struct file_operations drp_avail_fops = { .open = drp_avail_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index e98baf6916b..e35232a1857 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -67,11 +67,14 @@ static DEFINE_MUTEX(uvfb_lock); * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(struct cn_msg *msg) +static void uvesafb_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct uvesafb_task *utask; struct uvesafb_ktask *task; + if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) + return; + if (msg->seq >= UVESAFB_TASKS_MAX) return; diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 52ccb3d3a96..45c126fea31 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -306,7 +306,7 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm return error; } -static void w1_cn_callback(struct cn_msg *msg) +static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) { struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd; |