diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-21 16:23:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-21 16:23:01 -0400 |
commit | ed36604b25023c584fdf93df6073f65dac4b1129 (patch) | |
tree | 9bc35b4174f18af727f7d73b32e16efad85fce93 /drivers/atm | |
parent | 3f518390ab1b65bc2e2bc01774eb2c5918c433ee (diff) | |
parent | 1329f4550f8ee141437f3b5f4db0f2add7639e29 (diff) |
Merge branch 'master' of git://git.infradead.org/~dwmw2/solos-2.6
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/solos-attrlist.c | 70 | ||||
-rw-r--r-- | drivers/atm/solos-pci.c | 824 |
2 files changed, 734 insertions, 160 deletions
diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c new file mode 100644 index 000000000000..efa2808dd94d --- /dev/null +++ b/drivers/atm/solos-attrlist.c | |||
@@ -0,0 +1,70 @@ | |||
1 | SOLOS_ATTR_RO(DriverVersion) | ||
2 | SOLOS_ATTR_RO(APIVersion) | ||
3 | SOLOS_ATTR_RO(FirmwareVersion) | ||
4 | // SOLOS_ATTR_RO(DspVersion) | ||
5 | // SOLOS_ATTR_RO(CommonHandshake) | ||
6 | SOLOS_ATTR_RO(Connected) | ||
7 | SOLOS_ATTR_RO(OperationalMode) | ||
8 | SOLOS_ATTR_RO(State) | ||
9 | SOLOS_ATTR_RO(Watchdog) | ||
10 | SOLOS_ATTR_RO(OperationProgress) | ||
11 | SOLOS_ATTR_RO(LastFailed) | ||
12 | SOLOS_ATTR_RO(TxBitRate) | ||
13 | SOLOS_ATTR_RO(RxBitRate) | ||
14 | // SOLOS_ATTR_RO(DeltACTATPds) | ||
15 | // SOLOS_ATTR_RO(DeltACTATPus) | ||
16 | SOLOS_ATTR_RO(TxATTNDR) | ||
17 | SOLOS_ATTR_RO(RxATTNDR) | ||
18 | SOLOS_ATTR_RO(AnnexType) | ||
19 | SOLOS_ATTR_RO(GeneralFailure) | ||
20 | SOLOS_ATTR_RO(InterleaveDpDn) | ||
21 | SOLOS_ATTR_RO(InterleaveDpUp) | ||
22 | SOLOS_ATTR_RO(RSCorrectedErrorsDn) | ||
23 | SOLOS_ATTR_RO(RSUnCorrectedErrorsDn) | ||
24 | SOLOS_ATTR_RO(RSCorrectedErrorsUp) | ||
25 | SOLOS_ATTR_RO(RSUnCorrectedErrorsUp) | ||
26 | SOLOS_ATTR_RO(InterleaveRDn) | ||
27 | SOLOS_ATTR_RO(InterleaveRUp) | ||
28 | SOLOS_ATTR_RO(ShowtimeStart) | ||
29 | SOLOS_ATTR_RO(ATURVendor) | ||
30 | SOLOS_ATTR_RO(ATUCCountry) | ||
31 | SOLOS_ATTR_RO(ATURANSIRev) | ||
32 | SOLOS_ATTR_RO(ATURANSISTD) | ||
33 | SOLOS_ATTR_RO(ATUCANSIRev) | ||
34 | SOLOS_ATTR_RO(ATUCANSIId) | ||
35 | SOLOS_ATTR_RO(ATUCANSISTD) | ||
36 | SOLOS_ATTR_RO(DataBoost) | ||
37 | SOLOS_ATTR_RO(LocalITUCountryCode) | ||
38 | SOLOS_ATTR_RO(LocalSEF) | ||
39 | SOLOS_ATTR_RO(LocalEndLOS) | ||
40 | SOLOS_ATTR_RO(LocalSNRMargin) | ||
41 | SOLOS_ATTR_RO(LocalLineAttn) | ||
42 | SOLOS_ATTR_RO(RawAttn) | ||
43 | SOLOS_ATTR_RO(LocalTxPower) | ||
44 | SOLOS_ATTR_RO(RemoteTxPower) | ||
45 | SOLOS_ATTR_RO(RemoteSEF) | ||
46 | SOLOS_ATTR_RO(RemoteLOS) | ||
47 | SOLOS_ATTR_RO(RemoteLineAttn) | ||
48 | SOLOS_ATTR_RO(RemoteSNRMargin) | ||
49 | SOLOS_ATTR_RO(LineUpCount) | ||
50 | SOLOS_ATTR_RO(SRACnt) | ||
51 | SOLOS_ATTR_RO(SRACntUp) | ||
52 | SOLOS_ATTR_RO(ProfileStatus) | ||
53 | SOLOS_ATTR_RW(Action) | ||
54 | SOLOS_ATTR_RW(ActivateLine) | ||
55 | SOLOS_ATTR_RO(LineStatus) | ||
56 | SOLOS_ATTR_RW(HostControl) | ||
57 | SOLOS_ATTR_RW(AutoStart) | ||
58 | SOLOS_ATTR_RW(Failsafe) | ||
59 | SOLOS_ATTR_RW(ShowtimeLed) | ||
60 | SOLOS_ATTR_RW(Retrain) | ||
61 | SOLOS_ATTR_RW(Defaults) | ||
62 | SOLOS_ATTR_RW(LineMode) | ||
63 | SOLOS_ATTR_RW(Profile) | ||
64 | SOLOS_ATTR_RW(DetectNoise) | ||
65 | SOLOS_ATTR_RO(SupportedAnnexes) | ||
66 | SOLOS_ATTR_RO(Status) | ||
67 | SOLOS_ATTR_RO(TotalStart) | ||
68 | SOLOS_ATTR_RO(RecentShowtimeStart) | ||
69 | SOLOS_ATTR_RO(TotalRxBlocks) | ||
70 | SOLOS_ATTR_RO(TotalTxBlocks) | ||
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 89d7a6e94c9c..be204308cc1b 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Authors: Nathan Williams <nathan@traverse.com.au> | 10 | * Authors: Nathan Williams <nathan@traverse.com.au> |
11 | * David Woodhouse <dwmw2@infradead.org> | 11 | * David Woodhouse <dwmw2@infradead.org> |
12 | * Treker Chen <treker@xrio.com> | ||
12 | * | 13 | * |
13 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -36,8 +37,11 @@ | |||
36 | #include <linux/sysfs.h> | 37 | #include <linux/sysfs.h> |
37 | #include <linux/device.h> | 38 | #include <linux/device.h> |
38 | #include <linux/kobject.h> | 39 | #include <linux/kobject.h> |
40 | #include <linux/firmware.h> | ||
41 | #include <linux/ctype.h> | ||
42 | #include <linux/swab.h> | ||
39 | 43 | ||
40 | #define VERSION "0.04" | 44 | #define VERSION "0.07" |
41 | #define PTAG "solos-pci" | 45 | #define PTAG "solos-pci" |
42 | 46 | ||
43 | #define CONFIG_RAM_SIZE 128 | 47 | #define CONFIG_RAM_SIZE 128 |
@@ -45,16 +49,31 @@ | |||
45 | #define IRQ_EN_ADDR 0x78 | 49 | #define IRQ_EN_ADDR 0x78 |
46 | #define FPGA_VER 0x74 | 50 | #define FPGA_VER 0x74 |
47 | #define IRQ_CLEAR 0x70 | 51 | #define IRQ_CLEAR 0x70 |
48 | #define BUG_FLAG 0x6C | 52 | #define WRITE_FLASH 0x6C |
53 | #define PORTS 0x68 | ||
54 | #define FLASH_BLOCK 0x64 | ||
55 | #define FLASH_BUSY 0x60 | ||
56 | #define FPGA_MODE 0x5C | ||
57 | #define FLASH_MODE 0x58 | ||
58 | #define TX_DMA_ADDR(port) (0x40 + (4 * (port))) | ||
59 | #define RX_DMA_ADDR(port) (0x30 + (4 * (port))) | ||
49 | 60 | ||
50 | #define DATA_RAM_SIZE 32768 | 61 | #define DATA_RAM_SIZE 32768 |
51 | #define BUF_SIZE 4096 | 62 | #define BUF_SIZE 4096 |
63 | #define FPGA_PAGE 528 /* FPGA flash page size*/ | ||
64 | #define SOLOS_PAGE 512 /* Solos flash page size*/ | ||
65 | #define FPGA_BLOCK (FPGA_PAGE * 8) /* FPGA flash block size*/ | ||
66 | #define SOLOS_BLOCK (SOLOS_PAGE * 8) /* Solos flash block size*/ | ||
52 | 67 | ||
53 | #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) | 68 | #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) |
54 | #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) | 69 | #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) |
55 | 70 | ||
56 | static int debug = 0; | 71 | #define RX_DMA_SIZE 2048 |
72 | |||
73 | static int reset = 0; | ||
57 | static int atmdebug = 0; | 74 | static int atmdebug = 0; |
75 | static int firmware_upgrade = 0; | ||
76 | static int fpga_upgrade = 0; | ||
58 | 77 | ||
59 | struct pkt_hdr { | 78 | struct pkt_hdr { |
60 | __le16 size; | 79 | __le16 size; |
@@ -63,23 +82,48 @@ struct pkt_hdr { | |||
63 | __le16 type; | 82 | __le16 type; |
64 | }; | 83 | }; |
65 | 84 | ||
85 | struct solos_skb_cb { | ||
86 | struct atm_vcc *vcc; | ||
87 | uint32_t dma_addr; | ||
88 | }; | ||
89 | |||
90 | |||
91 | #define SKB_CB(skb) ((struct solos_skb_cb *)skb->cb) | ||
92 | |||
66 | #define PKT_DATA 0 | 93 | #define PKT_DATA 0 |
67 | #define PKT_COMMAND 1 | 94 | #define PKT_COMMAND 1 |
68 | #define PKT_POPEN 3 | 95 | #define PKT_POPEN 3 |
69 | #define PKT_PCLOSE 4 | 96 | #define PKT_PCLOSE 4 |
97 | #define PKT_STATUS 5 | ||
70 | 98 | ||
71 | struct solos_card { | 99 | struct solos_card { |
72 | void __iomem *config_regs; | 100 | void __iomem *config_regs; |
73 | void __iomem *buffers; | 101 | void __iomem *buffers; |
74 | int nr_ports; | 102 | int nr_ports; |
103 | int tx_mask; | ||
75 | struct pci_dev *dev; | 104 | struct pci_dev *dev; |
76 | struct atm_dev *atmdev[4]; | 105 | struct atm_dev *atmdev[4]; |
77 | struct tasklet_struct tlet; | 106 | struct tasklet_struct tlet; |
78 | spinlock_t tx_lock; | 107 | spinlock_t tx_lock; |
79 | spinlock_t tx_queue_lock; | 108 | spinlock_t tx_queue_lock; |
80 | spinlock_t cli_queue_lock; | 109 | spinlock_t cli_queue_lock; |
110 | spinlock_t param_queue_lock; | ||
111 | struct list_head param_queue; | ||
81 | struct sk_buff_head tx_queue[4]; | 112 | struct sk_buff_head tx_queue[4]; |
82 | struct sk_buff_head cli_queue[4]; | 113 | struct sk_buff_head cli_queue[4]; |
114 | struct sk_buff *tx_skb[4]; | ||
115 | struct sk_buff *rx_skb[4]; | ||
116 | wait_queue_head_t param_wq; | ||
117 | wait_queue_head_t fw_wq; | ||
118 | int using_dma; | ||
119 | }; | ||
120 | |||
121 | |||
122 | struct solos_param { | ||
123 | struct list_head list; | ||
124 | pid_t pid; | ||
125 | int port; | ||
126 | struct sk_buff *response; | ||
83 | }; | 127 | }; |
84 | 128 | ||
85 | #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) | 129 | #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) |
@@ -88,19 +132,22 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>"); | |||
88 | MODULE_DESCRIPTION("Solos PCI driver"); | 132 | MODULE_DESCRIPTION("Solos PCI driver"); |
89 | MODULE_VERSION(VERSION); | 133 | MODULE_VERSION(VERSION); |
90 | MODULE_LICENSE("GPL"); | 134 | MODULE_LICENSE("GPL"); |
91 | MODULE_PARM_DESC(debug, "Enable Loopback"); | 135 | MODULE_PARM_DESC(reset, "Reset Solos chips on startup"); |
92 | MODULE_PARM_DESC(atmdebug, "Print ATM data"); | 136 | MODULE_PARM_DESC(atmdebug, "Print ATM data"); |
93 | module_param(debug, int, 0444); | 137 | MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); |
94 | module_param(atmdebug, int, 0444); | 138 | MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade"); |
95 | 139 | module_param(reset, int, 0444); | |
96 | static int opens; | 140 | module_param(atmdebug, int, 0644); |
141 | module_param(firmware_upgrade, int, 0444); | ||
142 | module_param(fpga_upgrade, int, 0444); | ||
97 | 143 | ||
98 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | 144 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, |
99 | struct atm_vcc *vcc); | 145 | struct atm_vcc *vcc); |
100 | static int fpga_tx(struct solos_card *); | 146 | static uint32_t fpga_tx(struct solos_card *); |
101 | static irqreturn_t solos_irq(int irq, void *dev_id); | 147 | static irqreturn_t solos_irq(int irq, void *dev_id); |
102 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); | 148 | static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); |
103 | static int list_vccs(int vci); | 149 | static int list_vccs(int vci); |
150 | static void release_vccs(struct atm_dev *dev); | ||
104 | static int atm_init(struct solos_card *); | 151 | static int atm_init(struct solos_card *); |
105 | static void atm_remove(struct solos_card *); | 152 | static void atm_remove(struct solos_card *); |
106 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); | 153 | static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); |
@@ -115,6 +162,264 @@ static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb) | |||
115 | dev_kfree_skb_any(skb); | 162 | dev_kfree_skb_any(skb); |
116 | } | 163 | } |
117 | 164 | ||
165 | static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr, | ||
166 | char *buf) | ||
167 | { | ||
168 | struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); | ||
169 | struct solos_card *card = atmdev->dev_data; | ||
170 | struct solos_param prm; | ||
171 | struct sk_buff *skb; | ||
172 | struct pkt_hdr *header; | ||
173 | int buflen; | ||
174 | |||
175 | buflen = strlen(attr->attr.name) + 10; | ||
176 | |||
177 | skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); | ||
178 | if (!skb) { | ||
179 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n"); | ||
180 | return -ENOMEM; | ||
181 | } | ||
182 | |||
183 | header = (void *)skb_put(skb, sizeof(*header)); | ||
184 | |||
185 | buflen = snprintf((void *)&header[1], buflen - 1, | ||
186 | "L%05d\n%s\n", current->pid, attr->attr.name); | ||
187 | skb_put(skb, buflen); | ||
188 | |||
189 | header->size = cpu_to_le16(buflen); | ||
190 | header->vpi = cpu_to_le16(0); | ||
191 | header->vci = cpu_to_le16(0); | ||
192 | header->type = cpu_to_le16(PKT_COMMAND); | ||
193 | |||
194 | prm.pid = current->pid; | ||
195 | prm.response = NULL; | ||
196 | prm.port = SOLOS_CHAN(atmdev); | ||
197 | |||
198 | spin_lock_irq(&card->param_queue_lock); | ||
199 | list_add(&prm.list, &card->param_queue); | ||
200 | spin_unlock_irq(&card->param_queue_lock); | ||
201 | |||
202 | fpga_queue(card, prm.port, skb, NULL); | ||
203 | |||
204 | wait_event_timeout(card->param_wq, prm.response, 5 * HZ); | ||
205 | |||
206 | spin_lock_irq(&card->param_queue_lock); | ||
207 | list_del(&prm.list); | ||
208 | spin_unlock_irq(&card->param_queue_lock); | ||
209 | |||
210 | if (!prm.response) | ||
211 | return -EIO; | ||
212 | |||
213 | buflen = prm.response->len; | ||
214 | memcpy(buf, prm.response->data, buflen); | ||
215 | kfree_skb(prm.response); | ||
216 | |||
217 | return buflen; | ||
218 | } | ||
219 | |||
220 | static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr, | ||
221 | const char *buf, size_t count) | ||
222 | { | ||
223 | struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); | ||
224 | struct solos_card *card = atmdev->dev_data; | ||
225 | struct solos_param prm; | ||
226 | struct sk_buff *skb; | ||
227 | struct pkt_hdr *header; | ||
228 | int buflen; | ||
229 | ssize_t ret; | ||
230 | |||
231 | buflen = strlen(attr->attr.name) + 11 + count; | ||
232 | |||
233 | skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); | ||
234 | if (!skb) { | ||
235 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n"); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | |||
239 | header = (void *)skb_put(skb, sizeof(*header)); | ||
240 | |||
241 | buflen = snprintf((void *)&header[1], buflen - 1, | ||
242 | "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf); | ||
243 | |||
244 | skb_put(skb, buflen); | ||
245 | header->size = cpu_to_le16(buflen); | ||
246 | header->vpi = cpu_to_le16(0); | ||
247 | header->vci = cpu_to_le16(0); | ||
248 | header->type = cpu_to_le16(PKT_COMMAND); | ||
249 | |||
250 | prm.pid = current->pid; | ||
251 | prm.response = NULL; | ||
252 | prm.port = SOLOS_CHAN(atmdev); | ||
253 | |||
254 | spin_lock_irq(&card->param_queue_lock); | ||
255 | list_add(&prm.list, &card->param_queue); | ||
256 | spin_unlock_irq(&card->param_queue_lock); | ||
257 | |||
258 | fpga_queue(card, prm.port, skb, NULL); | ||
259 | |||
260 | wait_event_timeout(card->param_wq, prm.response, 5 * HZ); | ||
261 | |||
262 | spin_lock_irq(&card->param_queue_lock); | ||
263 | list_del(&prm.list); | ||
264 | spin_unlock_irq(&card->param_queue_lock); | ||
265 | |||
266 | skb = prm.response; | ||
267 | |||
268 | if (!skb) | ||
269 | return -EIO; | ||
270 | |||
271 | buflen = skb->len; | ||
272 | |||
273 | /* Sometimes it has a newline, sometimes it doesn't. */ | ||
274 | if (skb->data[buflen - 1] == '\n') | ||
275 | buflen--; | ||
276 | |||
277 | if (buflen == 2 && !strncmp(skb->data, "OK", 2)) | ||
278 | ret = count; | ||
279 | else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5)) | ||
280 | ret = -EIO; | ||
281 | else { | ||
282 | /* We know we have enough space allocated for this; we allocated | ||
283 | it ourselves */ | ||
284 | skb->data[buflen] = 0; | ||
285 | |||
286 | dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n", | ||
287 | skb->data); | ||
288 | ret = -EIO; | ||
289 | } | ||
290 | kfree_skb(skb); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static char *next_string(struct sk_buff *skb) | ||
296 | { | ||
297 | int i = 0; | ||
298 | char *this = skb->data; | ||
299 | |||
300 | for (i = 0; i < skb->len; i++) { | ||
301 | if (this[i] == '\n') { | ||
302 | this[i] = 0; | ||
303 | skb_pull(skb, i + 1); | ||
304 | return this; | ||
305 | } | ||
306 | if (!isprint(this[i])) | ||
307 | return NULL; | ||
308 | } | ||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Status packet has fields separated by \n, starting with a version number | ||
314 | * for the information therein. Fields are.... | ||
315 | * | ||
316 | * packet version | ||
317 | * RxBitRate (version >= 1) | ||
318 | * TxBitRate (version >= 1) | ||
319 | * State (version >= 1) | ||
320 | * LocalSNRMargin (version >= 1) | ||
321 | * LocalLineAttn (version >= 1) | ||
322 | */ | ||
323 | static int process_status(struct solos_card *card, int port, struct sk_buff *skb) | ||
324 | { | ||
325 | char *str, *end, *state_str, *snr, *attn; | ||
326 | int ver, rate_up, rate_down; | ||
327 | |||
328 | if (!card->atmdev[port]) | ||
329 | return -ENODEV; | ||
330 | |||
331 | str = next_string(skb); | ||
332 | if (!str) | ||
333 | return -EIO; | ||
334 | |||
335 | ver = simple_strtol(str, NULL, 10); | ||
336 | if (ver < 1) { | ||
337 | dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n", | ||
338 | ver); | ||
339 | return -EIO; | ||
340 | } | ||
341 | |||
342 | str = next_string(skb); | ||
343 | if (!str) | ||
344 | return -EIO; | ||
345 | if (!strcmp(str, "ERROR")) { | ||
346 | dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n", | ||
347 | port); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | rate_down = simple_strtol(str, &end, 10); | ||
352 | if (*end) | ||
353 | return -EIO; | ||
354 | |||
355 | str = next_string(skb); | ||
356 | if (!str) | ||
357 | return -EIO; | ||
358 | rate_up = simple_strtol(str, &end, 10); | ||
359 | if (*end) | ||
360 | return -EIO; | ||
361 | |||
362 | state_str = next_string(skb); | ||
363 | if (!state_str) | ||
364 | return -EIO; | ||
365 | |||
366 | /* Anything but 'Showtime' is down */ | ||
367 | if (strcmp(state_str, "Showtime")) { | ||
368 | card->atmdev[port]->signal = ATM_PHY_SIG_LOST; | ||
369 | release_vccs(card->atmdev[port]); | ||
370 | dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | snr = next_string(skb); | ||
375 | if (!str) | ||
376 | return -EIO; | ||
377 | attn = next_string(skb); | ||
378 | if (!attn) | ||
379 | return -EIO; | ||
380 | |||
381 | dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n", | ||
382 | port, state_str, rate_down/1000, rate_up/1000, | ||
383 | snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn); | ||
384 | |||
385 | card->atmdev[port]->link_rate = rate_down / 424; | ||
386 | card->atmdev[port]->signal = ATM_PHY_SIG_FOUND; | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int process_command(struct solos_card *card, int port, struct sk_buff *skb) | ||
392 | { | ||
393 | struct solos_param *prm; | ||
394 | unsigned long flags; | ||
395 | int cmdpid; | ||
396 | int found = 0; | ||
397 | |||
398 | if (skb->len < 7) | ||
399 | return 0; | ||
400 | |||
401 | if (skb->data[0] != 'L' || !isdigit(skb->data[1]) || | ||
402 | !isdigit(skb->data[2]) || !isdigit(skb->data[3]) || | ||
403 | !isdigit(skb->data[4]) || !isdigit(skb->data[5]) || | ||
404 | skb->data[6] != '\n') | ||
405 | return 0; | ||
406 | |||
407 | cmdpid = simple_strtol(&skb->data[1], NULL, 10); | ||
408 | |||
409 | spin_lock_irqsave(&card->param_queue_lock, flags); | ||
410 | list_for_each_entry(prm, &card->param_queue, list) { | ||
411 | if (prm->port == port && prm->pid == cmdpid) { | ||
412 | prm->response = skb; | ||
413 | skb_pull(skb, 7); | ||
414 | wake_up(&card->param_wq); | ||
415 | found = 1; | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | spin_unlock_irqrestore(&card->param_queue_lock, flags); | ||
420 | return found; | ||
421 | } | ||
422 | |||
118 | static ssize_t console_show(struct device *dev, struct device_attribute *attr, | 423 | static ssize_t console_show(struct device *dev, struct device_attribute *attr, |
119 | char *buf) | 424 | char *buf) |
120 | { | 425 | { |
@@ -140,8 +445,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_ | |||
140 | struct sk_buff *skb; | 445 | struct sk_buff *skb; |
141 | struct pkt_hdr *header; | 446 | struct pkt_hdr *header; |
142 | 447 | ||
143 | // dev_dbg(&card->dev->dev, "size: %d\n", size); | ||
144 | |||
145 | if (size > (BUF_SIZE - sizeof(*header))) { | 448 | if (size > (BUF_SIZE - sizeof(*header))) { |
146 | dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); | 449 | dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); |
147 | return 0; | 450 | return 0; |
@@ -180,82 +483,181 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr, | |||
180 | 483 | ||
181 | static DEVICE_ATTR(console, 0644, console_show, console_store); | 484 | static DEVICE_ATTR(console, 0644, console_show, console_store); |
182 | 485 | ||
486 | |||
487 | #define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL); | ||
488 | #define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store); | ||
489 | |||
490 | #include "solos-attrlist.c" | ||
491 | |||
492 | #undef SOLOS_ATTR_RO | ||
493 | #undef SOLOS_ATTR_RW | ||
494 | |||
495 | #define SOLOS_ATTR_RO(x) &dev_attr_##x.attr, | ||
496 | #define SOLOS_ATTR_RW(x) &dev_attr_##x.attr, | ||
497 | |||
498 | static struct attribute *solos_attrs[] = { | ||
499 | #include "solos-attrlist.c" | ||
500 | NULL | ||
501 | }; | ||
502 | |||
503 | static struct attribute_group solos_attr_group = { | ||
504 | .attrs = solos_attrs, | ||
505 | .name = "parameters", | ||
506 | }; | ||
507 | |||
508 | static int flash_upgrade(struct solos_card *card, int chip) | ||
509 | { | ||
510 | const struct firmware *fw; | ||
511 | const char *fw_name; | ||
512 | uint32_t data32 = 0; | ||
513 | int blocksize = 0; | ||
514 | int numblocks = 0; | ||
515 | int offset; | ||
516 | |||
517 | if (chip == 0) { | ||
518 | fw_name = "solos-FPGA.bin"; | ||
519 | blocksize = FPGA_BLOCK; | ||
520 | } else { | ||
521 | fw_name = "solos-Firmware.bin"; | ||
522 | blocksize = SOLOS_BLOCK; | ||
523 | } | ||
524 | |||
525 | if (request_firmware(&fw, fw_name, &card->dev->dev)) | ||
526 | return -ENOENT; | ||
527 | |||
528 | dev_info(&card->dev->dev, "Flash upgrade starting\n"); | ||
529 | |||
530 | numblocks = fw->size / blocksize; | ||
531 | dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size); | ||
532 | dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks); | ||
533 | |||
534 | dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); | ||
535 | iowrite32(1, card->config_regs + FPGA_MODE); | ||
536 | data32 = ioread32(card->config_regs + FPGA_MODE); | ||
537 | |||
538 | /* Set mode to Chip Erase */ | ||
539 | dev_info(&card->dev->dev, "Set FPGA Flash mode to %s Chip Erase\n", | ||
540 | chip?"Solos":"FPGA"); | ||
541 | iowrite32((chip * 2), card->config_regs + FLASH_MODE); | ||
542 | |||
543 | |||
544 | iowrite32(1, card->config_regs + WRITE_FLASH); | ||
545 | wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); | ||
546 | |||
547 | for (offset = 0; offset < fw->size; offset += blocksize) { | ||
548 | int i; | ||
549 | |||
550 | /* Clear write flag */ | ||
551 | iowrite32(0, card->config_regs + WRITE_FLASH); | ||
552 | |||
553 | /* Set mode to Block Write */ | ||
554 | /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */ | ||
555 | iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE); | ||
556 | |||
557 | /* Copy block to buffer, swapping each 16 bits */ | ||
558 | for(i = 0; i < blocksize; i += 4) { | ||
559 | uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i)); | ||
560 | iowrite32(word, RX_BUF(card, 3) + i); | ||
561 | } | ||
562 | |||
563 | /* Specify block number and then trigger flash write */ | ||
564 | iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK); | ||
565 | iowrite32(1, card->config_regs + WRITE_FLASH); | ||
566 | wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); | ||
567 | } | ||
568 | |||
569 | release_firmware(fw); | ||
570 | iowrite32(0, card->config_regs + WRITE_FLASH); | ||
571 | iowrite32(0, card->config_regs + FPGA_MODE); | ||
572 | iowrite32(0, card->config_regs + FLASH_MODE); | ||
573 | dev_info(&card->dev->dev, "Returning FPGA to Data mode\n"); | ||
574 | return 0; | ||
575 | } | ||
576 | |||
183 | static irqreturn_t solos_irq(int irq, void *dev_id) | 577 | static irqreturn_t solos_irq(int irq, void *dev_id) |
184 | { | 578 | { |
185 | struct solos_card *card = dev_id; | 579 | struct solos_card *card = dev_id; |
186 | int handled = 1; | 580 | int handled = 1; |
187 | 581 | ||
188 | //ACK IRQ | ||
189 | iowrite32(0, card->config_regs + IRQ_CLEAR); | 582 | iowrite32(0, card->config_regs + IRQ_CLEAR); |
190 | //Disable IRQs from FPGA | ||
191 | iowrite32(0, card->config_regs + IRQ_EN_ADDR); | ||
192 | 583 | ||
193 | /* If we only do it when the device is open, we lose console | 584 | /* If we're up and running, just kick the tasklet to process TX/RX */ |
194 | messages */ | 585 | if (card->atmdev[0]) |
195 | if (1 || opens) | ||
196 | tasklet_schedule(&card->tlet); | 586 | tasklet_schedule(&card->tlet); |
587 | else | ||
588 | wake_up(&card->fw_wq); | ||
197 | 589 | ||
198 | //Enable IRQs from FPGA | ||
199 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); | ||
200 | return IRQ_RETVAL(handled); | 590 | return IRQ_RETVAL(handled); |
201 | } | 591 | } |
202 | 592 | ||
203 | void solos_bh(unsigned long card_arg) | 593 | void solos_bh(unsigned long card_arg) |
204 | { | 594 | { |
205 | struct solos_card *card = (void *)card_arg; | 595 | struct solos_card *card = (void *)card_arg; |
206 | int port; | ||
207 | uint32_t card_flags; | 596 | uint32_t card_flags; |
208 | uint32_t tx_mask; | ||
209 | uint32_t rx_done = 0; | 597 | uint32_t rx_done = 0; |
598 | int port; | ||
210 | 599 | ||
211 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); | 600 | /* |
212 | 601 | * Since fpga_tx() is going to need to read the flags under its lock, | |
213 | /* The TX bits are set if the channel is busy; clear if not. We want to | 602 | * it can return them to us so that we don't have to hit PCI MMIO |
214 | invoke fpga_tx() unless _all_ the bits for active channels are set */ | 603 | * again for the same information |
215 | tx_mask = (1 << card->nr_ports) - 1; | 604 | */ |
216 | if ((card_flags & tx_mask) != tx_mask) | 605 | card_flags = fpga_tx(card); |
217 | fpga_tx(card); | ||
218 | 606 | ||
219 | for (port = 0; port < card->nr_ports; port++) { | 607 | for (port = 0; port < card->nr_ports; port++) { |
220 | if (card_flags & (0x10 << port)) { | 608 | if (card_flags & (0x10 << port)) { |
221 | struct pkt_hdr header; | 609 | struct pkt_hdr _hdr, *header; |
222 | struct sk_buff *skb; | 610 | struct sk_buff *skb; |
223 | struct atm_vcc *vcc; | 611 | struct atm_vcc *vcc; |
224 | int size; | 612 | int size; |
225 | 613 | ||
226 | rx_done |= 0x10 << port; | 614 | if (card->using_dma) { |
615 | skb = card->rx_skb[port]; | ||
616 | card->rx_skb[port] = NULL; | ||
227 | 617 | ||
228 | memcpy_fromio(&header, RX_BUF(card, port), sizeof(header)); | 618 | pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, |
619 | RX_DMA_SIZE, PCI_DMA_FROMDEVICE); | ||
229 | 620 | ||
230 | size = le16_to_cpu(header.size); | 621 | header = (void *)skb->data; |
622 | size = le16_to_cpu(header->size); | ||
623 | skb_put(skb, size + sizeof(*header)); | ||
624 | skb_pull(skb, sizeof(*header)); | ||
625 | } else { | ||
626 | header = &_hdr; | ||
231 | 627 | ||
232 | skb = alloc_skb(size, GFP_ATOMIC); | 628 | rx_done |= 0x10 << port; |
233 | if (!skb) { | 629 | |
234 | if (net_ratelimit()) | 630 | memcpy_fromio(header, RX_BUF(card, port), sizeof(*header)); |
235 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); | ||
236 | continue; | ||
237 | } | ||
238 | 631 | ||
239 | memcpy_fromio(skb_put(skb, size), | 632 | size = le16_to_cpu(header->size); |
240 | RX_BUF(card, port) + sizeof(header), | ||
241 | size); | ||
242 | 633 | ||
634 | skb = alloc_skb(size + 1, GFP_ATOMIC); | ||
635 | if (!skb) { | ||
636 | if (net_ratelimit()) | ||
637 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); | ||
638 | continue; | ||
639 | } | ||
640 | |||
641 | memcpy_fromio(skb_put(skb, size), | ||
642 | RX_BUF(card, port) + sizeof(*header), | ||
643 | size); | ||
644 | } | ||
243 | if (atmdebug) { | 645 | if (atmdebug) { |
244 | dev_info(&card->dev->dev, "Received: device %d\n", port); | 646 | dev_info(&card->dev->dev, "Received: device %d\n", port); |
245 | dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", | 647 | dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", |
246 | size, le16_to_cpu(header.vpi), | 648 | size, le16_to_cpu(header->vpi), |
247 | le16_to_cpu(header.vci)); | 649 | le16_to_cpu(header->vci)); |
248 | print_buffer(skb); | 650 | print_buffer(skb); |
249 | } | 651 | } |
250 | 652 | ||
251 | switch (le16_to_cpu(header.type)) { | 653 | switch (le16_to_cpu(header->type)) { |
252 | case PKT_DATA: | 654 | case PKT_DATA: |
253 | vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi), | 655 | vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi), |
254 | le16_to_cpu(header.vci)); | 656 | le16_to_cpu(header->vci)); |
255 | if (!vcc) { | 657 | if (!vcc) { |
256 | if (net_ratelimit()) | 658 | if (net_ratelimit()) |
257 | dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", | 659 | dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", |
258 | le16_to_cpu(header.vci), le16_to_cpu(header.vpi), | 660 | le16_to_cpu(header->vci), le16_to_cpu(header->vpi), |
259 | port); | 661 | port); |
260 | continue; | 662 | continue; |
261 | } | 663 | } |
@@ -264,19 +666,50 @@ void solos_bh(unsigned long card_arg) | |||
264 | atomic_inc(&vcc->stats->rx); | 666 | atomic_inc(&vcc->stats->rx); |
265 | break; | 667 | break; |
266 | 668 | ||
669 | case PKT_STATUS: | ||
670 | if (process_status(card, port, skb) && | ||
671 | net_ratelimit()) { | ||
672 | dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port); | ||
673 | print_buffer(skb); | ||
674 | } | ||
675 | dev_kfree_skb_any(skb); | ||
676 | break; | ||
677 | |||
267 | case PKT_COMMAND: | 678 | case PKT_COMMAND: |
268 | default: /* FIXME: Not really, surely? */ | 679 | default: /* FIXME: Not really, surely? */ |
680 | if (process_command(card, port, skb)) | ||
681 | break; | ||
269 | spin_lock(&card->cli_queue_lock); | 682 | spin_lock(&card->cli_queue_lock); |
270 | if (skb_queue_len(&card->cli_queue[port]) > 10) { | 683 | if (skb_queue_len(&card->cli_queue[port]) > 10) { |
271 | if (net_ratelimit()) | 684 | if (net_ratelimit()) |
272 | dev_warn(&card->dev->dev, "Dropping console response on port %d\n", | 685 | dev_warn(&card->dev->dev, "Dropping console response on port %d\n", |
273 | port); | 686 | port); |
687 | dev_kfree_skb_any(skb); | ||
274 | } else | 688 | } else |
275 | skb_queue_tail(&card->cli_queue[port], skb); | 689 | skb_queue_tail(&card->cli_queue[port], skb); |
276 | spin_unlock(&card->cli_queue_lock); | 690 | spin_unlock(&card->cli_queue_lock); |
277 | break; | 691 | break; |
278 | } | 692 | } |
279 | } | 693 | } |
694 | /* Allocate RX skbs for any ports which need them */ | ||
695 | if (card->using_dma && card->atmdev[port] && | ||
696 | !card->rx_skb[port]) { | ||
697 | struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC); | ||
698 | if (skb) { | ||
699 | SKB_CB(skb)->dma_addr = | ||
700 | pci_map_single(card->dev, skb->data, | ||
701 | RX_DMA_SIZE, PCI_DMA_FROMDEVICE); | ||
702 | iowrite32(SKB_CB(skb)->dma_addr, | ||
703 | card->config_regs + RX_DMA_ADDR(port)); | ||
704 | card->rx_skb[port] = skb; | ||
705 | } else { | ||
706 | if (net_ratelimit()) | ||
707 | dev_warn(&card->dev->dev, "Failed to allocate RX skb"); | ||
708 | |||
709 | /* We'll have to try again later */ | ||
710 | tasklet_schedule(&card->tlet); | ||
711 | } | ||
712 | } | ||
280 | } | 713 | } |
281 | if (rx_done) | 714 | if (rx_done) |
282 | iowrite32(rx_done, card->config_regs + FLAGS_ADDR); | 715 | iowrite32(rx_done, card->config_regs + FLAGS_ADDR); |
@@ -326,7 +759,7 @@ static int list_vccs(int vci) | |||
326 | vcc->vci); | 759 | vcc->vci); |
327 | } | 760 | } |
328 | } else { | 761 | } else { |
329 | for(i=0; i<32; i++){ | 762 | for(i = 0; i < VCC_HTABLE_SIZE; i++){ |
330 | head = &vcc_hash[i]; | 763 | head = &vcc_hash[i]; |
331 | sk_for_each(s, node, head) { | 764 | sk_for_each(s, node, head) { |
332 | num_found ++; | 765 | num_found ++; |
@@ -342,6 +775,28 @@ static int list_vccs(int vci) | |||
342 | return num_found; | 775 | return num_found; |
343 | } | 776 | } |
344 | 777 | ||
778 | static void release_vccs(struct atm_dev *dev) | ||
779 | { | ||
780 | int i; | ||
781 | |||
782 | write_lock_irq(&vcc_sklist_lock); | ||
783 | for (i = 0; i < VCC_HTABLE_SIZE; i++) { | ||
784 | struct hlist_head *head = &vcc_hash[i]; | ||
785 | struct hlist_node *node, *tmp; | ||
786 | struct sock *s; | ||
787 | struct atm_vcc *vcc; | ||
788 | |||
789 | sk_for_each_safe(s, node, tmp, head) { | ||
790 | vcc = atm_sk(s); | ||
791 | if (vcc->dev == dev) { | ||
792 | vcc_release_async(vcc, -EPIPE); | ||
793 | sk_del_node_init(s); | ||
794 | } | ||
795 | } | ||
796 | } | ||
797 | write_unlock_irq(&vcc_sklist_lock); | ||
798 | } | ||
799 | |||
345 | 800 | ||
346 | static int popen(struct atm_vcc *vcc) | 801 | static int popen(struct atm_vcc *vcc) |
347 | { | 802 | { |
@@ -349,6 +804,12 @@ static int popen(struct atm_vcc *vcc) | |||
349 | struct sk_buff *skb; | 804 | struct sk_buff *skb; |
350 | struct pkt_hdr *header; | 805 | struct pkt_hdr *header; |
351 | 806 | ||
807 | if (vcc->qos.aal != ATM_AAL5) { | ||
808 | dev_warn(&card->dev->dev, "Unsupported ATM type %d\n", | ||
809 | vcc->qos.aal); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
352 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | 813 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); |
353 | if (!skb && net_ratelimit()) { | 814 | if (!skb && net_ratelimit()) { |
354 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); | 815 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); |
@@ -356,22 +817,17 @@ static int popen(struct atm_vcc *vcc) | |||
356 | } | 817 | } |
357 | header = (void *)skb_put(skb, sizeof(*header)); | 818 | header = (void *)skb_put(skb, sizeof(*header)); |
358 | 819 | ||
359 | header->size = cpu_to_le16(sizeof(*header)); | 820 | header->size = cpu_to_le16(0); |
360 | header->vpi = cpu_to_le16(vcc->vpi); | 821 | header->vpi = cpu_to_le16(vcc->vpi); |
361 | header->vci = cpu_to_le16(vcc->vci); | 822 | header->vci = cpu_to_le16(vcc->vci); |
362 | header->type = cpu_to_le16(PKT_POPEN); | 823 | header->type = cpu_to_le16(PKT_POPEN); |
363 | 824 | ||
364 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); | 825 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); |
365 | 826 | ||
366 | // dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); | 827 | set_bit(ATM_VF_ADDR, &vcc->flags); |
367 | set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci | ||
368 | set_bit(ATM_VF_READY, &vcc->flags); | 828 | set_bit(ATM_VF_READY, &vcc->flags); |
369 | list_vccs(0); | 829 | list_vccs(0); |
370 | 830 | ||
371 | if (!opens) | ||
372 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); | ||
373 | |||
374 | opens++; //count open PVCs | ||
375 | 831 | ||
376 | return 0; | 832 | return 0; |
377 | } | 833 | } |
@@ -389,17 +845,13 @@ static void pclose(struct atm_vcc *vcc) | |||
389 | } | 845 | } |
390 | header = (void *)skb_put(skb, sizeof(*header)); | 846 | header = (void *)skb_put(skb, sizeof(*header)); |
391 | 847 | ||
392 | header->size = cpu_to_le16(sizeof(*header)); | 848 | header->size = cpu_to_le16(0); |
393 | header->vpi = cpu_to_le16(vcc->vpi); | 849 | header->vpi = cpu_to_le16(vcc->vpi); |
394 | header->vci = cpu_to_le16(vcc->vci); | 850 | header->vci = cpu_to_le16(vcc->vci); |
395 | header->type = cpu_to_le16(PKT_PCLOSE); | 851 | header->type = cpu_to_le16(PKT_PCLOSE); |
396 | 852 | ||
397 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); | 853 | fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); |
398 | 854 | ||
399 | // dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); | ||
400 | if (!--opens) | ||
401 | iowrite32(0, card->config_regs + IRQ_EN_ADDR); | ||
402 | |||
403 | clear_bit(ATM_VF_ADDR, &vcc->flags); | 855 | clear_bit(ATM_VF_ADDR, &vcc->flags); |
404 | clear_bit(ATM_VF_READY, &vcc->flags); | 856 | clear_bit(ATM_VF_READY, &vcc->flags); |
405 | 857 | ||
@@ -439,22 +891,26 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | |||
439 | struct atm_vcc *vcc) | 891 | struct atm_vcc *vcc) |
440 | { | 892 | { |
441 | int old_len; | 893 | int old_len; |
894 | unsigned long flags; | ||
442 | 895 | ||
443 | *(void **)skb->cb = vcc; | 896 | SKB_CB(skb)->vcc = vcc; |
444 | 897 | ||
445 | spin_lock(&card->tx_queue_lock); | 898 | spin_lock_irqsave(&card->tx_queue_lock, flags); |
446 | old_len = skb_queue_len(&card->tx_queue[port]); | 899 | old_len = skb_queue_len(&card->tx_queue[port]); |
447 | skb_queue_tail(&card->tx_queue[port], skb); | 900 | skb_queue_tail(&card->tx_queue[port], skb); |
448 | spin_unlock(&card->tx_queue_lock); | 901 | if (!old_len) |
902 | card->tx_mask |= (1 << port); | ||
903 | spin_unlock_irqrestore(&card->tx_queue_lock, flags); | ||
449 | 904 | ||
450 | /* If TX might need to be started, do so */ | 905 | /* Theoretically we could just schedule the tasklet here, but |
906 | that introduces latency we don't want -- it's noticeable */ | ||
451 | if (!old_len) | 907 | if (!old_len) |
452 | fpga_tx(card); | 908 | fpga_tx(card); |
453 | } | 909 | } |
454 | 910 | ||
455 | static int fpga_tx(struct solos_card *card) | 911 | static uint32_t fpga_tx(struct solos_card *card) |
456 | { | 912 | { |
457 | uint32_t tx_pending; | 913 | uint32_t tx_pending, card_flags; |
458 | uint32_t tx_started = 0; | 914 | uint32_t tx_started = 0; |
459 | struct sk_buff *skb; | 915 | struct sk_buff *skb; |
460 | struct atm_vcc *vcc; | 916 | struct atm_vcc *vcc; |
@@ -462,69 +918,77 @@ static int fpga_tx(struct solos_card *card) | |||
462 | unsigned long flags; | 918 | unsigned long flags; |
463 | 919 | ||
464 | spin_lock_irqsave(&card->tx_lock, flags); | 920 | spin_lock_irqsave(&card->tx_lock, flags); |
465 | 921 | ||
466 | tx_pending = ioread32(card->config_regs + FLAGS_ADDR); | 922 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); |
467 | 923 | /* | |
468 | dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); | 924 | * The queue lock is required for _writing_ to tx_mask, but we're |
469 | 925 | * OK to read it here without locking. The only potential update | |
470 | for (port = 0; port < card->nr_ports; port++) { | 926 | * that we could race with is in fpga_queue() where it sets a bit |
471 | if (!(tx_pending & (1 << port))) { | 927 | * for a new port... but it's going to call this function again if |
928 | * it's doing that, anyway. | ||
929 | */ | ||
930 | tx_pending = card->tx_mask & ~card_flags; | ||
931 | |||
932 | for (port = 0; tx_pending; tx_pending >>= 1, port++) { | ||
933 | if (tx_pending & 1) { | ||
934 | struct sk_buff *oldskb = card->tx_skb[port]; | ||
935 | if (oldskb) | ||
936 | pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr, | ||
937 | oldskb->len, PCI_DMA_TODEVICE); | ||
472 | 938 | ||
473 | spin_lock(&card->tx_queue_lock); | 939 | spin_lock(&card->tx_queue_lock); |
474 | skb = skb_dequeue(&card->tx_queue[port]); | 940 | skb = skb_dequeue(&card->tx_queue[port]); |
941 | if (!skb) | ||
942 | card->tx_mask &= ~(1 << port); | ||
475 | spin_unlock(&card->tx_queue_lock); | 943 | spin_unlock(&card->tx_queue_lock); |
476 | 944 | ||
477 | if (!skb) | 945 | if (skb && !card->using_dma) { |
946 | memcpy_toio(TX_BUF(card, port), skb->data, skb->len); | ||
947 | tx_started |= 1 << port; | ||
948 | oldskb = skb; /* We're done with this skb already */ | ||
949 | } else if (skb && card->using_dma) { | ||
950 | SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data, | ||
951 | skb->len, PCI_DMA_TODEVICE); | ||
952 | iowrite32(SKB_CB(skb)->dma_addr, | ||
953 | card->config_regs + TX_DMA_ADDR(port)); | ||
954 | } | ||
955 | |||
956 | if (!oldskb) | ||
478 | continue; | 957 | continue; |
479 | 958 | ||
959 | /* Clean up and free oldskb now it's gone */ | ||
480 | if (atmdebug) { | 960 | if (atmdebug) { |
481 | dev_info(&card->dev->dev, "Transmitted: port %d\n", | 961 | dev_info(&card->dev->dev, "Transmitted: port %d\n", |
482 | port); | 962 | port); |
483 | print_buffer(skb); | 963 | print_buffer(oldskb); |
484 | } | 964 | } |
485 | memcpy_toio(TX_BUF(card, port), skb->data, skb->len); | ||
486 | 965 | ||
487 | vcc = *(void **)skb->cb; | 966 | vcc = SKB_CB(oldskb)->vcc; |
488 | 967 | ||
489 | if (vcc) { | 968 | if (vcc) { |
490 | atomic_inc(&vcc->stats->tx); | 969 | atomic_inc(&vcc->stats->tx); |
491 | solos_pop(vcc, skb); | 970 | solos_pop(vcc, oldskb); |
492 | } else | 971 | } else |
493 | dev_kfree_skb_irq(skb); | 972 | dev_kfree_skb_irq(oldskb); |
494 | 973 | ||
495 | tx_started |= 1 << port; //Set TX full flag | ||
496 | } | 974 | } |
497 | } | 975 | } |
976 | /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ | ||
498 | if (tx_started) | 977 | if (tx_started) |
499 | iowrite32(tx_started, card->config_regs + FLAGS_ADDR); | 978 | iowrite32(tx_started, card->config_regs + FLAGS_ADDR); |
500 | 979 | ||
501 | spin_unlock_irqrestore(&card->tx_lock, flags); | 980 | spin_unlock_irqrestore(&card->tx_lock, flags); |
502 | return 0; | 981 | return card_flags; |
503 | } | 982 | } |
504 | 983 | ||
505 | static int psend(struct atm_vcc *vcc, struct sk_buff *skb) | 984 | static int psend(struct atm_vcc *vcc, struct sk_buff *skb) |
506 | { | 985 | { |
507 | struct solos_card *card = vcc->dev->dev_data; | 986 | struct solos_card *card = vcc->dev->dev_data; |
508 | struct sk_buff *skb2 = NULL; | ||
509 | struct pkt_hdr *header; | 987 | struct pkt_hdr *header; |
988 | int pktlen; | ||
510 | 989 | ||
511 | //dev_dbg(&card->dev->dev, "psend called.\n"); | 990 | pktlen = skb->len; |
512 | //dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci); | 991 | if (pktlen > (BUF_SIZE - sizeof(*header))) { |
513 | |||
514 | if (debug) { | ||
515 | skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC); | ||
516 | if (skb2) { | ||
517 | memcpy(skb2->data, skb->data, skb->len); | ||
518 | skb_put(skb2, skb->len); | ||
519 | vcc->push(vcc, skb2); | ||
520 | atomic_inc(&vcc->stats->rx); | ||
521 | } | ||
522 | atomic_inc(&vcc->stats->tx); | ||
523 | solos_pop(vcc, skb); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | if (skb->len > (BUF_SIZE - sizeof(*header))) { | ||
528 | dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); | 992 | dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); |
529 | solos_pop(vcc, skb); | 993 | solos_pop(vcc, skb); |
530 | return 0; | 994 | return 0; |
@@ -539,6 +1003,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb) | |||
539 | 1003 | ||
540 | ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); | 1004 | ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); |
541 | if (ret) { | 1005 | if (ret) { |
1006 | dev_warn(&card->dev->dev, "pskb_expand_head failed.\n"); | ||
542 | solos_pop(vcc, skb); | 1007 | solos_pop(vcc, skb); |
543 | return ret; | 1008 | return ret; |
544 | } | 1009 | } |
@@ -546,7 +1011,8 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb) | |||
546 | 1011 | ||
547 | header = (void *)skb_push(skb, sizeof(*header)); | 1012 | header = (void *)skb_push(skb, sizeof(*header)); |
548 | 1013 | ||
549 | header->size = cpu_to_le16(skb->len); | 1014 | /* This does _not_ include the size of the header */ |
1015 | header->size = cpu_to_le16(pktlen); | ||
550 | header->vpi = cpu_to_le16(vcc->vpi); | 1016 | header->vpi = cpu_to_le16(vcc->vpi); |
551 | header->vci = cpu_to_le16(vcc->vci); | 1017 | header->vci = cpu_to_le16(vcc->vci); |
552 | header->type = cpu_to_le16(PKT_DATA); | 1018 | header->type = cpu_to_le16(PKT_DATA); |
@@ -573,20 +1039,19 @@ static struct atmdev_ops fpga_ops = { | |||
573 | 1039 | ||
574 | static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | 1040 | static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) |
575 | { | 1041 | { |
576 | int err, i; | 1042 | int err; |
577 | uint16_t fpga_ver; | 1043 | uint16_t fpga_ver; |
578 | uint8_t major_ver, minor_ver; | 1044 | uint8_t major_ver, minor_ver; |
579 | uint32_t data32; | 1045 | uint32_t data32; |
580 | struct solos_card *card; | 1046 | struct solos_card *card; |
581 | 1047 | ||
582 | if (debug) | ||
583 | return 0; | ||
584 | |||
585 | card = kzalloc(sizeof(*card), GFP_KERNEL); | 1048 | card = kzalloc(sizeof(*card), GFP_KERNEL); |
586 | if (!card) | 1049 | if (!card) |
587 | return -ENOMEM; | 1050 | return -ENOMEM; |
588 | 1051 | ||
589 | card->dev = dev; | 1052 | card->dev = dev; |
1053 | init_waitqueue_head(&card->fw_wq); | ||
1054 | init_waitqueue_head(&card->param_wq); | ||
590 | 1055 | ||
591 | err = pci_enable_device(dev); | 1056 | err = pci_enable_device(dev); |
592 | if (err) { | 1057 | if (err) { |
@@ -594,6 +1059,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
594 | goto out; | 1059 | goto out; |
595 | } | 1060 | } |
596 | 1061 | ||
1062 | err = pci_set_dma_mask(dev, DMA_32BIT_MASK); | ||
1063 | if (err) { | ||
1064 | dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n"); | ||
1065 | goto out; | ||
1066 | } | ||
1067 | |||
597 | err = pci_request_regions(dev, "solos"); | 1068 | err = pci_request_regions(dev, "solos"); |
598 | if (err) { | 1069 | if (err) { |
599 | dev_warn(&dev->dev, "Failed to request regions\n"); | 1070 | dev_warn(&dev->dev, "Failed to request regions\n"); |
@@ -611,17 +1082,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
611 | goto out_unmap_config; | 1082 | goto out_unmap_config; |
612 | } | 1083 | } |
613 | 1084 | ||
614 | // for(i=0;i<64 ;i+=4){ | 1085 | if (reset) { |
615 | // data32=ioread32(card->buffers + i); | 1086 | iowrite32(1, card->config_regs + FPGA_MODE); |
616 | // dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32); | 1087 | data32 = ioread32(card->config_regs + FPGA_MODE); |
617 | // } | ||
618 | |||
619 | //Fill Config Mem with zeros | ||
620 | for(i = 0; i < 128; i += 4) | ||
621 | iowrite32(0, card->config_regs + i); | ||
622 | 1088 | ||
623 | //Set RX empty flags | 1089 | iowrite32(0, card->config_regs + FPGA_MODE); |
624 | iowrite32(0xF0, card->config_regs + FLAGS_ADDR); | 1090 | data32 = ioread32(card->config_regs + FPGA_MODE); |
1091 | } | ||
625 | 1092 | ||
626 | data32 = ioread32(card->config_regs + FPGA_VER); | 1093 | data32 = ioread32(card->config_regs + FPGA_VER); |
627 | fpga_ver = (data32 & 0x0000FFFF); | 1094 | fpga_ver = (data32 & 0x0000FFFF); |
@@ -630,55 +1097,53 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
630 | dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", | 1097 | dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", |
631 | major_ver, minor_ver, fpga_ver); | 1098 | major_ver, minor_ver, fpga_ver); |
632 | 1099 | ||
633 | card->nr_ports = 2; /* FIXME: Detect daughterboard */ | 1100 | if (0 && fpga_ver > 27) |
1101 | card->using_dma = 1; | ||
1102 | else { | ||
1103 | /* Set RX empty flag for all ports */ | ||
1104 | iowrite32(0xF0, card->config_regs + FLAGS_ADDR); | ||
1105 | } | ||
634 | 1106 | ||
635 | err = atm_init(card); | 1107 | data32 = ioread32(card->config_regs + PORTS); |
636 | if (err) | 1108 | card->nr_ports = (data32 & 0x000000FF); |
637 | goto out_unmap_both; | ||
638 | 1109 | ||
639 | pci_set_drvdata(dev, card); | 1110 | pci_set_drvdata(dev, card); |
1111 | |||
640 | tasklet_init(&card->tlet, solos_bh, (unsigned long)card); | 1112 | tasklet_init(&card->tlet, solos_bh, (unsigned long)card); |
641 | spin_lock_init(&card->tx_lock); | 1113 | spin_lock_init(&card->tx_lock); |
642 | spin_lock_init(&card->tx_queue_lock); | 1114 | spin_lock_init(&card->tx_queue_lock); |
643 | spin_lock_init(&card->cli_queue_lock); | 1115 | spin_lock_init(&card->cli_queue_lock); |
644 | /* | 1116 | spin_lock_init(&card->param_queue_lock); |
645 | // Set Loopback mode | 1117 | INIT_LIST_HEAD(&card->param_queue); |
646 | data32 = 0x00010000; | 1118 | |
647 | iowrite32(data32,card->config_regs + FLAGS_ADDR); | 1119 | err = request_irq(dev->irq, solos_irq, IRQF_SHARED, |
648 | */ | ||
649 | /* | ||
650 | // Fill Buffers with zeros | ||
651 | for (i = 0; i < BUF_SIZE * 8; i += 4) | ||
652 | iowrite32(0, card->buffers + i); | ||
653 | */ | ||
654 | /* | ||
655 | for(i = 0; i < (BUF_SIZE * 1); i += 4) | ||
656 | iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE)); | ||
657 | for(i = 0; i < (BUF_SIZE * 1); i += 4) | ||
658 | iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE)); | ||
659 | |||
660 | // Read Config Memory | ||
661 | printk(KERN_DEBUG "Reading Config MEM\n"); | ||
662 | i = 0; | ||
663 | for(i = 0; i < 16; i++) { | ||
664 | data32=ioread32(card->buffers + i*(BUF_SIZE/2)); | ||
665 | printk(KERN_ALERT "Addr: %lX Data: %08lX\n", | ||
666 | (unsigned long)(addr_start + i*(BUF_SIZE/2)), | ||
667 | (unsigned long)data32); | ||
668 | } | ||
669 | */ | ||
670 | //dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq); | ||
671 | err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED, | ||
672 | "solos-pci", card); | 1120 | "solos-pci", card); |
673 | if (err) | 1121 | if (err) { |
674 | dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); | 1122 | dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); |
1123 | goto out_unmap_both; | ||
1124 | } | ||
675 | 1125 | ||
676 | // Enable IRQs | ||
677 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); | 1126 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); |
678 | 1127 | ||
1128 | if (fpga_upgrade) | ||
1129 | flash_upgrade(card, 0); | ||
1130 | |||
1131 | if (firmware_upgrade) | ||
1132 | flash_upgrade(card, 1); | ||
1133 | |||
1134 | err = atm_init(card); | ||
1135 | if (err) | ||
1136 | goto out_free_irq; | ||
1137 | |||
679 | return 0; | 1138 | return 0; |
680 | 1139 | ||
1140 | out_free_irq: | ||
1141 | iowrite32(0, card->config_regs + IRQ_EN_ADDR); | ||
1142 | free_irq(dev->irq, card); | ||
1143 | tasklet_kill(&card->tlet); | ||
1144 | |||
681 | out_unmap_both: | 1145 | out_unmap_both: |
1146 | pci_set_drvdata(dev, NULL); | ||
682 | pci_iounmap(dev, card->config_regs); | 1147 | pci_iounmap(dev, card->config_regs); |
683 | out_unmap_config: | 1148 | out_unmap_config: |
684 | pci_iounmap(dev, card->buffers); | 1149 | pci_iounmap(dev, card->buffers); |
@@ -693,9 +1158,10 @@ static int atm_init(struct solos_card *card) | |||
693 | { | 1158 | { |
694 | int i; | 1159 | int i; |
695 | 1160 | ||
696 | opens = 0; | ||
697 | |||
698 | for (i = 0; i < card->nr_ports; i++) { | 1161 | for (i = 0; i < card->nr_ports; i++) { |
1162 | struct sk_buff *skb; | ||
1163 | struct pkt_hdr *header; | ||
1164 | |||
699 | skb_queue_head_init(&card->tx_queue[i]); | 1165 | skb_queue_head_init(&card->tx_queue[i]); |
700 | skb_queue_head_init(&card->cli_queue[i]); | 1166 | skb_queue_head_init(&card->cli_queue[i]); |
701 | 1167 | ||
@@ -707,6 +1173,8 @@ static int atm_init(struct solos_card *card) | |||
707 | } | 1173 | } |
708 | if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) | 1174 | if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) |
709 | dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); | 1175 | dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); |
1176 | if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group)) | ||
1177 | dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i); | ||
710 | 1178 | ||
711 | dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); | 1179 | dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); |
712 | 1180 | ||
@@ -714,6 +1182,22 @@ static int atm_init(struct solos_card *card) | |||
714 | card->atmdev[i]->ci_range.vci_bits = 16; | 1182 | card->atmdev[i]->ci_range.vci_bits = 16; |
715 | card->atmdev[i]->dev_data = card; | 1183 | card->atmdev[i]->dev_data = card; |
716 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; | 1184 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; |
1185 | card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN; | ||
1186 | |||
1187 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | ||
1188 | if (!skb) { | ||
1189 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); | ||
1190 | continue; | ||
1191 | } | ||
1192 | |||
1193 | header = (void *)skb_put(skb, sizeof(*header)); | ||
1194 | |||
1195 | header->size = cpu_to_le16(0); | ||
1196 | header->vpi = cpu_to_le16(0); | ||
1197 | header->vci = cpu_to_le16(0); | ||
1198 | header->type = cpu_to_le16(PKT_STATUS); | ||
1199 | |||
1200 | fpga_queue(card, i, skb, NULL); | ||
717 | } | 1201 | } |
718 | return 0; | 1202 | return 0; |
719 | } | 1203 | } |
@@ -724,8 +1208,28 @@ static void atm_remove(struct solos_card *card) | |||
724 | 1208 | ||
725 | for (i = 0; i < card->nr_ports; i++) { | 1209 | for (i = 0; i < card->nr_ports; i++) { |
726 | if (card->atmdev[i]) { | 1210 | if (card->atmdev[i]) { |
1211 | struct sk_buff *skb; | ||
1212 | |||
727 | dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); | 1213 | dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); |
1214 | |||
1215 | sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group); | ||
728 | atm_dev_deregister(card->atmdev[i]); | 1216 | atm_dev_deregister(card->atmdev[i]); |
1217 | |||
1218 | skb = card->rx_skb[i]; | ||
1219 | if (skb) { | ||
1220 | pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, | ||
1221 | RX_DMA_SIZE, PCI_DMA_FROMDEVICE); | ||
1222 | dev_kfree_skb(skb); | ||
1223 | } | ||
1224 | skb = card->tx_skb[i]; | ||
1225 | if (skb) { | ||
1226 | pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr, | ||
1227 | skb->len, PCI_DMA_TODEVICE); | ||
1228 | dev_kfree_skb(skb); | ||
1229 | } | ||
1230 | while ((skb = skb_dequeue(&card->tx_queue[i]))) | ||
1231 | dev_kfree_skb(skb); | ||
1232 | |||
729 | } | 1233 | } |
730 | } | 1234 | } |
731 | } | 1235 | } |
@@ -733,31 +1237,31 @@ static void atm_remove(struct solos_card *card) | |||
733 | static void fpga_remove(struct pci_dev *dev) | 1237 | static void fpga_remove(struct pci_dev *dev) |
734 | { | 1238 | { |
735 | struct solos_card *card = pci_get_drvdata(dev); | 1239 | struct solos_card *card = pci_get_drvdata(dev); |
1240 | |||
1241 | /* Disable IRQs */ | ||
1242 | iowrite32(0, card->config_regs + IRQ_EN_ADDR); | ||
736 | 1243 | ||
737 | if (debug) | 1244 | /* Reset FPGA */ |
738 | return; | 1245 | iowrite32(1, card->config_regs + FPGA_MODE); |
1246 | (void)ioread32(card->config_regs + FPGA_MODE); | ||
739 | 1247 | ||
740 | atm_remove(card); | 1248 | atm_remove(card); |
741 | 1249 | ||
742 | dev_vdbg(&dev->dev, "Freeing IRQ\n"); | ||
743 | // Disable IRQs from FPGA | ||
744 | iowrite32(0, card->config_regs + IRQ_EN_ADDR); | ||
745 | free_irq(dev->irq, card); | 1250 | free_irq(dev->irq, card); |
746 | tasklet_kill(&card->tlet); | 1251 | tasklet_kill(&card->tlet); |
747 | 1252 | ||
748 | // iowrite32(0x01,pciregs); | 1253 | /* Release device from reset */ |
749 | dev_vdbg(&dev->dev, "Unmapping PCI resource\n"); | 1254 | iowrite32(0, card->config_regs + FPGA_MODE); |
1255 | (void)ioread32(card->config_regs + FPGA_MODE); | ||
1256 | |||
750 | pci_iounmap(dev, card->buffers); | 1257 | pci_iounmap(dev, card->buffers); |
751 | pci_iounmap(dev, card->config_regs); | 1258 | pci_iounmap(dev, card->config_regs); |
752 | 1259 | ||
753 | dev_vdbg(&dev->dev, "Releasing PCI Region\n"); | ||
754 | pci_release_regions(dev); | 1260 | pci_release_regions(dev); |
755 | pci_disable_device(dev); | 1261 | pci_disable_device(dev); |
756 | 1262 | ||
757 | pci_set_drvdata(dev, NULL); | 1263 | pci_set_drvdata(dev, NULL); |
758 | kfree(card); | 1264 | kfree(card); |
759 | // dev_dbg(&card->dev->dev, "fpga_remove\n"); | ||
760 | return; | ||
761 | } | 1265 | } |
762 | 1266 | ||
763 | static struct pci_device_id fpga_pci_tbl[] __devinitdata = { | 1267 | static struct pci_device_id fpga_pci_tbl[] __devinitdata = { |