From patchwork Tue Feb 23 11:28:59 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 8391041 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 125C89F372 for ; Tue, 23 Feb 2016 11:31:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6243B202BE for ; Tue, 23 Feb 2016 11:31:50 +0000 (UTC) Received: from lists.xen.org (lists.xenproject.org [50.57.142.19]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8842C20274 for ; Tue, 23 Feb 2016 11:31:48 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xen.org) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aYB9P-0002aR-4x; Tue, 23 Feb 2016 11:29:07 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aYB9N-0002Zr-LT for xen-devel@lists.xenproject.org; Tue, 23 Feb 2016 11:29:05 +0000 Received: from [85.158.139.211] by server-13.bemta-5.messagelabs.com id 60/D0-02983-0824CC65; Tue, 23 Feb 2016 11:29:04 +0000 X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-9.tower-206.messagelabs.com!1456226941!24355844!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 7.35.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 6696 invoked from network); 23 Feb 2016 11:29:03 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-9.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 23 Feb 2016 11:29:03 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Tue, 23 Feb 2016 04:29:01 -0700 Message-Id: <56CC508B02000078000D52B1@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.0 Date: Tue, 23 Feb 2016 04:28:59 -0700 From: "Jan Beulich" To: "xen-devel" References: <56CC4F0B02000078000D5290@prv-mh.provo.novell.com> In-Reply-To: <56CC4F0B02000078000D5290@prv-mh.provo.novell.com> Mime-Version: 1.0 Cc: Ian Campbell , Keir Fraser , Ian Jackson , Tim Deegan Subject: [Xen-devel] [PATCH 2/4] ns16550: enable Pericom controller support X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Other than the controllers supported so far, multiple port Pericom boards map all of their ports via BAR0, which requires a number of adjustments: Instead of tracking "max_bars" we now flag whether all ports use BAR0, and whether to expect a port-I/O or MMIO resource. As a result pci_uart_config() now gets handed a port index, which it then maps into a BAR index or an offset into BAR0 depending on the bar0 flag. Signed-off-by: Jan Beulich ns16550: enable Pericom controller support Other than the controllers supported so far, multiple port Pericom boards map all of their ports via BAR0, which requires a number of adjustments: Instead of tracking "max_bars" we now flag whether all ports use BAR0, and whether to expect a port-I/O or MMIO resource. As a result pci_uart_config() now gets handed a port index, which it then maps into a BAR index or an offset into BAR0 depending on the bar0 flag. Signed-off-by: Jan Beulich --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -78,10 +78,20 @@ static struct ns16550 { #endif } ns16550_com[2] = { { 0 } }; -struct ns16550_config_mmio { +#ifdef CONFIG_HAS_PCI +struct ns16550_config { u16 vendor_id; u16 dev_id; - unsigned int param; + enum { + param_default, /* Must not be referenced by any table entry. */ + param_trumanage, + param_oxford, + param_oxford_2port, + param_pericom_1port, + param_pericom_2port, + param_pericom_4port, + param_pericom_8port, + } param; }; /* Defining uart config options for MMIO devices */ @@ -90,57 +100,91 @@ struct ns16550_config_param { unsigned int reg_width; unsigned int fifo_size; u8 lsr_mask; - unsigned int max_bars; + bool_t mmio; + bool_t bar0; + unsigned int max_ports; unsigned int base_baud; unsigned int uart_offset; unsigned int first_offset; }; - -#ifdef CONFIG_HAS_PCI -enum { - param_default = 0, - param_trumanage, - param_oxford, - param_oxford_2port, -}; /* - * Create lookup tables for specific MMIO devices.. - * It is assumed that if the device found is MMIO, - * then you have indexed it here. Else, the driver - * does nothing. + * Create lookup tables for specific devices. It is assumed that if + * the device found is MMIO, then you have indexed it here. Else, the + * driver does nothing for MMIO based devices. */ static const struct ns16550_config_param __initconst uart_param[] = { - [param_default] = { }, /* Ignored. */ + [param_default] = { + .reg_width = 1, + .lsr_mask = UART_LSR_THRE, + .max_ports = 1, + }, [param_trumanage] = { .reg_shift = 2, .reg_width = 1, .fifo_size = 16, .lsr_mask = (UART_LSR_THRE | UART_LSR_TEMT), - .max_bars = 1, + .mmio = 1, + .max_ports = 1, }, [param_oxford] = { .base_baud = 4000000, .uart_offset = 0x200, .first_offset = 0x1000, .reg_width = 1, - .reg_shift = 0, .fifo_size = 16, .lsr_mask = UART_LSR_THRE, - .max_bars = 1, /* It can do more, but we would need more custom code.*/ + .mmio = 1, + .max_ports = 1, /* It can do more, but we would need more custom code.*/ }, [param_oxford_2port] = { .base_baud = 4000000, .uart_offset = 0x200, .first_offset = 0x1000, .reg_width = 1, - .reg_shift = 0, .fifo_size = 16, .lsr_mask = UART_LSR_THRE, - .max_bars = 2, + .mmio = 1, + .max_ports = 2, + }, + [param_pericom_1port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 1, + }, + [param_pericom_2port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 2, + }, + [param_pericom_4port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 4, + }, + [param_pericom_8port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 8, } }; -static const struct ns16550_config_mmio __initconst uart_config[] = +static const struct ns16550_config __initconst uart_config[] = { /* Broadcom TruManage device */ { @@ -339,6 +383,30 @@ static const struct ns16550_config_mmio .vendor_id = PCI_VENDOR_ID_OXSEMI, .dev_id = 0xc4cf, .param = param_oxford, + }, + /* Pericom PI7C9X7951 Uno UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7951, + .param = param_pericom_1port + }, + /* Pericom PI7C9X7952 Duo UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7952, + .param = param_pericom_2port + }, + /* Pericom PI7C9X7954 Quad UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7954, + .param = param_pericom_4port + }, + /* Pericom PI7C9X7958 Octal UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7958, + .param = param_pericom_8port } }; #endif @@ -629,7 +697,8 @@ static void __init ns16550_init_postirq( uart->ps_bdf[2])); else { - if ( rangeset_add_range(mmio_ro_ranges, + if ( uart->param->mmio && + rangeset_add_range(mmio_ro_ranges, uart->io_base, uart->io_base + uart->io_size - 1) ) printk(XENLOG_INFO "Error while adding MMIO range of device to mmio_ro_ranges\n"); @@ -830,12 +899,11 @@ static int __init check_existence(struct #ifdef CONFIG_HAS_PCI static int __init -pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int bar_idx) +pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int idx) { u64 orig_base = uart->io_base; unsigned int b, d, f, nextf, i; - uart->io_base = 0; /* NB. Start at bus 1 to avoid AMT: a plug-in card cannot be on bus 0. */ for ( b = skip_amt ? 1 : 0; b < 0x100; b++ ) { @@ -843,8 +911,10 @@ pci_uart_config(struct ns16550 *uart, bo { for ( f = 0; f < 8; f = nextf ) { + unsigned int bar_idx = 0, port_idx = idx; uint32_t bar, bar_64 = 0, len, len_64; - u64 size; + u64 size = 0; + const struct ns16550_config_param *param = uart_param; nextf = (f || (pci_conf_read16(0, b, d, f, PCI_HEADER_TYPE) & 0x80)) ? f + 1 : 8; @@ -863,15 +933,38 @@ pci_uart_config(struct ns16550 *uart, bo continue; } + /* Check for params in uart_config lookup table */ + for ( i = 0; i < ARRAY_SIZE(uart_config); i++) + { + u16 vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID); + u16 device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID); + + if ( uart_config[i].vendor_id == vendor && + uart_config[i].dev_id == device ) + { + param += uart_config[i].param; + if ( !param->bar0 ) + { + bar_idx = idx; + port_idx = 0; + } + break; + } + } + + if ( port_idx >= param->max_ports ) + { + idx -= param->max_ports; + continue; + } + + uart->io_base = 0; bar = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4); /* MMIO based */ - if ( !(bar & PCI_BASE_ADDRESS_SPACE_IO) ) + if ( param->mmio && !(bar & PCI_BASE_ADDRESS_SPACE_IO) ) { - u16 vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID); - u16 device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID); - pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, ~0u); len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4); @@ -895,56 +988,11 @@ pci_uart_config(struct ns16550 *uart, bo else size = len & PCI_BASE_ADDRESS_MEM_MASK; - size &= -size; - - /* Check for params in uart_config lookup table */ - for ( i = 0; i < ARRAY_SIZE(uart_config); i++) - { - const struct ns16550_config_param *param; - - if ( uart_config[i].vendor_id != vendor ) - continue; - - if ( uart_config[i].dev_id != device ) - continue; - - param = uart_param + uart_config[i].param; - - /* - * Force length of mmio region to be at least - * 8 bytes times (1 << reg_shift) - */ - if ( size < (0x8 * (1 << param->reg_shift)) ) - continue; - - if ( bar_idx >= param->max_bars ) - continue; - - uart->param = param; - - if ( param->fifo_size ) - uart->fifo_size = param->fifo_size; - - uart->reg_shift = param->reg_shift; - uart->reg_width = param->reg_width; - uart->lsr_mask = param->lsr_mask; - uart->io_base = ((u64)bar_64 << 32) | - (bar & PCI_BASE_ADDRESS_MEM_MASK); - uart->io_base += param->first_offset; - uart->io_base += bar_idx * param->uart_offset; - if ( param->base_baud ) - uart->clock_hz = param->base_baud * 16; - size = max(8U << param->reg_shift, - param->uart_offset); - break; - } - - /* If we have an io_base, then we succeeded in the lookup */ - if ( !uart->io_base ) - continue; + uart->io_base = ((u64)bar_64 << 32) | + (bar & PCI_BASE_ADDRESS_MEM_MASK); } /* IO based */ - else + else if ( !param->mmio && (bar & PCI_BASE_ADDRESS_SPACE_IO) ) { pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, ~0u); @@ -952,22 +1000,45 @@ pci_uart_config(struct ns16550 *uart, bo pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, bar); size = len & PCI_BASE_ADDRESS_IO_MASK; - size &= -size; - - /* Not at least 8 bytes */ - if ( size < 8 ) - continue; uart->io_base = bar & ~PCI_BASE_ADDRESS_SPACE_IO; } + /* If we have an io_base, then we succeeded in the lookup. */ + if ( !uart->io_base ) + continue; + + size &= -size; + + /* + * Require length of actually used region to be at least + * 8 bytes times (1 << reg_shift). + */ + if ( size < param->first_offset + + port_idx * param->uart_offset + + (8 << param->reg_shift) ) + continue; + + uart->param = param; + + uart->reg_shift = param->reg_shift; + uart->reg_width = param->reg_width; + uart->lsr_mask = param->lsr_mask; + uart->io_base += param->first_offset + + port_idx * param->uart_offset; + if ( param->base_baud ) + uart->clock_hz = param->base_baud * 16; + if ( param->fifo_size ) + uart->fifo_size = param->fifo_size; + uart->ps_bdf[0] = b; uart->ps_bdf[1] = d; uart->ps_bdf[2] = f; uart->bar_idx = bar_idx; uart->bar = bar; uart->bar64 = bar_64; - uart->io_size = size; + uart->io_size = max(8U << param->reg_shift, + param->uart_offset); uart->irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ? pci_conf_read8(0, b, d, f, PCI_INTERRUPT_LINE) : 0; --- a/xen/include/xen/pci_ids.h +++ b/xen/include/xen/pci_ids.h @@ -2,6 +2,8 @@ #define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_VENDOR_ID_PERICOM 0x12d8 + #define PCI_VENDOR_ID_OXSEMI 0x1415 #define PCI_VENDOR_ID_BROADCOM 0x14e4 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -78,10 +78,20 @@ static struct ns16550 { #endif } ns16550_com[2] = { { 0 } }; -struct ns16550_config_mmio { +#ifdef CONFIG_HAS_PCI +struct ns16550_config { u16 vendor_id; u16 dev_id; - unsigned int param; + enum { + param_default, /* Must not be referenced by any table entry. */ + param_trumanage, + param_oxford, + param_oxford_2port, + param_pericom_1port, + param_pericom_2port, + param_pericom_4port, + param_pericom_8port, + } param; }; /* Defining uart config options for MMIO devices */ @@ -90,57 +100,91 @@ struct ns16550_config_param { unsigned int reg_width; unsigned int fifo_size; u8 lsr_mask; - unsigned int max_bars; + bool_t mmio; + bool_t bar0; + unsigned int max_ports; unsigned int base_baud; unsigned int uart_offset; unsigned int first_offset; }; - -#ifdef CONFIG_HAS_PCI -enum { - param_default = 0, - param_trumanage, - param_oxford, - param_oxford_2port, -}; /* - * Create lookup tables for specific MMIO devices.. - * It is assumed that if the device found is MMIO, - * then you have indexed it here. Else, the driver - * does nothing. + * Create lookup tables for specific devices. It is assumed that if + * the device found is MMIO, then you have indexed it here. Else, the + * driver does nothing for MMIO based devices. */ static const struct ns16550_config_param __initconst uart_param[] = { - [param_default] = { }, /* Ignored. */ + [param_default] = { + .reg_width = 1, + .lsr_mask = UART_LSR_THRE, + .max_ports = 1, + }, [param_trumanage] = { .reg_shift = 2, .reg_width = 1, .fifo_size = 16, .lsr_mask = (UART_LSR_THRE | UART_LSR_TEMT), - .max_bars = 1, + .mmio = 1, + .max_ports = 1, }, [param_oxford] = { .base_baud = 4000000, .uart_offset = 0x200, .first_offset = 0x1000, .reg_width = 1, - .reg_shift = 0, .fifo_size = 16, .lsr_mask = UART_LSR_THRE, - .max_bars = 1, /* It can do more, but we would need more custom code.*/ + .mmio = 1, + .max_ports = 1, /* It can do more, but we would need more custom code.*/ }, [param_oxford_2port] = { .base_baud = 4000000, .uart_offset = 0x200, .first_offset = 0x1000, .reg_width = 1, - .reg_shift = 0, .fifo_size = 16, .lsr_mask = UART_LSR_THRE, - .max_bars = 2, + .mmio = 1, + .max_ports = 2, + }, + [param_pericom_1port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 1, + }, + [param_pericom_2port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 2, + }, + [param_pericom_4port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 4, + }, + [param_pericom_8port] = { + .base_baud = 921600, + .uart_offset = 8, + .reg_width = 1, + .fifo_size = 16, + .lsr_mask = UART_LSR_THRE, + .bar0 = 1, + .max_ports = 8, } }; -static const struct ns16550_config_mmio __initconst uart_config[] = +static const struct ns16550_config __initconst uart_config[] = { /* Broadcom TruManage device */ { @@ -339,6 +383,30 @@ static const struct ns16550_config_mmio .vendor_id = PCI_VENDOR_ID_OXSEMI, .dev_id = 0xc4cf, .param = param_oxford, + }, + /* Pericom PI7C9X7951 Uno UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7951, + .param = param_pericom_1port + }, + /* Pericom PI7C9X7952 Duo UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7952, + .param = param_pericom_2port + }, + /* Pericom PI7C9X7954 Quad UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7954, + .param = param_pericom_4port + }, + /* Pericom PI7C9X7958 Octal UART */ + { + .vendor_id = PCI_VENDOR_ID_PERICOM, + .dev_id = 0x7958, + .param = param_pericom_8port } }; #endif @@ -629,7 +697,8 @@ static void __init ns16550_init_postirq( uart->ps_bdf[2])); else { - if ( rangeset_add_range(mmio_ro_ranges, + if ( uart->param->mmio && + rangeset_add_range(mmio_ro_ranges, uart->io_base, uart->io_base + uart->io_size - 1) ) printk(XENLOG_INFO "Error while adding MMIO range of device to mmio_ro_ranges\n"); @@ -830,12 +899,11 @@ static int __init check_existence(struct #ifdef CONFIG_HAS_PCI static int __init -pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int bar_idx) +pci_uart_config(struct ns16550 *uart, bool_t skip_amt, unsigned int idx) { u64 orig_base = uart->io_base; unsigned int b, d, f, nextf, i; - uart->io_base = 0; /* NB. Start at bus 1 to avoid AMT: a plug-in card cannot be on bus 0. */ for ( b = skip_amt ? 1 : 0; b < 0x100; b++ ) { @@ -843,8 +911,10 @@ pci_uart_config(struct ns16550 *uart, bo { for ( f = 0; f < 8; f = nextf ) { + unsigned int bar_idx = 0, port_idx = idx; uint32_t bar, bar_64 = 0, len, len_64; - u64 size; + u64 size = 0; + const struct ns16550_config_param *param = uart_param; nextf = (f || (pci_conf_read16(0, b, d, f, PCI_HEADER_TYPE) & 0x80)) ? f + 1 : 8; @@ -863,15 +933,38 @@ pci_uart_config(struct ns16550 *uart, bo continue; } + /* Check for params in uart_config lookup table */ + for ( i = 0; i < ARRAY_SIZE(uart_config); i++) + { + u16 vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID); + u16 device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID); + + if ( uart_config[i].vendor_id == vendor && + uart_config[i].dev_id == device ) + { + param += uart_config[i].param; + if ( !param->bar0 ) + { + bar_idx = idx; + port_idx = 0; + } + break; + } + } + + if ( port_idx >= param->max_ports ) + { + idx -= param->max_ports; + continue; + } + + uart->io_base = 0; bar = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4); /* MMIO based */ - if ( !(bar & PCI_BASE_ADDRESS_SPACE_IO) ) + if ( param->mmio && !(bar & PCI_BASE_ADDRESS_SPACE_IO) ) { - u16 vendor = pci_conf_read16(0, b, d, f, PCI_VENDOR_ID); - u16 device = pci_conf_read16(0, b, d, f, PCI_DEVICE_ID); - pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, ~0u); len = pci_conf_read32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4); @@ -895,56 +988,11 @@ pci_uart_config(struct ns16550 *uart, bo else size = len & PCI_BASE_ADDRESS_MEM_MASK; - size &= -size; - - /* Check for params in uart_config lookup table */ - for ( i = 0; i < ARRAY_SIZE(uart_config); i++) - { - const struct ns16550_config_param *param; - - if ( uart_config[i].vendor_id != vendor ) - continue; - - if ( uart_config[i].dev_id != device ) - continue; - - param = uart_param + uart_config[i].param; - - /* - * Force length of mmio region to be at least - * 8 bytes times (1 << reg_shift) - */ - if ( size < (0x8 * (1 << param->reg_shift)) ) - continue; - - if ( bar_idx >= param->max_bars ) - continue; - - uart->param = param; - - if ( param->fifo_size ) - uart->fifo_size = param->fifo_size; - - uart->reg_shift = param->reg_shift; - uart->reg_width = param->reg_width; - uart->lsr_mask = param->lsr_mask; - uart->io_base = ((u64)bar_64 << 32) | - (bar & PCI_BASE_ADDRESS_MEM_MASK); - uart->io_base += param->first_offset; - uart->io_base += bar_idx * param->uart_offset; - if ( param->base_baud ) - uart->clock_hz = param->base_baud * 16; - size = max(8U << param->reg_shift, - param->uart_offset); - break; - } - - /* If we have an io_base, then we succeeded in the lookup */ - if ( !uart->io_base ) - continue; + uart->io_base = ((u64)bar_64 << 32) | + (bar & PCI_BASE_ADDRESS_MEM_MASK); } /* IO based */ - else + else if ( !param->mmio && (bar & PCI_BASE_ADDRESS_SPACE_IO) ) { pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, ~0u); @@ -952,22 +1000,45 @@ pci_uart_config(struct ns16550 *uart, bo pci_conf_write32(0, b, d, f, PCI_BASE_ADDRESS_0 + bar_idx*4, bar); size = len & PCI_BASE_ADDRESS_IO_MASK; - size &= -size; - - /* Not at least 8 bytes */ - if ( size < 8 ) - continue; uart->io_base = bar & ~PCI_BASE_ADDRESS_SPACE_IO; } + /* If we have an io_base, then we succeeded in the lookup. */ + if ( !uart->io_base ) + continue; + + size &= -size; + + /* + * Require length of actually used region to be at least + * 8 bytes times (1 << reg_shift). + */ + if ( size < param->first_offset + + port_idx * param->uart_offset + + (8 << param->reg_shift) ) + continue; + + uart->param = param; + + uart->reg_shift = param->reg_shift; + uart->reg_width = param->reg_width; + uart->lsr_mask = param->lsr_mask; + uart->io_base += param->first_offset + + port_idx * param->uart_offset; + if ( param->base_baud ) + uart->clock_hz = param->base_baud * 16; + if ( param->fifo_size ) + uart->fifo_size = param->fifo_size; + uart->ps_bdf[0] = b; uart->ps_bdf[1] = d; uart->ps_bdf[2] = f; uart->bar_idx = bar_idx; uart->bar = bar; uart->bar64 = bar_64; - uart->io_size = size; + uart->io_size = max(8U << param->reg_shift, + param->uart_offset); uart->irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ? pci_conf_read8(0, b, d, f, PCI_INTERRUPT_LINE) : 0; --- a/xen/include/xen/pci_ids.h +++ b/xen/include/xen/pci_ids.h @@ -2,6 +2,8 @@ #define PCI_VENDOR_ID_NVIDIA 0x10de +#define PCI_VENDOR_ID_PERICOM 0x12d8 + #define PCI_VENDOR_ID_OXSEMI 0x1415 #define PCI_VENDOR_ID_BROADCOM 0x14e4