Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/ps3/gelic_udbg.c
26481 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* udbg debug output routine via GELIC UDP broadcasts
4
*
5
* Copyright (C) 2007 Sony Computer Entertainment Inc.
6
* Copyright 2006, 2007 Sony Corporation
7
* Copyright (C) 2010 Hector Martin <[email protected]>
8
* Copyright (C) 2011 Andre Heider <[email protected]>
9
*/
10
11
#include <linux/if_ether.h>
12
#include <linux/etherdevice.h>
13
#include <linux/if_vlan.h>
14
#include <linux/ip.h>
15
#include <linux/udp.h>
16
17
#include <asm/ps3.h>
18
#include <asm/io.h>
19
#include <asm/udbg.h>
20
#include <asm/lv1call.h>
21
22
#define GELIC_BUS_ID 1
23
#define GELIC_DEVICE_ID 0
24
#define GELIC_DEBUG_PORT 18194
25
#define GELIC_MAX_MESSAGE_SIZE 1000
26
27
#define GELIC_LV1_GET_MAC_ADDRESS 1
28
#define GELIC_LV1_GET_VLAN_ID 4
29
#define GELIC_LV1_VLAN_TX_ETHERNET_0 2
30
31
#define GELIC_DESCR_DMA_STAT_MASK 0xf0000000
32
#define GELIC_DESCR_DMA_CARDOWNED 0xa0000000
33
34
#define GELIC_DESCR_TX_DMA_IKE 0x00080000
35
#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000
36
#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000
37
38
#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \
39
GELIC_DESCR_TX_DMA_IKE | \
40
GELIC_DESCR_TX_DMA_NO_CHKSUM)
41
42
static u64 bus_addr;
43
44
struct gelic_descr {
45
/* as defined by the hardware */
46
__be32 buf_addr;
47
__be32 buf_size;
48
__be32 next_descr_addr;
49
__be32 dmac_cmd_status;
50
__be32 result_size;
51
__be32 valid_size; /* all zeroes for tx */
52
__be32 data_status;
53
__be32 data_error; /* all zeroes for tx */
54
} __attribute__((aligned(32)));
55
56
struct debug_block {
57
struct gelic_descr descr;
58
u8 pkt[1520];
59
} __packed;
60
61
static __iomem struct ethhdr *h_eth;
62
static __iomem struct vlan_hdr *h_vlan;
63
static __iomem struct iphdr *h_ip;
64
static __iomem struct udphdr *h_udp;
65
66
static __iomem char *pmsg;
67
static __iomem char *pmsgc;
68
69
static __iomem struct debug_block dbg __attribute__((aligned(32)));
70
71
static int header_size;
72
73
static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len,
74
u64 *real_bus_addr)
75
{
76
s64 result;
77
u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL;
78
u64 real_end = real_addr + len;
79
u64 map_start = real_addr & ~0xfff;
80
u64 map_end = (real_end + 0xfff) & ~0xfff;
81
u64 bus_addr = 0;
82
83
u64 flags = 0xf800000000000000UL;
84
85
result = lv1_allocate_device_dma_region(bus_id, dev_id,
86
map_end - map_start, 12, 0,
87
&bus_addr);
88
if (result)
89
lv1_panic(0);
90
91
result = lv1_map_device_dma_region(bus_id, dev_id, map_start,
92
bus_addr, map_end - map_start,
93
flags);
94
if (result)
95
lv1_panic(0);
96
97
*real_bus_addr = bus_addr + real_addr - map_start;
98
}
99
100
static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len)
101
{
102
s64 result;
103
u64 real_bus_addr;
104
105
real_bus_addr = bus_addr & ~0xfff;
106
len += bus_addr - real_bus_addr;
107
len = (len + 0xfff) & ~0xfff;
108
109
result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr,
110
len);
111
if (result)
112
return result;
113
114
return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr);
115
}
116
117
static void __init gelic_debug_init(void)
118
{
119
s64 result;
120
u64 v2;
121
u64 mac;
122
u64 vlan_id;
123
124
result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0);
125
if (result)
126
lv1_panic(0);
127
128
map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg),
129
&bus_addr);
130
131
memset(&dbg, 0, sizeof(dbg));
132
133
dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt);
134
135
wmb();
136
137
result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
138
GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0,
139
&mac, &v2);
140
if (result)
141
lv1_panic(0);
142
143
mac <<= 16;
144
145
h_eth = (struct ethhdr *)dbg.pkt;
146
147
eth_broadcast_addr(h_eth->h_dest);
148
memcpy(&h_eth->h_source, &mac, ETH_ALEN);
149
150
header_size = sizeof(struct ethhdr);
151
152
result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
153
GELIC_LV1_GET_VLAN_ID,
154
GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
155
&vlan_id, &v2);
156
if (!result) {
157
h_eth->h_proto= ETH_P_8021Q;
158
159
header_size += sizeof(struct vlan_hdr);
160
h_vlan = (struct vlan_hdr *)(h_eth + 1);
161
h_vlan->h_vlan_TCI = vlan_id;
162
h_vlan->h_vlan_encapsulated_proto = ETH_P_IP;
163
h_ip = (struct iphdr *)(h_vlan + 1);
164
} else {
165
h_eth->h_proto= 0x0800;
166
h_ip = (struct iphdr *)(h_eth + 1);
167
}
168
169
header_size += sizeof(struct iphdr);
170
h_ip->version = 4;
171
h_ip->ihl = 5;
172
h_ip->ttl = 10;
173
h_ip->protocol = 0x11;
174
h_ip->saddr = 0x00000000;
175
h_ip->daddr = 0xffffffff;
176
177
header_size += sizeof(struct udphdr);
178
h_udp = (struct udphdr *)(h_ip + 1);
179
h_udp->source = GELIC_DEBUG_PORT;
180
h_udp->dest = GELIC_DEBUG_PORT;
181
182
pmsgc = pmsg = (char *)(h_udp + 1);
183
}
184
185
static void gelic_debug_shutdown(void)
186
{
187
if (bus_addr)
188
unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID,
189
bus_addr, sizeof(dbg));
190
lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID);
191
}
192
193
static void gelic_sendbuf(int msgsize)
194
{
195
u16 *p;
196
u32 sum;
197
int i;
198
199
dbg.descr.buf_size = header_size + msgsize;
200
h_ip->tot_len = msgsize + sizeof(struct udphdr) +
201
sizeof(struct iphdr);
202
h_udp->len = msgsize + sizeof(struct udphdr);
203
204
h_ip->check = 0;
205
sum = 0;
206
p = (u16 *)h_ip;
207
for (i = 0; i < 5; i++)
208
sum += *p++;
209
h_ip->check = ~(sum + (sum >> 16));
210
211
dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM |
212
GELIC_DESCR_TX_DMA_FRAME_TAIL;
213
dbg.descr.result_size = 0;
214
dbg.descr.data_status = 0;
215
216
wmb();
217
218
lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0);
219
220
while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) ==
221
GELIC_DESCR_DMA_CARDOWNED)
222
cpu_relax();
223
}
224
225
static void ps3gelic_udbg_putc(char ch)
226
{
227
*pmsgc++ = ch;
228
if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) {
229
gelic_sendbuf(pmsgc-pmsg);
230
pmsgc = pmsg;
231
}
232
}
233
234
void __init udbg_init_ps3gelic(void)
235
{
236
gelic_debug_init();
237
udbg_putc = ps3gelic_udbg_putc;
238
}
239
240
void udbg_shutdown_ps3gelic(void)
241
{
242
udbg_putc = NULL;
243
gelic_debug_shutdown();
244
}
245
EXPORT_SYMBOL(udbg_shutdown_ps3gelic);
246
247