summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/x86_64/ia32/ia32entry.S18
-rw-r--r--arch/x86_64/kernel/ptrace.c4
-rw-r--r--drivers/ata/ahci.c10
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-sff.c5
-rw-r--r--drivers/ieee1394/ieee1394_core.c2
-rw-r--r--drivers/ieee1394/ohci1394.c4
-rw-r--r--drivers/net/bnx2.c7
-rw-r--r--drivers/net/myri10ge/myri10ge.c3
-rw-r--r--drivers/net/phy/phy.c1
-rw-r--r--drivers/net/pppoe.c3
-rw-r--r--drivers/net/pppol2tp.c118
-rw-r--r--drivers/net/sky2.c368
-rw-r--r--drivers/net/sky2.h41
-rw-r--r--fs/exec.c3
-rw-r--r--fs/signalfd.c190
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/sched.h2
-rw-r--r--include/linux/signalfd.h40
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/signal.c8
-rw-r--r--net/netfilter/nfnetlink_log.c13
-rw-r--r--net/sched/sch_sfq.c10
-rw-r--r--net/sunrpc/svcsock.c3
26 files changed, 437 insertions, 439 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c54a5ef0ba7..9a91d9e3f1f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2622,8 +2622,8 @@ P: Harald Welte
P: Jozsef Kadlecsik
P: Patrick McHardy
M: kaber@trash.net
-L: netfilter-devel@lists.netfilter.org
-L: netfilter@lists.netfilter.org (subscribers-only)
+L: netfilter-devel@vger.kernel.org
+L: netfilter@vger.kernel.org
L: coreteam@netfilter.org
W: http://www.netfilter.org/
W: http://www.iptables.org/
@@ -2676,7 +2676,7 @@ M: jmorris@namei.org
P: Hideaki YOSHIFUJI
M: yoshfuji@linux-ipv6.org
P: Patrick McHardy
-M: kaber@coreworks.de
+M: kaber@trash.net
L: netdev@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git
S: Maintained
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 938278697e20..18b231810908 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -38,6 +38,18 @@
movq %rax,R8(%rsp)
.endm
+ .macro LOAD_ARGS32 offset
+ movl \offset(%rsp),%r11d
+ movl \offset+8(%rsp),%r10d
+ movl \offset+16(%rsp),%r9d
+ movl \offset+24(%rsp),%r8d
+ movl \offset+40(%rsp),%ecx
+ movl \offset+48(%rsp),%edx
+ movl \offset+56(%rsp),%esi
+ movl \offset+64(%rsp),%edi
+ movl \offset+72(%rsp),%eax
+ .endm
+
.macro CFI_STARTPROC32 simple
CFI_STARTPROC \simple
CFI_UNDEFINED r8
@@ -152,7 +164,7 @@ sysenter_tracesys:
movq $-ENOSYS,RAX(%rsp) /* really needed? */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
+ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
movl %ebp, %ebp
/* no need to do an access_ok check here because rbp has been
@@ -255,7 +267,7 @@ cstar_tracesys:
movq $-ENOSYS,RAX(%rsp) /* really needed? */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
+ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
movl RSP-ARGOFFSET(%rsp), %r8d
/* no need to do an access_ok check here because r8 has been
@@ -334,7 +346,7 @@ ia32_tracesys:
movq $-ENOSYS,RAX(%rsp) /* really needed? */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
- LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
+ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
jmp ia32_do_syscall
END(ia32_syscall)
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index e83cc67155ac..eea3702427b4 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -232,10 +232,6 @@ static int putreg(struct task_struct *child,
{
unsigned long tmp;
- /* Some code in the 64bit emulation may not be 64bit clean.
- Don't take any chances. */
- if (test_tsk_thread_flag(child, TIF_IA32))
- value &= 0xffffffff;
switch (regno) {
case offsetof(struct user_regs_struct,fs):
if (value && (value & 3) != 3)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 06f212ff2b4f..c16820325d7b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -418,10 +418,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
- { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
- { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
- { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
- { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
+ { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c43de9a710db..772be09b4689 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3778,6 +3778,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ },
{ "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ },
{ "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ },
+ { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, },
+ { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
{ "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
ATA_HORKAGE_NONCQ },
/* NCQ hard hangs device under heavier load, needs hard power cycle */
@@ -3794,6 +3797,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
{ "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
+ { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, },
{ "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, },
/* devices which puke on READ_NATIVE_MAX */
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 1cce2198baaf..8023167bbbeb 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -297,7 +297,7 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- /* Strictly, one may wish to issue a readb() here, to
+ /* Strictly, one may wish to issue an ioread8() here, to
* flush the mmio write. However, control also passes
* to the hardware at this point, and it will interrupt
* us when we are to resume control. So, in effect,
@@ -307,6 +307,9 @@ void ata_bmdma_start (struct ata_queued_cmd *qc)
* is expected, so I think it is best to not add a readb()
* without first all the MMIO ATA cards/mobos.
* Or maybe I'm just being paranoid.
+ *
+ * FIXME: The posting of this write means I/O starts are
+ * unneccessarily delayed for MMIO
*/
}
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index ee45259573c8..98fd985a32ff 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1273,7 +1273,7 @@ static void __exit ieee1394_cleanup(void)
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
}
-fs_initcall(ieee1394_init); /* same as ohci1394 */
+module_init(ieee1394_init);
module_exit(ieee1394_cleanup);
/* Exported symbols */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 5667c8102efc..372c5c16eb31 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3537,7 +3537,5 @@ static int __init ohci1394_init(void)
return pci_register_driver(&ohci1394_pci_driver);
}
-/* Register before most other device drivers.
- * Useful for remote debugging via physical DMA, e.g. using firescope. */
-fs_initcall(ohci1394_init);
+module_init(ohci1394_init);
module_exit(ohci1394_cleanup);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 854d80c330ec..66eed22cbd21 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -54,8 +54,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.6.4"
-#define DRV_MODULE_RELDATE "August 3, 2007"
+#define DRV_MODULE_VERSION "1.6.5"
+#define DRV_MODULE_RELDATE "September 20, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -6727,7 +6727,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
CHIP_NUM(bp) == CHIP_NUM_5708)
bp->phy_flags |= PHY_CRC_FIX_FLAG;
- else if (CHIP_ID(bp) == CHIP_ID_5709_A0)
+ else if (CHIP_ID(bp) == CHIP_ID_5709_A0 ||
+ CHIP_ID(bp) == CHIP_ID_5709_A1)
bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1c42266bf889..556962f9612d 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -3094,9 +3094,12 @@ static void myri10ge_remove(struct pci_dev *pdev)
}
#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009
static struct pci_device_id myri10ge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
+ {PCI_DEVICE
+ (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
{0},
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 0cc4369cacba..cb230f44d6fc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phydev,
return 0;
}
+EXPORT_SYMBOL(phy_mii_ioctl);
/**
* phy_start_aneg - start auto-negotiation for this PHY device
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 0d7f570b9a54..9b30cd600a64 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -879,8 +879,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
dev->hard_header(skb, dev, ETH_P_PPP_SES,
po->pppoe_pa.remote, NULL, data_len);
- if (dev_queue_xmit(skb) < 0)
- goto abort;
+ dev_queue_xmit(skb);
return 1;
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 266e8b38fe10..abe91cb595f4 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -491,44 +491,46 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
u16 hdrflags;
u16 tunnel_id, session_id;
int length;
- struct udphdr *uh;
+ int offset;
tunnel = pppol2tp_sock_to_tunnel(sock);
if (tunnel == NULL)
goto error;
+ /* UDP always verifies the packet length. */
+ __skb_pull(skb, sizeof(struct udphdr));
+
/* Short packet? */
- if (skb->len < sizeof(struct udphdr)) {
+ if (!pskb_may_pull(skb, 12)) {
PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
"%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
goto error;
}
/* Point to L2TP header */
- ptr = skb->data + sizeof(struct udphdr);
+ ptr = skb->data;
/* Get L2TP header flags */
hdrflags = ntohs(*(__be16*)ptr);
/* Trace packet contents, if enabled */
if (tunnel->debug & PPPOL2TP_MSG_DATA) {
+ length = min(16u, skb->len);
+ if (!pskb_may_pull(skb, length))
+ goto error;
+
printk(KERN_DEBUG "%s: recv: ", tunnel->name);
- for (length = 0; length < 16; length++)
- printk(" %02X", ptr[length]);
+ offset = 0;
+ do {
+ printk(" %02X", ptr[offset]);
+ } while (++offset < length);
+
printk("\n");
}
/* Get length of L2TP packet */
- uh = (struct udphdr *) skb_transport_header(skb);
- length = ntohs(uh->len) - sizeof(struct udphdr);
-
- /* Too short? */
- if (length < 12) {
- PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
- "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length);
- goto error;
- }
+ length = skb->len;
/* If type is control packet, it is handled by userspace. */
if (hdrflags & L2TP_HDRFLAG_T) {
@@ -606,7 +608,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
goto discard;
}
@@ -625,7 +626,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
"%s: recv data has no seq numbers when required. "
"Discarding\n", session->name);
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
goto discard;
}
@@ -634,10 +634,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
}
/* If offset bit set, skip it. */
- if (hdrflags & L2TP_HDRFLAG_O)
- ptr += 2 + ntohs(*(__be16 *) ptr);
+ if (hdrflags & L2TP_HDRFLAG_O) {
+ offset = ntohs(*(__be16 *)ptr);
+ skb->transport_header += 2 + offset;
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2))
+ goto discard;
+ }
- skb_pull(skb, ptr - skb->data);
+ __skb_pull(skb, skb_transport_offset(skb));
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
* don't send the PPP header (PPP header compression enabled), but
@@ -673,7 +677,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
*/
if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
session->stats.rx_seq_discards++;
- session->stats.rx_errors++;
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
"%s: oos pkt %hu len %d discarded, "
"waiting for %hu, reorder_q_len=%d\n",
@@ -698,6 +701,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
return 0;
discard:
+ session->stats.rx_errors++;
kfree_skb(skb);
sock_put(session->sock);
@@ -958,7 +962,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
int data_len = skb->len;
struct inet_sock *inet;
__wsum csum = 0;
- struct sk_buff *skb2 = NULL;
struct udphdr *uh;
unsigned int len;
@@ -989,41 +992,30 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
*/
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
sizeof(struct udphdr) + hdr_len + sizeof(ppph);
- if (skb_headroom(skb) < headroom) {
- skb2 = skb_realloc_headroom(skb, headroom);
- if (skb2 == NULL)
- goto abort;
- } else
- skb2 = skb;
-
- /* Check that the socket has room */
- if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf)
- skb_set_owner_w(skb2, sk_tun);
- else
- goto discard;
+ if (skb_cow_head(skb, headroom))
+ goto abort;
/* Setup PPP header */
- skb_push(skb2, sizeof(ppph));
- skb2->data[0] = ppph[0];
- skb2->data[1] = ppph[1];
+ __skb_push(skb, sizeof(ppph));
+ skb->data[0] = ppph[0];
+ skb->data[1] = ppph[1];
/* Setup L2TP header */
- skb_push(skb2, hdr_len);
- pppol2tp_build_l2tp_header(session, skb2->data);
+ pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
/* Setup UDP header */
inet = inet_sk(sk_tun);
- skb_push(skb2, sizeof(struct udphdr));
- skb_reset_transport_header(skb2);
- uh = (struct udphdr *) skb2->data;
+ __skb_push(skb, sizeof(*uh));
+ skb_reset_transport_header(skb);
+ uh = udp_hdr(skb);
uh->source = inet->sport;
uh->dest = inet->dport;
uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
uh->check = 0;
- /* Calculate UDP checksum if configured to do so */
+ /* *BROKEN* Calculate UDP checksum if configured to do so */
if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
- csum = udp_csum_outgoing(sk_tun, skb2);
+ csum = udp_csum_outgoing(sk_tun, skb);
/* Debug */
if (session->send_seq)
@@ -1036,7 +1028,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if (session->debug & PPPOL2TP_MSG_DATA) {
int i;
- unsigned char *datap = skb2->data;
+ unsigned char *datap = skb->data;
printk(KERN_DEBUG "%s: xmit:", session->name);
for (i = 0; i < data_len; i++) {
@@ -1049,18 +1041,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
printk("\n");
}
- memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
- IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
- IPSKB_REROUTED);
- nf_reset(skb2);
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+ IPSKB_REROUTED);
+ nf_reset(skb);
/* Get routing info from the tunnel socket */
- dst_release(skb2->dst);
- skb2->dst = sk_dst_get(sk_tun);
+ dst_release(skb->dst);
+ skb->dst = sk_dst_get(sk_tun);
/* Queue the packet to IP for output */
- len = skb2->len;
- rc = ip_queue_xmit(skb2, 1);
+ len = skb->len;
+ rc = ip_queue_xmit(skb, 1);
/* Update stats */
if (rc >= 0) {
@@ -1073,17 +1065,12 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
session->stats.tx_errors++;
}
- /* Free the original skb */
- kfree_skb(skb);
-
return 1;
-discard:
- /* Free the new skb. Caller will free original skb. */
- if (skb2 != skb)
- kfree_skb(skb2);
abort:
- return 0;
+ /* Free the original skb */
+ kfree_skb(skb);
+ return 1;
}
/*****************************************************************************
@@ -1326,12 +1313,14 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
goto err;
}
+ sk = sock->sk;
+
/* Quick sanity checks */
- err = -ESOCKTNOSUPPORT;
- if (sock->type != SOCK_DGRAM) {
+ err = -EPROTONOSUPPORT;
+ if (sk->sk_protocol != IPPROTO_UDP) {
PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
- "tunl %hu: fd %d wrong type, got %d, expected %d\n",
- tunnel_id, fd, sock->type, SOCK_DGRAM);
+ "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+ tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
goto err;
}
err = -EAFNOSUPPORT;
@@ -1343,7 +1332,6 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
}
err = -ENOTCONN;
- sk = sock->sk;
/* Check if this socket has already been prepped */
tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 5d812de65d90..eaffe551d1d8 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -51,7 +51,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.17"
+#define DRV_VERSION "1.18"
#define PFX DRV_NAME " "
/*
@@ -118,12 +118,15 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
@@ -147,6 +150,7 @@ static const char *yukon2_name[] = {
"Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
+ "FE+", /* 0xb8 */
};
static void sky2_set_multicast(struct net_device *dev);
@@ -217,8 +221,7 @@ static void sky2_power_on(struct sky2_hw *hw)
else
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
- hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
u32 reg;
sky2_pci_write32(hw, PCI_DEV_REG3, 0);
@@ -311,10 +314,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
- if (sky2->autoneg == AUTONEG_ENABLE
- && !(hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX)) {
+ if (sky2->autoneg == AUTONEG_ENABLE &&
+ !(hw->flags & SKY2_HW_NEWER_PHY)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -334,7 +335,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
if (sky2_is_copper(hw)) {
- if (hw->chip_id == CHIP_ID_YUKON_FE) {
+ if (!(hw->flags & SKY2_HW_GIGABIT)) {
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
} else {
@@ -346,9 +347,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* downshift on PHY 88E1112 and 88E1149 is changed */
if (sky2->autoneg == AUTONEG_ENABLE
- && (hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX)) {
+ && (hw->flags & SKY2_HW_NEWER_PHY)) {
/* set downshift counter to 3x and enable downshift */
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
@@ -364,7 +363,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
/* special setup for PHY 88E1112 Fiber */
- if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) {
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
/* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
@@ -455,7 +454,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gma_write16(hw, port, GM_GP_CTRL, reg);
- if (hw->chip_id != CHIP_ID_YUKON_FE)
+ if (hw->flags & SKY2_HW_GIGABIT)
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
@@ -479,6 +478,23 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
break;
+ case CHIP_ID_YUKON_FE_P:
+ /* Enable Link Partner Next Page */
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ ctrl |= PHY_M_PC_ENA_LIP_NP;
+
+ /* disable Energy Detect and enable scrambler */
+ ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB);
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ /* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */
+ ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) |
+ PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) |
+ PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED);
+
+ gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
+ break;
+
case CHIP_ID_YUKON_XL:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
@@ -548,7 +564,13 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+ } else if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+ /* apply workaround for integrated resistors calibration */
+ gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17);
+ gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60);
} else if (hw->chip_id != CHIP_ID_YUKON_EX) {
+ /* no effect on Yukon-XL */
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -669,25 +691,25 @@ static void sky2_wol_init(struct sky2_port *sky2)
static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
{
- if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
+ struct net_device *dev = hw->dev[port];
+
+ if (dev->mtu <= ETH_DATA_LEN)
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_STFW_ENA |
- (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
- } else {
- if (hw->dev[port]->mtu > ETH_DATA_LEN) {
- /* set Tx GMAC FIFO Almost Empty Threshold */
- sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
- (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+ TX_JUMBO_DIS | TX_STFW_ENA);
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_ENA | TX_STFW_DIS);
+ else if (hw->chip_id != CHIP_ID_YUKON_EC_U)
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_STFW_ENA | TX_JUMBO_ENA);
+ else {
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+ sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+ (ECU_JUMBO_WM << 16) | ECU_AE_THR);
- /* Can't do offload because of lack of store/forward */
- hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
- | NETIF_F_ALL_CSUM);
- } else
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_DIS | TX_STFW_ENA);
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_JUMBO_ENA | TX_STFW_DIS);
+
+ /* Can't do offload because of lack of store/forward */
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
}
}
@@ -773,7 +795,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
- if (hw->chip_id == CHIP_ID_YUKON_EX)
+ if (hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
rx_reg |= GMF_RX_OVER_ON;
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
@@ -782,13 +805,18 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
/* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */
- sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
+ reg = RX_GMF_FL_THR_DEF + 1;
+ /* Another magic mystery workaround from sk98lin */
+ if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0)
+ reg = 0x178;
+ sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg);
/* Configure Tx MAC FIFO */
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (!(hw->flags & SKY2_HW_RAMBUFFER)) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
@@ -967,19 +995,15 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
*/
static void rx_set_checksum(struct sky2_port *sky2)
{
- struct sky2_rx_le *le;
+ struct sky2_rx_le *le = sky2_next_rx(sky2);
- if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) {
- le = sky2_next_rx(sky2);
- le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
- le->ctrl = 0;
- le->opcode = OP_TCPSTART | HW_OWNER;
-
- sky2_write32(sky2->hw,
- Q_ADDR(rxqaddr[sky2->port], Q_CSR),
- sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
- }
+ le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+ le->ctrl = 0;
+ le->opcode = OP_TCPSTART | HW_OWNER;
+ sky2_write32(sky2->hw,
+ Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+ sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
}
/*
@@ -1175,7 +1199,8 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
- rx_set_checksum(sky2);
+ if (!(hw->flags & SKY2_HW_NEW_LE))
+ rx_set_checksum(sky2);
/* Space needed for frame data + headers rounded up */
size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
@@ -1246,7 +1271,7 @@ static int sky2_up(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
- u32 ramsize, imask;
+ u32 imask;
int cap, err = -ENOMEM;
struct net_device *otherdev = hw->dev[sky2->port^1];
@@ -1301,13 +1326,13 @@ static int sky2_up(struct net_device *dev)
sky2_mac_init(hw, port);
- /* Register is number of 4K blocks on internal RAM buffer. */
- ramsize = sky2_read8(hw, B2_E_0) * 4;
- printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize);
-
- if (ramsize > 0) {
+ if (hw->flags & SKY2_HW_RAMBUFFER) {
+ /* Register is number of 4K blocks on internal RAM buffer. */
+ u32 ramsize = sky2_read8(hw, B2_E_0) * 4;
u32 rxspace;
+ printk(KERN_DEBUG PFX "%s: ram buffer %dK\n", dev->name, ramsize);
+
if (ramsize < 16)
rxspace = ramsize / 2;
else
@@ -1436,13 +1461,15 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Check for TCP Segmentation Offload */
mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
- if (hw->chip_id != CHIP_ID_YUKON_EX)
+
+ if (!(hw->flags & SKY2_HW_NEW_LE))
mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
if (mss != sky2->tx_last_mss) {
le = get_tx_le(sky2);
le->addr = cpu_to_le32(mss);
- if (hw->chip_id == CHIP_ID_YUKON_EX)
+
+ if (hw->flags & SKY2_HW_NEW_LE)
le->opcode = OP_MSS | HW_OWNER;
else
le->opcode = OP_LRGLEN | HW_OWNER;
@@ -1468,8 +1495,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
/* On Yukon EX (some versions) encoding change. */
- if (hw->chip_id == CHIP_ID_YUKON_EX
- && hw->chip_rev != CHIP_REV_YU_EX_B0)
+ if (hw->flags & SKY2_HW_AUTO_TX_SUM)
ctrl |= CALSUM; /* auto checksum */
else {
const unsigned offset = skb_transport_offset(skb);
@@ -1622,9 +1648,6 @@ static int sky2_down(struct net_device *dev)
if (netif_msg_ifdown(sky2))
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
- if (netif_carrier_ok(dev) && --hw->active == 0)
- del_timer(&hw->watchdog_timer);
-
/* Stop more packets from being queued */
netif_stop_queue(dev);
@@ -1708,11 +1731,15 @@ static int sky2_down(struct net_device *dev)
static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
{
- if (!sky2_is_copper(hw))
+ if (hw->flags & SKY2_HW_FIBRE_PHY)
return SPEED_1000;
- if (hw->chip_id == CHIP_ID_YUKON_FE)
- return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
+ if (!(hw->flags & SKY2_HW_GIGABIT)) {
+ if (aux & PHY_M_PS_SPEED_100)
+ return SPEED_100;
+ else
+ return SPEED_10;
+ }
switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
@@ -1745,17 +1772,13 @@ static void sky2_link_up(struct sky2_port *sky2)
netif_carrier_on(sky2->netdev);
- if (hw->active++ == 0)
- mod_timer(&hw->watchdog_timer, jiffies + 1);
-
+ mod_timer(&hw->watchdog_timer, jiffies + 1);
/* Turn on link LED */
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL
- || hw->chip_id == CHIP_ID_YUKON_EC_U
- || hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_NEWER_PHY) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
@@ -1800,11 +1823,6 @@ static void sky2_link_down(struct sky2_port *sky2)
netif_carrier_off(sky2->netdev);
- /* Stop watchdog if both ports are not active */
- if (--hw->active == 0)
- del_timer(&hw->watchdog_timer);
-
-
/* Turn on link LED */
sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
@@ -1847,7 +1865,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
/* Since the pause result bits seem to in different positions on
* different chips. look at registers.
*/
- if (!sky2_is_copper(hw)) {
+ if (hw->flags & SKY2_HW_FIBRE_PHY) {
/* Shift for bits in fiber PHY */
advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
@@ -1958,7 +1976,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
- if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE)
+ if (new_mtu > ETH_DATA_LEN &&
+ (hw->chip_id == CHIP_ID_YUKON_FE ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P))
return -EINVAL;
if (!netif_running(dev)) {
@@ -1975,7 +1995,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
synchronize_irq(hw->pdev->irq);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+ if (!(hw->flags & SKY2_HW_RAMBUFFER))
sky2_set_tx_stfwd(hw, port);
ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -2103,6 +2123,13 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
struct sky2_port *sky2 = netdev_priv(dev);
struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
+ u16 count = (status & GMR_FS_LEN) >> 16;
+
+#ifdef SKY2_VLAN_TAG_USED
+ /* Account for vlan tag */
+ if (sky2->vlgrp && (status & GMR_FS_VLAN))
+ count -= VLAN_HLEN;
+#endif
if (unlikely(netif_msg_rx_status(sky2)))
printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
@@ -2117,7 +2144,8 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
if (!(status & GMR_FS_RX_OK))
goto resubmit;
- if (status >> 16 != length)
+ /* if length reported by DMA does not match PHY, packet was truncated */
+ if (length != count)
goto len_mismatch;
if (length < copybreak)
@@ -2133,6 +2161,10 @@ len_mismatch:
/* Truncation of overlength packets
causes PHY length to not match MAC length */
++sky2->net_stats.rx_length_errors;
+ if (netif_msg_rx_err(sky2) && net_ratelimit())
+ pr_info(PFX "%s: rx length mismatch: length %d status %#x\n",
+ dev->name, length, status);
+ goto resubmit;
error:
++sky2->net_stats.rx_errors;
@@ -2202,7 +2234,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
/* This chip reports checksum status differently */
- if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (hw->flags & SKY2_HW_NEW_LE) {
if (sky2->rx_csum &&
(le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
(le->css & CSS_TCPUDPCSOK))
@@ -2243,8 +2275,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
if (!sky2->rx_csum)
break;
- if (hw->chip_id == CHIP_ID_YUKON_EX)
+ /* If this happens then driver assuming wrong format */
+ if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
+ if (net_ratelimit())
+ printk(KERN_NOTICE "%s: unexpected"
+ " checksum status\n",
+ dev->name);
break;
+ }
/* Both checksum counters are programmed to start at
* the same offset, so unless there is a problem they
@@ -2436,20 +2474,72 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port,
sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
}
-/* Check for lost IRQ once a second */
+static int sky2_rx_hung(struct net_device *dev)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+ unsigned port = sky2->port;
+ unsigned rxq = rxqaddr[port];
+ u32 mac_rp = sky2_read32(hw, SK_REG(port, RX_GMF_RP));
+ u8 mac_lev = sky2_read8(hw, SK_REG(port, RX_GMF_RLEV));
+ u8 fifo_rp = sky2_read8(hw, Q_ADDR(rxq, Q_RP));
+ u8 fifo_lev = sky2_read8(hw, Q_ADDR(rxq, Q_RL));
+
+ /* If idle and MAC or PCI is stuck */
+ if (sky2->check.last == dev->last_rx &&
+ ((mac_rp == sky2->check.mac_rp &&
+ mac_lev != 0 && mac_lev >= sky2->check.mac_lev) ||
+ /* Check if the PCI RX hang */
+ (fifo_rp == sky2->check.fifo_rp &&
+ fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) {
+ printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n",
+ dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp,
+ sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
+ return 1;
+ } else {
+ sky2->check.last = dev->last_rx;
+ sky2->check.mac_rp = mac_rp;
+ sky2->check.mac_lev = mac_lev;
+ sky2->check.fifo_rp = fifo_rp;
+ sky2->check.fifo_lev = fifo_lev;
+ return 0;
+ }
+}
+
static void sky2_watchdog(unsigned long arg)
{
struct sky2_hw *hw = (struct sky2_hw *) arg;
+ struct net_device *dev;
+ /* Check for lost IRQ once a second */
if (sky2_read32(hw, B0_ISRC)) {
- struct net_device *dev = hw->dev[0];
-
+ dev = hw->dev[0];
if (__netif_rx_schedule_prep(dev))
__netif_rx_schedule(dev);
+ } else {
+ int i, active = 0;
+
+ for (i = 0; i < hw->ports; i++) {
+ dev = hw->dev[i];
+ if (!netif_running(dev))
+ continue;
+ ++active;
+
+ /* For chips with Rx FIFO, check if stuck */
+ if ((hw->flags & SKY2_HW_RAMBUFFER) &&
+ sky2_rx_hung(dev)) {
+ pr_info(PFX "%s: receiver hang detected\n",
+ dev->name);
+ schedule_work(&hw->restart_work);
+ return;
+ }
+ }
+
+ if (active == 0)
+ return;
}
- if (hw->active > 0)
- mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ));
+ mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ));
}
/* Hardware/software error handling */
@@ -2546,17 +2636,25 @@ static void sky2_netpoll(struct net_device *dev)
#endif
/* Chip internal frequency for clock calculations */
-static inline u32 sky2_mhz(const struct sky2_hw *hw)
+static u32 sky2_mhz(const struct sky2_hw *hw)
{
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
case CHIP_ID_YUKON_EX:
- return 125; /* 125 Mhz */
+ return 125;
+
case CHIP_ID_YUKON_FE:
- return 100; /* 100 Mhz */
- default: /* YUKON_XL */
- return 156; /* 156 Mhz */
+ return 100;
+
+ case CHIP_ID_YUKON_FE_P:
+ return 50;
+
+ case CHIP_ID_YUKON_XL:
+ return 156;
+
+ default:
+ BUG();
}
}
@@ -2581,23 +2679,62 @@ static int __devinit sky2_init(struct sky2_hw *hw)
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
- if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
+ hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+
+ switch(hw->chip_id) {
+ case CHIP_ID_YUKON_XL:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY
+ | SKY2_HW_RAMBUFFER;
+ break;
+
+ case CHIP_ID_YUKON_EC_U:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY
+ | SKY2_HW_ADV_POWER_CTL;
+ break;
+
+ case CHIP_ID_YUKON_EX:
+ hw->flags = SKY2_HW_GIGABIT
+ | SKY2_HW_NEWER_PHY
+ | SKY2_HW_NEW_LE
+ | SKY2_HW_ADV_POWER_CTL;
+
+ /* New transmit checksum */
+ if (hw->chip_rev != CHIP_REV_YU_EX_B0)
+ hw->flags |= SKY2_HW_AUTO_TX_SUM;
+ break;
+
+ case CHIP_ID_YUKON_EC:
+ /* This rev is really old, and requires untested workarounds */
+ if (hw->chip_rev == CHIP_REV_YU_EC_A1) {
+ dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
+ return -EOPNOTSUPP;
+ }
+ hw->flags = SKY2_HW_GIGABIT | SKY2_HW_RAMBUFFER;
+ break;
+
+ case CHIP_ID_YUKON_FE:
+ hw->flags = SKY2_HW_RAMBUFFER;
+ break;
+
+ case CHIP_ID_YUKON_FE_P:
+ hw->flags = SKY2_HW_NEWER_PHY
+ | SKY2_HW_NEW_LE
+ | SKY2_HW_AUTO_TX_SUM
+ | SKY2_HW_ADV_POWER_CTL;
+ break;
+ default:
dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
hw->chip_id);
return -EOPNOTSUPP;
}
- hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
+ hw->flags |= SKY2_HW_FIBRE_PHY;
- /* This rev is really old, and requires untested workarounds */
- if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
- dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
- yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
- hw->chip_id, hw->chip_rev);
- return -EOPNOTSUPP;
- }
- hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
hw->ports = 1;
t8 = sky2_read8(hw, B2_Y2_HW_RES);
if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
@@ -2791,7 +2928,9 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
sky2->wol = wol->wolopts;
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
+ hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
@@ -2809,7 +2948,7 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw)
| SUPPORTED_100baseT_Full
| SUPPORTED_Autoneg | SUPPORTED_TP;
- if (hw->chip_id != CHIP_ID_YUKON_FE)
+ if (hw->flags & SKY2_HW_GIGABIT)
modes |= SUPPORTED_1000baseT_Half
| SUPPORTED_1000baseT_Full;
return modes;
@@ -2829,13 +2968,6 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->supported = sky2_supported_modes(hw);
ecmd->phy_address = PHY_ADDR_MARV;
if (sky2_is_copper(hw)) {
- ecmd->supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_TP;
ecmd->port = PORT_TP;
ecmd->speed = sky2->speed;
} else {
@@ -3791,6 +3923,13 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->hw = hw;
sky2->msg_enable = netif_msg_init(debug, default_msg);
+ /* This chip has hardware problems that generates
+ * bogus PHY receive status so by default shut up the message.
+ */
+ if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0)
+ sky2->msg_enable &= ~NETIF_MSG_RX_ERR;
+
/* Auto speed and flow control */
sky2->autoneg = AUTONEG_ENABLE;
sky2->flow_mode = FC_BOTH;
@@ -3846,7 +3985,7 @@ static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id)
return IRQ_NONE;
if (status & Y2_IS_IRQ_SW) {
- hw->msi = 1;
+ hw->flags |= SKY2_HW_USE_MSI;
wake_up(&hw->msi_wait);
sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
}
@@ -3874,9 +4013,9 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
sky2_read8(hw, B0_CTST);
- wait_event_timeout(hw->msi_wait, hw->msi, HZ/10);
+ wait_event_timeout(hw->msi_wait, (hw->flags & SKY2_HW_USE_MSI), HZ/10);
- if (!hw->msi) {
+ if (!(hw->flags & SKY2_HW_USE_MSI)) {
/* MSI test failed, go back to INTx mode */
dev_info(&pdev->dev, "No interrupt generated using MSI, "
"switching to INTx mode.\n");
@@ -4009,7 +4148,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED,
+ err = request_irq(pdev->irq, sky2_intr,
+ (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
dev->name, hw);
if (err) {
dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
@@ -4042,7 +4182,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
return 0;
err_out_unregister:
- if (hw->msi)
+ if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
unregister_netdev(dev);
err_out_free_netdev:
@@ -4091,7 +4231,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
sky2_read8(hw, B0_CTST);
free_irq(pdev->irq, hw);
- if (hw->msi)
+ if (hw->flags & SKY2_HW_USE_MSI)
pci_disable_msi(pdev);
pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
pci_release_regions(pdev);
@@ -4159,7 +4299,9 @@ static int sky2_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D0, 0);
/* Re-enable all clocks */
- if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ if (hw->chip_id == CHIP_ID_YUKON_EX ||
+ hw->chip_id == CHIP_ID_YUKON_EC_U ||
+ hw->chip_id == CHIP_ID_YUKON_FE_P)
sky2_pci_write32(hw, PCI_DEV_REG3, 0);
sky2_reset(hw);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 72e12b7cfa40..69cd98400fe6 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -470,18 +470,24 @@ enum {
CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
-
+ CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */
+};
+enum yukon_ec_rev {
CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */
CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */
CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */
-
+};
+enum yukon_ec_u_rev {
CHIP_REV_YU_EC_U_A0 = 1,
CHIP_REV_YU_EC_U_A1 = 2,
CHIP_REV_YU_EC_U_B0 = 3,
-
+};
+enum yukon_fe_rev {
CHIP_REV_YU_FE_A1 = 1,
CHIP_REV_YU_FE_A2 = 2,
-
+};
+enum yukon_fe_p_rev {
+ CHIP_REV_YU_FE2_A0 = 0,
};
enum yukon_ex_rev {
CHIP_REV_YU_EX_A0 = 1,
@@ -1668,7 +1674,7 @@ enum {
/* Receive Frame Status Encoding */
enum {
- GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */
+ GMR_FS_LEN = 0x7fff<<16, /* Bit 30..16: Rx Frame Length */
GMR_FS_VLAN = 1<<13, /* VLAN Packet */
GMR_FS_JABBER = 1<<12, /* Jabber Packet */
GMR_FS_UN_SIZE = 1<<11, /* Undersize Packet */
@@ -1729,6 +1735,10 @@ enum {
GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON,
};
+/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */
+enum {
+ TX_DYN_WM_ENA = 3, /* Yukon-FE+ specific */
+};
/* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */
enum {
@@ -2017,6 +2027,14 @@ struct sky2_port {
u16 rx_tag;
struct vlan_group *vlgrp;
#endif
+ struct {
+ unsigned long last;
+ u32 mac_rp;
+ u8 mac_lev;
+ u8 fifo_rp;
+ u8 fifo_lev;
+ } check;
+
dma_addr_t rx_le_map;
dma_addr_t tx_le_map;
@@ -2040,12 +2058,20 @@ struct sky2_hw {
void __iomem *regs;
struct pci_dev *pdev;
struct net_device *dev[2];
+ unsigned long flags;
+#define SKY2_HW_USE_MSI 0x00000001
+#define SKY2_HW_FIBRE_PHY 0x00000002
+#define SKY2_HW_GIGABIT 0x00000004
+#define SKY2_HW_NEWER_PHY 0x00000008
+#define SKY2_HW_RAMBUFFER 0x00000010 /* chip has RAM FIFO */
+#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */
+#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
+#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
u8 chip_id;
u8 chip_rev;
u8 pmd_type;
u8 ports;
- u8 active;
struct sky2_status_le *st_le;
u32 st_idx;
@@ -2053,13 +2079,12 @@ struct sky2_hw {
struct timer_list watchdog_timer;
struct work_struct restart_work;
- int msi;
wait_queue_head_t msi_wait;
};
static inline int sky2_is_copper(const struct sky2_hw *hw)
{
- return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P');
+ return !(hw->flags & SKY2_HW_FIBRE_PHY);
}
/* Register accessor for memory mapped device */
diff --git a/fs/exec.c b/fs/exec.c
index c21a8cc06277..073b0b8c6d05 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,7 +50,6 @@
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/audit.h>
-#include <linux/signalfd.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -784,7 +783,6 @@ static int de_thread(struct task_struct *tsk)
* and we can just re-use it all.
*/
if (atomic_read(&oldsighand->count) <= 1) {
- signalfd_detach(tsk);
exit_itimers(sig);
return 0;
}
@@ -923,7 +921,6 @@ static int de_thread(struct task_struct *tsk)
sig->flags = 0;
no_thread_group:
- signalfd_detach(tsk);
exit_itimers(sig);
if (leader)
release_task(leader);
diff --git a/fs/signalfd.c b/fs/signalfd.c
index a8e293d30034..aefb0be07942 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -11,8 +11,10 @@
* Now using anonymous inode source.
* Thanks to Oleg Nesterov for useful code review and suggestions.
* More comments and suggestions from Arnd Bergmann.
- * Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br>
+ * Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br>
* Retrieve multiple signals with one read() call
+ * Sun Jul 15, 2007: Davide Libenzi <davidel@xmailserver.org>
+ * Attach to the sighand only during read() and poll().
*/
#include <linux/file.h>
@@ -27,102 +29,12 @@
#include <linux/signalfd.h>
struct signalfd_ctx {
- struct list_head lnk;
- wait_queue_head_t wqh;
sigset_t sigmask;
- struct task_struct *tsk;
};
-struct signalfd_lockctx {
- struct task_struct *tsk;
- unsigned long flags;
-};
-
-/*
- * Tries to acquire the sighand lock. We do not increment the sighand
- * use count, and we do not even pin the task struct, so we need to
- * do it inside an RCU read lock, and we must be prepared for the
- * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand
- * being detached. We return 0 if the sighand has been detached, or
- * 1 if we were able to pin the sighand lock.
- */
-static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
-{
- struct sighand_struct *sighand = NULL;
-
- rcu_read_lock();
- lk->tsk = rcu_dereference(ctx->tsk);
- if (likely(lk->tsk != NULL))
- sighand = lock_task_sighand(lk->tsk, &lk->flags);
- rcu_read_unlock();
-
- if (!sighand)
- return 0;
-
- if (!ctx->tsk) {
- unlock_task_sighand(lk->tsk, &lk->flags);
- return 0;
- }
-
- if (lk->tsk->tgid == current->tgid)
- lk->tsk = current;
-
- return 1;
-}
-
-static void signalfd_unlock(struct signalfd_lockctx *lk)
-{
- unlock_task_sighand(lk->tsk, &lk->flags);
-}
-
-/*
- * This must be called with the sighand lock held.
- */
-void signalfd_deliver(struct task_struct *tsk, int sig)
-{
- struct sighand_struct *sighand = tsk->sighand;
- struct signalfd_ctx *ctx, *tmp;
-
- BUG_ON(!sig);
- list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) {
- /*
- * We use a negative signal value as a way to broadcast that the
- * sighand has been orphaned, so that we can notify all the
- * listeners about this. Remember the ctx->sigmask is inverted,
- * so if the user is interested in a signal, that corresponding
- * bit will be zero.
- */
- if (sig < 0) {
- if (ctx->tsk == tsk) {
- ctx->tsk = NULL;
- list_del_init(&ctx->lnk);
- wake_up(&ctx->wqh);
- }
- } else {
- if (!sigismember(&ctx->sigmask, sig))
- wake_up(&ctx->wqh);
- }
- }
-}
-
-static void signalfd_cleanup(struct signalfd_ctx *ctx)
-{
- struct signalfd_lockctx lk;
-
- /*
- * This is tricky. If the sighand is gone, we do not need to remove
- * context from the list, the list itself won't be there anymore.
- */
- if (signalfd_lock(ctx, &lk)) {
- list_del(&ctx->lnk);
- signalfd_unlock(&lk);
- }
- kfree(ctx);
-}
-
static int signalfd_release(struct inode *inode, struct file *file)
{
- signalfd_cleanup(file->private_data);
+ kfree(file->private_data);
return 0;
}
@@ -130,23 +42,15 @@ static unsigned int signalfd_poll(struct file *file, poll_table *wait)
{
struct signalfd_ctx *ctx = file->private_data;
unsigned int events = 0;
- struct signalfd_lockctx lk;
- poll_wait(file, &ctx->wqh, wait);
+ poll_wait(file, &current->sighand->signalfd_wqh, wait);
- /*
- * Let the caller get a POLLIN in this case, ala socket recv() when
- * the peer disconnects.
- */
- if (signalfd_lock(ctx, &lk)) {
- if ((lk.tsk == current &&
- next_signal(&lk.tsk->pending, &ctx->sigmask) > 0) ||
- next_signal(&lk.tsk->signal->shared_pending,
- &ctx->sigmask) > 0)
- events |= POLLIN;
- signalfd_unlock(&lk);
- } else
+ spin_lock_irq(&current->sighand->siglock);
+ if (next_signal(&current->pending, &ctx->sigmask) ||
+ next_signal(&current->signal->shared_pending,
+ &ctx->sigmask))
events |= POLLIN;
+ spin_unlock_irq(&current->sighand->siglock);
return events;
}
@@ -219,59 +123,46 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,
int nonblock)
{
ssize_t ret;
- struct signalfd_lockctx lk;
DECLARE_WAITQUEUE(wait, current);
- if (!signalfd_lock(ctx, &lk))
- return 0;
-
- ret = dequeue_signal(lk.tsk, &ctx->sigmask, info);
+ spin_lock_irq(&current->sighand->siglock);
+ ret = dequeue_signal(current, &ctx->sigmask, info);
switch (ret) {
case 0:
if (!nonblock)
break;
ret = -EAGAIN;
default:
- signalfd_unlock(&lk);
+ spin_unlock_irq(&current->sighand->siglock);
return ret;
}
- add_wait_queue(&ctx->wqh, &wait);
+ add_wait_queue(&current->sighand->signalfd_wqh, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- ret = dequeue_signal(lk.tsk, &ctx->sigmask, info);
- signalfd_unlock(&lk);
+ ret = dequeue_signal(current, &ctx->sigmask, info);
if (ret != 0)
break;
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
+ spin_unlock_irq(&current->sighand->siglock);
schedule();
- ret = signalfd_lock(ctx, &lk);
- if (unlikely(!ret)) {
- /*
- * Let the caller read zero byte, ala socket
- * recv() when the peer disconnect. This test
- * must be done before doing a dequeue_signal(),
- * because if the sighand has been orphaned,
- * the dequeue_signal() call is going to crash
- * because ->sighand will be long gone.
- */
- break;
- }
+ spin_lock_irq(&current->sighand->siglock);
}
+ spin_unlock_irq(&current->sighand->siglock);
- remove_wait_queue(&ctx->wqh, &wait);
+ remove_wait_queue(&current->sighand->signalfd_wqh, &wait);
__set_current_state(TASK_RUNNING);
return ret;
}
/*
- * Returns either the size of a "struct signalfd_siginfo", or zero if the
- * sighand we are attached to, has been orphaned. The "count" parameter
- * must be at least the size of a "struct signalfd_siginfo".
+ * Returns a multiple of the size of a "struct signalfd_siginfo", or a negative
+ * error code. The "count" parameter must be at least the size of a
+ * "struct signalfd_siginfo".
*/
static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
@@ -287,7 +178,6 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
return -EINVAL;
siginfo = (struct signalfd_siginfo __user *) buf;
-
do {
ret = signalfd_dequeue(ctx, &info, nonblock);
if (unlikely(ret <= 0))
@@ -300,7 +190,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
nonblock = 1;
} while (--count);
- return total ? total : ret;
+ return total ? total: ret;
}
static const struct file_operations signalfd_fops = {
@@ -309,20 +199,13 @@ static const struct file_operations signalfd_fops = {
.read = signalfd_read,
};
-/*
- * Create a file descriptor that is associated with our signal
- * state. We can pass it around to others if we want to, but
- * it will always be _our_ signal state.
- */
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
{
int error;
sigset_t sigmask;
struct signalfd_ctx *ctx;
- struct sighand_struct *sighand;
struct file *file;
struct inode *inode;
- struct signalfd_lockctx lk;
if (sizemask != sizeof(sigset_t) ||
copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
@@ -335,17 +218,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
if (!ctx)
return -ENOMEM;
- init_waitqueue_head(&ctx->wqh);
ctx->sigmask = sigmask;
- ctx->tsk = current->group_leader;
-
- sighand = current->sighand;
- /*
- * Add this fd to the list of signal listeners.
- */
- spin_lock_irq(&sighand->siglock);
- list_add_tail(&ctx->lnk, &sighand->signalfd_list);
- spin_unlock_irq(&sighand->siglock);
/*
* When we call this, the initialization must be complete, since
@@ -364,23 +237,18 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
fput(file);
return -EINVAL;
}
- /*
- * We need to be prepared of the fact that the sighand this fd
- * is attached to, has been detched. In that case signalfd_lock()
- * will return 0, and we'll just skip setting the new mask.
- */
- if (signalfd_lock(ctx, &lk)) {
- ctx->sigmask = sigmask;
- signalfd_unlock(&lk);
- }
- wake_up(&ctx->wqh);
+ spin_lock_irq(&current->sighand->siglock);
+ ctx->sigmask = sigmask;
+ spin_unlock_irq(&current->sighand->siglock);
+
+ wake_up(&current->sighand->signalfd_wqh);
fput(file);
}
return ufd;
err_fdalloc:
- signalfd_cleanup(ctx);
+ kfree(ctx);
return error;
}
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index cab741c2d603..f8abfa349ef9 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -86,7 +86,7 @@ extern struct nsproxy init_nsproxy;
.count = ATOMIC_INIT(1), \
.action = { { { .sa_handler = NULL, } }, }, \
.siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \
- .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \
+ .signalfd_wqh = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh), \
}
extern struct group_info init_groups;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3de79016f2a6..a01ac6dd5f5e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -438,7 +438,7 @@ struct sighand_struct {
atomic_t count;
struct k_sigaction action[_NSIG];
spinlock_t siglock;
- struct list_head signalfd_list;
+ wait_queue_head_t signalfd_wqh;
};
struct pacct_struct {
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
index 510429495690..4c9ff0910ae0 100644
--- a/include/linux/signalfd.h
+++ b/include/linux/signalfd.h
@@ -45,49 +45,17 @@ struct signalfd_siginfo {
#ifdef CONFIG_SIGNALFD
/*
- * Deliver the signal to listening signalfd. This must be called
- * with the sighand lock held. Same are the following that end up
- * calling signalfd_deliver().
- */
-void signalfd_deliver(struct task_struct *tsk, int sig);
-
-/*
- * No need to fall inside signalfd_deliver() if no signal listeners
- * are available.
+ * Deliver the signal to listening signalfd.
*/
static inline void signalfd_notify(struct task_struct *tsk, int sig)
{
- if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
- signalfd_deliver(tsk, sig);
-}
-
-/*
- * The signal -1 is used to notify the signalfd that the sighand
- * is on its way to be detached.
- */
-static inline void signalfd_detach_locked(struct task_struct *tsk)
-{
- if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
- signalfd_deliver(tsk, -1);
-}
-
-static inline void signalfd_detach(struct task_struct *tsk)
-{
- struct sighand_struct *sighand = tsk->sighand;
-
- if (unlikely(!list_empty(&sighand->signalfd_list))) {
- spin_lock_irq(&sighand->siglock);
- signalfd_deliver(tsk, -1);
- spin_unlock_irq(&sighand->siglock);
- }
+ if (unlikely(waitqueue_active(&tsk->sighand->signalfd_wqh)))
+ wake_up(&tsk->sighand->signalfd_wqh);
}
#else /* CONFIG_SIGNALFD */
-#define signalfd_deliver(t, s) do { } while (0)
-#define signalfd_notify(t, s) do { } while (0)
-#define signalfd_detach_locked(t) do { } while (0)
-#define signalfd_detach(t) do { } while (0)
+static inline void signalfd_notify(struct task_struct *tsk, int sig) { }
#endif /* CONFIG_SIGNALFD */
diff --git a/kernel/exit.c b/kernel/exit.c
index 06b24b3aa370..993369ee94d1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -24,7 +24,6 @@
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
-#include <linux/signalfd.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/kthread.h>
@@ -86,14 +85,6 @@ static void __exit_signal(struct task_struct *tsk)
sighand = rcu_dereference(tsk->sighand);
spin_lock(&sighand->siglock);
- /*
- * Notify that this sighand has been detached. This must
- * be called with the tsk->sighand lock held. Also, this
- * access tsk->sighand internally, so it must be called
- * before tsk->sighand is reset.
- */
- signalfd_detach_locked(tsk);
-
posix_cpu_timers_exit(tsk);
if (atomic_dec_and_test(&sig->count))
posix_cpu_timers_exit_group(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index 7332e236d367..33f12f48684a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1438,7 +1438,7 @@ static void sighand_ctor(void *data, struct kmem_cache *cachep,
struct sighand_struct *sighand = data;
spin_lock_init(&sighand->siglock);
- INIT_LIST_HEAD(&sighand->signalfd_list);
+ init_waitqueue_head(&sighand->signalfd_wqh);
}
void __init proc_caches_init(void)
diff --git a/kernel/signal.c b/kernel/signal.c
index 3169bed0b4d0..9fb91a32edda 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -378,8 +378,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
/* We only dequeue private signals from ourselves, we don't let
* signalfd steal them
*/
- if (likely(tsk == current))
- signr = __dequeue_signal(&tsk->pending, mask, info);
+ signr = __dequeue_signal(&tsk->pending, mask, info);
if (!signr) {
signr = __dequeue_signal(&tsk->signal->shared_pending,
mask, info);
@@ -407,8 +406,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
}
}
}
- if (likely(tsk == current))
- recalc_sigpending();
+ recalc_sigpending();
if (signr && unlikely(sig_kernel_stop(signr))) {
/*
* Set a marker that we have dequeued a stop signal. Our
@@ -425,7 +423,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT))
tsk->signal->flags |= SIGNAL_STOP_DEQUEUED;
}
- if (signr && likely(tsk == current) &&
+ if (signr &&
((info->si_code & __SI_MASK) == __SI_TIMER) &&
info->si_sys_private){
/*
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e185a5b55913..2351533a8507 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -58,7 +58,6 @@ struct nfulnl_instance {
unsigned int qlen; /* number of nlmsgs in skb */
struct sk_buff *skb; /* pre-allocatd skb */
- struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
struct timer_list timer;
int peer_pid; /* PID of the peer process */
@@ -345,10 +344,12 @@ static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size,
static int
__nfulnl_send(struct nfulnl_instance *inst)
{
- int status;
+ int status = -1;
if (inst->qlen > 1)
- inst->lastnlh->nlmsg_type = NLMSG_DONE;
+ NLMSG_PUT(inst->skb, 0, 0,
+ NLMSG_DONE,
+ sizeof(struct nfgenmsg));
status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);
if (status < 0) {
@@ -358,8 +359,8 @@ __nfulnl_send(struct nfulnl_instance *inst)
inst->qlen = 0;
inst->skb = NULL;
- inst->lastnlh = NULL;
+nlmsg_failure:
return status;
}
@@ -538,7 +539,6 @@ __build_packet_message(struct nfulnl_instance *inst,
}
nlh->nlmsg_len = inst->skb->tail - old_tail;
- inst->lastnlh = nlh;
return 0;
nlmsg_failure:
@@ -644,7 +644,8 @@ nfulnl_log_packet(unsigned int pf,
}
if (inst->qlen >= qthreshold ||
- (inst->skb && size > skb_tailroom(inst->skb))) {
+ (inst->skb && size >
+ skb_tailroom(inst->skb) - sizeof(struct nfgenmsg))) {
/* either the queue len is too high or we don't have
* enough room in the skb left. flush to userspace. */
UDEBUG("flushing old skb\n");
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 957957309859..3a23e30bc79e 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -270,7 +270,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
q->tail = x;
}
}
- if (++sch->q.qlen < q->limit-1) {
+ if (++sch->q.qlen <= q->limit) {
sch->bstats.bytes += skb->len;
sch->bstats.packets++;
return 0;
@@ -306,7 +306,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
q->tail = x;
}
}
- if (++sch->q.qlen < q->limit - 1) {
+ if (++sch->q.qlen <= q->limit) {
sch->qstats.requeues++;
return 0;
}
@@ -391,10 +391,10 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
q->perturb_period = ctl->perturb_period*HZ;
if (ctl->limit)
- q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
+ q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 2);
qlen = sch->q.qlen;
- while (sch->q.qlen >= q->limit-1)
+ while (sch->q.qlen > q->limit)
sfq_drop(sch);
qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
@@ -423,7 +423,7 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
}
- q->limit = SFQ_DEPTH;
+ q->limit = SFQ_DEPTH - 2;
q->max_depth = 0;
q->tail = SFQ_DEPTH;
if (opt == NULL) {
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 1a899924023f..036ab520df21 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1110,7 +1110,8 @@ svc_tcp_accept(struct svc_sock *svsk)
serv->sv_name);
printk(KERN_NOTICE
"%s: last TCP connect from %s\n",
- serv->sv_name, buf);
+ serv->sv_name, __svc_print_addr(sin,
+ buf, sizeof(buf)));
}
/*
* Always select the oldest socket. It's not fair,
OpenPOWER on IntegriCloud