diff --git a/doc/guides/cryptodevs/features/mlx5.ini b/doc/guides/cryptodevs/features/mlx5.ini
index 0d210b2114..9bf1defac8 100644
--- a/doc/guides/cryptodevs/features/mlx5.ini
+++ b/doc/guides/cryptodevs/features/mlx5.ini
@@ -30,6 +30,8 @@ AES XTS (256)  = Y
 ; Supported AEAD algorithms of a mlx5 crypto driver.
 ;
 [AEAD]
+AES GCM (128)  = Y
+AES GCM (256)  = Y
 
 ;
 ; Supported Asymmetric algorithms of a mlx5 crypto driver.
diff --git a/doc/guides/cryptodevs/mlx5.rst b/doc/guides/cryptodevs/mlx5.rst
index b35ac5f5f2..9a0ae8b0d2 100644
--- a/doc/guides/cryptodevs/mlx5.rst
+++ b/doc/guides/cryptodevs/mlx5.rst
@@ -21,6 +21,11 @@ and **NVIDIA BlueField-3** family adapters.
 Overview
 --------
 
+Nvidia MLX5 crypto driver supports AES-XTs and AES-GCM cryption.
+
+AES-XTS
+-------
+
 The device can provide disk encryption services,
 allowing data encryption and decryption towards a disk.
 Having all encryption/decryption operations done in a single device
@@ -38,13 +43,19 @@ The encryption does not require text to be aligned to the AES block size (128b).
 
 See :doc:`../../platform/mlx5` guide for more design details.
 
+AES-GCM
+-------
+The encryption and decryption processes the traffic as standard RTE crypto
+API defines. The supported AAD/digest/key size can be read from dev_info.
+
+
 Configuration
 -------------
 
 See the :ref:`mlx5 common configuration <mlx5_common_env>`.
 
 A device comes out of NVIDIA factory with pre-defined import methods.
-There are two possible import methods: wrapped or plaintext.
+There are two possible import methods: wrapped or plaintext(valid to AES-XTS only).
 
 In case the device is in wrapped mode, it needs to be moved to crypto operational mode.
 In order to move the device to crypto operational mode, credential and KEK
@@ -120,24 +131,36 @@ Driver options
 Please refer to :ref:`mlx5 common options <mlx5_common_driver_options>`
 for an additional list of options shared with other mlx5 drivers.
 
+- ``algo`` parameter [int]
+
+  - 0. AES-XTS crypto.
+
+  - 1. AES-GCM crypto.
+
+  Set to zero(AES-XTS) by default.
+
 - ``wcs_file`` parameter [string] - mandatory in wrapped mode
 
   File path including only the wrapped credential in string format of hexadecimal
   numbers, represent 48 bytes (8 bytes IV added by the AES key wrap algorithm).
+  This option is valid only to AES-XTS.
 
 - ``import_kek_id`` parameter [int]
 
   The identifier of the KEK, default value is 0 represents the operational
   register import_kek..
+  This option is valid only to AES-XTS.
 
 - ``credential_id`` parameter [int]
 
   The identifier of the credential, default value is 0 represents the operational
   register credential.
+  This option is valid only to AES-XTS.
 
 - ``keytag`` parameter [int]
 
   The plaintext of the keytag appended to the AES-XTS keys, default value is 0.
+  This option is valid only to AES-XTS.
 
 - ``max_segs_num`` parameter [int]
 
@@ -161,6 +184,8 @@ Limitations
 - The supported data-unit lengths are 512B and 4KB and 1MB. In case the `dataunit_len`
   is not provided in the cipher xform, the OP length is limited to the above
   values.
+- AES-GCM is only supported on BlueField-3.
+- AES-GCM only supported key import plaintext mode.
 
 
 Prerequisites
@@ -172,6 +197,7 @@ FW Prerequisites
 - xx.31.0328 for ConnectX-6.
 - xx.32.0108 for ConnectX-6 Dx and BlueField-2.
 - xx.36.xxxx for ConnectX-7 and BlueField-3.
+- xx.37.3010 for BlueField-3 and newer for AES-GCM.
 
 Linux Prerequisites
 ~~~~~~~~~~~~~~~~~~~
@@ -186,3 +212,23 @@ Windows Prerequisites
 
 - NVIDIA WINOF-2 version: **2.60** or higher.
   See :ref:`mlx5 common prerequisites <mlx5_windows_prerequisites>` for more details.
+
+
+Notes for rte_crypto AES-GCM
+----------------------------
+
+In AES-GCM mode, the HW requires continuous input and output of Additional
+Authenticated Data (AAD), payload, and digest (if needed). However, the RTE
+API only provides a single AAD input, which means that in the out-of-place
+mode, the AAD will be used in both input and output. This reuse of AAD in the
+out-of-place mode breaks the continuous output, which degrades the performance
+and introduces extra UMR WQE. If digest is not continuous after payload will
+also lead to that extra UMR WQE.
+
+To address this issue, current RTE API provides min_mbuf_headroom_req and
+min_mbuf_tailroom_req in rte_cryptodev_info as a hint to the PMD. It
+indicates the PMD can use the buffer before and after the mbuf payload as AAD
+and digest space. With this hint, the PMD will use the buffer before and
+after the mbuf payload directly via copying AAD and digest. However, the
+application must ensure that there is enough headroom and tailroom reserved
+for the mbuf. Or, for non-continuous operations, extra UMR WQE will be used.
diff --git a/doc/guides/rel_notes/release_23_07.rst b/doc/guides/rel_notes/release_23_07.rst
index 027ae7bd2d..bbb8eddbca 100644
--- a/doc/guides/rel_notes/release_23_07.rst
+++ b/doc/guides/rel_notes/release_23_07.rst
@@ -131,6 +131,7 @@ New Features
   * Added support for CQE compression on Windows.
   * Added support for enhanced multi-packet write on Windows.
   * Added support for quota flow action and item.
+  * Added support for AES-GCM crypto.
 
 * **Added vmxnet3 version 7 support.**
 
diff --git a/drivers/crypto/mlx5/mlx5_crypto.c b/drivers/crypto/mlx5/mlx5_crypto.c
index 4d7d3ef2a3..081e96ad4d 100644
--- a/drivers/crypto/mlx5/mlx5_crypto.c
+++ b/drivers/crypto/mlx5/mlx5_crypto.c
@@ -269,6 +269,14 @@ mlx5_crypto_args_check_handler(const char *key, const char *val, void *opaque)
 		attr->credential_pointer = (uint32_t)tmp;
 	} else if (strcmp(key, "keytag") == 0) {
 		devarg_prms->keytag = tmp;
+	} else if (strcmp(key, "algo") == 0) {
+		if (tmp == 1) {
+			devarg_prms->is_aes_gcm = 1;
+		} else if (tmp > 1) {
+			DRV_LOG(ERR, "Invalid algo.");
+			rte_errno = EINVAL;
+			return -rte_errno;
+		}
 	}
 	return 0;
 }
@@ -285,6 +293,7 @@ mlx5_crypto_parse_devargs(struct mlx5_kvargs_ctrl *mkvlist,
 		"keytag",
 		"max_segs_num",
 		"wcs_file",
+		"algo",
 		NULL,
 	};
 
@@ -370,10 +379,19 @@ mlx5_crypto_dev_probe(struct mlx5_common_device *cdev,
 	priv->crypto_dev = crypto_dev;
 	priv->is_wrapped_mode = wrapped_mode;
 	priv->max_segs_num = devarg_prms.max_segs_num;
-	ret = mlx5_crypto_xts_init(priv);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to init AES-XTS crypto.");
-		return -ENOTSUP;
+	/* Init and override AES-GCM configuration. */
+	if (devarg_prms.is_aes_gcm) {
+		ret = mlx5_crypto_gcm_init(priv);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to init AES-GCM crypto.");
+			return -ENOTSUP;
+		}
+	} else {
+		ret = mlx5_crypto_xts_init(priv);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to init AES-XTS crypto.");
+			return -ENOTSUP;
+		}
 	}
 	if (mlx5_devx_uar_prepare(cdev, &priv->uar) != 0) {
 		rte_cryptodev_pmd_destroy(priv->crypto_dev);
diff --git a/drivers/crypto/mlx5/mlx5_crypto.h b/drivers/crypto/mlx5/mlx5_crypto.h
index 6dcb41b27c..36dacdcda4 100644
--- a/drivers/crypto/mlx5/mlx5_crypto.h
+++ b/drivers/crypto/mlx5/mlx5_crypto.h
@@ -92,6 +92,7 @@ struct mlx5_crypto_devarg_params {
 	struct mlx5_devx_crypto_login_attr login_attr;
 	uint64_t keytag;
 	uint32_t max_segs_num;
+	uint32_t is_aes_gcm:1;
 };
 
 struct mlx5_crypto_session {
diff --git a/drivers/crypto/mlx5/mlx5_crypto_gcm.c b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
index 8389c03c91..e26a338365 100644
--- a/drivers/crypto/mlx5/mlx5_crypto_gcm.c
+++ b/drivers/crypto/mlx5/mlx5_crypto_gcm.c
@@ -109,6 +109,60 @@ mlx5_crypto_dek_fill_gcm_attr(struct mlx5_crypto_dek *dek,
 	return 0;
 }
 
+static int
+mlx5_crypto_generate_gcm_cap(struct mlx5_hca_crypto_mmo_attr *mmo_attr,
+			     struct rte_cryptodev_capabilities *cap)
+{
+	/* Init key size. */
+	if (mmo_attr->gcm_128_encrypt && mmo_attr->gcm_128_decrypt &&
+		mmo_attr->gcm_256_encrypt && mmo_attr->gcm_256_decrypt) {
+		cap->sym.aead.key_size.min = 16;
+		cap->sym.aead.key_size.max = 32;
+		cap->sym.aead.key_size.increment = 16;
+	} else if (mmo_attr->gcm_256_encrypt && mmo_attr->gcm_256_decrypt) {
+		cap->sym.aead.key_size.min = 32;
+		cap->sym.aead.key_size.max = 32;
+		cap->sym.aead.key_size.increment = 0;
+	} else if (mmo_attr->gcm_128_encrypt && mmo_attr->gcm_128_decrypt) {
+		cap->sym.aead.key_size.min = 16;
+		cap->sym.aead.key_size.max = 16;
+		cap->sym.aead.key_size.increment = 0;
+	} else {
+		DRV_LOG(ERR, "No available AES-GCM encryption/decryption supported.");
+		return -1;
+	}
+	/* Init tag size. */
+	if (mmo_attr->gcm_auth_tag_128 && mmo_attr->gcm_auth_tag_96) {
+		cap->sym.aead.digest_size.min = 12;
+		cap->sym.aead.digest_size.max = 16;
+		cap->sym.aead.digest_size.increment = 4;
+	} else if (mmo_attr->gcm_auth_tag_96) {
+		cap->sym.aead.digest_size.min = 12;
+		cap->sym.aead.digest_size.max = 12;
+		cap->sym.aead.digest_size.increment = 0;
+	} else if (mmo_attr->gcm_auth_tag_128) {
+		cap->sym.aead.digest_size.min = 16;
+		cap->sym.aead.digest_size.max = 16;
+		cap->sym.aead.digest_size.increment = 0;
+	} else {
+		DRV_LOG(ERR, "No available AES-GCM tag size supported.");
+		return -1;
+	}
+	/* Init AAD size. */
+	cap->sym.aead.aad_size.min = 0;
+	cap->sym.aead.aad_size.max = UINT16_MAX;
+	cap->sym.aead.aad_size.increment = 1;
+	/* Init IV size. */
+	cap->sym.aead.iv_size.min = 12;
+	cap->sym.aead.iv_size.max = 12;
+	cap->sym.aead.iv_size.increment = 0;
+	/* Init left items. */
+	cap->op = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
+	cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD;
+	cap->sym.aead.algo = RTE_CRYPTO_AEAD_AES_GCM;
+	return 0;
+}
+
 static int
 mlx5_crypto_sym_gcm_session_configure(struct rte_cryptodev *dev,
 				  struct rte_crypto_sym_xform *xform,
@@ -917,8 +971,10 @@ mlx5_crypto_gcm_dequeue_burst(void *queue_pair,
 int
 mlx5_crypto_gcm_init(struct mlx5_crypto_priv *priv)
 {
+	struct mlx5_common_device *cdev = priv->cdev;
 	struct rte_cryptodev *crypto_dev = priv->crypto_dev;
 	struct rte_cryptodev_ops *dev_ops = crypto_dev->dev_ops;
+	int ret;
 
 	/* Override AES-GCM specified ops. */
 	dev_ops->sym_session_configure = mlx5_crypto_sym_gcm_session_configure;
@@ -928,6 +984,13 @@ mlx5_crypto_gcm_init(struct mlx5_crypto_priv *priv)
 	crypto_dev->dequeue_burst = mlx5_crypto_gcm_dequeue_burst;
 	crypto_dev->enqueue_burst = mlx5_crypto_gcm_enqueue_burst;
 	priv->max_klm_num = RTE_ALIGN((priv->max_segs_num + 1) * 2 + 1, MLX5_UMR_KLM_NUM_ALIGN);
+	/* Generate GCM capability. */
+	ret = mlx5_crypto_generate_gcm_cap(&cdev->config.hca_attr.crypto_mmo,
+					   mlx5_crypto_gcm_caps);
+	if (ret) {
+		DRV_LOG(ERR, "No enough AES-GCM cap.");
+		return -1;
+	}
 	priv->caps = mlx5_crypto_gcm_caps;
 	return 0;
 }
