Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932748AbcLMEOX (ORCPT ); Mon, 12 Dec 2016 23:14:23 -0500 Received: from esa2.dell-outbound.iphmx.com ([68.232.149.220]:11518 "EHLO esa2.dell-outbound.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752173AbcLMEOV (ORCPT ); Mon, 12 Dec 2016 23:14:21 -0500 DomainKey-Signature: s=smtpout; d=dell.com; c=simple; q=dns; h=Received:Received:Received:X-DKIM:Received:Received:From: To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type: Content-Transfer-Encoding:X-Mailer:Thread-Index: Content-Language:X-RSA-Classifications: X-Sentrion-Hostname; b=P2QQgKPfEtW4HNvHxmjuIlaYXcCT5YmtfEu+sV04UCzyxchgZkuBLONW LFK5NikYsRVlCsxTLMiCM3B1UiYXoPo8pP5kcX1ze++Onds1eJPMttC7t GpVNpia2siWHJK3+7Qr/OgLeb+CWKeyuFxOeWuPObaGaEFXp95W5lxT5f I=; X-DKIM: OpenDKIM Filter v2.4.3 mailuogwprd02.lss.emc.com uBD4EElH008087 From: "Allen Hubbe" To: "'Serge Semin'" , , , Cc: , , Subject: RE: [PATCH v2 6/9] NTB: Add Messaging NTB API Date: Mon, 12 Dec 2016 23:13:58 -0500 Message-ID: <000501d254f7$56009620$0201c260$@dell.com> MIME-Version: 1.0 Content-Type: text/plain; charset="Windows-1252" Content-Transfer-Encoding: 7bit X-Mailer: Microsoft Outlook 14.0 Thread-Index: AdJU90790+uKYDzRTn6eqS8IvfQ4Ag== Content-Language: en-us X-RSA-Classifications: Source Code, public X-Sentrion-Hostname: mailuogwprd02.lss.emc.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 10764 Lines: 323 From: Serge Semin > Some IDT NTB-capable PCIe-switches have message registers to communicate with > peer devices. This patch adds new NTB API callback methods, which can be used > to utilize these registers functionality: > ntb_msg_count(); - get number of message registers > ntb_msg_inbits(); - get bitfield of inbound message registers status > ntb_msg_outbits(); - get bitfield of outbound message registers status > ntb_msg_read_sts(); - read the inbound and outbound message registers status > ntb_msg_clear_sts(); - clear status bits of message registers > ntb_msg_set_mask(); - mask interrupts raised by status bits of message > registers. > ntb_msg_clear_mask(); - clear interrupts mask bits of message registers > ntb_msg_read(midx, *pidx); - read message register with specified index, > additionally getting peer port index which data received from > ntb_msg_write(midx, pidx); - write data to the specified message register > sending it to the passed peer device connected over a pidx port > ntb_msg_event(); - notify driver context of a new message event > > Of course there is hadrware which doesn't support Message registers, so s/hadrware/hardware/ > this API is made optional. > > Signed-off-by: Serge Semin Acked-by: Allen Hubbe > > --- > drivers/ntb/ntb.c | 13 ++++ > include/linux/ntb.h | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 218 insertions(+) > > diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c > index f6153af..06574f8 100644 > --- a/drivers/ntb/ntb.c > +++ b/drivers/ntb/ntb.c > @@ -193,6 +193,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector) > } > EXPORT_SYMBOL(ntb_db_event); > > +void ntb_msg_event(struct ntb_dev *ntb) > +{ > + unsigned long irqflags; > + > + spin_lock_irqsave(&ntb->ctx_lock, irqflags); > + { > + if (ntb->ctx_ops && ntb->ctx_ops->msg_event) > + ntb->ctx_ops->msg_event(ntb->ctx); > + } > + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); > +} > +EXPORT_SYMBOL(ntb_msg_event); > + > static int ntb_probe(struct device *dev) > { > struct ntb_dev *ntb; > diff --git a/include/linux/ntb.h b/include/linux/ntb.h > index a6bf15d..90746df 100644 > --- a/include/linux/ntb.h > +++ b/include/linux/ntb.h > @@ -164,10 +164,12 @@ static inline int ntb_client_ops_is_valid(const struct > ntb_client_ops *ops) > * struct ntb_ctx_ops - ntb driver context operations > * @link_event: See ntb_link_event(). > * @db_event: See ntb_db_event(). > + * @msg_event: See ntb_msg_event(). > */ > struct ntb_ctx_ops { > void (*link_event)(void *ctx); > void (*db_event)(void *ctx, int db_vector); > + void (*msg_event)(void *ctx); > }; > > static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > @@ -176,6 +178,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > return > /* ops->link_event && */ > /* ops->db_event && */ > + /* ops->msg_event && */ > 1; > } > > @@ -220,6 +223,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > * @peer_spad_addr: See ntb_peer_spad_addr(). > * @peer_spad_read: See ntb_peer_spad_read(). > * @peer_spad_write: See ntb_peer_spad_write(). > + * @msg_count: See ntb_msg_count(). > + * @msg_inbits: See ntb_msg_inbits(). > + * @msg_outbits: See ntb_msg_outbits(). > + * @msg_read_sts: See ntb_msg_read_sts(). > + * @msg_clear_sts: See ntb_msg_clear_sts(). > + * @msg_set_mask: See ntb_msg_set_mask(). > + * @msg_clear_mask: See ntb_msg_clear_mask(). > + * @msg_read: See ntb_msg_read(). > + * @msg_write: See ntb_msg_write(). > */ > struct ntb_dev_ops { > int (*port_number)(struct ntb_dev *ntb); > @@ -282,6 +294,16 @@ struct ntb_dev_ops { > u32 (*peer_spad_read)(struct ntb_dev *ntb, int pidx, int sidx); > int (*peer_spad_write)(struct ntb_dev *ntb, int pidx, int sidx, > u32 val); > + > + int (*msg_count)(struct ntb_dev *ntb); > + u64 (*msg_inbits)(struct ntb_dev *ntb); > + u64 (*msg_outbits)(struct ntb_dev *ntb); > + u64 (*msg_read_sts)(struct ntb_dev *ntb); > + int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits); > + int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits); > + int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits); > + int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg); > + int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg); > }; > > static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) > @@ -329,6 +351,15 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) > /* !ops->peer_spad_addr == !ops->spad_count && */ > /* !ops->peer_spad_read == !ops->spad_count && */ > !ops->peer_spad_write == !ops->spad_count && > + > + !ops->msg_inbits == !ops->msg_count && > + !ops->msg_outbits == !ops->msg_count && > + !ops->msg_read_sts == !ops->msg_count && > + !ops->msg_clear_sts == !ops->msg_count && > + /* !ops->msg_set_mask == !ops->msg_count && */ > + /* !ops->msg_clear_mask == !ops->msg_count && */ > + !ops->msg_read == !ops->msg_count && > + !ops->msg_write == !ops->msg_count && > 1; > } > > @@ -472,6 +503,18 @@ void ntb_link_event(struct ntb_dev *ntb); > void ntb_db_event(struct ntb_dev *ntb, int vector); > > /** > + * ntb_msg_event() - notify driver context of a message event > + * @ntb: NTB device context. > + * > + * Notify the driver context of a message event. If hardware supports > + * message registers, this event indicates, that a new message arrived in > + * some incoming message register or last sent message couldn't be delivered. > + * The events can be masked/unmasked by the methods ntb_msg_set_mask() and > + * ntb_msg_clear_mask(). > + */ > +void ntb_msg_event(struct ntb_dev *ntb); > + > +/** > * ntb_port_number() - get the local port number > * @ntb: NTB device context. > * > @@ -1197,4 +1240,166 @@ static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int > pidx, int sidx, > return ntb->ops->peer_spad_write(ntb, pidx, sidx, val); > } > > +/** > + * ntb_msg_count() - get the number of message registers > + * @ntb: NTB device context. > + * > + * Hardware may support a different number of messge registers. > + * > + * Return: the number of message registers. > + */ > +static inline int ntb_msg_count(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_count) > + return 0; > + > + return ntb->ops->msg_count(ntb); > +} > + > +/** > + * ntb_msg_inbits() - get a bitsfield of inbound message registers status > + * @ntb: NTB device context. > + * > + * The method returns the bitsfield of status and mask registers, which related > + * to inbound message registers. > + * > + * Return: bitsfield of inbound message registers. > + */ > +static inline u64 ntb_msg_inbits(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_inbits) > + return 0; > + > + return ntb->ops->msg_inbits(ntb); > +} > + > +/** > + * ntb_msg_outbits() - get a bitsfield of outbound message registers status > + * @ntb: NTB device context. > + * > + * The method returns the bitsfield of status and mask registers, which related > + * to outbound message registers. > + * > + * Return: bitsfield of outbound message registers. > + */ > +static inline u64 ntb_msg_outbits(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_outbits) > + return 0; > + > + return ntb->ops->msg_outbits(ntb); > +} > + > +/** > + * ntb_msg_read_sts() - read the message registers status > + * @ntb: NTB device context. > + * > + * Read the status of message register. Inbound and outbound message registers > + * related bits can be filetered by masks retrieved from ntb_msg_inbits() and > + * ntb_msg_outbits(). > + * > + * Return: status bits of message registers > + */ > +static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_read_sts) > + return 0; > + > + return ntb->ops->msg_read_sts(ntb); > +} > + > +/** > + * ntb_msg_clear_sts() - clear status bits of message registers > + * @ntb: NTB device context. > + * @sts_bits: Status bits to clear. > + * > + * Clear bits in the status register. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits) > +{ > + if (!ntb->ops->msg_clear_sts) > + return -EINVAL; > + > + return ntb->ops->msg_clear_sts(ntb, sts_bits); > +} > + > +/** > + * ntb_msg_set_mask() - set mask of message register status bits > + * @ntb: NTB device context. > + * @mask_bits: Mask bits. > + * > + * Mask the message registers status bits from raising the message event. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits) > +{ > + if (!ntb->ops->msg_set_mask) > + return -EINVAL; > + > + return ntb->ops->msg_set_mask(ntb, mask_bits); > +} > + > +/** > + * ntb_msg_clear_mask() - clear message registers mask > + * @ntb: NTB device context. > + * @mask_bits: Mask bits to clear. > + * > + * Clear bits in the message events mask register. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits) > +{ > + if (!ntb->ops->msg_clear_mask) > + return -EINVAL; > + > + return ntb->ops->msg_clear_mask(ntb, mask_bits); > +} > + > +/** > + * ntb_msg_read() - read message register with specified index > + * @ntb: NTB device context. > + * @midx: Message register index > + * @pidx: OUT - Port index of peer device a message retrieved from > + * @msg: OUT - Data > + * > + * Read data from the specified message register. Source port index of a > + * message is retrieved as well. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, > + u32 *msg) > +{ > + if (!ntb->ops->msg_read) > + return -EINVAL; > + > + return ntb->ops->msg_read(ntb, midx, pidx, msg); > +} > + > +/** > + * ntb_msg_write() - write data to the specified message register > + * @ntb: NTB device context. > + * @midx: Message register index > + * @pidx: Port index of peer device a message being sent to > + * @msg: Data to send > + * > + * Send data to a specified peer device using the defined message register. > + * Message event can be raised if the midx registers isn't empty while > + * calling this method and the corresponding interrupt isn't masked. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx, > + u32 msg) > +{ > + if (!ntb->ops->msg_write) > + return -EINVAL; > + > + return ntb->ops->msg_write(ntb, midx, pidx, msg); > +} > + > #endif > -- > 2.6.6