forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdscc4.c
2057 lines (1810 loc) · 52.8 KB
/
dscc4.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* drivers/net/wan/dscc4/dscc4.c: a DSCC4 HDLC driver for Linux
*
* This software may be used and distributed according to the terms of the
* GNU General Public License.
*
* The author may be reached as [email protected].
* Specific bug reports/asian food will be welcome.
*
* Special thanks to the nice people at CS-Telecom for the hardware and the
* access to the test/measure tools.
*
*
* Theory of Operation
*
* I. Board Compatibility
*
* This device driver is designed for the Siemens PEB20534 4 ports serial
* controller as found on Etinc PCISYNC cards. The documentation for the
* chipset is available at http://www.infineon.com:
* - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with
* 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1";
* - Application Hint "Management of DSCC4 on-chip FIFO resources".
* - Errata sheet DS5 (courtesy of Michael Skerritt).
* Jens David has built an adapter based on the same chipset. Take a look
* at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific
* driver.
* Sample code (2 revisions) is available at Infineon.
*
* II. Board-specific settings
*
* Pcisync can transmit some clock signal to the outside world on the
* *first two* ports provided you put a quartz and a line driver on it and
* remove the jumpers. The operation is described on Etinc web site. If you
* go DCE on these ports, don't forget to use an adequate cable.
*
* Sharing of the PCI interrupt line for this board is possible.
*
* III. Driver operation
*
* The rx/tx operations are based on a linked list of descriptors. The driver
* doesn't use HOLD mode any more. HOLD mode is definitely buggy and the more
* I tried to fix it, the more it started to look like (convoluted) software
* mutation of LxDA method. Errata sheet DS5 suggests to use LxDA: consider
* this a rfc2119 MUST.
*
* Tx direction
* When the tx ring is full, the xmit routine issues a call to netdev_stop.
* The device is supposed to be enabled again during an ALLS irq (we could
* use HI but as it's easy to lose events, it's fscked).
*
* Rx direction
* The received frames aren't supposed to span over multiple receiving areas.
* I may implement it some day but it isn't the highest ranked item.
*
* IV. Notes
* The current error (XDU, RFO) recovery code is untested.
* So far, RDO takes his RX channel down and the right sequence to enable it
* again is still a mystery. If RDO happens, plan a reboot. More details
* in the code (NB: as this happens, TX still works).
* Don't mess the cables during operation, especially on DTE ports. I don't
* suggest it for DCE either but at least one can get some messages instead
* of a complete instant freeze.
* Tests are done on Rev. 20 of the silicium. The RDO handling changes with
* the documentation/chipset releases.
*
* TODO:
* - test X25.
* - use polling at high irq/s,
* - performance analysis,
* - endianness.
*
* 2001/12/10 Daniela Squassoni <[email protected]>
* - Contribution to support the new generic HDLC layer.
*
* 2002/01 Ueimor
* - old style interface removal
* - dscc4_release_ring fix (related to DMA mapping)
* - hard_start_xmit fix (hint: TxSizeMax)
* - misc crapectomy.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/cache.h>
#include <asm/byteorder.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/hdlc.h>
#include <linux/mutex.h>
/* Version */
static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n";
static int debug;
static int quartz;
#ifdef CONFIG_DSCC4_PCI_RST
static DEFINE_MUTEX(dscc4_mutex);
static u32 dscc4_pci_config_store[16];
#endif
#define DRV_NAME "dscc4"
#undef DSCC4_POLLING
/* Module parameters */
MODULE_AUTHOR("Maintainer: Francois Romieu <[email protected]>");
MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
MODULE_LICENSE("GPL");
module_param(debug, int, 0);
MODULE_PARM_DESC(debug,"Enable/disable extra messages");
module_param(quartz, int, 0);
MODULE_PARM_DESC(quartz,"If present, on-board quartz frequency (Hz)");
/* Structures */
struct thingie {
int define;
u32 bits;
};
struct TxFD {
__le32 state;
__le32 next;
__le32 data;
__le32 complete;
u32 jiffies; /* Allows sizeof(TxFD) == sizeof(RxFD) + extra hack */
/* FWIW, datasheet calls that "dummy" and says that card
* never looks at it; neither does the driver */
};
struct RxFD {
__le32 state1;
__le32 next;
__le32 data;
__le32 state2;
__le32 end;
};
#define DUMMY_SKB_SIZE 64
#define TX_LOW 8
#define TX_RING_SIZE 32
#define RX_RING_SIZE 32
#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct TxFD)
#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct RxFD)
#define IRQ_RING_SIZE 64 /* Keep it a multiple of 32 */
#define TX_TIMEOUT (HZ/10)
#define DSCC4_HZ_MAX 33000000
#define BRR_DIVIDER_MAX 64*0x00004000 /* Cf errata DS5 p.10 */
#define dev_per_card 4
#define SCC_REGISTERS_MAX 23 /* Cf errata DS5 p.4 */
#define SOURCE_ID(flags) (((flags) >> 28) & 0x03)
#define TO_SIZE(state) (((state) >> 16) & 0x1fff)
/*
* Given the operating range of Linux HDLC, the 2 defines below could be
* made simpler. However they are a fine reminder for the limitations of
* the driver: it's better to stay < TxSizeMax and < RxSizeMax.
*/
#define TO_STATE_TX(len) cpu_to_le32(((len) & TxSizeMax) << 16)
#define TO_STATE_RX(len) cpu_to_le32((RX_MAX(len) % RxSizeMax) << 16)
#define RX_MAX(len) ((((len) >> 5) + 1) << 5) /* Cf RLCR */
#define SCC_REG_START(dpriv) (SCC_START+(dpriv->dev_id)*SCC_OFFSET)
struct dscc4_pci_priv {
__le32 *iqcfg;
int cfg_cur;
spinlock_t lock;
struct pci_dev *pdev;
struct dscc4_dev_priv *root;
dma_addr_t iqcfg_dma;
u32 xtal_hz;
};
struct dscc4_dev_priv {
struct sk_buff *rx_skbuff[RX_RING_SIZE];
struct sk_buff *tx_skbuff[TX_RING_SIZE];
struct RxFD *rx_fd;
struct TxFD *tx_fd;
__le32 *iqrx;
__le32 *iqtx;
/* FIXME: check all the volatile are required */
volatile u32 tx_current;
u32 rx_current;
u32 iqtx_current;
u32 iqrx_current;
volatile u32 tx_dirty;
volatile u32 ltda;
u32 rx_dirty;
u32 lrda;
dma_addr_t tx_fd_dma;
dma_addr_t rx_fd_dma;
dma_addr_t iqtx_dma;
dma_addr_t iqrx_dma;
u32 scc_regs[SCC_REGISTERS_MAX]; /* Cf errata DS5 p.4 */
struct dscc4_pci_priv *pci_priv;
spinlock_t lock;
int dev_id;
volatile u32 flags;
u32 timer_help;
unsigned short encoding;
unsigned short parity;
struct net_device *dev;
sync_serial_settings settings;
void __iomem *base_addr;
u32 __pad __attribute__ ((aligned (4)));
};
/* GLOBAL registers definitions */
#define GCMDR 0x00
#define GSTAR 0x04
#define GMODE 0x08
#define IQLENR0 0x0C
#define IQLENR1 0x10
#define IQRX0 0x14
#define IQTX0 0x24
#define IQCFG 0x3c
#define FIFOCR1 0x44
#define FIFOCR2 0x48
#define FIFOCR3 0x4c
#define FIFOCR4 0x34
#define CH0CFG 0x50
#define CH0BRDA 0x54
#define CH0BTDA 0x58
#define CH0FRDA 0x98
#define CH0FTDA 0xb0
#define CH0LRDA 0xc8
#define CH0LTDA 0xe0
/* SCC registers definitions */
#define SCC_START 0x0100
#define SCC_OFFSET 0x80
#define CMDR 0x00
#define STAR 0x04
#define CCR0 0x08
#define CCR1 0x0c
#define CCR2 0x10
#define BRR 0x2C
#define RLCR 0x40
#define IMR 0x54
#define ISR 0x58
#define GPDIR 0x0400
#define GPDATA 0x0404
#define GPIM 0x0408
/* Bit masks */
#define EncodingMask 0x00700000
#define CrcMask 0x00000003
#define IntRxScc0 0x10000000
#define IntTxScc0 0x01000000
#define TxPollCmd 0x00000400
#define RxActivate 0x08000000
#define MTFi 0x04000000
#define Rdr 0x00400000
#define Rdt 0x00200000
#define Idr 0x00100000
#define Idt 0x00080000
#define TxSccRes 0x01000000
#define RxSccRes 0x00010000
#define TxSizeMax 0x1fff /* Datasheet DS1 - 11.1.1.1 */
#define RxSizeMax 0x1ffc /* Datasheet DS1 - 11.1.2.1 */
#define Ccr0ClockMask 0x0000003f
#define Ccr1LoopMask 0x00000200
#define IsrMask 0x000fffff
#define BrrExpMask 0x00000f00
#define BrrMultMask 0x0000003f
#define EncodingMask 0x00700000
#define Hold cpu_to_le32(0x40000000)
#define SccBusy 0x10000000
#define PowerUp 0x80000000
#define Vis 0x00001000
#define FrameOk (FrameVfr | FrameCrc)
#define FrameVfr 0x80
#define FrameRdo 0x40
#define FrameCrc 0x20
#define FrameRab 0x10
#define FrameAborted cpu_to_le32(0x00000200)
#define FrameEnd cpu_to_le32(0x80000000)
#define DataComplete cpu_to_le32(0x40000000)
#define LengthCheck 0x00008000
#define SccEvt 0x02000000
#define NoAck 0x00000200
#define Action 0x00000001
#define HiDesc cpu_to_le32(0x20000000)
/* SCC events */
#define RxEvt 0xf0000000
#define TxEvt 0x0f000000
#define Alls 0x00040000
#define Xdu 0x00010000
#define Cts 0x00004000
#define Xmr 0x00002000
#define Xpr 0x00001000
#define Rdo 0x00000080
#define Rfs 0x00000040
#define Cd 0x00000004
#define Rfo 0x00000002
#define Flex 0x00000001
/* DMA core events */
#define Cfg 0x00200000
#define Hi 0x00040000
#define Fi 0x00020000
#define Err 0x00010000
#define Arf 0x00000002
#define ArAck 0x00000001
/* State flags */
#define Ready 0x00000000
#define NeedIDR 0x00000001
#define NeedIDT 0x00000002
#define RdoSet 0x00000004
#define FakeReset 0x00000008
/* Don't mask RDO. Ever. */
#ifdef DSCC4_POLLING
#define EventsMask 0xfffeef7f
#else
#define EventsMask 0xfffa8f7a
#endif
/* Functions prototypes */
static void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
static int dscc4_found1(struct pci_dev *, void __iomem *ioaddr);
static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent);
static int dscc4_open(struct net_device *);
static netdev_tx_t dscc4_start_xmit(struct sk_buff *,
struct net_device *);
static int dscc4_close(struct net_device *);
static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int dscc4_init_ring(struct net_device *);
static void dscc4_release_ring(struct dscc4_dev_priv *);
static void dscc4_tx_timeout(struct net_device *);
static irqreturn_t dscc4_irq(int irq, void *dev_id);
static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short);
static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);
#ifdef DSCC4_POLLING
static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
#endif
static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev)
{
return dev_to_hdlc(dev)->priv;
}
static inline struct net_device *dscc4_to_dev(struct dscc4_dev_priv *p)
{
return p->dev;
}
static void scc_patchl(u32 mask, u32 value, struct dscc4_dev_priv *dpriv,
struct net_device *dev, int offset)
{
u32 state;
/* Cf scc_writel for concern regarding thread-safety */
state = dpriv->scc_regs[offset >> 2];
state &= ~mask;
state |= value;
dpriv->scc_regs[offset >> 2] = state;
writel(state, dpriv->base_addr + SCC_REG_START(dpriv) + offset);
}
static void scc_writel(u32 bits, struct dscc4_dev_priv *dpriv,
struct net_device *dev, int offset)
{
/*
* Thread-UNsafe.
* As of 2002/02/16, there are no thread racing for access.
*/
dpriv->scc_regs[offset >> 2] = bits;
writel(bits, dpriv->base_addr + SCC_REG_START(dpriv) + offset);
}
static inline u32 scc_readl(struct dscc4_dev_priv *dpriv, int offset)
{
return dpriv->scc_regs[offset >> 2];
}
static u32 scc_readl_star(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{
/* Cf errata DS5 p.4 */
readl(dpriv->base_addr + SCC_REG_START(dpriv) + STAR);
return readl(dpriv->base_addr + SCC_REG_START(dpriv) + STAR);
}
static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
dpriv->ltda = dpriv->tx_fd_dma +
((dpriv->tx_current-1)%TX_RING_SIZE)*sizeof(struct TxFD);
writel(dpriv->ltda, dpriv->base_addr + CH0LTDA + dpriv->dev_id*4);
/* Flush posted writes *NOW* */
readl(dpriv->base_addr + CH0LTDA + dpriv->dev_id*4);
}
static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
dpriv->lrda = dpriv->rx_fd_dma +
((dpriv->rx_dirty - 1)%RX_RING_SIZE)*sizeof(struct RxFD);
writel(dpriv->lrda, dpriv->base_addr + CH0LRDA + dpriv->dev_id*4);
}
static inline unsigned int dscc4_tx_done(struct dscc4_dev_priv *dpriv)
{
return dpriv->tx_current == dpriv->tx_dirty;
}
static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda;
}
static int state_check(u32 state, struct dscc4_dev_priv *dpriv,
struct net_device *dev, const char *msg)
{
int ret = 0;
if (debug > 1) {
if (SOURCE_ID(state) != dpriv->dev_id) {
printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n",
dev->name, msg, SOURCE_ID(state), state );
ret = -1;
}
if (state & 0x0df80c00) {
printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n",
dev->name, msg, state);
ret = -1;
}
}
return ret;
}
static void dscc4_tx_print(struct net_device *dev,
struct dscc4_dev_priv *dpriv,
char *msg)
{
printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n",
dev->name, dpriv->tx_current, dpriv->tx_dirty, msg);
}
static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
{
struct device *d = &dpriv->pci_priv->pdev->dev;
struct TxFD *tx_fd = dpriv->tx_fd;
struct RxFD *rx_fd = dpriv->rx_fd;
struct sk_buff **skbuff;
int i;
dma_free_coherent(d, TX_TOTAL_SIZE, tx_fd, dpriv->tx_fd_dma);
dma_free_coherent(d, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);
skbuff = dpriv->tx_skbuff;
for (i = 0; i < TX_RING_SIZE; i++) {
if (*skbuff) {
dma_unmap_single(d, le32_to_cpu(tx_fd->data),
(*skbuff)->len, DMA_TO_DEVICE);
dev_kfree_skb(*skbuff);
}
skbuff++;
tx_fd++;
}
skbuff = dpriv->rx_skbuff;
for (i = 0; i < RX_RING_SIZE; i++) {
if (*skbuff) {
dma_unmap_single(d, le32_to_cpu(rx_fd->data),
RX_MAX(HDLC_MAX_MRU),
DMA_FROM_DEVICE);
dev_kfree_skb(*skbuff);
}
skbuff++;
rx_fd++;
}
}
static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;
struct device *d = &dpriv->pci_priv->pdev->dev;
struct RxFD *rx_fd = dpriv->rx_fd + dirty;
const int len = RX_MAX(HDLC_MAX_MRU);
struct sk_buff *skb;
dma_addr_t addr;
skb = dev_alloc_skb(len);
if (!skb)
goto err_out;
skb->protocol = hdlc_type_trans(skb, dev);
addr = dma_map_single(d, skb->data, len, DMA_FROM_DEVICE);
if (dma_mapping_error(d, addr))
goto err_free_skb;
dpriv->rx_skbuff[dirty] = skb;
rx_fd->data = cpu_to_le32(addr);
return 0;
err_free_skb:
dev_kfree_skb_any(skb);
err_out:
rx_fd->data = 0;
return -1;
}
/*
* IRQ/thread/whatever safe
*/
static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,
struct net_device *dev, char *msg)
{
s8 i = 0;
do {
if (!(scc_readl_star(dpriv, dev) & SccBusy)) {
printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name,
msg, i);
goto done;
}
schedule_timeout_uninterruptible(msecs_to_jiffies(100));
rmb();
} while (++i > 0);
netdev_err(dev, "%s timeout\n", msg);
done:
return (i >= 0) ? i : -EAGAIN;
}
static int dscc4_do_action(struct net_device *dev, char *msg)
{
void __iomem *ioaddr = dscc4_priv(dev)->base_addr;
s16 i = 0;
writel(Action, ioaddr + GCMDR);
ioaddr += GSTAR;
do {
u32 state = readl(ioaddr);
if (state & ArAck) {
netdev_dbg(dev, "%s ack\n", msg);
writel(ArAck, ioaddr);
goto done;
} else if (state & Arf) {
netdev_err(dev, "%s failed\n", msg);
writel(Arf, ioaddr);
i = -1;
goto done;
}
rmb();
} while (++i > 0);
netdev_err(dev, "%s timeout\n", msg);
done:
return i;
}
static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
{
int cur = dpriv->iqtx_current%IRQ_RING_SIZE;
s8 i = 0;
do {
if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
(dpriv->iqtx[cur] & cpu_to_le32(Xpr)))
break;
smp_rmb();
schedule_timeout_uninterruptible(msecs_to_jiffies(100));
} while (++i > 0);
return (i >= 0 ) ? i : -EAGAIN;
}
#if 0 /* dscc4_{rx/tx}_reset are both unreliable - more tweak needed */
static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{
unsigned long flags;
spin_lock_irqsave(&dpriv->pci_priv->lock, flags);
/* Cf errata DS5 p.6 */
writel(0x00000000, dpriv->base_addr + CH0LRDA + dpriv->dev_id*4);
scc_patchl(PowerUp, 0, dpriv, dev, CCR0);
readl(dpriv->base_addr + CH0LRDA + dpriv->dev_id*4);
writel(MTFi|Rdr, dpriv->base_addr + dpriv->dev_id*0x0c + CH0CFG);
writel(Action, dpriv->base_addr + GCMDR);
spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
}
#endif
#if 0
static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
{
u16 i = 0;
/* Cf errata DS5 p.7 */
scc_patchl(PowerUp, 0, dpriv, dev, CCR0);
scc_writel(0x00050000, dpriv, dev, CCR2);
/*
* Must be longer than the time required to fill the fifo.
*/
while (!dscc4_tx_quiescent(dpriv, dev) && ++i) {
udelay(1);
wmb();
}
writel(MTFi|Rdt, dpriv->base_addr + dpriv->dev_id*0x0c + CH0CFG);
if (dscc4_do_action(dev, "Rdt") < 0)
netdev_err(dev, "Tx reset failed\n");
}
#endif
/* TODO: (ab)use this function to refill a completely depleted RX ring. */
static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE;
struct device *d = &dpriv->pci_priv->pdev->dev;
struct sk_buff *skb;
int pkt_len;
skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE];
if (!skb) {
printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __func__);
goto refill;
}
pkt_len = TO_SIZE(le32_to_cpu(rx_fd->state2));
dma_unmap_single(d, le32_to_cpu(rx_fd->data),
RX_MAX(HDLC_MAX_MRU), DMA_FROM_DEVICE);
if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
skb_put(skb, pkt_len);
if (netif_running(dev))
skb->protocol = hdlc_type_trans(skb, dev);
netif_rx(skb);
} else {
if (skb->data[pkt_len] & FrameRdo)
dev->stats.rx_fifo_errors++;
else if (!(skb->data[pkt_len] & FrameCrc))
dev->stats.rx_crc_errors++;
else if ((skb->data[pkt_len] & (FrameVfr | FrameRab)) !=
(FrameVfr | FrameRab))
dev->stats.rx_length_errors++;
dev->stats.rx_errors++;
dev_kfree_skb_irq(skb);
}
refill:
while ((dpriv->rx_dirty - dpriv->rx_current) % RX_RING_SIZE) {
if (try_get_rx_skb(dpriv, dev) < 0)
break;
dpriv->rx_dirty++;
}
dscc4_rx_update(dpriv, dev);
rx_fd->state2 = 0x00000000;
rx_fd->end = cpu_to_le32(0xbabeface);
}
static void dscc4_free1(struct pci_dev *pdev)
{
struct dscc4_pci_priv *ppriv;
struct dscc4_dev_priv *root;
int i;
ppriv = pci_get_drvdata(pdev);
root = ppriv->root;
for (i = 0; i < dev_per_card; i++)
unregister_hdlc_device(dscc4_to_dev(root + i));
for (i = 0; i < dev_per_card; i++)
free_netdev(root[i].dev);
kfree(root);
kfree(ppriv);
}
static int dscc4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct dscc4_pci_priv *priv;
struct dscc4_dev_priv *dpriv;
void __iomem *ioaddr;
int i, rc;
printk(KERN_DEBUG "%s", version);
rc = pci_enable_device(pdev);
if (rc < 0)
goto out;
rc = pci_request_region(pdev, 0, "registers");
if (rc < 0) {
pr_err("can't reserve MMIO region (regs)\n");
goto err_disable_0;
}
rc = pci_request_region(pdev, 1, "LBI interface");
if (rc < 0) {
pr_err("can't reserve MMIO region (lbi)\n");
goto err_free_mmio_region_1;
}
ioaddr = pci_ioremap_bar(pdev, 0);
if (!ioaddr) {
pr_err("cannot remap MMIO region %llx @ %llx\n",
(unsigned long long)pci_resource_len(pdev, 0),
(unsigned long long)pci_resource_start(pdev, 0));
rc = -EIO;
goto err_free_mmio_regions_2;
}
printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#llx (regs), %#llx (lbi), IRQ %d\n",
(unsigned long long)pci_resource_start(pdev, 0),
(unsigned long long)pci_resource_start(pdev, 1), pdev->irq);
/* Cf errata DS5 p.2 */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
pci_set_master(pdev);
rc = dscc4_found1(pdev, ioaddr);
if (rc < 0)
goto err_iounmap_3;
priv = pci_get_drvdata(pdev);
rc = request_irq(pdev->irq, dscc4_irq, IRQF_SHARED, DRV_NAME, priv->root);
if (rc < 0) {
pr_warn("IRQ %d busy\n", pdev->irq);
goto err_release_4;
}
/* power up/little endian/dma core controlled via lrda/ltda */
writel(0x00000001, ioaddr + GMODE);
/* Shared interrupt queue */
{
u32 bits;
bits = (IRQ_RING_SIZE >> 5) - 1;
bits |= bits << 4;
bits |= bits << 8;
bits |= bits << 16;
writel(bits, ioaddr + IQLENR0);
}
/* Global interrupt queue */
writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1);
rc = -ENOMEM;
priv->iqcfg = (__le32 *)dma_alloc_coherent(&pdev->dev,
IRQ_RING_SIZE*sizeof(__le32), &priv->iqcfg_dma, GFP_KERNEL);
if (!priv->iqcfg)
goto err_free_irq_5;
writel(priv->iqcfg_dma, ioaddr + IQCFG);
/*
* SCC 0-3 private rx/tx irq structures
* IQRX/TXi needs to be set soon. Learned it the hard way...
*/
for (i = 0; i < dev_per_card; i++) {
dpriv = priv->root + i;
dpriv->iqtx = (__le32 *)dma_alloc_coherent(&pdev->dev,
IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma,
GFP_KERNEL);
if (!dpriv->iqtx)
goto err_free_iqtx_6;
writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
}
for (i = 0; i < dev_per_card; i++) {
dpriv = priv->root + i;
dpriv->iqrx = (__le32 *)dma_alloc_coherent(&pdev->dev,
IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma,
GFP_KERNEL);
if (!dpriv->iqrx)
goto err_free_iqrx_7;
writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4);
}
/* Cf application hint. Beware of hard-lock condition on threshold. */
writel(0x42104000, ioaddr + FIFOCR1);
//writel(0x9ce69800, ioaddr + FIFOCR2);
writel(0xdef6d800, ioaddr + FIFOCR2);
//writel(0x11111111, ioaddr + FIFOCR4);
writel(0x18181818, ioaddr + FIFOCR4);
// FIXME: should depend on the chipset revision
writel(0x0000000e, ioaddr + FIFOCR3);
writel(0xff200001, ioaddr + GCMDR);
rc = 0;
out:
return rc;
err_free_iqrx_7:
while (--i >= 0) {
dpriv = priv->root + i;
dma_free_coherent(&pdev->dev, IRQ_RING_SIZE*sizeof(u32),
dpriv->iqrx, dpriv->iqrx_dma);
}
i = dev_per_card;
err_free_iqtx_6:
while (--i >= 0) {
dpriv = priv->root + i;
dma_free_coherent(&pdev->dev, IRQ_RING_SIZE*sizeof(u32),
dpriv->iqtx, dpriv->iqtx_dma);
}
dma_free_coherent(&pdev->dev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg,
priv->iqcfg_dma);
err_free_irq_5:
free_irq(pdev->irq, priv->root);
err_release_4:
dscc4_free1(pdev);
err_iounmap_3:
iounmap (ioaddr);
err_free_mmio_regions_2:
pci_release_region(pdev, 1);
err_free_mmio_region_1:
pci_release_region(pdev, 0);
err_disable_0:
pci_disable_device(pdev);
goto out;
};
/*
* Let's hope the default values are decent enough to protect my
* feet from the user's gun - Ueimor
*/
static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
struct net_device *dev)
{
/* No interrupts, SCC core disabled. Let's relax */
scc_writel(0x00000000, dpriv, dev, CCR0);
scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR);
/*
* No address recognition/crc-CCITT/cts enabled
* Shared flags transmission disabled - cf errata DS5 p.11
* Carrier detect disabled - cf errata p.14
* FIXME: carrier detection/polarity may be handled more gracefully.
*/
scc_writel(0x02408000, dpriv, dev, CCR1);
/* crc not forwarded - Cf errata DS5 p.11 */
scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2);
// crc forwarded
//scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2);
}
static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz)
{
int ret = 0;
if ((hz < 0) || (hz > DSCC4_HZ_MAX))
ret = -EOPNOTSUPP;
else
dpriv->pci_priv->xtal_hz = hz;
return ret;
}
static const struct net_device_ops dscc4_ops = {
.ndo_open = dscc4_open,
.ndo_stop = dscc4_close,
.ndo_start_xmit = hdlc_start_xmit,
.ndo_do_ioctl = dscc4_ioctl,
.ndo_tx_timeout = dscc4_tx_timeout,
};
static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
{
struct dscc4_pci_priv *ppriv;
struct dscc4_dev_priv *root;
int i, ret = -ENOMEM;
root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL);
if (!root)
goto err_out;
for (i = 0; i < dev_per_card; i++) {
root[i].dev = alloc_hdlcdev(root + i);
if (!root[i].dev)
goto err_free_dev;
}
ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL);
if (!ppriv)
goto err_free_dev;
ppriv->root = root;
spin_lock_init(&ppriv->lock);
for (i = 0; i < dev_per_card; i++) {
struct dscc4_dev_priv *dpriv = root + i;
struct net_device *d = dscc4_to_dev(dpriv);
hdlc_device *hdlc = dev_to_hdlc(d);
d->base_addr = (unsigned long)ioaddr;
d->irq = pdev->irq;
d->netdev_ops = &dscc4_ops;
d->watchdog_timeo = TX_TIMEOUT;
SET_NETDEV_DEV(d, &pdev->dev);
dpriv->dev_id = i;
dpriv->pci_priv = ppriv;
dpriv->base_addr = ioaddr;
spin_lock_init(&dpriv->lock);
hdlc->xmit = dscc4_start_xmit;
hdlc->attach = dscc4_hdlc_attach;
dscc4_init_registers(dpriv, d);
dpriv->parity = PARITY_CRC16_PR0_CCITT;
dpriv->encoding = ENCODING_NRZ;
ret = dscc4_init_ring(d);
if (ret < 0)
goto err_unregister;
ret = register_hdlc_device(d);
if (ret < 0) {
pr_err("unable to register\n");
dscc4_release_ring(dpriv);
goto err_unregister;
}
}
ret = dscc4_set_quartz(root, quartz);
if (ret < 0)
goto err_unregister;
pci_set_drvdata(pdev, ppriv);
return ret;
err_unregister:
while (i-- > 0) {
dscc4_release_ring(root + i);
unregister_hdlc_device(dscc4_to_dev(root + i));
}
kfree(ppriv);
i = dev_per_card;
err_free_dev:
while (i-- > 0)
free_netdev(root[i].dev);
kfree(root);
err_out:
return ret;
};
static void dscc4_tx_timeout(struct net_device *dev)
{
/* FIXME: something is missing there */
}
static int dscc4_loopback_check(struct dscc4_dev_priv *dpriv)
{
sync_serial_settings *settings = &dpriv->settings;
if (settings->loopback && (settings->clock_type != CLOCK_INT)) {
struct net_device *dev = dscc4_to_dev(dpriv);
netdev_info(dev, "loopback requires clock\n");
return -1;
}
return 0;
}