Commit | Line | Data |
---|---|---|
921a86e0 KH |
1 | /* |
2 | * SBE 2T3E3 synchronous serial card driver for Linux | |
3 | * | |
4 | * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of version 2 of the GNU General Public License | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This code is based on a driver written by SBE Inc. | |
11 | */ | |
12 | ||
13 | #include <linux/interrupt.h> | |
14 | #include <linux/netdevice.h> | |
15 | #include "2t3e3.h" | |
16 | ||
17 | void t3e3_init(struct channel *sc) | |
18 | { | |
19 | cpld_init(sc); | |
20 | dc_reset(sc); | |
21 | dc_init(sc); | |
22 | exar7250_init(sc); | |
23 | exar7300_init(sc); | |
24 | } | |
25 | ||
26 | int t3e3_if_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
27 | { | |
28 | struct channel *sc = dev_to_priv(dev); | |
29 | u32 current_write, last_write; | |
30 | unsigned long flags; | |
31 | struct sk_buff *skb2; | |
32 | ||
33 | if (skb == NULL) { | |
34 | sc->s.out_errors++; | |
35 | return 0; | |
36 | } | |
37 | ||
38 | if (sc->p.transmitter_on != SBE_2T3E3_ON) { | |
39 | sc->s.out_errors++; | |
40 | sc->s.out_dropped++; | |
41 | dev_kfree_skb_any(skb); | |
42 | return 0; | |
43 | } | |
44 | ||
45 | if (sc->s.OOF && sc->p.loopback == SBE_2T3E3_LOOPBACK_NONE) { | |
46 | sc->s.out_dropped++; | |
47 | dev_kfree_skb_any(skb); | |
48 | return 0; | |
49 | } | |
50 | ||
51 | spin_lock_irqsave(&sc->ether.tx_lock, flags); | |
52 | ||
53 | current_write = sc->ether.tx_ring_current_write; | |
54 | for (skb2 = skb; skb2 != NULL; skb2 = NULL) { | |
55 | if (skb2->len) { | |
56 | if ((sc->ether.tx_ring[current_write].tdes1 & | |
57 | SBE_2T3E3_TX_DESC_BUFFER_1_SIZE) > 0) | |
58 | break; | |
59 | current_write = (current_write + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; | |
60 | /* | |
61 | * Leave at least 1 tx desc free so that dc_intr_tx() can | |
62 | * identify empty list | |
63 | */ | |
64 | if (current_write == sc->ether.tx_ring_current_read) | |
65 | break; | |
66 | } | |
67 | } | |
68 | if (skb2 != NULL) { | |
69 | netif_stop_queue(sc->dev); | |
70 | sc->ether.tx_full = 1; | |
71 | dev_dbg(&sc->pdev->dev, "SBE 2T3E3: out of descriptors\n"); | |
72 | spin_unlock_irqrestore(&sc->ether.tx_lock, flags); | |
73 | return NETDEV_TX_BUSY; | |
74 | } | |
75 | ||
76 | current_write = last_write = sc->ether.tx_ring_current_write; | |
77 | dev_dbg(&sc->pdev->dev, "sending mbuf (current_write = %d)\n", | |
78 | current_write); | |
79 | ||
80 | for (skb2 = skb; skb2 != NULL; skb2 = NULL) { | |
81 | if (skb2->len) { | |
82 | dev_dbg(&sc->pdev->dev, | |
83 | "sending mbuf (len = %d, next = %p)\n", | |
84 | skb2->len, NULL); | |
85 | ||
86 | sc->ether.tx_free_cnt--; | |
87 | sc->ether.tx_ring[current_write].tdes0 = 0; | |
88 | sc->ether.tx_ring[current_write].tdes1 &= | |
89 | SBE_2T3E3_TX_DESC_END_OF_RING | | |
90 | SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED; | |
91 | /* DISABLE_PADDING sometimes gets lost somehow, hands off... */ | |
92 | sc->ether.tx_ring[current_write].tdes1 |= | |
93 | SBE_2T3E3_TX_DESC_DISABLE_PADDING | skb2->len; | |
94 | ||
95 | if (current_write == sc->ether.tx_ring_current_write) { | |
96 | sc->ether.tx_ring[current_write].tdes1 |= | |
97 | SBE_2T3E3_TX_DESC_FIRST_SEGMENT; | |
98 | } else { | |
99 | sc->ether.tx_ring[current_write].tdes0 = | |
100 | SBE_2T3E3_TX_DESC_21143_OWN; | |
101 | } | |
102 | ||
103 | sc->ether.tx_ring[current_write].tdes2 = virt_to_phys(skb2->data); | |
104 | sc->ether.tx_data[current_write] = NULL; | |
105 | ||
106 | last_write = current_write; | |
107 | current_write = (current_write + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; | |
108 | } | |
109 | } | |
110 | ||
111 | sc->ether.tx_data[last_write] = skb; | |
112 | sc->ether.tx_ring[last_write].tdes1 |= | |
113 | SBE_2T3E3_TX_DESC_LAST_SEGMENT | | |
114 | SBE_2T3E3_TX_DESC_INTERRUPT_ON_COMPLETION; | |
115 | sc->ether.tx_ring[sc->ether.tx_ring_current_write].tdes0 |= | |
116 | SBE_2T3E3_TX_DESC_21143_OWN; | |
117 | sc->ether.tx_ring_current_write = current_write; | |
118 | ||
119 | dev_dbg(&sc->pdev->dev, "txput: tdes0 = %08X tdes1 = %08X\n", | |
120 | sc->ether.tx_ring[last_write].tdes0, | |
121 | sc->ether.tx_ring[last_write].tdes1); | |
122 | ||
123 | dc_write(sc->addr, SBE_2T3E3_21143_REG_TRANSMIT_POLL_DEMAND, | |
124 | 0xffffffff); | |
125 | ||
126 | spin_unlock_irqrestore(&sc->ether.tx_lock, flags); | |
127 | return 0; | |
128 | } | |
129 | ||
130 | ||
131 | void t3e3_read_card_serial_number(struct channel *sc) | |
132 | { | |
133 | u32 i; | |
134 | ||
135 | for (i = 0; i < 3; i++) | |
136 | sc->ether.card_serial_number[i] = t3e3_eeprom_read_word(sc, 10 + i); | |
137 | ||
138 | printk(KERN_INFO "SBE wanPMC-2T3E3 serial number: %04X%04X%04X\n", | |
139 | sc->ether.card_serial_number[0], sc->ether.card_serial_number[1], | |
140 | sc->ether.card_serial_number[2]); | |
141 | } | |
142 | ||
143 | /* | |
144 | bit 0 led1 (green) | |
145 | bit 1 led1 (yellow) | |
146 | ||
147 | bit 2 led2 (green) | |
148 | bit 3 led2 (yellow) | |
149 | ||
150 | bit 4 led3 (green) | |
151 | bit 5 led3 (yellow) | |
152 | ||
153 | bit 6 led4 (green) | |
154 | bit 7 led4 (yellow) | |
155 | */ | |
156 | ||
157 | void update_led(struct channel *sc, int blinker) | |
158 | { | |
159 | int leds; | |
160 | if (sc->s.LOS) | |
161 | leds = 0; /* led1 = off */ | |
162 | else if (sc->s.OOF) | |
163 | leds = 2; /* led1 = yellow */ | |
164 | else if ((blinker & 1) && sc->rcv_count) { | |
165 | leds = 0; /* led1 = off */ | |
166 | sc->rcv_count = 0; | |
167 | } else | |
168 | leds = 1; /* led1 = green */ | |
169 | cpld_write(sc, SBE_2T3E3_CPLD_REG_LEDR, leds); | |
170 | sc->leds = leds; | |
171 | } |