diff options
34 files changed, 521 insertions, 279 deletions
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 0bbefba6469..1df9dda2e37 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,7 +40,7 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#define VERSION "1.2" +#define VERSION "1.3" static int minor = MISC_DYNAMIC_MINOR; @@ -51,14 +51,8 @@ struct vhci_data { wait_queue_head_t read_wait; struct sk_buff_head readq; - - struct fasync_struct *fasync; }; -#define VHCI_FASYNC 0x0010 - -static struct miscdevice vhci_miscdev; - static int vhci_open_dev(struct hci_dev *hdev) { set_bit(HCI_RUNNING, &hdev->flags); @@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb) memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&data->readq, skb); - if (data->flags & VHCI_FASYNC) - kill_fasync(&data->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&data->read_wait); return 0; @@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data, static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { - DECLARE_WAITQUEUE(wait, current); struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; - add_wait_queue(&data->read_wait, &wait); while (count) { - set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&data->readq); - if (!skb) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - schedule(); - continue; + if (skb) { + ret = vhci_put_user(data, skb, buf, count); + if (ret < 0) + skb_queue_head(&data->readq, skb); + else + kfree_skb(skb); + break; } - if (access_ok(VERIFY_WRITE, buf, count)) - ret = vhci_put_user(data, skb, buf, count); - else - ret = -EFAULT; + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - kfree_skb(skb); - break; + ret = wait_event_interruptible(data->read_wait, + !skb_queue_empty(&data->readq)); + if (ret < 0) + break; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&data->read_wait, &wait); return ret; } @@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file, { struct vhci_data *data = file->private_data; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - return vhci_get_user(data, buf, count); } @@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file) skb_queue_head_init(&data->readq); init_waitqueue_head(&data->read_wait); - lock_kernel(); hdev = hci_alloc_dev(); if (!hdev) { kfree(data); - unlock_kernel(); return -ENOMEM; } @@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file) BT_ERR("Can't register HCI device"); kfree(data); hci_free_dev(hdev); - unlock_kernel(); return -EBUSY; } file->private_data = data; - unlock_kernel(); return nonseekable_open(inode, file); } @@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file) return 0; } -static int vhci_fasync(int fd, struct file *file, int on) -{ - struct vhci_data *data = file->private_data; - int err = 0; - - lock_kernel(); - err = fasync_helper(fd, file, on, &data->fasync); - if (err < 0) - goto out; - - if (on) - data->flags |= VHCI_FASYNC; - else - data->flags &= ~VHCI_FASYNC; - -out: - unlock_kernel(); - return err; -} - static const struct file_operations vhci_fops = { - .owner = THIS_MODULE, .read = vhci_read, .write = vhci_write, .poll = vhci_poll, .ioctl = vhci_ioctl, .open = vhci_open, .release = vhci_release, - .fasync = vhci_fasync, }; static struct miscdevice vhci_miscdev= { - .name = "vhci", - .fops = &vhci_fops, + .name = "vhci", + .fops = &vhci_fops, + .minor = MISC_DYNAMIC_MINOR, }; static int __init vhci_init(void) { BT_INFO("Virtual HCI driver ver %s", VERSION); - vhci_miscdev.minor = minor; - if (misc_register(&vhci_miscdev) < 0) { BT_ERR("Can't register misc device with minor %d", minor); return -EIO; @@ -369,9 +320,6 @@ static void __exit vhci_exit(void) module_init(vhci_init); module_exit(vhci_exit); -module_param(minor, int, 0444); -MODULE_PARM_DESC(minor, "Miscellaneous minor device number"); - MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 776afc8c927..228ffbed128 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1806,10 +1806,9 @@ init_card(struct hfc_pci *hc) printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts " "during init %d\n", hc->irq, 4 - cnt); - if (cnt == 1) { - spin_unlock_irqrestore(&hc->lock, flags); - return -EIO; - } else { + if (cnt == 1) + break; + else { reset_hfcpci(hc); cnt--; } diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index f1265667b06..3d337d924c2 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -82,8 +82,9 @@ release_io_hfcpci(struct IsdnCardState *cs) Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ del_timer(&cs->hw.hfcpci.timer); - kfree(cs->hw.hfcpci.share_start); - cs->hw.hfcpci.share_start = NULL; + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); + cs->hw.hfcpci.fifos = NULL; iounmap((void *)cs->hw.hfcpci.pci_io); } @@ -1663,8 +1664,19 @@ setup_hfcpci(struct IsdnCard *card) dev_hfcpci); i++; if (tmp_hfcpci) { + dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL; if (pci_enable_device(tmp_hfcpci)) continue; + if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable DMA available.\n"); + continue; + } + if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) { + printk(KERN_WARNING + "HiSax hfc_pci: No suitable consistent DMA available.\n"); + continue; + } pci_set_master(tmp_hfcpci); if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK))) continue; @@ -1693,22 +1705,29 @@ setup_hfcpci(struct IsdnCard *card) printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); } + /* Allocate memory for FIFOS */ - /* Because the HFC-PCI needs a 32K physical alignment, we */ - /* need to allocate the double mem and align the address */ - if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { - printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); + cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev, + 0x8000, &cs->hw.hfcpci.dma); + if (!cs->hw.hfcpci.fifos) { + printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n"); + return 0; + } + if (cs->hw.hfcpci.dma & 0x7fff) { + printk(KERN_WARNING + "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n", + (u_long)cs->hw.hfcpci.dma); + pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, + cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); return 0; } - cs->hw.hfcpci.fifos = (void *) - (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; - pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); + pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma); cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); printk(KERN_INFO - "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n", + "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n", cs->hw.hfcpci.pci_io, cs->hw.hfcpci.fifos, - (u_int) virt_to_bus(cs->hw.hfcpci.fifos), + (u_long)cs->hw.hfcpci.dma, cs->irq, HZ); spin_lock_irqsave(&cs->lock, flags); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index f8527046f19..0685c194696 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -703,7 +703,7 @@ struct hfcPCI_hw { int nt_timer; struct pci_dev *dev; unsigned char *pci_io; /* start of PCI IO memory */ - void *share_start; /* shared memory for Fifos start */ + dma_addr_t dma; /* dma handle for Fifos */ void *fifos; /* FIFO memory */ int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ struct timer_list timer; diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 1a2222cbb80..b4d4522e507 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1592,7 +1592,7 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp) int retval, line; line = tty->index; - if (line < 0 || line > ISDN_MAX_CHANNELS) + if (line < 0 || line >= ISDN_MAX_CHANNELS) return -ENODEV; info = &dev->mdm.info[line]; if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index ac61f198eb3..e9941678edf 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -55,20 +55,19 @@ static ssize_t attr_show_args(struct device *dev, struct device_attribute *attr, char *buf) { struct mISDN_dsp_element *elem = dev_get_drvdata(dev); - ssize_t len = 0; - int i = 0; + int i; + char *p = buf; *buf = 0; - for (; i < elem->num_args; ++i) - len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n" - "\n", buf, + for (i = 0; i < elem->num_args; i++) + p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n", elem->args[i].name, elem->args[i].def ? "Default: " : "", elem->args[i].def ? elem->args[i].def : "", elem->args[i].def ? "\n" : "", elem->args[i].desc); - return len; + return p - buf; } static struct device_attribute element_attributes[] = { diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index bfcdd97df95..e04bad6c5ba 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -862,8 +862,7 @@ static int ph_data_ind(struct manager *mgr, struct sk_buff *skb) { int ret = -EINVAL; - struct layer2 *l2; - u_long flags; + struct layer2 *l2, *nl2; u_char mt; if (skb->len < 8) { @@ -908,11 +907,9 @@ ph_data_ind(struct manager *mgr, struct sk_buff *skb) new_tei_req(mgr, &skb->data[4]); goto done; } - read_lock_irqsave(&mgr->lock, flags); - list_for_each_entry(l2, &mgr->layer2, list) { + list_for_each_entry_safe(l2, nl2, &mgr->layer2, list) { tei_ph_data_ind(l2->tm, mt, &skb->data[4], skb->len - 4); } - read_unlock_irqrestore(&mgr->lock, flags); done: return ret; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 347d002fa42..66bb56874d9 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -168,6 +168,7 @@ static void netdev_stats_update(struct be_adapter *adapter) struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->stats.net_stats; + struct be_erx_stats *erx_stats = &hw_stats->erx; dev_stats->rx_packets = port_stats->rx_total_frames; dev_stats->tx_packets = port_stats->tx_unicastframes + @@ -181,29 +182,33 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_errors = port_stats->rx_crc_errors + port_stats->rx_alignment_symbol_errors + port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; - - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space in linux buffers */ - dev_stats->rx_dropped = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->multicast = port_stats->tx_multicastframes; - dev_stats->collisions = 0; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long + + port_stats->rx_dropped_too_small + + port_stats->rx_dropped_too_short + + port_stats->rx_dropped_header_too_small + + port_stats->rx_dropped_tcp_length + + port_stats->rx_dropped_runt + + port_stats->rx_tcp_checksum_errs + + port_stats->rx_ip_checksum_errs + + port_stats->rx_udp_checksum_errs; + + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long; + /* receive ring buffer overflow */ dev_stats->rx_over_errors = 0; + dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + @@ -211,6 +216,16 @@ static void netdev_stats_update(struct be_adapter *adapter) rxf_stats->rx_drops_no_pbuf; /* receiver missed packetd */ dev_stats->rx_missed_errors = 0; + + /* packet transmit problems */ + dev_stats->tx_errors = 0; + + /* no space available in linux */ + dev_stats->tx_dropped = 0; + + dev_stats->multicast = port_stats->tx_multicastframes; + dev_stats->collisions = 0; + /* detailed tx_errors */ dev_stats->tx_aborted_errors = 0; dev_stats->tx_carrier_errors = 0; @@ -728,7 +743,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); - return; + goto done; } /* More frags present for this completion */ @@ -750,6 +765,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, memset(page_info, 0, sizeof(*page_info)); } +done: be_rx_stats_update(adapter, pktsize, num_rcvd); return; } @@ -860,12 +876,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; - queue_tail_inc(&adapter->rx_obj.cq); return rxcp; } +/* To reset the valid bit, we need to reset the whole word as + * when walking the queue the valid entries are little-endian + * and invalid entries are host endian + */ +static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +{ + rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +} + static inline struct page *be_alloc_pages(u32 size) { gfp_t alloc_flags = GFP_ATOMIC; @@ -997,6 +1020,7 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* First cleanup pending rx completions */ while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); + be_rx_compl_reset(rxcp); be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); } @@ -1032,8 +1056,13 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) struct be_queue_info *q; q = &adapter->tx_obj.q; - if (q->created) + if (q->created) { be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + + /* No more tx completions can be rcvd now; clean up if there + * are any pending completions or pending tx requests */ + be_tx_q_clean(adapter); + } be_queue_free(adapter, q); q = &adapter->tx_obj.cq; @@ -1041,10 +1070,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); be_queue_free(adapter, q); - /* No more tx completions can be rcvd now; clean up if there are - * any pending completions or pending tx requests */ - be_tx_q_clean(adapter); - q = &adapter->tx_eq.q; if (q->created) be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); @@ -1278,6 +1303,8 @@ int be_poll_rx(struct napi_struct *napi, int budget) be_rx_compl_process_lro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); + + be_rx_compl_reset(rxcp); } lro_flush_all(&adapter->rx_obj.lro_mgr); @@ -1533,7 +1560,7 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; - cancel_delayed_work(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_stop_queue(netdev); netif_carrier_off(netdev); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 3a1b7b04eb7..5fb861a0866 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1541,6 +1541,7 @@ int bond_create_sysfs(void) printk(KERN_ERR "network device named %s already exists in sysfs", class_attr_bonding_masters.attr.name); + ret = 0; } return ret; diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index e48e508b963..1694fad3872 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -253,6 +253,8 @@ struct adapter { struct mutex mdio_lock; spinlock_t stats_lock; spinlock_t work_lock; + + struct sk_buff *nofail_skb; }; static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index aef3ab21f5f..538dda4422d 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -433,40 +433,78 @@ static int init_tp_parity(struct adapter *adap) for (i = 0; i < 16; i++) { struct cpl_smt_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); req->iff = i; t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_l2t_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); req->params = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } for (i = 0; i < 2048; i++) { struct cpl_rte_write_req *req; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); memset(req, 0, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); req->l2t_idx = htonl(V_L2T_W_IDX(i)); t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } } - skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); memset(greq, 0, sizeof(*greq)); greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); @@ -475,8 +513,17 @@ static int init_tp_parity(struct adapter *adap) t3_mgmt_tx(adap, skb); i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + if (skb == adap->nofail_skb) { + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + } + t3_tp_set_offload_mode(adap, 0); return i; + +alloc_skb_fail: + t3_tp_set_offload_mode(adap, 0); + return -ENOMEM; } /** @@ -871,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, struct mngt_pktsched_wr *req; int ret; - skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + return -ENOMEM; + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; @@ -881,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, req->max = hi; req->binding = port; ret = t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL); + if (!adap->nofail_skb) + ret = -ENOMEM; + } return ret; } @@ -3020,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev, goto out_disable_device; } + adapter->nofail_skb = + alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); + if (!adapter->nofail_skb) { + dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); + err = -ENOMEM; + goto out_free_adapter; + } + adapter->regs = ioremap_nocache(mmio_start, mmio_len); if (!adapter->regs) { dev_err(&pdev->dev, "cannot map device registers\n"); @@ -3176,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev) free_netdev(adapter->port[i]); iounmap(adapter->regs); + if (adapter->nofail_skb) + kfree_skb(adapter->nofail_skb); kfree(adapter); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 620d80be6aa..f9f54b57b28 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work) spin_unlock_bh(&td->tid_release_lock); skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL | __GFP_NOFAIL); + GFP_KERNEL); + if (!skb) + skb = td->nofail_skb; + if (!skb) { + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = (struct t3c_tid_entry *)p; + break; + } mk_tid_release(skb, p - td->tid_maps.tid_tab); cxgb3_ofld_send(tdev, skb); p->ctx = NULL; + if (skb == td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); spin_lock_bh(&td->tid_release_lock); } + td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; spin_unlock_bh(&td->tid_release_lock); + + if (!td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); } /* use ctx as a next pointer in the tid release list */ @@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) p->ctx = (void *)td->tid_release_list; p->client = NULL; td->tid_release_list = p; - if (!p->ctx) + if (!p->ctx || td->release_list_incomplete) schedule_work(&td->tid_release_task); spin_unlock_bh(&td->tid_release_lock); } @@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter) if (list_empty(&adapter_list)) register_netevent_notifier(&nb); + t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); + t->release_list_incomplete = 0; + add_adapter(adapter); return 0; @@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter) T3C_DATA(tdev) = NULL; t3_free_l2t(L2DATA(tdev)); L2DATA(tdev) = NULL; + if (t->nofail_skb) + kfree_skb(t->nofail_skb); kfree(t); } diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index a8e8e5fcdf8..55945f422ae 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -191,6 +191,9 @@ struct t3c_data { struct t3c_tid_entry *tid_release_list; spinlock_t tid_release_lock; struct work_struct tid_release_task; + + struct sk_buff *nofail_skb; + unsigned int release_list_incomplete; }; /* diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index 66483035f68..dc45e9856c3 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -296,6 +296,23 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || ecmd->speed == SPEED_10000); } + + /* 10GBASE-T MDI/MDI-X */ + if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) { + switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, + MDIO_PMA_10GBT_SWAPPOL)) { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + ecmd->eth_tp_mdix = ETH_TP_MDI; + break; + case 0: + ecmd->eth_tp_mdix = ETH_TP_MDI_X; + break; + default: + /* It's complicated... */ + ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; + break; + } + } } EXPORT_SYMBOL(mdio45_ethtool_gset_npage); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 4a51c31330d..6f77ad58e3b 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -178,10 +178,8 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter) for (ring = 0; ring < adapter->max_rds_rings; ring++) { rds_ring = &recv_ctx->rds_rings[ring]; - if (rds_ring->rx_buf_arr) { - vfree(rds_ring->rx_buf_arr); - rds_ring->rx_buf_arr = NULL; - } + vfree(rds_ring->rx_buf_arr); + rds_ring->rx_buf_arr = NULL; } kfree(recv_ctx->rds_rings); @@ -190,8 +188,7 @@ skip_rds: return; tx_ring = adapter->tx_ring; - if (tx_ring->cmd_buf_arr) - vfree(tx_ring->cmd_buf_arr); + vfree(tx_ring->cmd_buf_arr); } int netxen_alloc_sw_resources(struct netxen_adapter *adapter) diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 5eb52ca0898..156e02e8905 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -27,6 +27,8 @@ "%s: " fmt, __func__, ##args); \ } while (0) +#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ + #define QLGE_VENDOR_ID 0x1077 #define QLGE_DEVICE_ID_8012 0x8012 #define QLGE_DEVICE_ID_8000 0x8000 @@ -39,7 +41,18 @@ #define NUM_SMALL_BUFFERS 512 #define NUM_LARGE_BUFFERS 512 +#define DB_PAGE_SIZE 4096 + +/* Calculate the number of (4k) pages required to + * contain a buffer queue of the given length. + */ +#define MAX_DB_PAGES_PER_BQ(x) \ + (((x * sizeof(u64)) / DB_PAGE_SIZE) + \ + (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0)) +#define RX_RING_SHADOW_SPACE (sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) #define SMALL_BUFFER_SIZE 256 #define LARGE_BUFFER_SIZE PAGE_SIZE #define MAX_SPLIT_SIZE 1023 @@ -63,8 +76,6 @@ #define TX_DESC_PER_OAL 0 #endif -#define DB_PAGE_SIZE 4096 - /* MPI test register definitions. This register * is used for determining alternate NIC function's * PCI->func number. diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 024c7343ada..b9a5f59d6c9 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2237,7 +2237,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, &tx_ring->wq_base_dma); if ((tx_ring->wq_base == NULL) - || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) { + || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); return -ENOMEM; } @@ -2552,14 +2552,16 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) { struct cqicb *cqicb = &rx_ring->cqicb; void *shadow_reg = qdev->rx_ring_shadow_reg_area + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma + - (rx_ring->cq_id * sizeof(u64) * 4); + (rx_ring->cq_id * RX_RING_SHADOW_SPACE); void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; u16 bq_len; u64 tmp; + __le64 *base_indirect_ptr; + int page_entries; /* Set up the shadow registers for this ring. */ rx_ring->prod_idx_sh_reg = shadow_reg; @@ -2568,8 +2570,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) shadow_reg_dma += sizeof(u64); rx_ring->lbq_base_indirect = shadow_reg; rx_ring->lbq_base_indirect_dma = shadow_reg_dma; - shadow_reg += sizeof(u64); - shadow_reg_dma += sizeof(u64); + shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); + shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); rx_ring->sbq_base_indirect = shadow_reg; rx_ring->sbq_base_indirect_dma = shadow_reg_dma; @@ -2606,7 +2608,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ tmp = (u64)rx_ring->lbq_base_dma;; - *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->lbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : @@ -2623,7 +2632,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ tmp = (u64)rx_ring->sbq_base_dma;; - *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp); + base_indirect_ptr = (__le64 *) rx_ring->sbq_base_indirect; + page_entries = 0; + do { + *base_indirect_ptr = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + base_indirect_ptr++; + page_entries++; + } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index e94316b7868..007c881896d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3379,7 +3379,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev, rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - dev_kfree_skb_irq(tx_skb->skb); + dev_kfree_skb(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index db723c58f6f..f4d509015f7 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -63,6 +63,7 @@ /* extended status register */ #define PMA_PMD_XSTATUS_REG 49153 +#define PMA_PMD_XSTAT_MDIX_LBN 14 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ @@ -741,9 +742,17 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - if (efx->phy_type != PHY_TYPE_SFX7101) + if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); + if (ecmd->speed != SPEED_10000) { + ecmd->eth_tp_mdix = + (efx_mdio_read(efx, MDIO_MMD_PMAPMD, + PMA_PMD_XSTATUS_REG) & + (1 << PMA_PMD_XSTAT_MDIX_LBN)) + ? ETH_TP_MDI_X : ETH_TP_MDI; + } + } /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 093807a182f..3c2679cd196 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -948,8 +948,7 @@ static void print_rxfd(struct rxf_desc *rxfd); static void bdx_rxdb_destroy(struct rxdb *db) { - if (db) - vfree(db); + vfree(db); } static struct rxdb *bdx_rxdb_create(int nelem) @@ -1482,10 +1481,8 @@ static void bdx_tx_db_close(struct txdb *d) { BDX_ASSERT(d == NULL); - if (d->start) { - vfree(d->start); - d->start = NULL; - } + vfree(d->start); + d->start = NULL; } /************************************************************************* diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 6b41c884a33..26cde573af4 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -1884,17 +1884,13 @@ void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) mempool->memblock_size, dma_object); } - if (mempool->items_arr) - vfree(mempool->items_arr); + vfree(mempool->items_arr); - if (mempool->memblocks_dma_arr) - vfree(mempool->memblocks_dma_arr); + vfree(mempool->memblocks_dma_arr); - if (mempool->memblocks_priv_arr) - vfree(mempool->memblocks_priv_arr); + vfree(mempool->memblocks_priv_arr); - if (mempool->memblocks_arr) - vfree(mempool->memblocks_arr); + vfree(mempool->memblocks_arr); vfree(mempool); } diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index ce900f4c245..7f9831da847 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -89,11 +89,6 @@ struct dchannel { void (*phfunc) (struct dchannel *); u_int state; void *l1; - /* HW access */ - u_char (*read_reg) (void *, u_char); - void (*write_reg) (void *, u_char, u_char); - void (*read_fifo) (void *, u_char *, int); - void (*write_fifo) (void *, u_char *, int); void *hw; int slot; /* multiport card channel slot */ struct timer_list timer; @@ -151,11 +146,6 @@ struct bchannel { u_long Flags; struct work_struct workq; u_int state; - /* HW access */ - u_char (*read_reg) (void *, u_char); - void (*write_reg) (void *, u_char, u_char); - void (*read_fifo) (void *, u_char *, int); - void (*write_fifo) (void *, u_char *, int); void *hw; int slot; /* multiport card channel slot */ struct timer_list timer; diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 56851646529..cfdf1df2875 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -45,6 +45,7 @@ #define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ /* Media-dependent registers. */ +#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ #define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ #define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. * Lanes B-D are numbered 134-136. */ @@ -195,6 +196,14 @@ #define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 #define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 +/* PMA 10GBASE-T pair swap & polarity */ +#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */ + /* PMA 10GBASE-T TX power register. */ #define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 144d1d5dd82..968166a45f8 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -81,12 +81,6 @@ enum { BT_CLOSED }; -/* Endianness conversions */ -#define htobs(a) __cpu_to_le16(a) -#define htobl(a) __cpu_to_le32(a) -#define btohs(a) __le16_to_cpu(a) -#define btohl(a) __le32_to_cpu(a) - /* BD Address */ typedef struct { __u8 b[6]; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 73aead222b3..c4ca4228b08 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -137,6 +137,8 @@ struct hci_dev { struct device *parent; struct device dev; + struct rfkill *rfkill; + struct module *owner; int (*open)(struct hci_dev *hdev); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f566aa1f0a4..e919fca1072 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -26,8 +26,13 @@ #define __L2CAP_H /* L2CAP defaults */ -#define L2CAP_DEFAULT_MTU 672 -#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF +#define L2CAP_DEFAULT_MTU 672 +#define L2CAP_DEFAULT_FLUSH_TO 0xffff +#define L2CAP_DEFAULT_RX_WINDOW 1 +#define L2CAP_DEFAULT_MAX_RECEIVE 1 +#define L2CAP_DEFAULT_RETRANS_TO 300 /* 300 milliseconds */ +#define L2CAP_DEFAULT_MONITOR_TO 1000 /* 1 second */ +#define L2CAP_DEFAULT_MAX_RX_APDU 0xfff7 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ @@ -64,17 +69,29 @@ struct l2cap_conninfo { #define L2CAP_LM_SECURE 0x0020 /* L2CAP command codes */ -#define L2CAP_COMMAND_REJ 0x01 -#define L2CAP_CONN_REQ 0x02 -#define L2CAP_CONN_RSP 0x03 -#define L2CAP_CONF_REQ 0x04 -#define L2CAP_CONF_RSP 0x05 -#define L2CAP_DISCONN_REQ 0x06 -#define L2CAP_DISCONN_RSP 0x07 -#define L2CAP_ECHO_REQ 0x08 -#define L2CAP_ECHO_RSP 0x09 -#define L2CAP_INFO_REQ 0x0a -#define L2CAP_INFO_RSP 0x0b +#define L2CAP_COMMAND_REJ 0x01 +#define L2CAP_CONN_REQ 0x02 +#define L2CAP_CONN_RSP 0x03 +#define L2CAP_CONF_REQ 0x04 +#define L2CAP_CONF_RSP 0x05 +#define L2CAP_DISCONN_REQ 0x06 +#define L2CAP_DISCONN_RSP 0x07 +#define L2CAP_ECHO_REQ 0x08 +#define L2CAP_ECHO_RSP 0x09 +#define L2CAP_INFO_REQ 0x0a +#define L2CAP_INFO_RSP 0x0b + +/* L2CAP feature mask */ +#define L2CAP_FEAT_FLOWCTL 0x00000001 +#define L2CAP_FEAT_RETRANS 0x00000002 +#define L2CAP_FEAT_ERTM 0x00000008 +#define L2CAP_FEAT_STREAMING 0x00000010 +#define L2CAP_FEAT_FCS 0x00000020 +#define L2CAP_FEAT_FIXED_CHAN 0x00000080 + +/* L2CAP checksum option */ +#define L2CAP_FCS_NONE 0x00 +#define L2CAP_FCS_CRC16 0x01 /* L2CAP structures */ struct l2cap_hdr { @@ -106,17 +123,23 @@ struct l2cap_conn_rsp { __le16 status; } __attribute__ ((packed)); +/* channel indentifier */ +#define L2CAP_CID_SIGNALING 0x0001 +#define L2CAP_CID_CONN_LESS 0x0002 +#define L2CAP_CID_DYN_START 0x0040 +#define L2CAP_CID_DYN_END 0xffff + /* connect result */ -#define L2CAP_CR_SUCCESS 0x0000 -#define L2CAP_CR_PEND 0x0001 -#define L2CAP_CR_BAD_PSM 0x0002 -#define L2CAP_CR_SEC_BLOCK 0x0003 -#define L2CAP_CR_NO_MEM 0x0004 +#define L2CAP_CR_SUCCESS 0x0000 +#define L2CAP_CR_PEND 0x0001 +#define L2CAP_CR_BAD_PSM 0x0002 +#define L2CAP_CR_SEC_BLOCK 0x0003 +#define L2CAP_CR_NO_MEM 0x0004 /* connect status */ -#define L2CAP_CS_NO_INFO 0x0000 -#define L2CAP_CS_AUTHEN_PEND 0x0001 -#define L2CAP_CS_AUTHOR_PEND 0x0002 +#define L2CAP_CS_NO_INFO 0x0000 +#define L2CAP_CS_AUTHEN_PEND 0x0001 +#define L2CAP_CS_AUTHOR_PEND 0x0002 struct l2cap_conf_req { __le16 dcid; @@ -143,10 +166,14 @@ struct l2cap_conf_opt { } __attribute__ ((packed)); #define L2CAP_CONF_OPT_SIZE 2 +#define L2CAP_CONF_HINT 0x80 +#define L2CAP_CONF_MASK 0x7f + #define L2CAP_CONF_MTU 0x01 #define L2CAP_CONF_FLUSH_TO 0x02 #define L2CAP_CONF_QOS 0x03 #define L2CAP_CONF_RFC 0x04 +#define L2CAP_CONF_FCS 0x05 #define L2CAP_CONF_MAX_SIZE 22 @@ -162,6 +189,8 @@ struct l2cap_conf_rfc { #define L2CAP_MODE_BASIC 0x00 #define L2CAP_MODE_RETRANS 0x01 #define L2CAP_MODE_FLOWCTL 0x02 +#define L2CAP_MODE_ERTM 0x03 +#define L2CAP_MODE_STREAM 0x04 struct l2cap_disconn_req { __le16 dcid; diff --git a/include/net/sock.h b/include/net/sock.h index 4bb1ff9fd15..010e14a93c9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1217,9 +1217,13 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from, static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) { - sock_hold(sk); skb->sk = sk; skb->destructor = sock_wfree; + /* + * We used to take a refcount on sk, but following operation + * is enough to guarantee sk_free() wont free this sock until + * all in-flight packets are completed + */ atomic_add(skb->truesize, &sk->sk_wmem_alloc); } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cd061510b6b..406ad07cdea 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -39,6 +39,7 @@ #include <linux/skbuff.h> #include <linux/interrupt.h> #include <linux/notifier.h> +#include <linux/rfkill.h> #include <net/sock.h> #include <asm/system.h> @@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev) hci_req_lock(hdev); + if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { + ret = -ERFKILL; + goto done; + } + if (test_bit(HCI_UP, &hdev->flags)) { ret = -EALREADY; goto done; @@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg) /* ---- Interface to HCI drivers ---- */ +static int hci_rfkill_set_block(void *data, bool blocked) +{ + struct hci_dev *hdev = data; + + BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked); + + if (!blocked) + return 0; + + hci_dev_do_close(hdev); + + return 0; +} + +static const struct rfkill_ops hci_rfkill_ops = { + .set_block = hci_rfkill_set_block, +}; + /* Alloc HCI device */ struct hci_dev *hci_alloc_dev(void) { @@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id = 0; - BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner); + BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, + hdev->type, hdev->owner); if (!hdev->open || !hdev->close || !hdev->destruct) return -EINVAL; @@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev) hci_register_sysfs(hdev); + hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, + RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); + if (hdev->rfkill) { + if (rfkill_register(hdev->rfkill) < 0) { + rfkill_destroy(hdev->rfkill); + hdev->rfkill = NULL; + } + } + hci_notify(hdev, HCI_DEV_REG); return id; @@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_notify(hdev, HCI_DEV_UNREG); + if (hdev->rfkill) { + rfkill_unregister(hdev->rfkill); + rfkill_destroy(hdev->rfkill); + } + hci_unregister_sysfs(hdev); __hci_dev_put(hdev); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ca4d3b40d5c..bd0a4c1bced 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -40,10 +40,10 @@ #include <linux/skbuff.h> #include <linux/list.h> #include <linux/device.h> +#include <linux/uaccess.h> #include <net/sock.h> #include <asm/system.h> -#include <asm/uaccess.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -52,7 +52,7 @@ #define VERSION "2.13" -static u32 l2cap_feat_mask = 0x0080; +static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; static const struct proto_ops l2cap_sock_ops; @@ -134,7 +134,8 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_scid(l, cid); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } @@ -154,17 +155,18 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 struct sock *s; read_lock(&l->lock); s = __l2cap_get_chan_by_ident(l, ident); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l->lock); return s; } static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) { - u16 cid = 0x0040; + u16 cid = L2CAP_CID_DYN_START; - for (; cid < 0xffff; cid++) { - if(!__l2cap_get_chan_by_scid(l, cid)) + for (; cid < L2CAP_CID_DYN_END; cid++) { + if (!__l2cap_get_chan_by_scid(l, cid)) return cid; } @@ -204,7 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so { struct l2cap_chan_list *l = &conn->chan_list; - BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, + l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); conn->disc_reason = 0x13; @@ -215,13 +218,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so l2cap_pi(sk)->scid = l2cap_alloc_cid(l); } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = 0x0002; - l2cap_pi(sk)->dcid = 0x0002; + l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; + l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = 0x0001; - l2cap_pi(sk)->dcid = 0x0001; + l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; + l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } @@ -272,7 +275,7 @@ static inline int l2cap_check_security(struct sock *sk) if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) auth_type = HCI_AT_NO_BONDING_MITM; else - auth_type = HCI_AT_NO_BONDING; + auth_type = HCI_AT_NO_BONDING; if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; @@ -588,7 +591,8 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t struct sock *s; read_lock(&l2cap_sk_list.lock); s = __l2cap_get_sock_by_psm(state, psm, src); - if (s) bh_lock_sock(s); + if (s) + bh_lock_sock(s); read_unlock(&l2cap_sk_list.lock); return s; } @@ -808,7 +812,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) goto done; } - if (la.l2_psm && btohs(la.l2_psm) < 0x1001 && + if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) { err = -EACCES; goto done; @@ -825,7 +829,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) l2cap_pi(sk)->sport = la.l2_psm; sk->sk_state = BT_BOUND; - if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003) + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; } @@ -844,12 +849,13 @@ static int l2cap_do_connect(struct sock *sk) struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; - int err = 0; + int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); - if (!(hdev = hci_get_route(dst, src))) + hdev = hci_get_route(dst, src); + if (!hdev) return -EHOSTUNREACH; hci_dev_lock_bh(hdev); @@ -950,7 +956,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch(sk->sk_state) { + switch (sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: @@ -975,7 +981,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; - if ((err = l2cap_do_connect(sk))) + err = l2cap_do_connect(sk); + if (err) goto done; wait: @@ -1009,9 +1016,9 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) write_lock_bh(&l2cap_sk_list.lock); for (psm = 0x1001; psm < 0x1100; psm += 2) - if (!__l2cap_get_sock_by_addr(htobs(psm), src)) { - l2cap_pi(sk)->psm = htobs(psm); - l2cap_pi(sk)->sport = htobs(psm); + if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { + l2cap_pi(sk)->psm = cpu_to_le16(psm); + l2cap_pi(sk)->sport = cpu_to_le16(psm); err = 0; break; } @@ -1100,11 +1107,11 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l if (peer) { la->l2_psm = l2cap_pi(sk)->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = htobs(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); } else { la->l2_psm = l2cap_pi(sk)->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = htobs(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); } return 0; @@ -1114,7 +1121,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb, **frag; - int err, hlen, count, sent=0; + int err, hlen, count, sent = 0; struct l2cap_hdr *lh; BT_DBG("sk %p len %d", sk, len); @@ -1167,8 +1174,8 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) frag = &(*frag)->next; } - - if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) + err = hci_send_acl(conn->hcon, skb, 0); + if (err < 0) goto fail; return sent; @@ -1556,7 +1563,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; - struct sock * sk; + struct sock *sk; BT_DBG("conn %p", conn); @@ -1568,8 +1575,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) /* Don't send frame to the socket it came from */ if (skb->sk == sk) continue; - - if (!(nskb = skb_clone(skb, GFP_ATOMIC))) + nskb = skb_clone(skb, GFP_ATOMIC); + if (!nskb) continue; if (sock_queue_rcv_skb(sk, nskb)) @@ -1587,7 +1594,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, struct l2cap_hdr *lh; int len, count; - BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", + conn, code, ident, dlen); len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -1598,7 +1606,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); - lh->cid = cpu_to_le16(0x0001); + lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd->code = code; @@ -1739,8 +1747,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); - hint = type & 0x80; - type &= 0x7f; + hint = type & L2CAP_CONF_HINT; + type &= L2CAP_CONF_MASK; switch (type) { case L2CAP_CONF_MTU: @@ -1966,10 +1974,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; } else { - if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident))) + sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!sk) return 0; } @@ -2012,7 +2022,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return -ENOENT; if (sk->sk_state == BT_DISCONN) @@ -2079,9 +2090,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", + scid, flags, result); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; switch (result) { @@ -2142,7 +2155,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!sk) return 0; rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); @@ -2169,7 +2183,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) + sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!sk) return 0; l2cap_chan_del(sk, 0); @@ -2230,7 +2245,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm if (type == L2CAP_IT_FEAT_MASK) { conn->feat_mask = get_unaligned_le32(rsp->data); - if (conn->feat_mask & 0x0080) { + if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { struct l2cap_info_req req; req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); @@ -2403,7 +2418,8 @@ drop: kfree_skb(skb); done: - if (sk) bh_unlock_sock(sk); + if (sk) + bh_unlock_sock(sk); return 0; } @@ -2420,11 +2436,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) BT_DBG("len %d, cid 0x%4.4x", len, cid); switch (cid) { - case 0x0001: + case L2CAP_CID_SIGNALING: l2cap_sig_channel(conn, skb); break; - case 0x0002: + case L2CAP_CID_CONN_LESS: psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); @@ -2650,7 +2666,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl } /* Allocate skb for the complete frame (with header) */ - if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC))) + conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!conn->rx_skb) goto drop; skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), @@ -2704,13 +2721,13 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level); + sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, + pi->dcid, pi->imtu, pi->omtu, pi->sec_level); } read_unlock_bh(&l2cap_sk_list.lock); - return (str - buf); + return str - buf; } static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 374536e050a..e50566ebf9f 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst bacpy(&addr.l2_bdaddr, dst); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); if (*err == 0 || *err == -EINPROGRESS) @@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d } if (cr && channel_mtu >= 0) - pn->mtu = htobs(channel_mtu); + pn->mtu = cpu_to_le16(channel_mtu); else - pn->mtu = htobs(d->mtu); + pn->mtu = cpu_to_le16(d->mtu); *ptr = __fcs(buf); ptr++; @@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) if (len > 127) { hdr = (void *) skb_push(skb, 4); - put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len); + put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len); } else { hdr = (void *) skb_push(skb, 3); hdr->len = __len8(len); @@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) d->priority = pn->priority; - d->mtu = btohs(pn->mtu); + d->mtu = __le16_to_cpu(pn->mtu); if (cr && d->mtu > s->mtu) d->mtu = s->mtu; @@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Bind socket */ bacpy(&addr.l2_bdaddr, ba); addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(RFCOMM_PSM); + addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_cid = 0; err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0) { diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c54229befcf..163b4f5b036 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n) p->ucast_probes + p->app_probes + p->mcast_probes); } +static void neigh_invalidate(struct neighbour *neigh) +{ + struct sk_buff *skb; + + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); + NEIGH_PRINTK2("neigh %p is failed.\n", neigh); + neigh->updated = jiffies; + + /* It is very thin place. report_unreachable is very complicated + routine. Particularly, it can hit the same neighbour entry! + + So that, we try to be accurate and avoid dead loop. --ANK + */ + while (neigh->nud_state == NUD_FAILED && + (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { + write_unlock(&neigh->lock); + neigh->ops->error_report(neigh, skb); + write_lock(&neigh->lock); + } + skb_queue_purge(&neigh->arp_queue); +} + /* Called when a timer expires for a neighbour entry. */ static void neigh_timer_handler(unsigned long arg) @@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg) if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { - struct sk_buff *skb; - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; notify = 1; - NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); - NEIGH_PRINTK2("neigh %p is failed.\n", neigh); - - /* It is very thin place. report_unreachable is very complicated - routine. Particularly, it can hit the same neighbour entry! - - So that, we try to be accurate and avoid dead loop. --ANK - */ - while (neigh->nud_state == NUD_FAILED && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - write_unlock(&neigh->lock); - neigh->ops->error_report(neigh, skb); - write_lock(&neigh->lock); - } - skb_queue_purge(&neigh->arp_queue); + neigh_invalidate(neigh); } if (neigh->nud_state & NUD_IN_TIMER) { @@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh->nud_state = new; err = 0; notify = old & NUD_VALID; + if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && + (new & NUD_FAILED)) { + neigh_invalidate(neigh); + notify = 1; + } goto out; } diff --git a/net/core/sock.c b/net/core/sock.c index 04e35eb2e73..06e26b77ad9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1008,7 +1008,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, } EXPORT_SYMBOL(sk_alloc); -void sk_free(struct sock *sk) +static void __sk_free(struct sock *sk) { struct sk_filter *filter; @@ -1031,6 +1031,17 @@ void sk_free(struct sock *sk) put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } + +void sk_free(struct sock *sk) +{ + /* + * We substract one from sk_wmem_alloc and can know if + * some packets are still in some tx queue. + * If not null, sock_wfree() will call __sk_free(sk) later + */ + if (atomic_dec_and_test(&sk->sk_wmem_alloc)) + __sk_free(sk); +} EXPORT_SYMBOL(sk_free); /* @@ -1071,7 +1082,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; atomic_set(&newsk->sk_rmem_alloc, 0); - atomic_set(&newsk->sk_wmem_alloc, 0); + /* + * sk_wmem_alloc set to one (see sk_free() and sock_wfree()) + */ + atomic_set(&newsk->sk_wmem_alloc, 1); atomic_set(&newsk->sk_omem_alloc, 0); skb_queue_head_init(&newsk->sk_receive_queue); skb_queue_head_init(&newsk->sk_write_queue); @@ -1175,12 +1189,18 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; + int res; /* In case it might be waiting for more memory. */ - atomic_sub(skb->truesize, &sk->sk_wmem_alloc); + res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) sk->sk_write_space(sk); - sock_put(sk); + /* + * if sk_wmem_alloc reached 0, we are last user and should + * free this sock, as sk_free() call could not do it. + */ + if (res == 0) + __sk_free(sk); } EXPORT_SYMBOL(sock_wfree); @@ -1819,6 +1839,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp = ktime_set(-1L, 0); atomic_set(&sk->sk_refcnt, 1); + atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_drops, 0); } EXPORT_SYMBOL(sock_init_data); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 9248d2807ba..24702628266 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -498,7 +498,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index db6c7224a86..7c76e3d1821 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -680,7 +680,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) BUG_ON(frag->sk); if (skb->sk) { - sock_hold(skb->sk); frag->sk = skb->sk; frag->destructor = sock_wfree; truesizes += frag->truesize; |