main.c 7.73 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#include <lcd_config/pre_hook.h>

#include <linux/module.h>
#include <linux/kernel.h>
#include <liblcd/liblcd.h>
#include <liblcd/sync_ipc_poll.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <thc.h>


#include "./ixgbe_callee.h"

/* COMPILER: This is always included after all includes. */
#include <lcd_config/post_hook.h>
/* LOOP ------------------------------------------------------------ */
struct net_info {
	struct thc_channel *chnl;
	struct glue_cspace *cspace;
	cptr_t sync_endpoint;
	struct list_head list;
};
static LIST_HEAD(net_infos);

extern int setup_async_net_ring_channel(cptr_t tx, cptr_t rx, 
				struct thc_channel **chnl_out);
extern void destroy_async_net_ring_channel(struct thc_channel *chnl);
Vikram Narayanan's avatar
Vikram Narayanan committed
28 29 30 31
extern int ixgbe_trigger_dump(struct thc_channel *_channel);
extern int ixgbe_service_event_sched(struct thc_channel *_channel);
extern int trigger_exit_to_lcd(struct thc_channel *_channel);
extern struct timer_list service_timer;
32 33
extern struct glue_cspace *c_cspace;

Vikram Narayanan's avatar
Vikram Narayanan committed
34
/* mechanism for unloading LCD gracefully */
35 36 37
static bool unload_lcd =0;
module_param_named(unload, unload_lcd, bool, S_IWUSR);

Vikram Narayanan's avatar
Vikram Narayanan committed
38 39 40 41
/* to dump ixgbe registers */
static bool ixgbe_dump =0;
module_param_named(dump_regs, ixgbe_dump, bool, S_IWUSR);

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
struct net_info *
add_net(struct thc_channel *chnl, struct glue_cspace *cspace,
	cptr_t sync_endpoint)
{
	struct net_info *net_info;

	net_info = kmalloc(sizeof(*net_info), GFP_KERNEL);
	if (!net_info)
		goto fail1;
	net_info->chnl = chnl;
	net_info->cspace = cspace;
	net_info->sync_endpoint = sync_endpoint;
	INIT_LIST_HEAD(&net_info->list);
	list_add(&net_info->list, &net_infos);

	return net_info;

fail1:
	return NULL;
}

void remove_net(struct net_info *net)
{
	list_del_init(&net->list);
	kfree(net);
}

69 70 71 72 73 74 75 76 77
static int __get_net(struct net_info **net_out)
{
	struct net_info *first;
	first = list_first_entry_or_null(&net_infos, struct net_info, list);
	if (first)
		*net_out = first;
	return first ? 1 : 0;
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
static int async_loop(struct net_info **net_out, struct fipc_message **msg_out)
{
	struct net_info *cursor, *next;
	int ret;

	list_for_each_entry_safe(cursor, next, &net_infos, list) {

		ret = thc_ipc_poll_recv(cursor->chnl, msg_out);
		if (ret == -EPIPE) {
			/*
			 * net channel is dead; free the channel,
			 * and remove from list
			 */
			kfree(cursor->chnl);
			remove_net(cursor);
		} else if (ret == -EWOULDBLOCK) {
			/*
			 * Skip over empty channels
			 */
			continue;
		} else if (ret) {
			/*
			 * Unexpected error
			 */
			LIBLCD_ERR("error ret = %d on async channel");
			return ret;
		} else {
			/*
			 * Got a msg
			 */
			*net_out = cursor;
			return 0;
		}

	}
	/*
	 * Nothing for us to recv right now
	 */
	return -EWOULDBLOCK;
}

Vikram Narayanan's avatar
Vikram Narayanan committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
void ixgbe_service_timer(unsigned long data)
{
	unsigned long next_event_offset;
	struct net_info *net;

	next_event_offset = msecs_to_jiffies(10000);

	/* Reset the timer */
	mod_timer(&service_timer, next_event_offset + jiffies);

	if (__get_net(&net)) {
		ixgbe_service_event_sched(net->chnl);
	}
}


135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
/* LOOP -------------------------------------------------- */
static int do_one_register(cptr_t register_chnl)
{
	int ret;
	cptr_t sync_endpoint, tx, rx;
	struct thc_channel *chnl;
	struct net_info *net_info;

	/*
	 * Set up cptrs
	 */
	ret = lcd_cptr_alloc(&sync_endpoint);
	if (ret) {
		LIBLCD_ERR("cptr alloc failed");
		goto fail1;
	}
	ret = lcd_cptr_alloc(&tx);
	if (ret) {
		LIBLCD_ERR("cptr alloc failed");
		goto fail2;
	}
	ret = lcd_cptr_alloc(&rx);
	if (ret) {
		LIBLCD_ERR("cptr alloc failed");
		goto fail3;
	}
	/*
	 * Set up regs and poll
	 */
	lcd_set_cr0(sync_endpoint);
	lcd_set_cr1(tx);
	lcd_set_cr2(rx);
	ret = lcd_sync_poll_recv(register_chnl);
	if (ret) {
		if (ret == -EWOULDBLOCK)
			ret = 0;
		goto free_cptrs;
	}
#ifdef SYNC_TX
	/*
	 * Dispatch to register handler
	 */
	ret = dispatch_sync_loop();
	if (ret)
		return ret; /* dispatch fn is responsible for cptr cleanup */
#endif
	LIBLCD_MSG("settingup net_ring channel");
	/*
	 * Set up async ring channel
	 */
	ret = setup_async_net_ring_channel(tx, rx, &chnl);
	if (ret) {
		LIBLCD_ERR("error setting up ring channel");
		goto fail6;
	}
	/*
	 * Add to dispatch loop
	 */
	LIBLCD_MSG("Adding to fsinfo cspace %lu | chnl %p | sync_ep %lu", c_cspace, chnl, sync_endpoint);
 
	net_info = add_net(chnl, c_cspace, sync_endpoint);
	if (!net_info) {
		LIBLCD_ERR("error adding to dispatch loop");
		goto fail7;
	}

	LIBLCD_MSG("Returning from %s", __func__);
	lcd_set_cr0(CAP_CPTR_NULL);
	lcd_set_cr1(CAP_CPTR_NULL);
	lcd_set_cr2(CAP_CPTR_NULL);
	if (lcd_sync_reply())
		LIBLCD_ERR("Error reply");
	return 0;

fail6:
	destroy_async_net_ring_channel(chnl);
fail7:
free_cptrs:
	lcd_set_cr0(CAP_CPTR_NULL);
	lcd_set_cr1(CAP_CPTR_NULL);
	lcd_set_cr2(CAP_CPTR_NULL);
	lcd_cptr_free(sync_endpoint);
fail3:
	lcd_cptr_free(tx);
fail2:
	lcd_cptr_free(rx);
fail1:
	return ret;
}
#define REGISTER_FREQ	50

226

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
static void loop(cptr_t register_chnl)
{
	unsigned long tics = jiffies + REGISTER_FREQ;
	struct fipc_message *msg;
	struct net_info *net;
	int stop = 0;
	int ret;

	DO_FINISH(

		while (!stop) {
			if (jiffies >= tics) {
				/*
				 * Listen for a register call
				 */
				ret = do_one_register(register_chnl);
				if (ret) {
					LIBLCD_ERR("register error");
					break;
				}
				tics = jiffies + REGISTER_FREQ;
				continue;
			}
			if (stop)
				break;
252 253 254 255 256 257 258 259 260 261

			/*
			 * will be updated by a write into sysfs
			 * from userspace.
			 */
			if (unload_lcd) {
				unload_lcd = 0;
				if (__get_net(&net))
					trigger_exit_to_lcd(net->chnl);
			}
Vikram Narayanan's avatar
Vikram Narayanan committed
262 263 264 265 266
			if (ixgbe_dump) {
				ixgbe_dump = 0;
				if (__get_net(&net))
					ixgbe_trigger_dump(net->chnl);
			}
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
			ret = async_loop(&net, &msg);
			if (!ret) {
				ASYNC(
					ret = dispatch_async_loop(
						net->chnl,
						msg,
						net->cspace,
						net->sync_endpoint);
					if (ret) {
						LIBLCD_ERR("net dispatch err");
						/* (break won't work here) */
						stop = 1;
					}
					);
			} else if (ret != -EWOULDBLOCK) {
				LIBLCD_ERR("async loop failed");
				stop = 1;
				break;
			}

			if (kthread_should_stop()) {
				LIBLCD_MSG("kthread should stop");
				stop = 1;
				break;
			}

#ifndef CONFIG_PREEMPT
			/*
			 * Play nice with the rest of the system
			 */
			cond_resched();
#endif
		}

		LIBLCD_MSG("net layer exited loop");

		THCStopAllAwes();

		);

307
	LIBLCD_MSG("EXITED net_klcd DO_FINISH");
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
}

/* INIT / EXIT ---------------------------------------- */
struct cspace *klcd_cspace;
static int net_klcd_init(void)
{
	int ret;
	cptr_t net_chnl;
	/*
	 * Set up cptr cache, etc.
	 */
	ret = lcd_enter();
	if (ret) {
		LIBLCD_ERR("lcd enter");
		goto fail1;
	}

	/*
	 * XXX: Hack: boot provided us with one cptr for the net chnl
	 */
	ret = lcd_cptr_alloc(&net_chnl);
	if (ret) {
		LIBLCD_ERR("alloc cptr");
		goto fail2;
	}
	LIBLCD_MSG("==========> got cptr %lu\n", net_chnl.cptr);
	/* save cspace for future use
	 * when userspace functions call function pointers,
	 * we need to get access to the sync_ep of this klcd
	 * to transfer pointers and data thro sync IPC to the lcd
	 */
	klcd_cspace = get_current_cspace(current);
	/*
	 * Init net glue
	 */
	ret = glue_ixgbe_init();
	LIBLCD_MSG("-===== > glue ixgbe init called\n");
	if (ret) {
		LIBLCD_ERR("net init");
		goto fail3;
	}
	/*
	 * Enter sync/async dispatch loop
	 */
	LIBLCD_MSG(">>>>> Looping .... \n");
	loop(net_chnl);
	/*
	 * Tear down net glue
	 */
	glue_ixgbe_exit();

	lcd_exit(0);

	return 0;

fail3:
fail2:
	lcd_exit(ret);
fail1:
	return ret;
}

static int __net_klcd_init(void)
{
	int ret;
	LIBLCD_MSG("%s: entering", __func__);
	LCD_MAIN({

			ret = net_klcd_init();

		});
	return ret;
}

/*
 * make module loader happy (so we can unload). we don't actually call
 * this before unloading the lcd (yet)
 */
static void __exit net_klcd_exit(void)
{
	LIBLCD_MSG("%s: exiting", __func__);
	return;
}

module_init(__net_klcd_init);
module_exit(net_klcd_exit);
MODULE_LICENSE("GPL");