1/* 2 * udbg debug output routine via GELIC UDP broadcasts 3 * 4 * Copyright (C) 2007 Sony Computer Entertainment Inc. 5 * Copyright 2006, 2007 Sony Corporation 6 * Copyright (C) 2010 Hector Martin <hector@marcansoft.com> 7 * Copyright (C) 2011 Andre Heider <a.heider@gmail.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 */ 15 16#include <asm/io.h> 17#include <asm/udbg.h> 18#include <asm/lv1call.h> 19 20#define GELIC_BUS_ID 1 21#define GELIC_DEVICE_ID 0 22#define GELIC_DEBUG_PORT 18194 23#define GELIC_MAX_MESSAGE_SIZE 1000 24 25#define GELIC_LV1_GET_MAC_ADDRESS 1 26#define GELIC_LV1_GET_VLAN_ID 4 27#define GELIC_LV1_VLAN_TX_ETHERNET_0 2 28 29#define GELIC_DESCR_DMA_STAT_MASK 0xf0000000 30#define GELIC_DESCR_DMA_CARDOWNED 0xa0000000 31 32#define GELIC_DESCR_TX_DMA_IKE 0x00080000 33#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000 34#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000 35 36#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \ 37 GELIC_DESCR_TX_DMA_IKE | \ 38 GELIC_DESCR_TX_DMA_NO_CHKSUM) 39 40static u64 bus_addr; 41 42struct gelic_descr { 43 /* as defined by the hardware */ 44 __be32 buf_addr; 45 __be32 buf_size; 46 __be32 next_descr_addr; 47 __be32 dmac_cmd_status; 48 __be32 result_size; 49 __be32 valid_size; /* all zeroes for tx */ 50 __be32 data_status; 51 __be32 data_error; /* all zeroes for tx */ 52} __attribute__((aligned(32))); 53 54struct debug_block { 55 struct gelic_descr descr; 56 u8 pkt[1520]; 57} __packed; 58 59struct ethhdr { 60 u8 dest[6]; 61 u8 src[6]; 62 u16 type; 63} __packed; 64 65struct vlantag { 66 u16 vlan; 67 u16 subtype; 68} __packed; 69 70struct iphdr { 71 u8 ver_len; 72 u8 dscp_ecn; 73 u16 total_length; 74 u16 ident; 75 u16 frag_off_flags; 76 u8 ttl; 77 u8 proto; 78 u16 checksum; 79 u32 src; 80 u32 dest; 81} __packed; 82 83struct udphdr { 84 u16 src; 85 u16 dest; 86 u16 len; 87 u16 checksum; 88} __packed; 89 90static __iomem struct ethhdr *h_eth; 91static __iomem struct vlantag *h_vlan; 92static __iomem struct iphdr *h_ip; 93static __iomem struct udphdr *h_udp; 94 95static __iomem char *pmsg; 96static __iomem char *pmsgc; 97 98static __iomem struct debug_block dbg __attribute__((aligned(32))); 99 100static int header_size; 101 102static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len, 103 u64 *real_bus_addr) 104{ 105 s64 result; 106 u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL; 107 u64 real_end = real_addr + len; 108 u64 map_start = real_addr & ~0xfff; 109 u64 map_end = (real_end + 0xfff) & ~0xfff; 110 u64 bus_addr = 0; 111 112 u64 flags = 0xf800000000000000UL; 113 114 result = lv1_allocate_device_dma_region(bus_id, dev_id, 115 map_end - map_start, 12, 0, 116 &bus_addr); 117 if (result) 118 lv1_panic(0); 119 120 result = lv1_map_device_dma_region(bus_id, dev_id, map_start, 121 bus_addr, map_end - map_start, 122 flags); 123 if (result) 124 lv1_panic(0); 125 126 *real_bus_addr = bus_addr + real_addr - map_start; 127} 128 129static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len) 130{ 131 s64 result; 132 u64 real_bus_addr; 133 134 real_bus_addr = bus_addr & ~0xfff; 135 len += bus_addr - real_bus_addr; 136 len = (len + 0xfff) & ~0xfff; 137 138 result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr, 139 len); 140 if (result) 141 return result; 142 143 return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr); 144} 145 146static void gelic_debug_init(void) 147{ 148 s64 result; 149 u64 v2; 150 u64 mac; 151 u64 vlan_id; 152 153 result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0); 154 if (result) 155 lv1_panic(0); 156 157 map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg), 158 &bus_addr); 159 160 memset(&dbg, 0, sizeof(dbg)); 161 162 dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt); 163 164 wmb(); 165 166 result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, 167 GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, 168 &mac, &v2); 169 if (result) 170 lv1_panic(0); 171 172 mac <<= 16; 173 174 h_eth = (struct ethhdr *)dbg.pkt; 175 176 memset(&h_eth->dest, 0xff, 6); 177 memcpy(&h_eth->src, &mac, 6); 178 179 header_size = sizeof(struct ethhdr); 180 181 result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID, 182 GELIC_LV1_GET_VLAN_ID, 183 GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, 184 &vlan_id, &v2); 185 if (!result) { 186 h_eth->type = 0x8100; 187 188 header_size += sizeof(struct vlantag); 189 h_vlan = (struct vlantag *)(h_eth + 1); 190 h_vlan->vlan = vlan_id; 191 h_vlan->subtype = 0x0800; 192 h_ip = (struct iphdr *)(h_vlan + 1); 193 } else { 194 h_eth->type = 0x0800; 195 h_ip = (struct iphdr *)(h_eth + 1); 196 } 197 198 header_size += sizeof(struct iphdr); 199 h_ip->ver_len = 0x45; 200 h_ip->ttl = 10; 201 h_ip->proto = 0x11; 202 h_ip->src = 0x00000000; 203 h_ip->dest = 0xffffffff; 204 205 header_size += sizeof(struct udphdr); 206 h_udp = (struct udphdr *)(h_ip + 1); 207 h_udp->src = GELIC_DEBUG_PORT; 208 h_udp->dest = GELIC_DEBUG_PORT; 209 210 pmsgc = pmsg = (char *)(h_udp + 1); 211} 212 213static void gelic_debug_shutdown(void) 214{ 215 if (bus_addr) 216 unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, 217 bus_addr, sizeof(dbg)); 218 lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID); 219} 220 221static void gelic_sendbuf(int msgsize) 222{ 223 u16 *p; 224 u32 sum; 225 int i; 226 227 dbg.descr.buf_size = header_size + msgsize; 228 h_ip->total_length = msgsize + sizeof(struct udphdr) + 229 sizeof(struct iphdr); 230 h_udp->len = msgsize + sizeof(struct udphdr); 231 232 h_ip->checksum = 0; 233 sum = 0; 234 p = (u16 *)h_ip; 235 for (i = 0; i < 5; i++) 236 sum += *p++; 237 h_ip->checksum = ~(sum + (sum >> 16)); 238 239 dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM | 240 GELIC_DESCR_TX_DMA_FRAME_TAIL; 241 dbg.descr.result_size = 0; 242 dbg.descr.data_status = 0; 243 244 wmb(); 245 246 lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0); 247 248 while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) == 249 GELIC_DESCR_DMA_CARDOWNED) 250 cpu_relax(); 251} 252 253static void ps3gelic_udbg_putc(char ch) 254{ 255 *pmsgc++ = ch; 256 if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) { 257 gelic_sendbuf(pmsgc-pmsg); 258 pmsgc = pmsg; 259 } 260} 261 262void __init udbg_init_ps3gelic(void) 263{ 264 gelic_debug_init(); 265 udbg_putc = ps3gelic_udbg_putc; 266} 267 268void udbg_shutdown_ps3gelic(void) 269{ 270 udbg_putc = NULL; 271 gelic_debug_shutdown(); 272} 273EXPORT_SYMBOL(udbg_shutdown_ps3gelic); 274