serial: ns16550: do not write to device cfg struct when PCIE=y
When PCIe is enabled for UART, the port address is probed during initialization and is written back into the device config struct. However, the device config struct is supposed to be const and read only. This results in page faults when MMU is enabled as the struct cannot be written into. So fix this by storing port address in device data struct if a particular UART instance is of PCIE. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
36674f6bf8
commit
af43e14bd0
1 changed files with 29 additions and 14 deletions
|
@ -207,21 +207,21 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
|
||||||
#define DEV_DATA(dev) \
|
#define DEV_DATA(dev) \
|
||||||
((struct uart_ns16550_dev_data_t *)(dev)->driver_data)
|
((struct uart_ns16550_dev_data_t *)(dev)->driver_data)
|
||||||
|
|
||||||
#define THR(dev) (DEV_CFG(dev)->devconf.port + REG_THR * UART_REG_ADDR_INTERVAL)
|
#define THR(dev) (get_port(dev) + REG_THR * UART_REG_ADDR_INTERVAL)
|
||||||
#define RDR(dev) (DEV_CFG(dev)->devconf.port + REG_RDR * UART_REG_ADDR_INTERVAL)
|
#define RDR(dev) (get_port(dev) + REG_RDR * UART_REG_ADDR_INTERVAL)
|
||||||
#define BRDL(dev) \
|
#define BRDL(dev) \
|
||||||
(DEV_CFG(dev)->devconf.port + REG_BRDL * UART_REG_ADDR_INTERVAL)
|
(get_port(dev) + REG_BRDL * UART_REG_ADDR_INTERVAL)
|
||||||
#define BRDH(dev) \
|
#define BRDH(dev) \
|
||||||
(DEV_CFG(dev)->devconf.port + REG_BRDH * UART_REG_ADDR_INTERVAL)
|
(get_port(dev) + REG_BRDH * UART_REG_ADDR_INTERVAL)
|
||||||
#define IER(dev) (DEV_CFG(dev)->devconf.port + REG_IER * UART_REG_ADDR_INTERVAL)
|
#define IER(dev) (get_port(dev) + REG_IER * UART_REG_ADDR_INTERVAL)
|
||||||
#define IIR(dev) (DEV_CFG(dev)->devconf.port + REG_IIR * UART_REG_ADDR_INTERVAL)
|
#define IIR(dev) (get_port(dev) + REG_IIR * UART_REG_ADDR_INTERVAL)
|
||||||
#define FCR(dev) (DEV_CFG(dev)->devconf.port + REG_FCR * UART_REG_ADDR_INTERVAL)
|
#define FCR(dev) (get_port(dev) + REG_FCR * UART_REG_ADDR_INTERVAL)
|
||||||
#define LCR(dev) (DEV_CFG(dev)->devconf.port + REG_LCR * UART_REG_ADDR_INTERVAL)
|
#define LCR(dev) (get_port(dev) + REG_LCR * UART_REG_ADDR_INTERVAL)
|
||||||
#define MDC(dev) (DEV_CFG(dev)->devconf.port + REG_MDC * UART_REG_ADDR_INTERVAL)
|
#define MDC(dev) (get_port(dev) + REG_MDC * UART_REG_ADDR_INTERVAL)
|
||||||
#define LSR(dev) (DEV_CFG(dev)->devconf.port + REG_LSR * UART_REG_ADDR_INTERVAL)
|
#define LSR(dev) (get_port(dev) + REG_LSR * UART_REG_ADDR_INTERVAL)
|
||||||
#define MSR(dev) (DEV_CFG(dev)->devconf.port + REG_MSR * UART_REG_ADDR_INTERVAL)
|
#define MSR(dev) (get_port(dev) + REG_MSR * UART_REG_ADDR_INTERVAL)
|
||||||
#define DLF(dev) (DEV_CFG(dev)->devconf.port + REG_DLF)
|
#define DLF(dev) (get_port(dev) + REG_DLF)
|
||||||
#define PCP(dev) (DEV_CFG(dev)->devconf.port + REG_PCP)
|
#define PCP(dev) (get_port(dev) + REG_PCP)
|
||||||
|
|
||||||
#define IIRC(dev) (DEV_DATA(dev)->iir_cache)
|
#define IIRC(dev) (DEV_DATA(dev)->iir_cache)
|
||||||
|
|
||||||
|
@ -257,6 +257,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE");
|
||||||
/* device config */
|
/* device config */
|
||||||
struct uart_ns16550_device_config {
|
struct uart_ns16550_device_config {
|
||||||
struct uart_device_config devconf;
|
struct uart_device_config devconf;
|
||||||
|
|
||||||
#ifdef UART_NS16550_PCP_ENABLED
|
#ifdef UART_NS16550_PCP_ENABLED
|
||||||
u32_t pcp;
|
u32_t pcp;
|
||||||
#endif
|
#endif
|
||||||
|
@ -270,6 +271,9 @@ struct uart_ns16550_device_config {
|
||||||
|
|
||||||
/** Device data structure */
|
/** Device data structure */
|
||||||
struct uart_ns16550_dev_data_t {
|
struct uart_ns16550_dev_data_t {
|
||||||
|
#ifdef UART_NS16550_PCIE_ENABLED
|
||||||
|
struct uart_device_config devconf;
|
||||||
|
#endif
|
||||||
struct uart_config uart_config;
|
struct uart_config uart_config;
|
||||||
struct k_spinlock lock;
|
struct k_spinlock lock;
|
||||||
|
|
||||||
|
@ -286,6 +290,17 @@ struct uart_ns16550_dev_data_t {
|
||||||
|
|
||||||
static const struct uart_driver_api uart_ns16550_driver_api;
|
static const struct uart_driver_api uart_ns16550_driver_api;
|
||||||
|
|
||||||
|
static inline u32_t get_port(struct device *dev)
|
||||||
|
{
|
||||||
|
#ifdef UART_NS16550_PCIE_ENABLED
|
||||||
|
if (DEV_CFG(dev)->pcie) {
|
||||||
|
return DEV_DATA(dev)->devconf.port;
|
||||||
|
}
|
||||||
|
#endif /* UART_NS16550_PCIE_ENABLED */
|
||||||
|
|
||||||
|
return DEV_CFG(dev)->devconf.port;
|
||||||
|
}
|
||||||
|
|
||||||
static void set_baud_rate(struct device *dev, u32_t baud_rate)
|
static void set_baud_rate(struct device *dev, u32_t baud_rate)
|
||||||
{
|
{
|
||||||
const struct uart_ns16550_device_config * const dev_cfg = DEV_CFG(dev);
|
const struct uart_ns16550_device_config * const dev_cfg = DEV_CFG(dev);
|
||||||
|
@ -337,7 +352,7 @@ static int uart_ns16550_configure(struct device *dev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_cfg->devconf.port = pcie_get_mbar(dev_cfg->pcie_bdf, 0);
|
dev_data->devconf.port = pcie_get_mbar(dev_cfg->pcie_bdf, 0);
|
||||||
pcie_set_cmd(dev_cfg->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true);
|
pcie_set_cmd(dev_cfg->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue