Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/ps3: Add gelic udbg driver

Add a new udbg driver for the PS3 gelic Ehthernet device.

This driver shares only a few stucture and constant definitions with the
gelic Ethernet device driver, so is implemented as a stand-alone driver
with no dependencies on the gelic Ethernet device driver.

Signed-off-by: Hector Martin <hector@marcansoft.com>
Signed-off-by: Andre Heider <a.heider@gmail.com>
Signed-off-by: Geoff Levand <geoff@infradead.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Hector Martin and committed by
Benjamin Herrenschmidt
c26afe9e 8feaa434

+306
+8
arch/powerpc/Kconfig.debug
··· 258 258 depends on PPC_WSP 259 259 select PPC_UDBG_16550 260 260 261 + config PPC_EARLY_DEBUG_PS3GELIC 262 + bool "Early debugging through the PS3 Ethernet port" 263 + depends on PPC_PS3 264 + select PS3GELIC_UDBG 265 + help 266 + Select this to enable early debugging for the PlayStation3 via 267 + UDP broadcasts sent out through the Ethernet port. 268 + 261 269 endchoice 262 270 263 271 config PPC_EARLY_DEBUG_HVSI_VTERMNO
+1
arch/powerpc/include/asm/udbg.h
··· 54 54 extern void __init udbg_init_cpm(void); 55 55 extern void __init udbg_init_usbgecko(void); 56 56 extern void __init udbg_init_wsp(void); 57 + extern void __init udbg_init_ps3gelic(void); 57 58 58 59 #endif /* __KERNEL__ */ 59 60 #endif /* _ASM_POWERPC_UDBG_H */
+2
arch/powerpc/kernel/udbg.c
··· 67 67 udbg_init_usbgecko(); 68 68 #elif defined(CONFIG_PPC_EARLY_DEBUG_WSP) 69 69 udbg_init_wsp(); 70 + #elif defined(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) 71 + udbg_init_ps3gelic(); 70 72 #endif 71 73 72 74 #ifdef CONFIG_PPC_EARLY_DEBUG
+12
arch/powerpc/platforms/ps3/Kconfig
··· 148 148 profiling support of the Cell processor with programs like 149 149 oprofile and perfmon2, then say Y or M, otherwise say N. 150 150 151 + config PS3GELIC_UDBG 152 + bool "PS3 udbg output via UDP broadcasts on Ethernet" 153 + depends on PPC_PS3 154 + help 155 + Enables udbg early debugging output by sending broadcast UDP 156 + via the Ethernet port (UDP port number 18194). 157 + 158 + This driver uses a trivial implementation and is independent 159 + from the main network driver. 160 + 161 + If in doubt, say N here. 162 + 151 163 endmenu
+1
arch/powerpc/platforms/ps3/Makefile
··· 2 2 obj-y += interrupt.o exports.o os-area.o 3 3 obj-y += system-bus.o 4 4 5 + obj-$(CONFIG_PS3GELIC_UDBG) += gelic_udbg.o 5 6 obj-$(CONFIG_SMP) += smp.o 6 7 obj-$(CONFIG_SPU_BASE) += spu.o 7 8 obj-y += device-init.o
+273
arch/powerpc/platforms/ps3/gelic_udbg.c
··· 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 + 40 + static u64 bus_addr; 41 + 42 + struct 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 + 54 + struct debug_block { 55 + struct gelic_descr descr; 56 + u8 pkt[1520]; 57 + } __packed; 58 + 59 + struct ethhdr { 60 + u8 dest[6]; 61 + u8 src[6]; 62 + u16 type; 63 + } __packed; 64 + 65 + struct vlantag { 66 + u16 vlan; 67 + u16 subtype; 68 + } __packed; 69 + 70 + struct 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 + 83 + struct udphdr { 84 + u16 src; 85 + u16 dest; 86 + u16 len; 87 + u16 checksum; 88 + } __packed; 89 + 90 + static __iomem struct ethhdr *h_eth; 91 + static __iomem struct vlantag *h_vlan; 92 + static __iomem struct iphdr *h_ip; 93 + static __iomem struct udphdr *h_udp; 94 + 95 + static __iomem char *pmsg; 96 + static __iomem char *pmsgc; 97 + 98 + static __iomem struct debug_block dbg __attribute__((aligned(32))); 99 + 100 + static int header_size; 101 + 102 + static 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 + 129 + static 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 + 146 + static 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 + 213 + static 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 + 221 + static 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 + 253 + static 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 + 262 + void __init udbg_init_ps3gelic(void) 263 + { 264 + gelic_debug_init(); 265 + udbg_putc = ps3gelic_udbg_putc; 266 + } 267 + 268 + void udbg_shutdown_ps3gelic(void) 269 + { 270 + udbg_putc = NULL; 271 + gelic_debug_shutdown(); 272 + } 273 + EXPORT_SYMBOL(udbg_shutdown_ps3gelic);
+3
drivers/net/ps3_gelic_net.c
··· 1674 1674 int result; 1675 1675 1676 1676 pr_debug("%s: called\n", __func__); 1677 + 1678 + udbg_shutdown_ps3gelic(); 1679 + 1677 1680 result = ps3_open_hv_device(dev); 1678 1681 1679 1682 if (result) {
+6
drivers/net/ps3_gelic_net.h
··· 359 359 return port->priv; 360 360 } 361 361 362 + #ifdef CONFIG_PPC_EARLY_DEBUG_PS3GELIC 363 + extern void udbg_shutdown_ps3gelic(void); 364 + #else 365 + static inline void udbg_shutdown_ps3gelic(void) {} 366 + #endif 367 + 362 368 extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask); 363 369 /* shared netdev ops */ 364 370 extern void gelic_card_up(struct gelic_card *card);