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 <hector@marcansoft.com> 8 * Copyright (C) 2011 Andre Heider <a.heider@gmail.com> 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.