diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/aspeed-mctp.h | 135 | ||||
-rw-r--r-- | include/linux/i2c-mux.h | 4 | ||||
-rw-r--r-- | include/linux/i2c.h | 27 | ||||
-rw-r--r-- | include/linux/i3c/ccc.h | 12 | ||||
-rw-r--r-- | include/linux/i3c/master.h | 1 | ||||
-rw-r--r-- | include/linux/jtag.h | 47 | ||||
-rw-r--r-- | include/linux/mfd/intel-peci-client.h | 161 | ||||
-rw-r--r-- | include/linux/peci.h | 151 |
8 files changed, 538 insertions, 0 deletions
diff --git a/include/linux/aspeed-mctp.h b/include/linux/aspeed-mctp.h new file mode 100644 index 000000000000..d56dceaf146d --- /dev/null +++ b/include/linux/aspeed-mctp.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2020 Intel Corporation */ + +#ifndef __LINUX_ASPEED_MCTP_H +#define __LINUX_ASPEED_MCTP_H + +#include <linux/types.h> + +struct mctp_client; +struct aspeed_mctp; + +struct pcie_transport_hdr { + u8 fmt_type; + u8 mbz; + u8 mbz_attr_len_hi; + u8 len_lo; + u16 requester; + u8 tag; + u8 code; + u16 target; + u16 vendor; +} __packed; + +struct mctp_protocol_hdr { + u8 ver; + u8 dest; + u8 src; + u8 flags_seq_tag; +} __packed; + +#define PCIE_VDM_HDR_SIZE 16 +#define MCTP_BTU_SIZE 64 +#define PCIE_VDM_DATA_SIZE_DW (MCTP_BTU_SIZE / 4) +#define PCIE_VDM_HDR_SIZE_DW (PCIE_VDM_HDR_SIZE / 4) + +#define PCIE_MCTP_MIN_PACKET_SIZE (PCIE_VDM_HDR_SIZE + 4) + +struct mctp_pcie_packet_data { + u32 hdr[PCIE_VDM_HDR_SIZE_DW]; + u32 payload[PCIE_VDM_DATA_SIZE_DW]; +}; + +struct mctp_pcie_packet { + struct mctp_pcie_packet_data data; + u32 size; +}; + +/** + * aspeed_mctp_add_type_handler() - register for the given MCTP message type + * @client: pointer to the existing mctp_client context + * @mctp_type: message type code according to DMTF DSP0239 spec. + * @pci_vendor_id: vendor ID (non-zero if msg_type is Vendor Defined PCI, + * otherwise it should be set to 0) + * @vdm_type: vendor defined message type (it should be set to 0 for non-Vendor + * Defined PCI message type) + * @vdm_mask: vendor defined message mask (it should be set to 0 for non-Vendor + * Defined PCI message type) + * + * Return: + * * 0 - success, + * * -EINVAL - arguments passed are incorrect, + * * -ENOMEM - cannot alloc a new handler, + * * -EBUSY - given message has already registered handler. + */ + +int aspeed_mctp_add_type_handler(struct mctp_client *client, u8 mctp_type, + u16 pci_vendor_id, u16 vdm_type, u16 vdm_mask); + +/** + * aspeed_mctp_create_client() - create mctp_client context + * @priv pointer to aspeed-mctp context + * + * Returns struct mctp_client or NULL. + */ +struct mctp_client *aspeed_mctp_create_client(struct aspeed_mctp *priv); + +/** + * aspeed_mctp_delete_client()- delete mctp_client context + * @client: pointer to existing mctp_client context + */ +void aspeed_mctp_delete_client(struct mctp_client *client); + +/** + * aspeed_mctp_send_packet() - send mctp_packet + * @client: pointer to existing mctp_client context + * @tx_packet: the allocated packet that needs to be send via aspeed-mctp + * + * After the function returns success, the packet is no longer owned by the + * caller, and as such, the caller should not attempt to free it. + * + * Return: + * * 0 - success, + * * -ENOSPC - failed to send packet due to lack of available space. + */ +int aspeed_mctp_send_packet(struct mctp_client *client, + struct mctp_pcie_packet *tx_packet); + +/** + * aspeed_mctp_receive_packet() - receive mctp_packet + * @client: pointer to existing mctp_client context + * @timeout: timeout, in jiffies + * + * The function will sleep for up to @timeout if no packet is ready to read. + * + * After the function returns valid packet, the caller takes its ownership and + * is responsible for freeing it. + * + * Returns struct mctp_pcie_packet from or ERR_PTR in case of error or the + * @timeout elapsed. + */ +struct mctp_pcie_packet *aspeed_mctp_receive_packet(struct mctp_client *client, + unsigned long timeout); + +/** + * aspeed_mctp_flush_rx_queue() - remove all mctp_packets from rx queue + * @client: pointer to existing mctp_client context + */ +void aspeed_mctp_flush_rx_queue(struct mctp_client *client); + +/** + * aspeed_mctp_get_eid_bdf() - return PCIe address for requested endpoint ID + * @client: pointer to existing mctp_client context + * @eid: requested eid + * @bdf: pointer to store BDF value + * + * Return: + * * 0 - success, + * * -ENOENT - there is no record for requested endpoint id. + */ +int aspeed_mctp_get_eid_bdf(struct mctp_client *client, u8 eid, u16 *bdf); + +void *aspeed_mctp_packet_alloc(gfp_t flags); +void aspeed_mctp_packet_free(void *packet); + +#endif /* __LINUX_ASPEED_MCTP_H */ diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h index 98ef73b7c8fd..43c40680d8c5 100644 --- a/include/linux/i2c-mux.h +++ b/include/linux/i2c-mux.h @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #include <linux/bitops.h> +#include <linux/workqueue.h> struct i2c_mux_core { struct i2c_adapter *parent; @@ -27,6 +28,9 @@ struct i2c_mux_core { int (*select)(struct i2c_mux_core *, u32 chan_id); int (*deselect)(struct i2c_mux_core *, u32 chan_id); + struct mutex hold_lock; /* mutex for channel holding */ + struct delayed_work unhold_work; + int num_adapters; int max_adapters; struct i2c_adapter *adapter[]; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index a670ae129f4b..0d996b722b75 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -19,6 +19,7 @@ #include <linux/irqdomain.h> /* for Host Notify IRQ */ #include <linux/of.h> /* for struct device_node */ #include <linux/swab.h> /* for swab16 */ +#include <linux/workqueue.h> #include <uapi/linux/i2c.h> extern struct bus_type i2c_bus_type; @@ -366,6 +367,7 @@ enum i2c_slave_event { I2C_SLAVE_WRITE_REQUESTED, I2C_SLAVE_READ_PROCESSED, I2C_SLAVE_WRITE_RECEIVED, + I2C_SLAVE_GCALL_REQUESTED, I2C_SLAVE_STOP, }; @@ -723,6 +725,13 @@ struct i2c_adapter { const struct i2c_adapter_quirks *quirks; struct irq_domain *host_notify_domain; + + /* + * These will be used by root adpaters only. For muxes, each mux core + * has these individually. + */ + struct mutex hold_lock; /* mutex for bus holding */ + struct delayed_work unhold_work; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -1019,4 +1028,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha } #endif /* CONFIG_ACPI */ +enum i2c_hold_msg_type { + I2C_HOLD_MSG_NONE, + I2C_HOLD_MSG_SET, + I2C_HOLD_MSG_RESET +}; + +static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf) +{ + if (flags & I2C_M_HOLD && len == sizeof(u16)) { + if (*buf) + return I2C_HOLD_MSG_SET; + + return I2C_HOLD_MSG_RESET; + } + + return I2C_HOLD_MSG_NONE; +} + #endif /* _LINUX_I2C_H */ diff --git a/include/linux/i3c/ccc.h b/include/linux/i3c/ccc.h index 73b0982cc519..a7a19ebe6b6d 100644 --- a/include/linux/i3c/ccc.h +++ b/include/linux/i3c/ccc.h @@ -32,6 +32,9 @@ #define I3C_CCC_DEFSLVS I3C_CCC_ID(0x8, true) #define I3C_CCC_ENTTM I3C_CCC_ID(0xb, true) #define I3C_CCC_ENTHDR(x) I3C_CCC_ID(0x20 + (x), true) +#define I3C_CCC_SETAASA I3C_CCC_ID(0x29, true) +#define I3C_CCC_SETHID I3C_CCC_ID(0x61, true) +#define I3C_CCC_DEVCTRL I3C_CCC_ID(0x62, true) /* Unicast-only commands */ #define I3C_CCC_SETDASA I3C_CCC_ID(0x7, false) @@ -243,6 +246,15 @@ struct i3c_ccc_setbrgtgt { struct i3c_ccc_bridged_slave_desc bslaves[0]; } __packed; + +/** + * struct i3c_ccc_sethid - payload passed to SETHID CCC + * + * @hid: 3-bit HID + */ +struct i3c_ccc_sethid { + u8 hid; +}; /** * enum i3c_sdr_max_data_rate - max data rate values for private SDR transfers */ diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h index 9cb39d901cd5..11cdcc062b3e 100644 --- a/include/linux/i3c/master.h +++ b/include/linux/i3c/master.h @@ -487,6 +487,7 @@ struct i3c_master_controller { const struct i3c_master_controller_ops *ops; unsigned int secondary : 1; unsigned int init_done : 1; + unsigned int jdec_spd : 1; struct { struct list_head i3c; struct list_head i2c; diff --git a/include/linux/jtag.h b/include/linux/jtag.h new file mode 100644 index 000000000000..fab12dc4fc5e --- /dev/null +++ b/include/linux/jtag.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */ +/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */ +/* Copyright (c) 2019 Intel Corporation */ + +#ifndef __LINUX_JTAG_H +#define __LINUX_JTAG_H + +#include <linux/types.h> +#include <uapi/linux/jtag.h> + +#define JTAG_MAX_XFER_DATA_LEN 65535 + +struct jtag; +/** + * struct jtag_ops - callbacks for JTAG control functions: + * + * @freq_get: get frequency function. Filled by dev driver + * @freq_set: set frequency function. Filled by dev driver + * @status_get: get JTAG TAPC state function. Mandatory, Filled by dev driver + * @status_set: set JTAG TAPC state function. Mandatory, Filled by dev driver + * @xfer: send JTAG xfer function. Mandatory func. Filled by dev driver + * @mode_set: set specific work mode for JTAG. Filled by dev driver + * @bitbang: set low level bitbang operations. Filled by dev driver + * @enable: enables JTAG interface in master mode. Filled by dev driver + * @disable: disables JTAG interface master mode. Filled by dev driver + */ +struct jtag_ops { + int (*freq_get)(struct jtag *jtag, u32 *freq); + int (*freq_set)(struct jtag *jtag, u32 freq); + int (*status_get)(struct jtag *jtag, u32 *state); + int (*status_set)(struct jtag *jtag, struct jtag_tap_state *endst); + int (*xfer)(struct jtag *jtag, struct jtag_xfer *xfer, u8 *xfer_data); + int (*mode_set)(struct jtag *jtag, struct jtag_mode *jtag_mode); + int (*bitbang)(struct jtag *jtag, struct bitbang_packet *bitbang, + struct tck_bitbang *bitbang_data); + int (*enable)(struct jtag *jtag); + int (*disable)(struct jtag *jtag); +}; + +void *jtag_priv(struct jtag *jtag); +int devm_jtag_register(struct device *dev, struct jtag *jtag); +struct jtag *jtag_alloc(struct device *host, size_t priv_size, + const struct jtag_ops *ops); +void jtag_free(struct jtag *jtag); + +#endif /* __LINUX_JTAG_H */ diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h new file mode 100644 index 000000000000..55dec5be3245 --- /dev/null +++ b/include/linux/mfd/intel-peci-client.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2020 Intel Corporation */ + +#ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H +#define __LINUX_MFD_INTEL_PECI_CLIENT_H + +#include <linux/peci.h> + +#if IS_ENABLED(CONFIG_X86) +#include <asm/intel-family.h> +#else +/* + * Architectures other than x86 cannot include the header file so define these + * at here. These are needed for detecting type of client x86 CPUs behind a PECI + * connection. + */ +#define INTEL_FAM6_HASWELL_X 0x3F +#define INTEL_FAM6_BROADWELL_X 0x4F +#define INTEL_FAM6_SKYLAKE_X 0x55 +#define INTEL_FAM6_SKYLAKE_XD 0x56 +#define INTEL_FAM6_ICELAKE_X 0x6A +#define INTEL_FAM6_ICELAKE_XD 0x6C +#endif + +#define INTEL_FAM6 6 /* P6 (Pentium Pro and later) */ + +#define CORE_MASK_BITS_ON_HSX 18 +#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */ +#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */ + +#define CORE_MASK_BITS_ON_BDX 24 +#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */ +#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */ + +#define CORE_MASK_BITS_ON_SKX 28 +#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */ +#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */ + +#define CORE_MASK_BITS_ON_SKXD 28 +#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */ +#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */ + +#define CORE_MASK_BITS_ON_ICX 64 +#define CHAN_RANK_MAX_ON_ICX 8 /* Max number of channel ranks on Icelake */ +#define DIMM_IDX_MAX_ON_ICX 2 /* Max DIMM index per channel on Icelake */ + +#define CORE_MASK_BITS_ON_ICXD 64 +#define CHAN_RANK_MAX_ON_ICXD 4 /* Max number of channel ranks on Icelake D */ +#define DIMM_IDX_MAX_ON_ICXD 2 /* Max DIMM index per channel on Icelake D */ + +#define CORE_MASK_BITS_MAX CORE_MASK_BITS_ON_ICX +#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX +#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX +#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX) + +/** + * struct cpu_gen_info - CPU generation specific information + * @family: CPU family ID + * @model: CPU model + * @core_mask_bits: number of resolved core bits + * @chan_rank_max: max number of channel ranks + * @dimm_idx_max: max number of DIMM indices + * + * CPU generation specific information to identify maximum number of cores and + * DIMM slots. + */ +struct cpu_gen_info { + u16 family; + u8 model; + uint core_mask_bits; + uint chan_rank_max; + uint dimm_idx_max; +}; + +/** + * struct peci_client_manager - PECI client manager information + * @client; pointer to the PECI client + * @name: PECI client manager name + * @gen_info: CPU generation info of the detected CPU + * + * PECI client manager information for managing PECI sideband functions on a CPU + * client. + */ +struct peci_client_manager { + struct peci_client *client; + char name[PECI_NAME_SIZE]; + const struct cpu_gen_info *gen_info; +}; + +/** + * peci_client_read_package_config - read from the Package Configuration Space + * @priv: driver private data structure + * @index: encoding index for the requested service + * @param: parameter to specify the exact data being requested + * @data: data buffer to store the result + * Context: can sleep + * + * A generic PECI command that provides read access to the + * "Package Configuration Space" that is maintained by the PCU, including + * various power and thermal management functions. Typical PCS read services + * supported by the processor may include access to temperature data, energy + * status, run time information, DIMM temperatures and so on. + * + * Return: zero on success, else a negative error code. + */ +static inline int +peci_client_read_package_config(struct peci_client_manager *priv, + u8 index, u16 param, u8 *data) +{ + struct peci_rd_pkg_cfg_msg msg; + int ret; + + msg.addr = priv->client->addr; + msg.index = index; + msg.param = param; + msg.rx_len = 4; + + ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg); + if (msg.cc != PECI_DEV_CC_SUCCESS) + ret = -EAGAIN; + if (ret) + return ret; + + memcpy(data, msg.pkg_config, 4); + + return 0; +} + +/** + * peci_client_write_package_config - write to the Package Configuration Space + * @priv: driver private data structure + * @index: encoding index for the requested service + * @param: parameter to specify the exact data being requested + * @data: data buffer with values to write + * Context: can sleep + * + * Return: zero on success, else a negative error code. + */ +static inline int +peci_client_write_package_config(struct peci_client_manager *priv, + u8 index, u16 param, u8 *data) +{ + struct peci_rd_pkg_cfg_msg msg; + int ret; + + msg.addr = priv->client->addr; + msg.index = index; + msg.param = param; + msg.rx_len = 4u; + memcpy(msg.pkg_config, data, msg.rx_len); + + ret = peci_command(priv->client->adapter, PECI_CMD_WR_PKG_CFG, &msg); + if (!ret) { + if (msg.cc != PECI_DEV_CC_SUCCESS) + ret = -EAGAIN; + } + + return ret; +} + +#endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */ diff --git a/include/linux/peci.h b/include/linux/peci.h new file mode 100644 index 000000000000..45cb77d1913c --- /dev/null +++ b/include/linux/peci.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2019 Intel Corporation */ + +#ifndef __LINUX_PECI_H +#define __LINUX_PECI_H + +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/peci-ioctl.h> + +#define PECI_NAME_SIZE 32 + +struct peci_board_info { + char type[PECI_NAME_SIZE]; + u8 addr; /* CPU client address */ + struct device_node *of_node; +}; + +/** + * struct peci_adapter - represent a PECI adapter + * @owner: owner module of the PECI adpater + * @bus_lock: mutex for exclusion of multiple callers + * @dev: device interface to this driver + * @nr: the bus number to map + * @name: name of the adapter + * @userspace_clients_lock: mutex for exclusion of clients handling + * @userspace_clients: list of registered clients + * @xfer: low-level transfer function pointer of the adapter + * @cmd_mask: mask for supportable PECI commands + * @use_dma: flag for indicating that adapter uses DMA + * + * Each PECI adapter can communicate with one or more PECI client children. + * These make a small bus, sharing a single wired PECI connection. + */ +struct peci_adapter { + struct module *owner; + struct mutex bus_lock; /* mutex for bus locking */ + struct device dev; + int nr; + char name[PECI_NAME_SIZE]; + struct mutex userspace_clients_lock; /* clients list mutex */ + struct list_head userspace_clients; + int (*xfer)(struct peci_adapter *adapter, + struct peci_xfer_msg *msg); + u32 cmd_mask; + bool use_dma; + u8 peci_revision; +}; + +static inline struct peci_adapter *to_peci_adapter(void *d) +{ + return container_of(d, struct peci_adapter, dev); +} + +static inline void *peci_get_adapdata(const struct peci_adapter *adapter) +{ + return dev_get_drvdata(&adapter->dev); +} + +static inline void peci_set_adapdata(struct peci_adapter *adapter, void *data) +{ + dev_set_drvdata(&adapter->dev, data); +} + +/** + * struct peci_client - represent a PECI client device + * @dev: driver model device node for the client + * @adapter: manages the bus segment hosting this PECI device + * @addr: address used on the PECI bus connected to the parent adapter + * @name: indicates the type of the device + * @detected: detected PECI clients list + * + * A peci_client identifies a single device (i.e. CPU) connected to a peci bus. + * The behaviour exposed to Linux is defined by the driver managing the device. + */ +struct peci_client { + struct device dev; + struct peci_adapter *adapter; + u8 addr; + char name[PECI_NAME_SIZE]; + struct list_head detected; +}; + +static inline struct peci_client *to_peci_client(void *d) +{ + return container_of(d, struct peci_client, dev); +} + +struct peci_device_id { + char name[PECI_NAME_SIZE]; + ulong driver_data; /* Data private to the driver */ +}; + +/** + * struct peci_driver - represent a PECI device driver + * @probe: callback for device binding + * @remove: callback for device unbinding + * @shutdown: callback for device shutdown + * @driver: device driver model driver + * @id_table: list of PECI devices supported by this driver + * + * The driver.owner field should be set to the module owner of this driver. + * The driver.name field should be set to the name of this driver. + */ +struct peci_driver { + int (*probe)(struct peci_client *client); + int (*remove)(struct peci_client *client); + void (*shutdown)(struct peci_client *client); + struct device_driver driver; + const struct peci_device_id *id_table; +}; + +static inline struct peci_driver *to_peci_driver(void *d) +{ + return container_of(d, struct peci_driver, driver); +} + +/** + * module_peci_driver - Helper macro for registering a modular PECI driver + * @__peci_driver: peci_driver struct + * + * Helper macro for PECI drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only + * use this macro once, and calling it replaces module_init() and module_exit() + */ +#define module_peci_driver(__peci_driver) \ + module_driver(__peci_driver, peci_add_driver, peci_del_driver) + +/* use a define to avoid include chaining to get THIS_MODULE */ +#define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver) + +extern struct bus_type peci_bus_type; +extern struct device_type peci_adapter_type; +extern struct device_type peci_client_type; + +int peci_register_driver(struct module *owner, struct peci_driver *drv); +void peci_del_driver(struct peci_driver *driver); +struct peci_client *peci_verify_client(struct device *dev); +struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size); +struct peci_adapter *peci_get_adapter(int nr); +void peci_put_adapter(struct peci_adapter *adapter); +int peci_add_adapter(struct peci_adapter *adapter); +void peci_del_adapter(struct peci_adapter *adapter); +struct peci_adapter *peci_verify_adapter(struct device *dev); +int peci_for_each_dev(void *data, int (*fn)(struct device *, void *)); +struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len); +void peci_put_xfer_msg(struct peci_xfer_msg *msg); +int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg); +int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id); + +#endif /* __LINUX_PECI_H */ |