kernel: oxpcie serial card support.
ask to map in oxpcie i/o memory and support serial i/o for it in the kernel. set oxpcie=<address> in boot monitor (retrieve address using pci_debug=1 output). (no sanity checking is done on the address currently.) disabled by default. The change also contains some other minor cleanup (a new serial.h to set register info common to UART and the OXPCIe card, in-kernel memory mapping a little more structured and env_get() to get sysenv variables without knowing about the params_buffer).
This commit is contained in:
		
							parent
							
								
									dcc81d73e8
								
							
						
					
					
						commit
						9ba760e603
					
				@ -14,6 +14,7 @@ SRCS+=	arch_do_vmctl.c \
 | 
			
		||||
	i8259.c \
 | 
			
		||||
	klib.S \
 | 
			
		||||
	memory.c \
 | 
			
		||||
	oxpcie.c \
 | 
			
		||||
	protect.c \
 | 
			
		||||
	arch_system.c \
 | 
			
		||||
	apic.c \
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,8 @@
 | 
			
		||||
 | 
			
		||||
#include "archconst.h"
 | 
			
		||||
#include "proto.h"
 | 
			
		||||
#include "serial.h"
 | 
			
		||||
#include "oxpcie.h"
 | 
			
		||||
#include "kernel/proc.h"
 | 
			
		||||
#include "kernel/debug.h"
 | 
			
		||||
 | 
			
		||||
@ -220,18 +222,15 @@ PUBLIC void arch_init(void)
 | 
			
		||||
	fpu_init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define COM1_BASE       0x3F8
 | 
			
		||||
#define COM1_THR        (COM1_BASE + 0)
 | 
			
		||||
#define COM1_RBR (COM1_BASE + 0)
 | 
			
		||||
#define COM1_LSR        (COM1_BASE + 5)
 | 
			
		||||
#define		LSR_DR		0x01
 | 
			
		||||
#define		LSR_THRE	0x20
 | 
			
		||||
 | 
			
		||||
PUBLIC void ser_putc(char c)
 | 
			
		||||
{
 | 
			
		||||
        int i;
 | 
			
		||||
        int lsr, thr;
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
	oxpcie_putc(c);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        lsr= COM1_LSR;
 | 
			
		||||
        thr= COM1_THR;
 | 
			
		||||
        for (i= 0; i<100000; i++)
 | 
			
		||||
@ -249,6 +248,14 @@ PUBLIC void do_ser_debug()
 | 
			
		||||
{
 | 
			
		||||
	u8_t c, lsr;
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
	{
 | 
			
		||||
		int oxin;
 | 
			
		||||
		if((oxin = oxpcie_in()) >= 0)
 | 
			
		||||
		ser_debug(oxin);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	lsr= inb(COM1_LSR);
 | 
			
		||||
	if (!(lsr & LSR_DR))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
@ -12,9 +12,11 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <machine/vm.h>
 | 
			
		||||
 | 
			
		||||
#include "oxpcie.h"
 | 
			
		||||
#include "proto.h"
 | 
			
		||||
#include "kernel/proto.h"
 | 
			
		||||
#include "kernel/debug.h"
 | 
			
		||||
@ -935,32 +937,70 @@ void i386_freepde(const int pde)
 | 
			
		||||
	freepdes[nfreepdes++] = pde;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int lapic_mapping_index = -1, oxpcie_mapping_index = -1;
 | 
			
		||||
 | 
			
		||||
PUBLIC int arch_phys_map(const int index, phys_bytes *addr,
 | 
			
		||||
  phys_bytes *len, int *flags)
 | 
			
		||||
{
 | 
			
		||||
	static int first = 1;
 | 
			
		||||
	int freeidx = 0;
 | 
			
		||||
	static char *ser_var = NULL;
 | 
			
		||||
 | 
			
		||||
	if(first) {
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
		if(lapic_addr)
 | 
			
		||||
			lapic_mapping_index = freeidx++;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OXPCIE
 | 
			
		||||
		if((ser_var = env_get("oxpcie"))) {
 | 
			
		||||
			if(ser_var[0] != '0' || ser_var[1] != 'x') {
 | 
			
		||||
				printf("oxpcie address in hex please\n");
 | 
			
		||||
			} else {
 | 
			
		||||
				oxpcie_mapping_index = freeidx++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		first = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	/* map the local APIC if enabled */
 | 
			
		||||
	if (index == 0 && lapic_addr) {
 | 
			
		||||
	if (index == lapic_mapping_index) {
 | 
			
		||||
		*addr = vir2phys(lapic_addr);
 | 
			
		||||
		*len = 4 << 10 /* 4kB */;
 | 
			
		||||
		*flags = VMMF_UNCACHED;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
	return EINVAL;
 | 
			
		||||
#else
 | 
			
		||||
	/* we don't want anything */
 | 
			
		||||
	return EINVAL;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
	if(index == oxpcie_mapping_index) {
 | 
			
		||||
		*addr = strtoul(ser_var+2, NULL, 16);
 | 
			
		||||
		*len = 0x4000;
 | 
			
		||||
		*flags = VMMF_UNCACHED;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC int arch_phys_map_reply(const int index, const vir_bytes addr)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	/* if local APIC is enabled */
 | 
			
		||||
	if (index == 0 && lapic_addr) {
 | 
			
		||||
	if (index == lapic_mapping_index && lapic_addr) {
 | 
			
		||||
		lapic_addr_vaddr = addr;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
	if (index == oxpcie_mapping_index) {
 | 
			
		||||
		oxpcie_set_vaddr((unsigned char *) addr);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										83
									
								
								kernel/arch/i386/oxpcie.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								kernel/arch/i386/oxpcie.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
 | 
			
		||||
/* Documentation is at http://www.plxtech.com/products/uart/oxpcie952 */
 | 
			
		||||
 | 
			
		||||
#include "oxpcie.h"
 | 
			
		||||
#include "serial.h"
 | 
			
		||||
 | 
			
		||||
PRIVATE unsigned char *oxpcie_vaddr = NULL;
 | 
			
		||||
 | 
			
		||||
PUBLIC void oxpcie_set_vaddr(unsigned char *vaddr)
 | 
			
		||||
{
 | 
			
		||||
	oxpcie_vaddr = vaddr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void oxpcie_init(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("oxpcie_init\n");
 | 
			
		||||
	/* Enable access to EFR and DLM+DLL */
 | 
			
		||||
	OXPCIE_LCR = 0xBF;
 | 
			
		||||
 | 
			
		||||
	/* Set FICR[1] to increase FIFO */
 | 
			
		||||
	OXPCIE_FICR = 0x01;
 | 
			
		||||
 | 
			
		||||
	/* Set enhanced mode [4]
 | 
			
		||||
	 * no RTS/CTS [7:6]
 | 
			
		||||
	 * no special char detection [5]
 | 
			
		||||
	 * no in-band receive flow control [1:0]
 | 
			
		||||
	 * no in-band transmit flow control [3:2]
 | 
			
		||||
	 */
 | 
			
		||||
	OXPCIE_EFR  = 0x10; 
 | 
			
		||||
 | 
			
		||||
	/* Set divisor register to 115200 baud. */
 | 
			
		||||
	OXPCIE_DLM = 0x00;
 | 
			
		||||
	OXPCIE_DLL = 0x22;
 | 
			
		||||
 | 
			
		||||
	/* Forget DLM and DLL, set LCR to config. */
 | 
			
		||||
	OXPCIE_LCR = LCR_CONFIG;
 | 
			
		||||
	OXPCIE_LCR = LCR_CONFIG;
 | 
			
		||||
 | 
			
		||||
	OXPCIE_TCR = 0x01;
 | 
			
		||||
	OXPCIE_CPR = 0x20;
 | 
			
		||||
	OXPCIE_CPR2 = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void oxpcie_putc(char c)
 | 
			
		||||
{
 | 
			
		||||
	static int inuse = 0;
 | 
			
		||||
 | 
			
		||||
	if(vm_running && oxpcie_vaddr && !inuse) {
 | 
			
		||||
        	int i;
 | 
			
		||||
		static int init_done;
 | 
			
		||||
		inuse = 1;
 | 
			
		||||
 | 
			
		||||
		if(!init_done) {
 | 
			
		||||
			oxpcie_init();
 | 
			
		||||
			init_done = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        	for (i= 0; i<100000; i++) {
 | 
			
		||||
			if(OXPCIE_LSR & LSR_THRE)
 | 
			
		||||
                       		break;
 | 
			
		||||
		}
 | 
			
		||||
		OXPCIE_THR = c;
 | 
			
		||||
		inuse = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC int oxpcie_in(void)
 | 
			
		||||
{
 | 
			
		||||
	if(vm_running && oxpcie_vaddr) {
 | 
			
		||||
		int lsr;
 | 
			
		||||
		lsr = OXPCIE_LSR;
 | 
			
		||||
		if(lsr & LSR_DR)
 | 
			
		||||
			return (int) OXPCIE_RBR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										31
									
								
								kernel/arch/i386/oxpcie.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								kernel/arch/i386/oxpcie.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE( void oxpcie_set_vaddr, (unsigned char *vaddr));
 | 
			
		||||
_PROTOTYPE( void oxpcie_putc, (char c));
 | 
			
		||||
_PROTOTYPE( int oxpcie_in, (void));
 | 
			
		||||
 | 
			
		||||
#include "serial.h"
 | 
			
		||||
 | 
			
		||||
/* OXPCIe952 info */
 | 
			
		||||
#define UART1BASE_550   0x1000
 | 
			
		||||
#define UART1BASE_650   0x1090
 | 
			
		||||
#define UART1BASE_950
 | 
			
		||||
#define BASELINEICR     (UART1BASE_550 + 0xC0)
 | 
			
		||||
#define         OXPCIE_THR      oxpcie_vaddr[UART1BASE_550 + THRREG]
 | 
			
		||||
#define         OXPCIE_RBR      oxpcie_vaddr[UART1BASE_550 + RBRREG]
 | 
			
		||||
#define         OXPCIE_LSR      oxpcie_vaddr[UART1BASE_550 + LSRREG]
 | 
			
		||||
#define         OXPCIE_LCR      oxpcie_vaddr[UART1BASE_550 + LCRREG]
 | 
			
		||||
#define         OXPCIE_DLL      oxpcie_vaddr[UART1BASE_550 + 0x00]
 | 
			
		||||
#define         OXPCIE_DLM      oxpcie_vaddr[UART1BASE_550 + 0x01]
 | 
			
		||||
#define         OXPCIE_FICR     oxpcie_vaddr[UART1BASE_550 + FICRREG]
 | 
			
		||||
#define         OXPCIE_SPR      oxpcie_vaddr[UART1BASE_550 + SPRREG]
 | 
			
		||||
#define         OXPCIE_EFR      oxpcie_vaddr[UART1BASE_650 + 0x10]
 | 
			
		||||
#define         OXPCIE_ICR      oxpcie_vaddr[UART1BASE_950 + 0x05]
 | 
			
		||||
 | 
			
		||||
#define         OXPCIE_CPR      oxpcie_vaddr[BASELINEICR + 0x01]
 | 
			
		||||
#define         OXPCIE_TCR      oxpcie_vaddr[BASELINEICR + 0x02]
 | 
			
		||||
#define         OXPCIE_CPR2     oxpcie_vaddr[BASELINEICR + 0x03]
 | 
			
		||||
#define         OXPCIE_CSR      oxpcie_vaddr[BASELINEICR + 0x0C]
 | 
			
		||||
#define         OXPCIE_PIDX     oxpcie_vaddr[BASELINEICR + 0x12]
 | 
			
		||||
 | 
			
		||||
#define         LCR_CONFIG      0x03 /* bits 6:0 -= 0x03 => 8N1, no break. */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								kernel/arch/i386/serial.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								kernel/arch/i386/serial.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
 | 
			
		||||
#ifndef _KERN_SERIAL_H
 | 
			
		||||
#define _KERN_SERIAL_H 1
 | 
			
		||||
 | 
			
		||||
#define THRREG  0
 | 
			
		||||
#define RBRREG  0
 | 
			
		||||
#define FICRREG 2
 | 
			
		||||
#define LSRREG  5
 | 
			
		||||
#define LCRREG  3
 | 
			
		||||
#define SPRREG  7
 | 
			
		||||
 | 
			
		||||
#define COM1_BASE       0x3F8
 | 
			
		||||
#define COM1_THR        (COM1_BASE + THRREG)
 | 
			
		||||
#define COM1_RBR (COM1_BASE + RBRREG)
 | 
			
		||||
#define COM1_LSR        (COM1_BASE + LSRREG)
 | 
			
		||||
#define         LSR_DR          0x01
 | 
			
		||||
#define         LSR_THRE        0x20
 | 
			
		||||
#define         LCR_DLA         0x80
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -14,6 +14,9 @@
 | 
			
		||||
#define CONFIG_MAX_CPUS	1
 | 
			
		||||
#define cpuid		0
 | 
			
		||||
 | 
			
		||||
/* OXPCIe952 PCIe with 2 UARTs in-kernel support */
 | 
			
		||||
#define CONFIG_OXPCIE	0
 | 
			
		||||
 | 
			
		||||
/* This is the master header for the kernel.  It includes some other files
 | 
			
		||||
 * and defines the principal constants.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -55,6 +55,7 @@ _PROTOTYPE( void check_ticks_left, (struct proc *p));
 | 
			
		||||
/* start.c */
 | 
			
		||||
_PROTOTYPE( void cstart, (u16_t cs, u16_t ds, u16_t mds,
 | 
			
		||||
				u16_t parmoff, u16_t parmsize)		);
 | 
			
		||||
_PROTOTYPE( char *env_get, (const char *key));
 | 
			
		||||
 | 
			
		||||
/* system.c */
 | 
			
		||||
_PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type)	);
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,6 @@
 | 
			
		||||
#include "watchdog.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
FORWARD _PROTOTYPE( char *get_value, (const char *params, const char *key));
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				cstart					     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
@ -43,7 +42,7 @@ PUBLIC void cstart(
 | 
			
		||||
  arch_get_params(params_buffer, sizeof(params_buffer));
 | 
			
		||||
 | 
			
		||||
  /* determine verbosity */
 | 
			
		||||
  if ((value = get_value(params_buffer, VERBOSEBOOTVARNAME)))
 | 
			
		||||
  if ((value = env_get(VERBOSEBOOTVARNAME)))
 | 
			
		||||
	  verboseboot = atoi(value);
 | 
			
		||||
 | 
			
		||||
  DEBUGEXTRA(("cstart\n"));
 | 
			
		||||
@ -63,10 +62,10 @@ PUBLIC void cstart(
 | 
			
		||||
	kloadinfo.proc_load_history[h] = 0;
 | 
			
		||||
 | 
			
		||||
  /* Processor? Decide if mode is protected for older machines. */
 | 
			
		||||
  machine.processor=atoi(get_value(params_buffer, "processor")); 
 | 
			
		||||
  machine.processor=atoi(env_get("processor")); 
 | 
			
		||||
 | 
			
		||||
  /* XT, AT or MCA bus? */
 | 
			
		||||
  value = get_value(params_buffer, "bus");
 | 
			
		||||
  value = env_get("bus");
 | 
			
		||||
  if (value == NULL || strcmp(value, "at") == 0) {
 | 
			
		||||
      machine.pc_at = TRUE;			/* PC-AT compatible hardware */
 | 
			
		||||
  } else if (strcmp(value, "mca") == 0) {
 | 
			
		||||
@ -74,22 +73,22 @@ PUBLIC void cstart(
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Type of VDU: */
 | 
			
		||||
  value = get_value(params_buffer, "video");	/* EGA or VGA video unit */
 | 
			
		||||
  value = env_get("video");	/* EGA or VGA video unit */
 | 
			
		||||
  if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
 | 
			
		||||
  if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
 | 
			
		||||
 | 
			
		||||
  /* Get clock tick frequency. */
 | 
			
		||||
  value = get_value(params_buffer, "hz");
 | 
			
		||||
  value = env_get("hz");
 | 
			
		||||
  if(value)
 | 
			
		||||
	system_hz = atoi(value);
 | 
			
		||||
  if(!value || system_hz < 2 || system_hz > 50000)	/* sanity check */
 | 
			
		||||
	system_hz = DEFAULT_HZ;
 | 
			
		||||
  value = get_value(params_buffer, SERVARNAME);
 | 
			
		||||
  value = env_get(SERVARNAME);
 | 
			
		||||
  if(value && atoi(value) == 0)
 | 
			
		||||
	do_serial_debug=1;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
  value = get_value(params_buffer, "no_apic");
 | 
			
		||||
  value = env_get("no_apic");
 | 
			
		||||
  if(value)
 | 
			
		||||
	config_no_apic = atoi(value);
 | 
			
		||||
  else
 | 
			
		||||
@ -97,7 +96,7 @@ PUBLIC void cstart(
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_WATCHDOG
 | 
			
		||||
  value = get_value(params_buffer, "watchdog");
 | 
			
		||||
  value = env_get("watchdog");
 | 
			
		||||
  if (value)
 | 
			
		||||
	  watchdog_enabled = atoi(value);
 | 
			
		||||
#endif
 | 
			
		||||
@ -134,3 +133,12 @@ PRIVATE char *get_value(
 | 
			
		||||
  }
 | 
			
		||||
  return(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *				env_get				     	*
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
PUBLIC char *env_get(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	return get_value(params_buffer, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user