diff options
Diffstat (limited to 'drivers/rapidio/switches')
-rw-r--r-- | drivers/rapidio/switches/Kconfig | 28 | ||||
-rw-r--r-- | drivers/rapidio/switches/Makefile | 9 | ||||
-rw-r--r-- | drivers/rapidio/switches/idtcps.c | 137 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi500.c | 20 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi568.c | 146 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi57x.c | 315 |
6 files changed, 653 insertions, 2 deletions
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig new file mode 100644 index 000000000000..2b4e9b2b6631 --- /dev/null +++ b/drivers/rapidio/switches/Kconfig | |||
@@ -0,0 +1,28 @@ | |||
1 | # | ||
2 | # RapidIO switches configuration | ||
3 | # | ||
4 | config RAPIDIO_TSI57X | ||
5 | bool "IDT Tsi57x SRIO switches support" | ||
6 | depends on RAPIDIO | ||
7 | ---help--- | ||
8 | Includes support for IDT Tsi57x family of serial RapidIO switches. | ||
9 | |||
10 | config RAPIDIO_CPS_XX | ||
11 | bool "IDT CPS-xx SRIO switches support" | ||
12 | depends on RAPIDIO | ||
13 | ---help--- | ||
14 | Includes support for IDT CPS-16/12/10/8 serial RapidIO switches. | ||
15 | |||
16 | config RAPIDIO_TSI568 | ||
17 | bool "Tsi568 SRIO switch support" | ||
18 | depends on RAPIDIO | ||
19 | default n | ||
20 | ---help--- | ||
21 | Includes support for IDT Tsi568 serial RapidIO switch. | ||
22 | |||
23 | config RAPIDIO_TSI500 | ||
24 | bool "Tsi500 Parallel RapidIO switch support" | ||
25 | depends on RAPIDIO | ||
26 | default n | ||
27 | ---help--- | ||
28 | Includes support for IDT Tsi500 parallel RapidIO switch. | ||
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile index b924f8301761..fe4adc3e8d5f 100644 --- a/drivers/rapidio/switches/Makefile +++ b/drivers/rapidio/switches/Makefile | |||
@@ -2,4 +2,11 @@ | |||
2 | # Makefile for RIO switches | 2 | # Makefile for RIO switches |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_RAPIDIO) += tsi500.o | 5 | obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o |
6 | obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o | ||
7 | obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o | ||
8 | obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o | ||
9 | |||
10 | ifeq ($(CONFIG_RAPIDIO_DEBUG),y) | ||
11 | EXTRA_CFLAGS += -DDEBUG | ||
12 | endif | ||
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c new file mode 100644 index 000000000000..2c790c144f89 --- /dev/null +++ b/drivers/rapidio/switches/idtcps.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * IDT CPS RapidIO switches support | ||
3 | * | ||
4 | * Copyright 2009-2010 Integrated Device Technology, Inc. | ||
5 | * Alexandre Bounine <alexandre.bounine@idt.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/rio.h> | ||
14 | #include <linux/rio_drv.h> | ||
15 | #include <linux/rio_ids.h> | ||
16 | #include "../rio.h" | ||
17 | |||
18 | #define CPS_DEFAULT_ROUTE 0xde | ||
19 | #define CPS_NO_ROUTE 0xdf | ||
20 | |||
21 | #define IDTCPS_RIO_DOMAIN 0xf20020 | ||
22 | |||
23 | static int | ||
24 | idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
25 | u16 table, u16 route_destid, u8 route_port) | ||
26 | { | ||
27 | u32 result; | ||
28 | |||
29 | if (table == RIO_GLOBAL_TABLE) { | ||
30 | rio_mport_write_config_32(mport, destid, hopcount, | ||
31 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); | ||
32 | |||
33 | rio_mport_read_config_32(mport, destid, hopcount, | ||
34 | RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); | ||
35 | |||
36 | result = (0xffffff00 & result) | (u32)route_port; | ||
37 | rio_mport_write_config_32(mport, destid, hopcount, | ||
38 | RIO_STD_RTE_CONF_PORT_SEL_CSR, result); | ||
39 | } | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int | ||
45 | idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
46 | u16 table, u16 route_destid, u8 *route_port) | ||
47 | { | ||
48 | u32 result; | ||
49 | |||
50 | if (table == RIO_GLOBAL_TABLE) { | ||
51 | rio_mport_write_config_32(mport, destid, hopcount, | ||
52 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); | ||
53 | |||
54 | rio_mport_read_config_32(mport, destid, hopcount, | ||
55 | RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); | ||
56 | |||
57 | if (CPS_DEFAULT_ROUTE == (u8)result || | ||
58 | CPS_NO_ROUTE == (u8)result) | ||
59 | *route_port = RIO_INVALID_ROUTE; | ||
60 | else | ||
61 | *route_port = (u8)result; | ||
62 | } | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
69 | u16 table) | ||
70 | { | ||
71 | u32 i; | ||
72 | |||
73 | if (table == RIO_GLOBAL_TABLE) { | ||
74 | for (i = 0x80000000; i <= 0x800000ff;) { | ||
75 | rio_mport_write_config_32(mport, destid, hopcount, | ||
76 | RIO_STD_RTE_CONF_DESTID_SEL_CSR, i); | ||
77 | rio_mport_write_config_32(mport, destid, hopcount, | ||
78 | RIO_STD_RTE_CONF_PORT_SEL_CSR, | ||
79 | (CPS_DEFAULT_ROUTE << 24) | | ||
80 | (CPS_DEFAULT_ROUTE << 16) | | ||
81 | (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE); | ||
82 | i += 4; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int | ||
90 | idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
91 | u8 sw_domain) | ||
92 | { | ||
93 | /* | ||
94 | * Switch domain configuration operates only at global level | ||
95 | */ | ||
96 | rio_mport_write_config_32(mport, destid, hopcount, | ||
97 | IDTCPS_RIO_DOMAIN, (u32)sw_domain); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
103 | u8 *sw_domain) | ||
104 | { | ||
105 | u32 regval; | ||
106 | |||
107 | /* | ||
108 | * Switch domain configuration operates only at global level | ||
109 | */ | ||
110 | rio_mport_read_config_32(mport, destid, hopcount, | ||
111 | IDTCPS_RIO_DOMAIN, ®val); | ||
112 | |||
113 | *sw_domain = (u8)(regval & 0xff); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) | ||
119 | { | ||
120 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); | ||
121 | rdev->rswitch->add_entry = idtcps_route_add_entry; | ||
122 | rdev->rswitch->get_entry = idtcps_route_get_entry; | ||
123 | rdev->rswitch->clr_table = idtcps_route_clr_table; | ||
124 | rdev->rswitch->set_domain = idtcps_set_domain; | ||
125 | rdev->rswitch->get_domain = idtcps_get_domain; | ||
126 | rdev->rswitch->em_init = NULL; | ||
127 | rdev->rswitch->em_handle = NULL; | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init); | ||
133 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init); | ||
134 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init); | ||
135 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init); | ||
136 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init); | ||
137 | DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init); | ||
diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c index c77c23bd9840..914eddd5aa42 100644 --- a/drivers/rapidio/switches/tsi500.c +++ b/drivers/rapidio/switches/tsi500.c | |||
@@ -1,6 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * RapidIO Tsi500 switch support | 2 | * RapidIO Tsi500 switch support |
3 | * | 3 | * |
4 | * Copyright 2009-2010 Integrated Device Technology, Inc. | ||
5 | * Alexandre Bounine <alexandre.bounine@idt.com> | ||
6 | * - Modified switch operations initialization. | ||
7 | * | ||
4 | * Copyright 2005 MontaVista Software, Inc. | 8 | * Copyright 2005 MontaVista Software, Inc. |
5 | * Matt Porter <mporter@kernel.crashing.org> | 9 | * Matt Porter <mporter@kernel.crashing.org> |
6 | * | 10 | * |
@@ -57,4 +61,18 @@ tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 tab | |||
57 | return ret; | 61 | return ret; |
58 | } | 62 | } |
59 | 63 | ||
60 | DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry); | 64 | static int tsi500_switch_init(struct rio_dev *rdev, int do_enum) |
65 | { | ||
66 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); | ||
67 | rdev->rswitch->add_entry = tsi500_route_add_entry; | ||
68 | rdev->rswitch->get_entry = tsi500_route_get_entry; | ||
69 | rdev->rswitch->clr_table = NULL; | ||
70 | rdev->rswitch->set_domain = NULL; | ||
71 | rdev->rswitch->get_domain = NULL; | ||
72 | rdev->rswitch->em_init = NULL; | ||
73 | rdev->rswitch->em_handle = NULL; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init); | ||
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c new file mode 100644 index 000000000000..f7fd7898606e --- /dev/null +++ b/drivers/rapidio/switches/tsi568.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * RapidIO Tsi568 switch support | ||
3 | * | ||
4 | * Copyright 2009-2010 Integrated Device Technology, Inc. | ||
5 | * Alexandre Bounine <alexandre.bounine@idt.com> | ||
6 | * - Added EM support | ||
7 | * - Modified switch operations initialization. | ||
8 | * | ||
9 | * Copyright 2005 MontaVista Software, Inc. | ||
10 | * Matt Porter <mporter@kernel.crashing.org> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/rio.h> | ||
19 | #include <linux/rio_drv.h> | ||
20 | #include <linux/rio_ids.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include "../rio.h" | ||
23 | |||
24 | /* Global (broadcast) route registers */ | ||
25 | #define SPBC_ROUTE_CFG_DESTID 0x10070 | ||
26 | #define SPBC_ROUTE_CFG_PORT 0x10074 | ||
27 | |||
28 | /* Per port route registers */ | ||
29 | #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) | ||
30 | #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) | ||
31 | |||
32 | #define TSI568_SP_MODE_BC 0x10004 | ||
33 | #define TSI568_SP_MODE_PW_DIS 0x08000000 | ||
34 | |||
35 | static int | ||
36 | tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
37 | u16 table, u16 route_destid, u8 route_port) | ||
38 | { | ||
39 | if (table == RIO_GLOBAL_TABLE) { | ||
40 | rio_mport_write_config_32(mport, destid, hopcount, | ||
41 | SPBC_ROUTE_CFG_DESTID, route_destid); | ||
42 | rio_mport_write_config_32(mport, destid, hopcount, | ||
43 | SPBC_ROUTE_CFG_PORT, route_port); | ||
44 | } else { | ||
45 | rio_mport_write_config_32(mport, destid, hopcount, | ||
46 | SPP_ROUTE_CFG_DESTID(table), | ||
47 | route_destid); | ||
48 | rio_mport_write_config_32(mport, destid, hopcount, | ||
49 | SPP_ROUTE_CFG_PORT(table), route_port); | ||
50 | } | ||
51 | |||
52 | udelay(10); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
59 | u16 table, u16 route_destid, u8 *route_port) | ||
60 | { | ||
61 | int ret = 0; | ||
62 | u32 result; | ||
63 | |||
64 | if (table == RIO_GLOBAL_TABLE) { | ||
65 | rio_mport_write_config_32(mport, destid, hopcount, | ||
66 | SPBC_ROUTE_CFG_DESTID, route_destid); | ||
67 | rio_mport_read_config_32(mport, destid, hopcount, | ||
68 | SPBC_ROUTE_CFG_PORT, &result); | ||
69 | } else { | ||
70 | rio_mport_write_config_32(mport, destid, hopcount, | ||
71 | SPP_ROUTE_CFG_DESTID(table), | ||
72 | route_destid); | ||
73 | rio_mport_read_config_32(mport, destid, hopcount, | ||
74 | SPP_ROUTE_CFG_PORT(table), &result); | ||
75 | } | ||
76 | |||
77 | *route_port = result; | ||
78 | if (*route_port > 15) | ||
79 | ret = -1; | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
86 | u16 table) | ||
87 | { | ||
88 | u32 route_idx; | ||
89 | u32 lut_size; | ||
90 | |||
91 | lut_size = (mport->sys_size) ? 0x1ff : 0xff; | ||
92 | |||
93 | if (table == RIO_GLOBAL_TABLE) { | ||
94 | rio_mport_write_config_32(mport, destid, hopcount, | ||
95 | SPBC_ROUTE_CFG_DESTID, 0x80000000); | ||
96 | for (route_idx = 0; route_idx <= lut_size; route_idx++) | ||
97 | rio_mport_write_config_32(mport, destid, hopcount, | ||
98 | SPBC_ROUTE_CFG_PORT, | ||
99 | RIO_INVALID_ROUTE); | ||
100 | } else { | ||
101 | rio_mport_write_config_32(mport, destid, hopcount, | ||
102 | SPP_ROUTE_CFG_DESTID(table), | ||
103 | 0x80000000); | ||
104 | for (route_idx = 0; route_idx <= lut_size; route_idx++) | ||
105 | rio_mport_write_config_32(mport, destid, hopcount, | ||
106 | SPP_ROUTE_CFG_PORT(table), | ||
107 | RIO_INVALID_ROUTE); | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int | ||
114 | tsi568_em_init(struct rio_dev *rdev) | ||
115 | { | ||
116 | struct rio_mport *mport = rdev->net->hport; | ||
117 | u16 destid = rdev->rswitch->destid; | ||
118 | u8 hopcount = rdev->rswitch->hopcount; | ||
119 | u32 regval; | ||
120 | |||
121 | pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount); | ||
122 | |||
123 | /* Make sure that Port-Writes are disabled (for all ports) */ | ||
124 | rio_mport_read_config_32(mport, destid, hopcount, | ||
125 | TSI568_SP_MODE_BC, ®val); | ||
126 | rio_mport_write_config_32(mport, destid, hopcount, | ||
127 | TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int tsi568_switch_init(struct rio_dev *rdev, int do_enum) | ||
133 | { | ||
134 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); | ||
135 | rdev->rswitch->add_entry = tsi568_route_add_entry; | ||
136 | rdev->rswitch->get_entry = tsi568_route_get_entry; | ||
137 | rdev->rswitch->clr_table = tsi568_route_clr_table; | ||
138 | rdev->rswitch->set_domain = NULL; | ||
139 | rdev->rswitch->get_domain = NULL; | ||
140 | rdev->rswitch->em_init = tsi568_em_init; | ||
141 | rdev->rswitch->em_handle = NULL; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init); | ||
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c new file mode 100644 index 000000000000..d34df722d95f --- /dev/null +++ b/drivers/rapidio/switches/tsi57x.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * RapidIO Tsi57x switch family support | ||
3 | * | ||
4 | * Copyright 2009-2010 Integrated Device Technology, Inc. | ||
5 | * Alexandre Bounine <alexandre.bounine@idt.com> | ||
6 | * - Added EM support | ||
7 | * - Modified switch operations initialization. | ||
8 | * | ||
9 | * Copyright 2005 MontaVista Software, Inc. | ||
10 | * Matt Porter <mporter@kernel.crashing.org> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/rio.h> | ||
19 | #include <linux/rio_drv.h> | ||
20 | #include <linux/rio_ids.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include "../rio.h" | ||
23 | |||
24 | /* Global (broadcast) route registers */ | ||
25 | #define SPBC_ROUTE_CFG_DESTID 0x10070 | ||
26 | #define SPBC_ROUTE_CFG_PORT 0x10074 | ||
27 | |||
28 | /* Per port route registers */ | ||
29 | #define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) | ||
30 | #define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) | ||
31 | |||
32 | #define TSI578_SP_MODE(n) (0x11004 + n*0x100) | ||
33 | #define TSI578_SP_MODE_GLBL 0x10004 | ||
34 | #define TSI578_SP_MODE_PW_DIS 0x08000000 | ||
35 | #define TSI578_SP_MODE_LUT_512 0x01000000 | ||
36 | |||
37 | #define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100) | ||
38 | #define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100) | ||
39 | #define TSI578_SP_CS_TX(n) (0x13014 + n*0x100) | ||
40 | #define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100) | ||
41 | |||
42 | #define TSI578_GLBL_ROUTE_BASE 0x10078 | ||
43 | |||
44 | static int | ||
45 | tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
46 | u16 table, u16 route_destid, u8 route_port) | ||
47 | { | ||
48 | if (table == RIO_GLOBAL_TABLE) { | ||
49 | rio_mport_write_config_32(mport, destid, hopcount, | ||
50 | SPBC_ROUTE_CFG_DESTID, route_destid); | ||
51 | rio_mport_write_config_32(mport, destid, hopcount, | ||
52 | SPBC_ROUTE_CFG_PORT, route_port); | ||
53 | } else { | ||
54 | rio_mport_write_config_32(mport, destid, hopcount, | ||
55 | SPP_ROUTE_CFG_DESTID(table), route_destid); | ||
56 | rio_mport_write_config_32(mport, destid, hopcount, | ||
57 | SPP_ROUTE_CFG_PORT(table), route_port); | ||
58 | } | ||
59 | |||
60 | udelay(10); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int | ||
66 | tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
67 | u16 table, u16 route_destid, u8 *route_port) | ||
68 | { | ||
69 | int ret = 0; | ||
70 | u32 result; | ||
71 | |||
72 | if (table == RIO_GLOBAL_TABLE) { | ||
73 | /* Use local RT of the ingress port to avoid possible | ||
74 | race condition */ | ||
75 | rio_mport_read_config_32(mport, destid, hopcount, | ||
76 | RIO_SWP_INFO_CAR, &result); | ||
77 | table = (result & RIO_SWP_INFO_PORT_NUM_MASK); | ||
78 | } | ||
79 | |||
80 | rio_mport_write_config_32(mport, destid, hopcount, | ||
81 | SPP_ROUTE_CFG_DESTID(table), route_destid); | ||
82 | rio_mport_read_config_32(mport, destid, hopcount, | ||
83 | SPP_ROUTE_CFG_PORT(table), &result); | ||
84 | |||
85 | *route_port = (u8)result; | ||
86 | if (*route_port > 15) | ||
87 | ret = -1; | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
94 | u16 table) | ||
95 | { | ||
96 | u32 route_idx; | ||
97 | u32 lut_size; | ||
98 | |||
99 | lut_size = (mport->sys_size) ? 0x1ff : 0xff; | ||
100 | |||
101 | if (table == RIO_GLOBAL_TABLE) { | ||
102 | rio_mport_write_config_32(mport, destid, hopcount, | ||
103 | SPBC_ROUTE_CFG_DESTID, 0x80000000); | ||
104 | for (route_idx = 0; route_idx <= lut_size; route_idx++) | ||
105 | rio_mport_write_config_32(mport, destid, hopcount, | ||
106 | SPBC_ROUTE_CFG_PORT, | ||
107 | RIO_INVALID_ROUTE); | ||
108 | } else { | ||
109 | rio_mport_write_config_32(mport, destid, hopcount, | ||
110 | SPP_ROUTE_CFG_DESTID(table), 0x80000000); | ||
111 | for (route_idx = 0; route_idx <= lut_size; route_idx++) | ||
112 | rio_mport_write_config_32(mport, destid, hopcount, | ||
113 | SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE); | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int | ||
120 | tsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
121 | u8 sw_domain) | ||
122 | { | ||
123 | u32 regval; | ||
124 | |||
125 | /* | ||
126 | * Switch domain configuration operates only at global level | ||
127 | */ | ||
128 | |||
129 | /* Turn off flat (LUT_512) mode */ | ||
130 | rio_mport_read_config_32(mport, destid, hopcount, | ||
131 | TSI578_SP_MODE_GLBL, ®val); | ||
132 | rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL, | ||
133 | regval & ~TSI578_SP_MODE_LUT_512); | ||
134 | /* Set switch domain base */ | ||
135 | rio_mport_write_config_32(mport, destid, hopcount, | ||
136 | TSI578_GLBL_ROUTE_BASE, | ||
137 | (u32)(sw_domain << 24)); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int | ||
142 | tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, | ||
143 | u8 *sw_domain) | ||
144 | { | ||
145 | u32 regval; | ||
146 | |||
147 | /* | ||
148 | * Switch domain configuration operates only at global level | ||
149 | */ | ||
150 | rio_mport_read_config_32(mport, destid, hopcount, | ||
151 | TSI578_GLBL_ROUTE_BASE, ®val); | ||
152 | |||
153 | *sw_domain = (u8)(regval >> 24); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int | ||
159 | tsi57x_em_init(struct rio_dev *rdev) | ||
160 | { | ||
161 | struct rio_mport *mport = rdev->net->hport; | ||
162 | u16 destid = rdev->rswitch->destid; | ||
163 | u8 hopcount = rdev->rswitch->hopcount; | ||
164 | u32 regval; | ||
165 | int portnum; | ||
166 | |||
167 | pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount); | ||
168 | |||
169 | for (portnum = 0; portnum < 16; portnum++) { | ||
170 | /* Make sure that Port-Writes are enabled (for all ports) */ | ||
171 | rio_mport_read_config_32(mport, destid, hopcount, | ||
172 | TSI578_SP_MODE(portnum), ®val); | ||
173 | rio_mport_write_config_32(mport, destid, hopcount, | ||
174 | TSI578_SP_MODE(portnum), | ||
175 | regval & ~TSI578_SP_MODE_PW_DIS); | ||
176 | |||
177 | /* Clear all pending interrupts */ | ||
178 | rio_mport_read_config_32(mport, destid, hopcount, | ||
179 | rdev->phys_efptr + | ||
180 | RIO_PORT_N_ERR_STS_CSR(portnum), | ||
181 | ®val); | ||
182 | rio_mport_write_config_32(mport, destid, hopcount, | ||
183 | rdev->phys_efptr + | ||
184 | RIO_PORT_N_ERR_STS_CSR(portnum), | ||
185 | regval & 0x07120214); | ||
186 | |||
187 | rio_mport_read_config_32(mport, destid, hopcount, | ||
188 | TSI578_SP_INT_STATUS(portnum), ®val); | ||
189 | rio_mport_write_config_32(mport, destid, hopcount, | ||
190 | TSI578_SP_INT_STATUS(portnum), | ||
191 | regval & 0x000700bd); | ||
192 | |||
193 | /* Enable all interrupts to allow ports to send a port-write */ | ||
194 | rio_mport_read_config_32(mport, destid, hopcount, | ||
195 | TSI578_SP_CTL_INDEP(portnum), ®val); | ||
196 | rio_mport_write_config_32(mport, destid, hopcount, | ||
197 | TSI578_SP_CTL_INDEP(portnum), | ||
198 | regval | 0x000b0000); | ||
199 | |||
200 | /* Skip next (odd) port if the current port is in x4 mode */ | ||
201 | rio_mport_read_config_32(mport, destid, hopcount, | ||
202 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), | ||
203 | ®val); | ||
204 | if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4) | ||
205 | portnum++; | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int | ||
212 | tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) | ||
213 | { | ||
214 | struct rio_mport *mport = rdev->net->hport; | ||
215 | u16 destid = rdev->rswitch->destid; | ||
216 | u8 hopcount = rdev->rswitch->hopcount; | ||
217 | u32 intstat, err_status; | ||
218 | int sendcount, checkcount; | ||
219 | u8 route_port; | ||
220 | u32 regval; | ||
221 | |||
222 | rio_mport_read_config_32(mport, destid, hopcount, | ||
223 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), | ||
224 | &err_status); | ||
225 | |||
226 | if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) && | ||
227 | (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | | ||
228 | RIO_PORT_N_ERR_STS_PW_INP_ES))) { | ||
229 | /* Remove any queued packets by locking/unlocking port */ | ||
230 | rio_mport_read_config_32(mport, destid, hopcount, | ||
231 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), | ||
232 | ®val); | ||
233 | if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) { | ||
234 | rio_mport_write_config_32(mport, destid, hopcount, | ||
235 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), | ||
236 | regval | RIO_PORT_N_CTL_LOCKOUT); | ||
237 | udelay(50); | ||
238 | rio_mport_write_config_32(mport, destid, hopcount, | ||
239 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), | ||
240 | regval); | ||
241 | } | ||
242 | |||
243 | /* Read from link maintenance response register to clear | ||
244 | * valid bit | ||
245 | */ | ||
246 | rio_mport_read_config_32(mport, destid, hopcount, | ||
247 | rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum), | ||
248 | ®val); | ||
249 | |||
250 | /* Send a Packet-Not-Accepted/Link-Request-Input-Status control | ||
251 | * symbol to recover from IES/OES | ||
252 | */ | ||
253 | sendcount = 3; | ||
254 | while (sendcount) { | ||
255 | rio_mport_write_config_32(mport, destid, hopcount, | ||
256 | TSI578_SP_CS_TX(portnum), 0x40fc8000); | ||
257 | checkcount = 3; | ||
258 | while (checkcount--) { | ||
259 | udelay(50); | ||
260 | rio_mport_read_config_32( | ||
261 | mport, destid, hopcount, | ||
262 | rdev->phys_efptr + | ||
263 | RIO_PORT_N_MNT_RSP_CSR(portnum), | ||
264 | ®val); | ||
265 | if (regval & RIO_PORT_N_MNT_RSP_RVAL) | ||
266 | goto exit_es; | ||
267 | } | ||
268 | |||
269 | sendcount--; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | exit_es: | ||
274 | /* Clear implementation specific error status bits */ | ||
275 | rio_mport_read_config_32(mport, destid, hopcount, | ||
276 | TSI578_SP_INT_STATUS(portnum), &intstat); | ||
277 | pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n", | ||
278 | destid, hopcount, portnum, intstat); | ||
279 | |||
280 | if (intstat & 0x10000) { | ||
281 | rio_mport_read_config_32(mport, destid, hopcount, | ||
282 | TSI578_SP_LUT_PEINF(portnum), ®val); | ||
283 | regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24); | ||
284 | route_port = rdev->rswitch->route_table[regval]; | ||
285 | pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n", | ||
286 | rio_name(rdev), portnum, regval); | ||
287 | tsi57x_route_add_entry(mport, destid, hopcount, | ||
288 | RIO_GLOBAL_TABLE, regval, route_port); | ||
289 | } | ||
290 | |||
291 | rio_mport_write_config_32(mport, destid, hopcount, | ||
292 | TSI578_SP_INT_STATUS(portnum), | ||
293 | intstat & 0x000700bd); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum) | ||
299 | { | ||
300 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); | ||
301 | rdev->rswitch->add_entry = tsi57x_route_add_entry; | ||
302 | rdev->rswitch->get_entry = tsi57x_route_get_entry; | ||
303 | rdev->rswitch->clr_table = tsi57x_route_clr_table; | ||
304 | rdev->rswitch->set_domain = tsi57x_set_domain; | ||
305 | rdev->rswitch->get_domain = tsi57x_get_domain; | ||
306 | rdev->rswitch->em_init = tsi57x_em_init; | ||
307 | rdev->rswitch->em_handle = tsi57x_em_handler; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init); | ||
313 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init); | ||
314 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init); | ||
315 | DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init); | ||